Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  *  linux/drivers/video/pm3fb.c -- 3DLabs Permedia3 frame buffer device
0003  *
0004  *  Copyright (C) 2001 Romain Dolbeau <romain@dolbeau.org>.
0005  *
0006  *  Ported to 2.6 kernel on 1 May 2007 by Krzysztof Helt <krzysztof.h1@wp.pl>
0007  *  based on pm2fb.c
0008  *
0009  *  Based on code written by:
0010  *     Sven Luther, <luther@dpt-info.u-strasbg.fr>
0011  *     Alan Hourihane, <alanh@fairlite.demon.co.uk>
0012  *     Russell King, <rmk@arm.linux.org.uk>
0013  *  Based on linux/drivers/video/skeletonfb.c:
0014  *  Copyright (C) 1997 Geert Uytterhoeven
0015  *  Based on linux/driver/video/pm2fb.c:
0016  *  Copyright (C) 1998-1999 Ilario Nardinocchi (nardinoc@CS.UniBO.IT)
0017  *  Copyright (C) 1999 Jakub Jelinek (jakub@redhat.com)
0018  *
0019  *  This file is subject to the terms and conditions of the GNU General Public
0020  *  License. See the file COPYING in the main directory of this archive for
0021  *  more details.
0022  *
0023  */
0024 
0025 #include <linux/module.h>
0026 #include <linux/kernel.h>
0027 #include <linux/errno.h>
0028 #include <linux/string.h>
0029 #include <linux/mm.h>
0030 #include <linux/slab.h>
0031 #include <linux/delay.h>
0032 #include <linux/fb.h>
0033 #include <linux/init.h>
0034 #include <linux/pci.h>
0035 
0036 #include <video/pm3fb.h>
0037 
0038 #if !defined(CONFIG_PCI)
0039 #error "Only generic PCI cards supported."
0040 #endif
0041 
0042 #undef PM3FB_MASTER_DEBUG
0043 #ifdef PM3FB_MASTER_DEBUG
0044 #define DPRINTK(a, b...)    \
0045     printk(KERN_DEBUG "pm3fb: %s: " a, __func__ , ## b)
0046 #else
0047 #define DPRINTK(a, b...)    no_printk(a, ##b)
0048 #endif
0049 
0050 #define PM3_PIXMAP_SIZE (2048 * 4)
0051 
0052 /*
0053  * Driver data
0054  */
0055 static int hwcursor = 1;
0056 static char *mode_option;
0057 static bool noaccel;
0058 static bool nomtrr;
0059 
0060 /*
0061  * This structure defines the hardware state of the graphics card. Normally
0062  * you place this in a header file in linux/include/video. This file usually
0063  * also includes register information. That allows other driver subsystems
0064  * and userland applications the ability to use the same header file to
0065  * avoid duplicate work and easy porting of software.
0066  */
0067 struct pm3_par {
0068     unsigned char   __iomem *v_regs;/* virtual address of p_regs */
0069     u32     video;      /* video flags before blanking */
0070     u32     base;       /* screen base in 128 bits unit */
0071     u32     palette[16];
0072     int     wc_cookie;
0073 };
0074 
0075 /*
0076  * Here we define the default structs fb_fix_screeninfo and fb_var_screeninfo
0077  * if we don't use modedb. If we do use modedb see pm3fb_init how to use it
0078  * to get a fb_var_screeninfo. Otherwise define a default var as well.
0079  */
0080 static struct fb_fix_screeninfo pm3fb_fix = {
0081     .id =       "Permedia3",
0082     .type =     FB_TYPE_PACKED_PIXELS,
0083     .visual =   FB_VISUAL_PSEUDOCOLOR,
0084     .xpanstep = 1,
0085     .ypanstep = 1,
0086     .ywrapstep =    0,
0087     .accel =    FB_ACCEL_3DLABS_PERMEDIA3,
0088 };
0089 
0090 /*
0091  * Utility functions
0092  */
0093 
0094 static inline u32 PM3_READ_REG(struct pm3_par *par, s32 off)
0095 {
0096     return fb_readl(par->v_regs + off);
0097 }
0098 
0099 static inline void PM3_WRITE_REG(struct pm3_par *par, s32 off, u32 v)
0100 {
0101     fb_writel(v, par->v_regs + off);
0102 }
0103 
0104 static inline void PM3_WAIT(struct pm3_par *par, u32 n)
0105 {
0106     while (PM3_READ_REG(par, PM3InFIFOSpace) < n)
0107         cpu_relax();
0108 }
0109 
0110 static inline void PM3_WRITE_DAC_REG(struct pm3_par *par, unsigned r, u8 v)
0111 {
0112     PM3_WAIT(par, 3);
0113     PM3_WRITE_REG(par, PM3RD_IndexHigh, (r >> 8) & 0xff);
0114     PM3_WRITE_REG(par, PM3RD_IndexLow, r & 0xff);
0115     wmb();
0116     PM3_WRITE_REG(par, PM3RD_IndexedData, v);
0117     wmb();
0118 }
0119 
0120 static inline void pm3fb_set_color(struct pm3_par *par, unsigned char regno,
0121             unsigned char r, unsigned char g, unsigned char b)
0122 {
0123     PM3_WAIT(par, 4);
0124     PM3_WRITE_REG(par, PM3RD_PaletteWriteAddress, regno);
0125     wmb();
0126     PM3_WRITE_REG(par, PM3RD_PaletteData, r);
0127     wmb();
0128     PM3_WRITE_REG(par, PM3RD_PaletteData, g);
0129     wmb();
0130     PM3_WRITE_REG(par, PM3RD_PaletteData, b);
0131     wmb();
0132 }
0133 
0134 static void pm3fb_clear_colormap(struct pm3_par *par,
0135             unsigned char r, unsigned char g, unsigned char b)
0136 {
0137     int i;
0138 
0139     for (i = 0; i < 256 ; i++)
0140         pm3fb_set_color(par, i, r, g, b);
0141 
0142 }
0143 
0144 /* Calculating various clock parameters */
0145 static void pm3fb_calculate_clock(unsigned long reqclock,
0146                 unsigned char *prescale,
0147                 unsigned char *feedback,
0148                 unsigned char *postscale)
0149 {
0150     int f, pre, post;
0151     unsigned long freq;
0152     long freqerr = 1000;
0153     long currerr;
0154 
0155     for (f = 1; f < 256; f++) {
0156         for (pre = 1; pre < 256; pre++) {
0157             for (post = 0; post < 5; post++) {
0158                 freq = ((2*PM3_REF_CLOCK * f) >> post) / pre;
0159                 currerr = (reqclock > freq)
0160                     ? reqclock - freq
0161                     : freq - reqclock;
0162                 if (currerr < freqerr) {
0163                     freqerr = currerr;
0164                     *feedback = f;
0165                     *prescale = pre;
0166                     *postscale = post;
0167                 }
0168             }
0169         }
0170     }
0171 }
0172 
0173 static inline int pm3fb_depth(const struct fb_var_screeninfo *var)
0174 {
0175     if (var->bits_per_pixel == 16)
0176         return var->red.length + var->green.length
0177             + var->blue.length;
0178 
0179     return var->bits_per_pixel;
0180 }
0181 
0182 static inline int pm3fb_shift_bpp(unsigned bpp, int v)
0183 {
0184     switch (bpp) {
0185     case 8:
0186         return (v >> 4);
0187     case 16:
0188         return (v >> 3);
0189     case 32:
0190         return (v >> 2);
0191     }
0192     DPRINTK("Unsupported depth %u\n", bpp);
0193     return 0;
0194 }
0195 
0196 /* acceleration */
0197 static int pm3fb_sync(struct fb_info *info)
0198 {
0199     struct pm3_par *par = info->par;
0200 
0201     PM3_WAIT(par, 2);
0202     PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync);
0203     PM3_WRITE_REG(par, PM3Sync, 0);
0204     mb();
0205     do {
0206         while ((PM3_READ_REG(par, PM3OutFIFOWords)) == 0)
0207             cpu_relax();
0208     } while ((PM3_READ_REG(par, PM3OutputFifo)) != PM3Sync_Tag);
0209 
0210     return 0;
0211 }
0212 
0213 static void pm3fb_init_engine(struct fb_info *info)
0214 {
0215     struct pm3_par *par = info->par;
0216     const u32 width = (info->var.xres_virtual + 7) & ~7;
0217 
0218     PM3_WAIT(par, 50);
0219     PM3_WRITE_REG(par, PM3FilterMode, PM3FilterModeSync);
0220     PM3_WRITE_REG(par, PM3StatisticMode, 0x0);
0221     PM3_WRITE_REG(par, PM3DeltaMode, 0x0);
0222     PM3_WRITE_REG(par, PM3RasterizerMode, 0x0);
0223     PM3_WRITE_REG(par, PM3ScissorMode, 0x0);
0224     PM3_WRITE_REG(par, PM3LineStippleMode, 0x0);
0225     PM3_WRITE_REG(par, PM3AreaStippleMode, 0x0);
0226     PM3_WRITE_REG(par, PM3GIDMode, 0x0);
0227     PM3_WRITE_REG(par, PM3DepthMode, 0x0);
0228     PM3_WRITE_REG(par, PM3StencilMode, 0x0);
0229     PM3_WRITE_REG(par, PM3StencilData, 0x0);
0230     PM3_WRITE_REG(par, PM3ColorDDAMode, 0x0);
0231     PM3_WRITE_REG(par, PM3TextureCoordMode, 0x0);
0232     PM3_WRITE_REG(par, PM3TextureIndexMode0, 0x0);
0233     PM3_WRITE_REG(par, PM3TextureIndexMode1, 0x0);
0234     PM3_WRITE_REG(par, PM3TextureReadMode, 0x0);
0235     PM3_WRITE_REG(par, PM3LUTMode, 0x0);
0236     PM3_WRITE_REG(par, PM3TextureFilterMode, 0x0);
0237     PM3_WRITE_REG(par, PM3TextureCompositeMode, 0x0);
0238     PM3_WRITE_REG(par, PM3TextureApplicationMode, 0x0);
0239     PM3_WRITE_REG(par, PM3TextureCompositeColorMode1, 0x0);
0240     PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode1, 0x0);
0241     PM3_WRITE_REG(par, PM3TextureCompositeColorMode0, 0x0);
0242     PM3_WRITE_REG(par, PM3TextureCompositeAlphaMode0, 0x0);
0243     PM3_WRITE_REG(par, PM3FogMode, 0x0);
0244     PM3_WRITE_REG(par, PM3ChromaTestMode, 0x0);
0245     PM3_WRITE_REG(par, PM3AlphaTestMode, 0x0);
0246     PM3_WRITE_REG(par, PM3AntialiasMode, 0x0);
0247     PM3_WRITE_REG(par, PM3YUVMode, 0x0);
0248     PM3_WRITE_REG(par, PM3AlphaBlendColorMode, 0x0);
0249     PM3_WRITE_REG(par, PM3AlphaBlendAlphaMode, 0x0);
0250     PM3_WRITE_REG(par, PM3DitherMode, 0x0);
0251     PM3_WRITE_REG(par, PM3LogicalOpMode, 0x0);
0252     PM3_WRITE_REG(par, PM3RouterMode, 0x0);
0253     PM3_WRITE_REG(par, PM3Window, 0x0);
0254 
0255     PM3_WRITE_REG(par, PM3Config2D, 0x0);
0256 
0257     PM3_WRITE_REG(par, PM3SpanColorMask, 0xffffffff);
0258 
0259     PM3_WRITE_REG(par, PM3XBias, 0x0);
0260     PM3_WRITE_REG(par, PM3YBias, 0x0);
0261     PM3_WRITE_REG(par, PM3DeltaControl, 0x0);
0262 
0263     PM3_WRITE_REG(par, PM3BitMaskPattern, 0xffffffff);
0264 
0265     PM3_WRITE_REG(par, PM3FBDestReadEnables,
0266                PM3FBDestReadEnables_E(0xff) |
0267                PM3FBDestReadEnables_R(0xff) |
0268                PM3FBDestReadEnables_ReferenceAlpha(0xff));
0269     PM3_WRITE_REG(par, PM3FBDestReadBufferAddr0, 0x0);
0270     PM3_WRITE_REG(par, PM3FBDestReadBufferOffset0, 0x0);
0271     PM3_WRITE_REG(par, PM3FBDestReadBufferWidth0,
0272                PM3FBDestReadBufferWidth_Width(width));
0273 
0274     PM3_WRITE_REG(par, PM3FBDestReadMode,
0275                PM3FBDestReadMode_ReadEnable |
0276                PM3FBDestReadMode_Enable0);
0277     PM3_WRITE_REG(par, PM3FBSourceReadBufferAddr, 0x0);
0278     PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset, 0x0);
0279     PM3_WRITE_REG(par, PM3FBSourceReadBufferWidth,
0280                PM3FBSourceReadBufferWidth_Width(width));
0281     PM3_WRITE_REG(par, PM3FBSourceReadMode,
0282                PM3FBSourceReadMode_Blocking |
0283                PM3FBSourceReadMode_ReadEnable);
0284 
0285     PM3_WAIT(par, 2);
0286     {
0287         /* invert bits in bitmask */
0288         unsigned long rm = 1 | (3 << 7);
0289         switch (info->var.bits_per_pixel) {
0290         case 8:
0291             PM3_WRITE_REG(par, PM3PixelSize,
0292                        PM3PixelSize_GLOBAL_8BIT);
0293 #ifdef __BIG_ENDIAN
0294             rm |= 3 << 15;
0295 #endif
0296             break;
0297         case 16:
0298             PM3_WRITE_REG(par, PM3PixelSize,
0299                        PM3PixelSize_GLOBAL_16BIT);
0300 #ifdef __BIG_ENDIAN
0301             rm |= 2 << 15;
0302 #endif
0303             break;
0304         case 32:
0305             PM3_WRITE_REG(par, PM3PixelSize,
0306                        PM3PixelSize_GLOBAL_32BIT);
0307             break;
0308         default:
0309             DPRINTK("Unsupported depth %d\n",
0310                 info->var.bits_per_pixel);
0311             break;
0312         }
0313         PM3_WRITE_REG(par, PM3RasterizerMode, rm);
0314     }
0315 
0316     PM3_WAIT(par, 20);
0317     PM3_WRITE_REG(par, PM3FBSoftwareWriteMask, 0xffffffff);
0318     PM3_WRITE_REG(par, PM3FBHardwareWriteMask, 0xffffffff);
0319     PM3_WRITE_REG(par, PM3FBWriteMode,
0320                PM3FBWriteMode_WriteEnable |
0321                PM3FBWriteMode_OpaqueSpan |
0322                PM3FBWriteMode_Enable0);
0323     PM3_WRITE_REG(par, PM3FBWriteBufferAddr0, 0x0);
0324     PM3_WRITE_REG(par, PM3FBWriteBufferOffset0, 0x0);
0325     PM3_WRITE_REG(par, PM3FBWriteBufferWidth0,
0326                PM3FBWriteBufferWidth_Width(width));
0327 
0328     PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 0x0);
0329     {
0330         /* size in lines of FB */
0331         unsigned long sofb = info->screen_size /
0332             info->fix.line_length;
0333         if (sofb > 4095)
0334             PM3_WRITE_REG(par, PM3SizeOfFramebuffer, 4095);
0335         else
0336             PM3_WRITE_REG(par, PM3SizeOfFramebuffer, sofb);
0337 
0338         switch (info->var.bits_per_pixel) {
0339         case 8:
0340             PM3_WRITE_REG(par, PM3DitherMode,
0341                        (1 << 10) | (2 << 3));
0342             break;
0343         case 16:
0344             PM3_WRITE_REG(par, PM3DitherMode,
0345                        (1 << 10) | (1 << 3));
0346             break;
0347         case 32:
0348             PM3_WRITE_REG(par, PM3DitherMode,
0349                        (1 << 10) | (0 << 3));
0350             break;
0351         default:
0352             DPRINTK("Unsupported depth %d\n",
0353                 info->var.bits_per_pixel);
0354             break;
0355         }
0356     }
0357 
0358     PM3_WRITE_REG(par, PM3dXDom, 0x0);
0359     PM3_WRITE_REG(par, PM3dXSub, 0x0);
0360     PM3_WRITE_REG(par, PM3dY, 1 << 16);
0361     PM3_WRITE_REG(par, PM3StartXDom, 0x0);
0362     PM3_WRITE_REG(par, PM3StartXSub, 0x0);
0363     PM3_WRITE_REG(par, PM3StartY, 0x0);
0364     PM3_WRITE_REG(par, PM3Count, 0x0);
0365 
0366 /* Disable LocalBuffer. better safe than sorry */
0367     PM3_WRITE_REG(par, PM3LBDestReadMode, 0x0);
0368     PM3_WRITE_REG(par, PM3LBDestReadEnables, 0x0);
0369     PM3_WRITE_REG(par, PM3LBSourceReadMode, 0x0);
0370     PM3_WRITE_REG(par, PM3LBWriteMode, 0x0);
0371 
0372     pm3fb_sync(info);
0373 }
0374 
0375 static void pm3fb_fillrect(struct fb_info *info,
0376                 const struct fb_fillrect *region)
0377 {
0378     struct pm3_par *par = info->par;
0379     struct fb_fillrect modded;
0380     int vxres, vyres;
0381     int rop;
0382     u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
0383         ((u32 *)info->pseudo_palette)[region->color] : region->color;
0384 
0385     if (info->state != FBINFO_STATE_RUNNING)
0386         return;
0387     if (info->flags & FBINFO_HWACCEL_DISABLED) {
0388         cfb_fillrect(info, region);
0389         return;
0390     }
0391     if (region->rop == ROP_COPY )
0392         rop = PM3Config2D_ForegroundROP(0x3); /* GXcopy */
0393     else
0394         rop = PM3Config2D_ForegroundROP(0x6) | /* GXxor */
0395             PM3Config2D_FBDestReadEnable;
0396 
0397     vxres = info->var.xres_virtual;
0398     vyres = info->var.yres_virtual;
0399 
0400     memcpy(&modded, region, sizeof(struct fb_fillrect));
0401 
0402     if (!modded.width || !modded.height ||
0403         modded.dx >= vxres || modded.dy >= vyres)
0404         return;
0405 
0406     if (modded.dx + modded.width  > vxres)
0407         modded.width  = vxres - modded.dx;
0408     if (modded.dy + modded.height > vyres)
0409         modded.height = vyres - modded.dy;
0410 
0411     if (info->var.bits_per_pixel == 8)
0412         color |= color << 8;
0413     if (info->var.bits_per_pixel <= 16)
0414         color |= color << 16;
0415 
0416     PM3_WAIT(par, 4);
0417     /* ROP Ox3 is GXcopy */
0418     PM3_WRITE_REG(par, PM3Config2D,
0419             PM3Config2D_UseConstantSource |
0420             PM3Config2D_ForegroundROPEnable |
0421             rop |
0422             PM3Config2D_FBWriteEnable);
0423 
0424     PM3_WRITE_REG(par, PM3ForegroundColor, color);
0425 
0426     PM3_WRITE_REG(par, PM3RectanglePosition,
0427             PM3RectanglePosition_XOffset(modded.dx) |
0428             PM3RectanglePosition_YOffset(modded.dy));
0429 
0430     PM3_WRITE_REG(par, PM3Render2D,
0431               PM3Render2D_XPositive |
0432               PM3Render2D_YPositive |
0433               PM3Render2D_Operation_Normal |
0434               PM3Render2D_SpanOperation |
0435               PM3Render2D_Width(modded.width) |
0436               PM3Render2D_Height(modded.height));
0437 }
0438 
0439 static void pm3fb_copyarea(struct fb_info *info,
0440                 const struct fb_copyarea *area)
0441 {
0442     struct pm3_par *par = info->par;
0443     struct fb_copyarea modded;
0444     u32 vxres, vyres;
0445     int x_align, o_x, o_y;
0446 
0447     if (info->state != FBINFO_STATE_RUNNING)
0448         return;
0449     if (info->flags & FBINFO_HWACCEL_DISABLED) {
0450         cfb_copyarea(info, area);
0451         return;
0452     }
0453 
0454     memcpy(&modded, area, sizeof(struct fb_copyarea));
0455 
0456     vxres = info->var.xres_virtual;
0457     vyres = info->var.yres_virtual;
0458 
0459     if (!modded.width || !modded.height ||
0460         modded.sx >= vxres || modded.sy >= vyres ||
0461         modded.dx >= vxres || modded.dy >= vyres)
0462         return;
0463 
0464     if (modded.sx + modded.width > vxres)
0465         modded.width = vxres - modded.sx;
0466     if (modded.dx + modded.width > vxres)
0467         modded.width = vxres - modded.dx;
0468     if (modded.sy + modded.height > vyres)
0469         modded.height = vyres - modded.sy;
0470     if (modded.dy + modded.height > vyres)
0471         modded.height = vyres - modded.dy;
0472 
0473     o_x = modded.sx - modded.dx;    /*(sx > dx ) ? (sx - dx) : (dx - sx); */
0474     o_y = modded.sy - modded.dy;    /*(sy > dy ) ? (sy - dy) : (dy - sy); */
0475 
0476     x_align = (modded.sx & 0x1f);
0477 
0478     PM3_WAIT(par, 6);
0479 
0480     PM3_WRITE_REG(par, PM3Config2D,
0481             PM3Config2D_UserScissorEnable |
0482             PM3Config2D_ForegroundROPEnable |
0483             PM3Config2D_Blocking |
0484             PM3Config2D_ForegroundROP(0x3) | /* Ox3 is GXcopy */
0485             PM3Config2D_FBWriteEnable);
0486 
0487     PM3_WRITE_REG(par, PM3ScissorMinXY,
0488             ((modded.dy & 0x0fff) << 16) | (modded.dx & 0x0fff));
0489     PM3_WRITE_REG(par, PM3ScissorMaxXY,
0490             (((modded.dy + modded.height) & 0x0fff) << 16) |
0491             ((modded.dx + modded.width) & 0x0fff));
0492 
0493     PM3_WRITE_REG(par, PM3FBSourceReadBufferOffset,
0494             PM3FBSourceReadBufferOffset_XOffset(o_x) |
0495             PM3FBSourceReadBufferOffset_YOffset(o_y));
0496 
0497     PM3_WRITE_REG(par, PM3RectanglePosition,
0498             PM3RectanglePosition_XOffset(modded.dx - x_align) |
0499             PM3RectanglePosition_YOffset(modded.dy));
0500 
0501     PM3_WRITE_REG(par, PM3Render2D,
0502             ((modded.sx > modded.dx) ? PM3Render2D_XPositive : 0) |
0503             ((modded.sy > modded.dy) ? PM3Render2D_YPositive : 0) |
0504             PM3Render2D_Operation_Normal |
0505             PM3Render2D_SpanOperation |
0506             PM3Render2D_FBSourceReadEnable |
0507             PM3Render2D_Width(modded.width + x_align) |
0508             PM3Render2D_Height(modded.height));
0509 }
0510 
0511 static void pm3fb_imageblit(struct fb_info *info, const struct fb_image *image)
0512 {
0513     struct pm3_par *par = info->par;
0514     u32 height = image->height;
0515     u32 fgx, bgx;
0516     const u32 *src = (const u32 *)image->data;
0517 
0518     if (info->state != FBINFO_STATE_RUNNING)
0519         return;
0520     if (info->flags & FBINFO_HWACCEL_DISABLED) {
0521         cfb_imageblit(info, image);
0522         return;
0523     }
0524     switch (info->fix.visual) {
0525     case FB_VISUAL_PSEUDOCOLOR:
0526         fgx = image->fg_color;
0527         bgx = image->bg_color;
0528         break;
0529     case FB_VISUAL_TRUECOLOR:
0530     default:
0531         fgx = par->palette[image->fg_color];
0532         bgx = par->palette[image->bg_color];
0533         break;
0534     }
0535     if (image->depth != 1) {
0536         cfb_imageblit(info, image);
0537         return;
0538     }
0539 
0540     if (info->var.bits_per_pixel == 8) {
0541         fgx |= fgx << 8;
0542         bgx |= bgx << 8;
0543     }
0544     if (info->var.bits_per_pixel <= 16) {
0545         fgx |= fgx << 16;
0546         bgx |= bgx << 16;
0547     }
0548 
0549     PM3_WAIT(par, 7);
0550 
0551     PM3_WRITE_REG(par, PM3ForegroundColor, fgx);
0552     PM3_WRITE_REG(par, PM3BackgroundColor, bgx);
0553 
0554     /* ROP Ox3 is GXcopy */
0555     PM3_WRITE_REG(par, PM3Config2D,
0556             PM3Config2D_UserScissorEnable |
0557             PM3Config2D_UseConstantSource |
0558             PM3Config2D_ForegroundROPEnable |
0559             PM3Config2D_ForegroundROP(0x3) |
0560             PM3Config2D_OpaqueSpan |
0561             PM3Config2D_FBWriteEnable);
0562     PM3_WRITE_REG(par, PM3ScissorMinXY,
0563             ((image->dy & 0x0fff) << 16) | (image->dx & 0x0fff));
0564     PM3_WRITE_REG(par, PM3ScissorMaxXY,
0565             (((image->dy + image->height) & 0x0fff) << 16) |
0566             ((image->dx + image->width) & 0x0fff));
0567     PM3_WRITE_REG(par, PM3RectanglePosition,
0568             PM3RectanglePosition_XOffset(image->dx) |
0569             PM3RectanglePosition_YOffset(image->dy));
0570     PM3_WRITE_REG(par, PM3Render2D,
0571             PM3Render2D_XPositive |
0572             PM3Render2D_YPositive |
0573             PM3Render2D_Operation_SyncOnBitMask |
0574             PM3Render2D_SpanOperation |
0575             PM3Render2D_Width(image->width) |
0576             PM3Render2D_Height(image->height));
0577 
0578 
0579     while (height--) {
0580         int width = ((image->width + 7) >> 3)
0581                 + info->pixmap.scan_align - 1;
0582         width >>= 2;
0583 
0584         while (width >= PM3_FIFO_SIZE) {
0585             int i = PM3_FIFO_SIZE - 1;
0586 
0587             PM3_WAIT(par, PM3_FIFO_SIZE);
0588             while (i--) {
0589                 PM3_WRITE_REG(par, PM3BitMaskPattern, *src);
0590                 src++;
0591             }
0592             width -= PM3_FIFO_SIZE - 1;
0593         }
0594 
0595         PM3_WAIT(par, width + 1);
0596         while (width--) {
0597             PM3_WRITE_REG(par, PM3BitMaskPattern, *src);
0598             src++;
0599         }
0600     }
0601 }
0602 /* end of acceleration functions */
0603 
0604 /*
0605  *  Hardware Cursor support.
0606  */
0607 static const u8 cursor_bits_lookup[16] = {
0608     0x00, 0x40, 0x10, 0x50, 0x04, 0x44, 0x14, 0x54,
0609     0x01, 0x41, 0x11, 0x51, 0x05, 0x45, 0x15, 0x55
0610 };
0611 
0612 static int pm3fb_cursor(struct fb_info *info, struct fb_cursor *cursor)
0613 {
0614     struct pm3_par *par = info->par;
0615     u8 mode;
0616 
0617     if (!hwcursor)
0618         return -EINVAL; /* just to force soft_cursor() call */
0619 
0620     /* Too large of a cursor or wrong bpp :-( */
0621     if (cursor->image.width > 64 ||
0622         cursor->image.height > 64 ||
0623         cursor->image.depth > 1)
0624         return -EINVAL;
0625 
0626     mode = PM3RD_CursorMode_TYPE_X;
0627     if (cursor->enable)
0628          mode |= PM3RD_CursorMode_CURSOR_ENABLE;
0629 
0630     PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, mode);
0631 
0632     /*
0633      * If the cursor is not be changed this means either we want the
0634      * current cursor state (if enable is set) or we want to query what
0635      * we can do with the cursor (if enable is not set)
0636      */
0637     if (!cursor->set)
0638         return 0;
0639 
0640     if (cursor->set & FB_CUR_SETPOS) {
0641         int x = cursor->image.dx - info->var.xoffset;
0642         int y = cursor->image.dy - info->var.yoffset;
0643 
0644         PM3_WRITE_DAC_REG(par, PM3RD_CursorXLow, x & 0xff);
0645         PM3_WRITE_DAC_REG(par, PM3RD_CursorXHigh, (x >> 8) & 0xf);
0646         PM3_WRITE_DAC_REG(par, PM3RD_CursorYLow, y & 0xff);
0647         PM3_WRITE_DAC_REG(par, PM3RD_CursorYHigh, (y >> 8) & 0xf);
0648     }
0649 
0650     if (cursor->set & FB_CUR_SETHOT) {
0651         PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotX,
0652                   cursor->hot.x & 0x3f);
0653         PM3_WRITE_DAC_REG(par, PM3RD_CursorHotSpotY,
0654                   cursor->hot.y & 0x3f);
0655     }
0656 
0657     if (cursor->set & FB_CUR_SETCMAP) {
0658         u32 fg_idx = cursor->image.fg_color;
0659         u32 bg_idx = cursor->image.bg_color;
0660         struct fb_cmap cmap = info->cmap;
0661 
0662         /* the X11 driver says one should use these color registers */
0663         PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(39),
0664                   cmap.red[fg_idx] >> 8 );
0665         PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(40),
0666                   cmap.green[fg_idx] >> 8 );
0667         PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(41),
0668                   cmap.blue[fg_idx] >> 8 );
0669 
0670         PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(42),
0671                   cmap.red[bg_idx] >> 8 );
0672         PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(43),
0673                   cmap.green[bg_idx] >> 8 );
0674         PM3_WRITE_DAC_REG(par, PM3RD_CursorPalette(44),
0675                   cmap.blue[bg_idx] >> 8 );
0676     }
0677 
0678     if (cursor->set & (FB_CUR_SETSHAPE | FB_CUR_SETIMAGE)) {
0679         u8 *bitmap = (u8 *)cursor->image.data;
0680         u8 *mask = (u8 *)cursor->mask;
0681         int i;
0682         int pos = PM3RD_CursorPattern(0);
0683 
0684         for (i = 0; i < cursor->image.height; i++) {
0685             int j = (cursor->image.width + 7) >> 3;
0686             int k = 8 - j;
0687 
0688             for (; j > 0; j--) {
0689                 u8 data = *bitmap ^ *mask;
0690 
0691                 if (cursor->rop == ROP_COPY)
0692                     data = *mask & *bitmap;
0693                 /* Upper 4 bits of bitmap data */
0694                 PM3_WRITE_DAC_REG(par, pos++,
0695                     cursor_bits_lookup[data >> 4] |
0696                     (cursor_bits_lookup[*mask >> 4] << 1));
0697                 /* Lower 4 bits of bitmap */
0698                 PM3_WRITE_DAC_REG(par, pos++,
0699                     cursor_bits_lookup[data & 0xf] |
0700                     (cursor_bits_lookup[*mask & 0xf] << 1));
0701                 bitmap++;
0702                 mask++;
0703             }
0704             for (; k > 0; k--) {
0705                 PM3_WRITE_DAC_REG(par, pos++, 0);
0706                 PM3_WRITE_DAC_REG(par, pos++, 0);
0707             }
0708         }
0709         while (pos < PM3RD_CursorPattern(1024))
0710             PM3_WRITE_DAC_REG(par, pos++, 0);
0711     }
0712     return 0;
0713 }
0714 
0715 /* write the mode to registers */
0716 static void pm3fb_write_mode(struct fb_info *info)
0717 {
0718     struct pm3_par *par = info->par;
0719     char tempsync = 0x00;
0720     char tempmisc = 0x00;
0721     const u32 hsstart = info->var.right_margin;
0722     const u32 hsend = hsstart + info->var.hsync_len;
0723     const u32 hbend = hsend + info->var.left_margin;
0724     const u32 xres = (info->var.xres + 31) & ~31;
0725     const u32 htotal = xres + hbend;
0726     const u32 vsstart = info->var.lower_margin;
0727     const u32 vsend = vsstart + info->var.vsync_len;
0728     const u32 vbend = vsend + info->var.upper_margin;
0729     const u32 vtotal = info->var.yres + vbend;
0730     const u32 width = (info->var.xres_virtual + 7) & ~7;
0731     const unsigned bpp = info->var.bits_per_pixel;
0732 
0733     PM3_WAIT(par, 20);
0734     PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xffffffff);
0735     PM3_WRITE_REG(par, PM3Aperture0, 0x00000000);
0736     PM3_WRITE_REG(par, PM3Aperture1, 0x00000000);
0737     PM3_WRITE_REG(par, PM3FIFODis, 0x00000007);
0738 
0739     PM3_WRITE_REG(par, PM3HTotal,
0740                pm3fb_shift_bpp(bpp, htotal - 1));
0741     PM3_WRITE_REG(par, PM3HsEnd,
0742                pm3fb_shift_bpp(bpp, hsend));
0743     PM3_WRITE_REG(par, PM3HsStart,
0744                pm3fb_shift_bpp(bpp, hsstart));
0745     PM3_WRITE_REG(par, PM3HbEnd,
0746                pm3fb_shift_bpp(bpp, hbend));
0747     PM3_WRITE_REG(par, PM3HgEnd,
0748                pm3fb_shift_bpp(bpp, hbend));
0749     PM3_WRITE_REG(par, PM3ScreenStride,
0750                pm3fb_shift_bpp(bpp, width));
0751     PM3_WRITE_REG(par, PM3VTotal, vtotal - 1);
0752     PM3_WRITE_REG(par, PM3VsEnd, vsend - 1);
0753     PM3_WRITE_REG(par, PM3VsStart, vsstart - 1);
0754     PM3_WRITE_REG(par, PM3VbEnd, vbend);
0755 
0756     switch (bpp) {
0757     case 8:
0758         PM3_WRITE_REG(par, PM3ByAperture1Mode,
0759                    PM3ByApertureMode_PIXELSIZE_8BIT);
0760         PM3_WRITE_REG(par, PM3ByAperture2Mode,
0761                    PM3ByApertureMode_PIXELSIZE_8BIT);
0762         break;
0763 
0764     case 16:
0765 #ifndef __BIG_ENDIAN
0766         PM3_WRITE_REG(par, PM3ByAperture1Mode,
0767                    PM3ByApertureMode_PIXELSIZE_16BIT);
0768         PM3_WRITE_REG(par, PM3ByAperture2Mode,
0769                    PM3ByApertureMode_PIXELSIZE_16BIT);
0770 #else
0771         PM3_WRITE_REG(par, PM3ByAperture1Mode,
0772                    PM3ByApertureMode_PIXELSIZE_16BIT |
0773                    PM3ByApertureMode_BYTESWAP_BADC);
0774         PM3_WRITE_REG(par, PM3ByAperture2Mode,
0775                    PM3ByApertureMode_PIXELSIZE_16BIT |
0776                    PM3ByApertureMode_BYTESWAP_BADC);
0777 #endif /* ! __BIG_ENDIAN */
0778         break;
0779 
0780     case 32:
0781 #ifndef __BIG_ENDIAN
0782         PM3_WRITE_REG(par, PM3ByAperture1Mode,
0783                    PM3ByApertureMode_PIXELSIZE_32BIT);
0784         PM3_WRITE_REG(par, PM3ByAperture2Mode,
0785                    PM3ByApertureMode_PIXELSIZE_32BIT);
0786 #else
0787         PM3_WRITE_REG(par, PM3ByAperture1Mode,
0788                    PM3ByApertureMode_PIXELSIZE_32BIT |
0789                    PM3ByApertureMode_BYTESWAP_DCBA);
0790         PM3_WRITE_REG(par, PM3ByAperture2Mode,
0791                    PM3ByApertureMode_PIXELSIZE_32BIT |
0792                    PM3ByApertureMode_BYTESWAP_DCBA);
0793 #endif /* ! __BIG_ENDIAN */
0794         break;
0795 
0796     default:
0797         DPRINTK("Unsupported depth %d\n", bpp);
0798         break;
0799     }
0800 
0801     /*
0802      * Oxygen VX1 - it appears that setting PM3VideoControl and
0803      * then PM3RD_SyncControl to the same SYNC settings undoes
0804      * any net change - they seem to xor together.  Only set the
0805      * sync options in PM3RD_SyncControl.  --rmk
0806      */
0807     {
0808         unsigned int video = par->video;
0809 
0810         video &= ~(PM3VideoControl_HSYNC_MASK |
0811                PM3VideoControl_VSYNC_MASK);
0812         video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
0813              PM3VideoControl_VSYNC_ACTIVE_HIGH;
0814         PM3_WRITE_REG(par, PM3VideoControl, video);
0815     }
0816     PM3_WRITE_REG(par, PM3VClkCtl,
0817                (PM3_READ_REG(par, PM3VClkCtl) & 0xFFFFFFFC));
0818     PM3_WRITE_REG(par, PM3ScreenBase, par->base);
0819     PM3_WRITE_REG(par, PM3ChipConfig,
0820                (PM3_READ_REG(par, PM3ChipConfig) & 0xFFFFFFFD));
0821 
0822     wmb();
0823     {
0824         unsigned char m;    /* ClkPreScale */
0825         unsigned char n;    /* ClkFeedBackScale */
0826         unsigned char p;    /* ClkPostScale */
0827         unsigned long pixclock = PICOS2KHZ(info->var.pixclock);
0828 
0829         (void)pm3fb_calculate_clock(pixclock, &m, &n, &p);
0830 
0831         DPRINTK("Pixclock: %ld, Pre: %d, Feedback: %d, Post: %d\n",
0832             pixclock, (int) m, (int) n, (int) p);
0833 
0834         PM3_WRITE_DAC_REG(par, PM3RD_DClk0PreScale, m);
0835         PM3_WRITE_DAC_REG(par, PM3RD_DClk0FeedbackScale, n);
0836         PM3_WRITE_DAC_REG(par, PM3RD_DClk0PostScale, p);
0837     }
0838     /*
0839        PM3_WRITE_DAC_REG(par, PM3RD_IndexControl, 0x00);
0840      */
0841     /*
0842        PM3_SLOW_WRITE_REG(par, PM3RD_IndexControl, 0x00);
0843      */
0844     if ((par->video & PM3VideoControl_HSYNC_MASK) ==
0845         PM3VideoControl_HSYNC_ACTIVE_HIGH)
0846         tempsync |= PM3RD_SyncControl_HSYNC_ACTIVE_HIGH;
0847     if ((par->video & PM3VideoControl_VSYNC_MASK) ==
0848         PM3VideoControl_VSYNC_ACTIVE_HIGH)
0849         tempsync |= PM3RD_SyncControl_VSYNC_ACTIVE_HIGH;
0850 
0851     PM3_WRITE_DAC_REG(par, PM3RD_SyncControl, tempsync);
0852     DPRINTK("PM3RD_SyncControl: %d\n", tempsync);
0853 
0854     PM3_WRITE_DAC_REG(par, PM3RD_DACControl, 0x00);
0855 
0856     switch (pm3fb_depth(&info->var)) {
0857     case 8:
0858         PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
0859                   PM3RD_PixelSize_8_BIT_PIXELS);
0860         PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
0861                   PM3RD_ColorFormat_CI8_COLOR |
0862                   PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
0863         tempmisc |= PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
0864         break;
0865     case 12:
0866         PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
0867                   PM3RD_PixelSize_16_BIT_PIXELS);
0868         PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
0869                   PM3RD_ColorFormat_4444_COLOR |
0870                   PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
0871                   PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
0872         tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
0873             PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
0874         break;
0875     case 15:
0876         PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
0877                   PM3RD_PixelSize_16_BIT_PIXELS);
0878         PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
0879                   PM3RD_ColorFormat_5551_FRONT_COLOR |
0880                   PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
0881                   PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
0882         tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
0883             PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
0884         break;
0885     case 16:
0886         PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
0887                   PM3RD_PixelSize_16_BIT_PIXELS);
0888         PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
0889                   PM3RD_ColorFormat_565_FRONT_COLOR |
0890                   PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW |
0891                   PM3RD_ColorFormat_LINEAR_COLOR_EXT_ENABLE);
0892         tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
0893             PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
0894         break;
0895     case 32:
0896         PM3_WRITE_DAC_REG(par, PM3RD_PixelSize,
0897                   PM3RD_PixelSize_32_BIT_PIXELS);
0898         PM3_WRITE_DAC_REG(par, PM3RD_ColorFormat,
0899                   PM3RD_ColorFormat_8888_COLOR |
0900                   PM3RD_ColorFormat_COLOR_ORDER_BLUE_LOW);
0901         tempmisc |= PM3RD_MiscControl_DIRECTCOLOR_ENABLE |
0902             PM3RD_MiscControl_HIGHCOLOR_RES_ENABLE;
0903         break;
0904     }
0905     PM3_WRITE_DAC_REG(par, PM3RD_MiscControl, tempmisc);
0906 }
0907 
0908 /*
0909  * hardware independent functions
0910  */
0911 static int pm3fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
0912 {
0913     u32 lpitch;
0914     unsigned bpp = var->red.length + var->green.length
0915             + var->blue.length + var->transp.length;
0916 
0917     if (bpp != var->bits_per_pixel) {
0918         /* set predefined mode for bits_per_pixel settings */
0919 
0920         switch (var->bits_per_pixel) {
0921         case 8:
0922             var->red.length = 8;
0923             var->green.length = 8;
0924             var->blue.length = 8;
0925             var->red.offset = 0;
0926             var->green.offset = 0;
0927             var->blue.offset = 0;
0928             var->transp.offset = 0;
0929             var->transp.length = 0;
0930             break;
0931         case 16:
0932             var->red.length = 5;
0933             var->blue.length = 5;
0934             var->green.length = 6;
0935             var->transp.length = 0;
0936             break;
0937         case 32:
0938             var->red.length = 8;
0939             var->green.length = 8;
0940             var->blue.length = 8;
0941             var->transp.length = 8;
0942             break;
0943         default:
0944             DPRINTK("depth not supported: %u\n",
0945                 var->bits_per_pixel);
0946             return -EINVAL;
0947         }
0948     }
0949     /* it is assumed BGRA order */
0950     if (var->bits_per_pixel > 8 ) {
0951         var->blue.offset = 0;
0952         var->green.offset = var->blue.length;
0953         var->red.offset = var->green.offset + var->green.length;
0954         var->transp.offset = var->red.offset + var->red.length;
0955     }
0956     var->height = -1;
0957     var->width = -1;
0958 
0959     if (var->xres != var->xres_virtual) {
0960         DPRINTK("virtual x resolution != "
0961             "physical x resolution not supported\n");
0962         return -EINVAL;
0963     }
0964 
0965     if (var->yres > var->yres_virtual) {
0966         DPRINTK("virtual y resolution < "
0967             "physical y resolution not possible\n");
0968         return -EINVAL;
0969     }
0970 
0971     if (var->xoffset) {
0972         DPRINTK("xoffset not supported\n");
0973         return -EINVAL;
0974     }
0975 
0976     if ((var->vmode & FB_VMODE_MASK) == FB_VMODE_INTERLACED) {
0977         DPRINTK("interlace not supported\n");
0978         return -EINVAL;
0979     }
0980 
0981     var->xres = (var->xres + 31) & ~31; /* could sometimes be 8 */
0982     lpitch = var->xres * ((var->bits_per_pixel + 7) >> 3);
0983 
0984     if (var->xres < 200 || var->xres > 2048) {
0985         DPRINTK("width not supported: %u\n", var->xres);
0986         return -EINVAL;
0987     }
0988 
0989     if (var->yres < 200 || var->yres > 4095) {
0990         DPRINTK("height not supported: %u\n", var->yres);
0991         return -EINVAL;
0992     }
0993 
0994     if (lpitch * var->yres_virtual > info->fix.smem_len) {
0995         DPRINTK("no memory for screen (%ux%ux%u)\n",
0996             var->xres, var->yres_virtual, var->bits_per_pixel);
0997         return -EINVAL;
0998     }
0999 
1000     if (PICOS2KHZ(var->pixclock) > PM3_MAX_PIXCLOCK) {
1001         DPRINTK("pixclock too high (%ldKHz)\n",
1002             PICOS2KHZ(var->pixclock));
1003         return -EINVAL;
1004     }
1005 
1006     var->accel_flags = 0;   /* Can't mmap if this is on */
1007 
1008     DPRINTK("Checking graphics mode at %dx%d depth %d\n",
1009         var->xres, var->yres, var->bits_per_pixel);
1010     return 0;
1011 }
1012 
1013 static int pm3fb_set_par(struct fb_info *info)
1014 {
1015     struct pm3_par *par = info->par;
1016     const u32 xres = (info->var.xres + 31) & ~31;
1017     const unsigned bpp = info->var.bits_per_pixel;
1018 
1019     par->base = pm3fb_shift_bpp(bpp, (info->var.yoffset * xres)
1020                     + info->var.xoffset);
1021     par->video = 0;
1022 
1023     if (info->var.sync & FB_SYNC_HOR_HIGH_ACT)
1024         par->video |= PM3VideoControl_HSYNC_ACTIVE_HIGH;
1025     else
1026         par->video |= PM3VideoControl_HSYNC_ACTIVE_LOW;
1027 
1028     if (info->var.sync & FB_SYNC_VERT_HIGH_ACT)
1029         par->video |= PM3VideoControl_VSYNC_ACTIVE_HIGH;
1030     else
1031         par->video |= PM3VideoControl_VSYNC_ACTIVE_LOW;
1032 
1033     if ((info->var.vmode & FB_VMODE_MASK) == FB_VMODE_DOUBLE)
1034         par->video |= PM3VideoControl_LINE_DOUBLE_ON;
1035 
1036     if ((info->var.activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW)
1037         par->video |= PM3VideoControl_ENABLE;
1038     else
1039         DPRINTK("PM3Video disabled\n");
1040 
1041     switch (bpp) {
1042     case 8:
1043         par->video |= PM3VideoControl_PIXELSIZE_8BIT;
1044         break;
1045     case 16:
1046         par->video |= PM3VideoControl_PIXELSIZE_16BIT;
1047         break;
1048     case 32:
1049         par->video |= PM3VideoControl_PIXELSIZE_32BIT;
1050         break;
1051     default:
1052         DPRINTK("Unsupported depth\n");
1053         break;
1054     }
1055 
1056     info->fix.visual =
1057         (bpp == 8) ? FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
1058     info->fix.line_length = ((info->var.xres_virtual + 7)  >> 3) * bpp;
1059 
1060 /*  pm3fb_clear_memory(info, 0);*/
1061     pm3fb_clear_colormap(par, 0, 0, 0);
1062     PM3_WRITE_DAC_REG(par, PM3RD_CursorMode, 0);
1063     pm3fb_init_engine(info);
1064     pm3fb_write_mode(info);
1065     return 0;
1066 }
1067 
1068 static int pm3fb_setcolreg(unsigned regno, unsigned red, unsigned green,
1069                unsigned blue, unsigned transp,
1070                struct fb_info *info)
1071 {
1072     struct pm3_par *par = info->par;
1073 
1074     if (regno >= 256)  /* no. of hw registers */
1075        return -EINVAL;
1076 
1077     /* grayscale works only partially under directcolor */
1078     /* grayscale = 0.30*R + 0.59*G + 0.11*B */
1079     if (info->var.grayscale)
1080        red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
1081 
1082     /* Directcolor:
1083      *   var->{color}.offset contains start of bitfield
1084      *   var->{color}.length contains length of bitfield
1085      *   {hardwarespecific} contains width of DAC
1086      *   pseudo_palette[X] is programmed to (X << red.offset) |
1087      *                  (X << green.offset) |
1088      *                  (X << blue.offset)
1089      *   RAMDAC[X] is programmed to (red, green, blue)
1090      *   color depth = SUM(var->{color}.length)
1091      *
1092      * Pseudocolor:
1093      *  var->{color}.offset is 0
1094      *  var->{color}.length contains width of DAC or the number
1095      *          of unique colors available (color depth)
1096      *  pseudo_palette is not used
1097      *  RAMDAC[X] is programmed to (red, green, blue)
1098      *  color depth = var->{color}.length
1099      */
1100 
1101     /*
1102      * This is the point where the color is converted to something that
1103      * is acceptable by the hardware.
1104      */
1105 #define CNVT_TOHW(val, width) ((((val) << (width)) + 0x7FFF - (val)) >> 16)
1106     red = CNVT_TOHW(red, info->var.red.length);
1107     green = CNVT_TOHW(green, info->var.green.length);
1108     blue = CNVT_TOHW(blue, info->var.blue.length);
1109     transp = CNVT_TOHW(transp, info->var.transp.length);
1110 #undef CNVT_TOHW
1111 
1112     if (info->fix.visual == FB_VISUAL_TRUECOLOR ||
1113     info->fix.visual == FB_VISUAL_DIRECTCOLOR) {
1114         u32 v;
1115 
1116         if (regno >= 16)
1117             return -EINVAL;
1118 
1119         v = (red << info->var.red.offset) |
1120             (green << info->var.green.offset) |
1121             (blue << info->var.blue.offset) |
1122             (transp << info->var.transp.offset);
1123 
1124         switch (info->var.bits_per_pixel) {
1125         case 8:
1126             break;
1127         case 16:
1128         case 32:
1129             ((u32 *)(info->pseudo_palette))[regno] = v;
1130             break;
1131         }
1132         return 0;
1133     } else if (info->fix.visual == FB_VISUAL_PSEUDOCOLOR)
1134         pm3fb_set_color(par, regno, red, green, blue);
1135 
1136     return 0;
1137 }
1138 
1139 static int pm3fb_pan_display(struct fb_var_screeninfo *var,
1140                  struct fb_info *info)
1141 {
1142     struct pm3_par *par = info->par;
1143     const u32 xres = (info->var.xres + 31) & ~31;
1144 
1145     par->base = pm3fb_shift_bpp(info->var.bits_per_pixel,
1146                     (var->yoffset * xres)
1147                     + var->xoffset);
1148     PM3_WAIT(par, 1);
1149     PM3_WRITE_REG(par, PM3ScreenBase, par->base);
1150     return 0;
1151 }
1152 
1153 static int pm3fb_blank(int blank_mode, struct fb_info *info)
1154 {
1155     struct pm3_par *par = info->par;
1156     u32 video = par->video;
1157 
1158     /*
1159      * Oxygen VX1 - it appears that setting PM3VideoControl and
1160      * then PM3RD_SyncControl to the same SYNC settings undoes
1161      * any net change - they seem to xor together.  Only set the
1162      * sync options in PM3RD_SyncControl.  --rmk
1163      */
1164     video &= ~(PM3VideoControl_HSYNC_MASK |
1165            PM3VideoControl_VSYNC_MASK);
1166     video |= PM3VideoControl_HSYNC_ACTIVE_HIGH |
1167          PM3VideoControl_VSYNC_ACTIVE_HIGH;
1168 
1169     switch (blank_mode) {
1170     case FB_BLANK_UNBLANK:
1171         video |= PM3VideoControl_ENABLE;
1172         break;
1173     case FB_BLANK_NORMAL:
1174         video &= ~PM3VideoControl_ENABLE;
1175         break;
1176     case FB_BLANK_HSYNC_SUSPEND:
1177         video &= ~(PM3VideoControl_HSYNC_MASK |
1178               PM3VideoControl_BLANK_ACTIVE_LOW);
1179         break;
1180     case FB_BLANK_VSYNC_SUSPEND:
1181         video &= ~(PM3VideoControl_VSYNC_MASK |
1182               PM3VideoControl_BLANK_ACTIVE_LOW);
1183         break;
1184     case FB_BLANK_POWERDOWN:
1185         video &= ~(PM3VideoControl_HSYNC_MASK |
1186               PM3VideoControl_VSYNC_MASK |
1187               PM3VideoControl_BLANK_ACTIVE_LOW);
1188         break;
1189     default:
1190         DPRINTK("Unsupported blanking %d\n", blank_mode);
1191         return 1;
1192     }
1193 
1194     PM3_WAIT(par, 1);
1195     PM3_WRITE_REG(par, PM3VideoControl, video);
1196     return 0;
1197 }
1198 
1199     /*
1200      *  Frame buffer operations
1201      */
1202 
1203 static const struct fb_ops pm3fb_ops = {
1204     .owner      = THIS_MODULE,
1205     .fb_check_var   = pm3fb_check_var,
1206     .fb_set_par = pm3fb_set_par,
1207     .fb_setcolreg   = pm3fb_setcolreg,
1208     .fb_pan_display = pm3fb_pan_display,
1209     .fb_fillrect    = pm3fb_fillrect,
1210     .fb_copyarea    = pm3fb_copyarea,
1211     .fb_imageblit   = pm3fb_imageblit,
1212     .fb_blank   = pm3fb_blank,
1213     .fb_sync    = pm3fb_sync,
1214     .fb_cursor  = pm3fb_cursor,
1215 };
1216 
1217 /* ------------------------------------------------------------------------- */
1218 
1219     /*
1220      *  Initialization
1221      */
1222 
1223 /* mmio register are already mapped when this function is called */
1224 /* the pm3fb_fix.smem_start is also set */
1225 static unsigned long pm3fb_size_memory(struct pm3_par *par)
1226 {
1227     unsigned long   memsize = 0;
1228     unsigned long   tempBypass, i, temp1, temp2;
1229     unsigned char   __iomem *screen_mem;
1230 
1231     pm3fb_fix.smem_len = 64 * 1024l * 1024; /* request full aperture size */
1232     /* Linear frame buffer - request region and map it. */
1233     if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
1234                  "pm3fb smem")) {
1235         printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");
1236         return 0;
1237     }
1238     screen_mem =
1239         ioremap(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
1240     if (!screen_mem) {
1241         printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
1242         release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
1243         return 0;
1244     }
1245 
1246     /* TODO: card-specific stuff, *before* accessing *any* FB memory */
1247     /* For Appian Jeronimo 2000 board second head */
1248 
1249     tempBypass = PM3_READ_REG(par, PM3MemBypassWriteMask);
1250 
1251     DPRINTK("PM3MemBypassWriteMask was: 0x%08lx\n", tempBypass);
1252 
1253     PM3_WAIT(par, 1);
1254     PM3_WRITE_REG(par, PM3MemBypassWriteMask, 0xFFFFFFFF);
1255 
1256     /* pm3 split up memory, replicates, and do a lot of
1257      * nasty stuff IMHO ;-)
1258      */
1259     for (i = 0; i < 32; i++) {
1260         fb_writel(i * 0x00345678,
1261               (screen_mem + (i * 1048576)));
1262         mb();
1263         temp1 = fb_readl((screen_mem + (i * 1048576)));
1264 
1265         /* Let's check for wrapover, write will fail at 16MB boundary */
1266         if (temp1 == (i * 0x00345678))
1267             memsize = i;
1268         else
1269             break;
1270     }
1271 
1272     DPRINTK("First detect pass already got %ld MB\n", memsize + 1);
1273 
1274     if (memsize + 1 == i) {
1275         for (i = 0; i < 32; i++) {
1276             /* Clear first 32MB ; 0 is 0, no need to byteswap */
1277             writel(0x0000000, (screen_mem + (i * 1048576)));
1278         }
1279         wmb();
1280 
1281         for (i = 32; i < 64; i++) {
1282             fb_writel(i * 0x00345678,
1283                   (screen_mem + (i * 1048576)));
1284             mb();
1285             temp1 =
1286                 fb_readl((screen_mem + (i * 1048576)));
1287             temp2 =
1288                 fb_readl((screen_mem + ((i - 32) * 1048576)));
1289             /* different value, different RAM... */
1290             if ((temp1 == (i * 0x00345678)) && (temp2 == 0))
1291                 memsize = i;
1292             else
1293                 break;
1294         }
1295     }
1296     DPRINTK("Second detect pass got %ld MB\n", memsize + 1);
1297 
1298     PM3_WAIT(par, 1);
1299     PM3_WRITE_REG(par, PM3MemBypassWriteMask, tempBypass);
1300 
1301     iounmap(screen_mem);
1302     release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
1303     memsize = 1048576 * (memsize + 1);
1304 
1305     DPRINTK("Returning 0x%08lx bytes\n", memsize);
1306 
1307     return memsize;
1308 }
1309 
1310 static int pm3fb_probe(struct pci_dev *dev, const struct pci_device_id *ent)
1311 {
1312     struct fb_info *info;
1313     struct pm3_par *par;
1314     struct device *device = &dev->dev; /* for pci drivers */
1315     int err;
1316     int retval = -ENXIO;
1317 
1318     err = pci_enable_device(dev);
1319     if (err) {
1320         printk(KERN_WARNING "pm3fb: Can't enable PCI dev: %d\n", err);
1321         return err;
1322     }
1323     /*
1324      * Dynamically allocate info and par
1325      */
1326     info = framebuffer_alloc(sizeof(struct pm3_par), device);
1327 
1328     if (!info)
1329         return -ENOMEM;
1330     par = info->par;
1331 
1332     /*
1333      * Here we set the screen_base to the virtual memory address
1334      * for the framebuffer.
1335      */
1336     pm3fb_fix.mmio_start = pci_resource_start(dev, 0);
1337     pm3fb_fix.mmio_len = PM3_REGS_SIZE;
1338 #if defined(__BIG_ENDIAN)
1339     pm3fb_fix.mmio_start += PM3_REGS_SIZE;
1340     DPRINTK("Adjusting register base for big-endian.\n");
1341 #endif
1342 
1343     /* Registers - request region and map it. */
1344     if (!request_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len,
1345                  "pm3fb regbase")) {
1346         printk(KERN_WARNING "pm3fb: Can't reserve regbase.\n");
1347         goto err_exit_neither;
1348     }
1349     par->v_regs =
1350         ioremap(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
1351     if (!par->v_regs) {
1352         printk(KERN_WARNING "pm3fb: Can't remap %s register area.\n",
1353             pm3fb_fix.id);
1354         release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
1355         goto err_exit_neither;
1356     }
1357 
1358     /* Linear frame buffer - request region and map it. */
1359     pm3fb_fix.smem_start = pci_resource_start(dev, 1);
1360     pm3fb_fix.smem_len = pm3fb_size_memory(par);
1361     if (!pm3fb_fix.smem_len) {
1362         printk(KERN_WARNING "pm3fb: Can't find memory on board.\n");
1363         goto err_exit_mmio;
1364     }
1365     if (!request_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len,
1366                  "pm3fb smem")) {
1367         printk(KERN_WARNING "pm3fb: Can't reserve smem.\n");
1368         goto err_exit_mmio;
1369     }
1370     info->screen_base = ioremap_wc(pm3fb_fix.smem_start,
1371                        pm3fb_fix.smem_len);
1372     if (!info->screen_base) {
1373         printk(KERN_WARNING "pm3fb: Can't ioremap smem area.\n");
1374         release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
1375         goto err_exit_mmio;
1376     }
1377     info->screen_size = pm3fb_fix.smem_len;
1378 
1379     if (!nomtrr)
1380         par->wc_cookie = arch_phys_wc_add(pm3fb_fix.smem_start,
1381                           pm3fb_fix.smem_len);
1382     info->fbops = &pm3fb_ops;
1383 
1384     par->video = PM3_READ_REG(par, PM3VideoControl);
1385 
1386     info->fix = pm3fb_fix;
1387     info->pseudo_palette = par->palette;
1388     info->flags = FBINFO_DEFAULT |
1389             FBINFO_HWACCEL_XPAN |
1390             FBINFO_HWACCEL_YPAN |
1391             FBINFO_HWACCEL_COPYAREA |
1392             FBINFO_HWACCEL_IMAGEBLIT |
1393             FBINFO_HWACCEL_FILLRECT;
1394 
1395     if (noaccel) {
1396         printk(KERN_DEBUG "disabling acceleration\n");
1397         info->flags |= FBINFO_HWACCEL_DISABLED;
1398     }
1399     info->pixmap.addr = kmalloc(PM3_PIXMAP_SIZE, GFP_KERNEL);
1400     if (!info->pixmap.addr) {
1401         retval = -ENOMEM;
1402         goto err_exit_pixmap;
1403     }
1404     info->pixmap.size = PM3_PIXMAP_SIZE;
1405     info->pixmap.buf_align = 4;
1406     info->pixmap.scan_align = 4;
1407     info->pixmap.access_align = 32;
1408     info->pixmap.flags = FB_PIXMAP_SYSTEM;
1409 
1410     /*
1411      * This should give a reasonable default video mode. The following is
1412      * done when we can set a video mode.
1413      */
1414     if (!mode_option)
1415         mode_option = "640x480@60";
1416 
1417     retval = fb_find_mode(&info->var, info, mode_option, NULL, 0, NULL, 8);
1418 
1419     if (!retval || retval == 4) {
1420         retval = -EINVAL;
1421         goto err_exit_both;
1422     }
1423 
1424     if (fb_alloc_cmap(&info->cmap, 256, 0) < 0) {
1425         retval = -ENOMEM;
1426         goto err_exit_both;
1427     }
1428 
1429     /*
1430      * For drivers that can...
1431      */
1432     pm3fb_check_var(&info->var, info);
1433 
1434     if (register_framebuffer(info) < 0) {
1435         retval = -EINVAL;
1436         goto err_exit_all;
1437     }
1438     fb_info(info, "%s frame buffer device\n", info->fix.id);
1439     pci_set_drvdata(dev, info);
1440     return 0;
1441 
1442  err_exit_all:
1443     fb_dealloc_cmap(&info->cmap);
1444  err_exit_both:
1445     kfree(info->pixmap.addr);
1446  err_exit_pixmap:
1447     iounmap(info->screen_base);
1448     release_mem_region(pm3fb_fix.smem_start, pm3fb_fix.smem_len);
1449  err_exit_mmio:
1450     iounmap(par->v_regs);
1451     release_mem_region(pm3fb_fix.mmio_start, pm3fb_fix.mmio_len);
1452  err_exit_neither:
1453     framebuffer_release(info);
1454     return retval;
1455 }
1456 
1457     /*
1458      *  Cleanup
1459      */
1460 static void pm3fb_remove(struct pci_dev *dev)
1461 {
1462     struct fb_info *info = pci_get_drvdata(dev);
1463 
1464     if (info) {
1465         struct fb_fix_screeninfo *fix = &info->fix;
1466         struct pm3_par *par = info->par;
1467 
1468         unregister_framebuffer(info);
1469         fb_dealloc_cmap(&info->cmap);
1470 
1471         arch_phys_wc_del(par->wc_cookie);
1472         iounmap(info->screen_base);
1473         release_mem_region(fix->smem_start, fix->smem_len);
1474         iounmap(par->v_regs);
1475         release_mem_region(fix->mmio_start, fix->mmio_len);
1476 
1477         kfree(info->pixmap.addr);
1478         framebuffer_release(info);
1479     }
1480 }
1481 
1482 static const struct pci_device_id pm3fb_id_table[] = {
1483     { PCI_VENDOR_ID_3DLABS, 0x0a,
1484       PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
1485     { 0, }
1486 };
1487 
1488 /* For PCI drivers */
1489 static struct pci_driver pm3fb_driver = {
1490     .name =     "pm3fb",
1491     .id_table = pm3fb_id_table,
1492     .probe =    pm3fb_probe,
1493     .remove =   pm3fb_remove,
1494 };
1495 
1496 MODULE_DEVICE_TABLE(pci, pm3fb_id_table);
1497 
1498 #ifndef MODULE
1499     /*
1500      *  Setup
1501      */
1502 
1503 /*
1504  * Only necessary if your driver takes special options,
1505  * otherwise we fall back on the generic fb_setup().
1506  */
1507 static int __init pm3fb_setup(char *options)
1508 {
1509     char *this_opt;
1510 
1511     /* Parse user specified options (`video=pm3fb:') */
1512     if (!options || !*options)
1513         return 0;
1514 
1515     while ((this_opt = strsep(&options, ",")) != NULL) {
1516         if (!*this_opt)
1517             continue;
1518         else if (!strncmp(this_opt, "noaccel", 7))
1519             noaccel = 1;
1520         else if (!strncmp(this_opt, "hwcursor=", 9))
1521             hwcursor = simple_strtoul(this_opt + 9, NULL, 0);
1522         else if (!strncmp(this_opt, "nomtrr", 6))
1523             nomtrr = 1;
1524         else
1525             mode_option = this_opt;
1526     }
1527     return 0;
1528 }
1529 #endif /* MODULE */
1530 
1531 static int __init pm3fb_init(void)
1532 {
1533     /*
1534      *  For kernel boot options (in 'video=pm3fb:<options>' format)
1535      */
1536 #ifndef MODULE
1537     char *option = NULL;
1538 
1539     if (fb_get_options("pm3fb", &option))
1540         return -ENODEV;
1541     pm3fb_setup(option);
1542 #endif
1543 
1544     return pci_register_driver(&pm3fb_driver);
1545 }
1546 
1547 #ifdef MODULE
1548 static void __exit pm3fb_exit(void)
1549 {
1550     pci_unregister_driver(&pm3fb_driver);
1551 }
1552 
1553 module_exit(pm3fb_exit);
1554 #endif
1555 module_init(pm3fb_init);
1556 
1557 module_param(mode_option, charp, 0);
1558 MODULE_PARM_DESC(mode_option, "Initial video mode e.g. '648x480-8@60'");
1559 module_param(noaccel, bool, 0);
1560 MODULE_PARM_DESC(noaccel, "Disable acceleration");
1561 module_param(hwcursor, int, 0644);
1562 MODULE_PARM_DESC(hwcursor, "Enable hardware cursor "
1563             "(1=enable, 0=disable, default=1)");
1564 module_param(nomtrr, bool, 0);
1565 MODULE_PARM_DESC(nomtrr, "Disable MTRR support (0 or 1=disabled) (default=0)");
1566 
1567 MODULE_DESCRIPTION("Permedia3 framebuffer device driver");
1568 MODULE_LICENSE("GPL");