intelfb: support 945GME (as used in ASUS Eee 901)
[safe/jmp/linux-2.6] / drivers / video / cirrusfb.c
index 0b9fe74..e729fb2 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/delay.h>
 #include <linux/fb.h>
 #include <linux/init.h>
-#include <linux/selection.h>
 #include <asm/pgtable.h>
 
 #ifdef CONFIG_ZORRO
@@ -64,8 +63,8 @@
 #define isPReP 0
 #endif
 
-#include "video/vga.h"
-#include "video/cirrus.h"
+#include <video/vga.h>
+#include <video/cirrus.h>
 
 /*****************************************************************
  *
@@ -82,7 +81,7 @@
 /* debug output */
 #ifdef CIRRUSFB_DEBUG
 #define DPRINTK(fmt, args...) \
-       printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
+       printk(KERN_DEBUG "%s: " fmt, __func__ , ## args)
 #else
 #define DPRINTK(fmt, args...)
 #endif
 #define assert(expr) \
        if (!(expr)) { \
                printk("Assertion failed! %s,%s,%s,line=%d\n", \
-               #expr, __FILE__, __FUNCTION__, __LINE__); \
+               #expr, __FILE__, __func__, __LINE__); \
        }
 #else
 #define assert(expr)
 #endif
 
 #define MB_ (1024 * 1024)
-#define KB_ (1024)
-
-#define MAX_NUM_BOARDS 7
 
 /*****************************************************************
  *
  */
 
 /* board types */
-typedef enum {
+enum cirrus_board {
        BT_NONE = 0,
        BT_SD64,
        BT_PICCOLO,
@@ -120,12 +116,12 @@ typedef enum {
        BT_ALPINE,      /* GD543x/4x */
        BT_GD5480,
        BT_LAGUNA,      /* GD546x */
-} cirrusfb_board_t;
+};
 
 /*
  * per-board-type information, used for enumerating and abstracting
  * chip-specific information
- * NOTE: MUST be in the same order as cirrusfb_board_t in order to
+ * NOTE: MUST be in the same order as enum cirrus_board in order to
  * use direct indexing on this array
  * NOTE: '__initdata' cannot be used as some of this info
  * is required at runtime.  Maybe separate into an init-only and
@@ -331,10 +327,6 @@ static const struct {
 #endif /* CONFIG_ZORRO */
 
 struct cirrusfb_regs {
-       __u32 line_length;      /* in BYTES! */
-       __u32 visual;
-       __u32 type;
-
        long freq;
        long nom;
        long den;
@@ -361,31 +353,22 @@ struct cirrusfb_regs {
 };
 
 #ifdef CIRRUSFB_DEBUG
-typedef enum {
+enum cirrusfb_dbg_reg_class {
        CRT,
        SEQ
-} cirrusfb_dbg_reg_class_t;
+};
 #endif         /* CIRRUSFB_DEBUG */
 
 /* info about board */
 struct cirrusfb_info {
-       struct fb_info *info;
-
-       u8 __iomem *fbmem;
        u8 __iomem *regbase;
-       u8 __iomem *mem;
-       unsigned long size;
-       cirrusfb_board_t btype;
+       enum cirrus_board btype;
        unsigned char SFR;      /* Shadow of special function register */
 
-       unsigned long fbmem_phys;
-       unsigned long fbregs_phys;
-
        struct cirrusfb_regs currentmode;
        int blank_mode;
 
        u32     pseudo_palette[16];
-       struct { u8 red, green, blue, pad; } palette[256];
 
 #ifdef CONFIG_ZORRO
        struct zorro_dev *zdev;
@@ -393,7 +376,7 @@ struct cirrusfb_info {
 #ifdef CONFIG_PCI
        struct pci_dev *pdev;
 #endif
-       void (*unmap)(struct cirrusfb_info *cinfo);
+       void (*unmap)(struct fb_info *info);
 };
 
 static unsigned cirrusfb_def_mode = 1;
@@ -534,9 +517,9 @@ static struct fb_ops cirrusfb_ops = {
 /*--- Hardware Specific Routines -------------------------------------------*/
 static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
                                struct cirrusfb_regs *regs,
-                               const struct fb_info *info);
+                               struct fb_info *info);
 /*--- Internal routines ----------------------------------------------------*/
-static void init_vgachip(struct cirrusfb_info *cinfo);
+static void init_vgachip(struct fb_info *info);
 static void switch_monitor(struct cirrusfb_info *cinfo, int on);
 static void WGen(const struct cirrusfb_info *cinfo,
                 int regnum, unsigned char val);
@@ -571,7 +554,7 @@ static void bestclock(long freq, long *best,
 static void cirrusfb_dump(void);
 static void cirrusfb_dbg_reg_dump(caddr_t regbase);
 static void cirrusfb_dbg_print_regs(caddr_t regbase,
-                                   cirrusfb_dbg_reg_class_t reg_class, ...);
+                                   enum cirrusfb_dbg_reg_class reg_class, ...);
 static void cirrusfb_dbg_print_byte(const char *name, unsigned char val);
 #endif /* CIRRUSFB_DEBUG */
 
@@ -645,43 +628,19 @@ static long cirrusfb_get_mclk(long freq, int bpp, long *div)
 static int cirrusfb_check_var(struct fb_var_screeninfo *var,
                              struct fb_info *info)
 {
-       struct cirrusfb_info *cinfo = info->par;
-       int nom, den;           /* translyting from pixels->bytes */
-       int yres, i;
-       static struct { int xres, yres; } modes[] =
-       { { 1600, 1280 },
-         { 1280, 1024 },
-         { 1024, 768 },
-         { 800, 600 },
-         { 640, 480 },
-         { -1, -1 } };
+       int yres;
+       /* memory size in pixels */
+       unsigned pixels = info->screen_size * 8 / var->bits_per_pixel;
 
        switch (var->bits_per_pixel) {
-       case 0 ... 1:
-               var->bits_per_pixel = 1;
-               nom = 4;
-               den = 8;
+       case 1:
+               pixels /= 4;
                break;          /* 8 pixel per byte, only 1/4th of mem usable */
-       case 2 ... 8:
-               var->bits_per_pixel = 8;
-               nom = 1;
-               den = 1;
+       case 8:
+       case 16:
+       case 24:
+       case 32:
                break;          /* 1 pixel == 1 byte */
-       case 9 ... 16:
-               var->bits_per_pixel = 16;
-               nom = 2;
-               den = 1;
-               break;          /* 2 bytes per pixel */
-       case 17 ... 24:
-               var->bits_per_pixel = 24;
-               nom = 3;
-               den = 1;
-               break;          /* 3 bytes per pixel */
-       case 25 ... 32:
-               var->bits_per_pixel = 32;
-               nom = 4;
-               den = 1;
-               break;          /* 4 bytes per pixel */
        default:
                printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."
                        "color depth not supported.\n",
@@ -690,42 +649,29 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
                return -EINVAL;
        }
 
-       if (var->xres * nom / den * var->yres > cinfo->size) {
-               printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected..."
-                       "resolution too high to fit into video memory!\n",
-                       var->xres, var->yres, var->bits_per_pixel);
-               DPRINTK("EXIT - EINVAL error\n");
-               return -EINVAL;
-       }
-
+       if (var->xres_virtual < var->xres)
+               var->xres_virtual = var->xres;
        /* use highest possible virtual resolution */
-       if (var->xres_virtual == -1 &&
-           var->yres_virtual == -1) {
-               printk(KERN_INFO
-                    "cirrusfb: using maximum available virtual resolution\n");
-               for (i = 0; modes[i].xres != -1; i++) {
-                       if (modes[i].xres * nom / den * modes[i].yres < cinfo->size / 2)
-                               break;
-               }
-               if (modes[i].xres == -1) {
-                       printk(KERN_ERR "cirrusfb: could not find a virtual "
-                               "resolution that fits into video memory!!\n");
-                       DPRINTK("EXIT - EINVAL error\n");
-                       return -EINVAL;
-               }
-               var->xres_virtual = modes[i].xres;
-               var->yres_virtual = modes[i].yres;
+       if (var->yres_virtual == -1) {
+               var->yres_virtual = pixels / var->xres_virtual;
 
                printk(KERN_INFO "cirrusfb: virtual resolution set to "
                        "maximum of %dx%d\n", var->xres_virtual,
                        var->yres_virtual);
        }
-
-       if (var->xres_virtual < var->xres)
-               var->xres_virtual = var->xres;
        if (var->yres_virtual < var->yres)
                var->yres_virtual = var->yres;
 
+       if (var->xres_virtual * var->yres_virtual > pixels) {
+               printk(KERN_ERR "cirrusfb: mode %dx%dx%d rejected... "
+                     "virtual resolution too high to fit into video memory!\n",
+                       var->xres_virtual, var->yres_virtual,
+                       var->bits_per_pixel);
+               DPRINTK("EXIT - EINVAL error\n");
+               return -EINVAL;
+       }
+
+
        if (var->xoffset < 0)
                var->xoffset = 0;
        if (var->yoffset < 0)
@@ -741,19 +687,15 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
        case 1:
                var->red.offset = 0;
                var->red.length = 1;
-               var->green.offset = 0;
-               var->green.length = 1;
-               var->blue.offset = 0;
-               var->blue.length = 1;
+               var->green = var->red;
+               var->blue = var->red;
                break;
 
        case 8:
                var->red.offset = 0;
                var->red.length = 6;
-               var->green.offset = 0;
-               var->green.length = 6;
-               var->blue.offset = 0;
-               var->blue.length = 6;
+               var->green = var->red;
+               var->blue = var->red;
                break;
 
        case 16:
@@ -772,20 +714,6 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
                break;
 
        case 24:
-               if (isPReP) {
-                       var->red.offset = 8;
-                       var->green.offset = 16;
-                       var->blue.offset = 24;
-               } else {
-                       var->red.offset = 16;
-                       var->green.offset = 8;
-                       var->blue.offset = 0;
-               }
-               var->red.length = 8;
-               var->green.length = 8;
-               var->blue.length = 8;
-               break;
-
        case 32:
                if (isPReP) {
                        var->red.offset = 8;
@@ -833,44 +761,31 @@ static int cirrusfb_check_var(struct fb_var_screeninfo *var,
 
 static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
                                struct cirrusfb_regs *regs,
-                               const struct fb_info *info)
+                               struct fb_info *info)
 {
        long freq;
        long maxclock;
-       int maxclockidx = 0;
+       int maxclockidx = var->bits_per_pixel >> 3;
        struct cirrusfb_info *cinfo = info->par;
        int xres, hfront, hsync, hback;
        int yres, vfront, vsync, vback;
 
        switch (var->bits_per_pixel) {
        case 1:
-               regs->line_length = var->xres_virtual / 8;
-               regs->visual = FB_VISUAL_MONO10;
-               maxclockidx = 0;
+               info->fix.line_length = var->xres_virtual / 8;
+               info->fix.visual = FB_VISUAL_MONO10;
                break;
 
        case 8:
-               regs->line_length = var->xres_virtual;
-               regs->visual = FB_VISUAL_PSEUDOCOLOR;
-               maxclockidx = 1;
+               info->fix.line_length = var->xres_virtual;
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
                break;
 
        case 16:
-               regs->line_length = var->xres_virtual * 2;
-               regs->visual = FB_VISUAL_DIRECTCOLOR;
-               maxclockidx = 2;
-               break;
-
        case 24:
-               regs->line_length = var->xres_virtual * 3;
-               regs->visual = FB_VISUAL_DIRECTCOLOR;
-               maxclockidx = 3;
-               break;
-
        case 32:
-               regs->line_length = var->xres_virtual * 4;
-               regs->visual = FB_VISUAL_DIRECTCOLOR;
-               maxclockidx = 4;
+               info->fix.line_length = var->xres_virtual * maxclockidx;
+               info->fix.visual = FB_VISUAL_DIRECTCOLOR;
                break;
 
        default:
@@ -880,10 +795,10 @@ static int cirrusfb_decode_var(const struct fb_var_screeninfo *var,
                break;
        }
 
-       regs->type = FB_TYPE_PACKED_PIXELS;
+       info->fix.type = FB_TYPE_PACKED_PIXELS;
 
        /* convert from ps to kHz */
-       freq = 1000000000 / var->pixclock;
+       freq = PICOS2KHZ(var->pixclock);
 
        DPRINTK("desired pixclock: %ld kHz\n", freq);
 
@@ -1018,7 +933,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
               var->xres, var->yres, var->bits_per_pixel);
        DPRINTK("pixclock: %d\n", var->pixclock);
 
-       init_vgachip(cinfo);
+       init_vgachip(info);
 
        err = cirrusfb_decode_var(var, &regs, info);
        if (err) {
@@ -1222,7 +1137,8 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                        break;
 
                case BT_PICCOLO:
-                       DPRINTK("(for Piccolo)\n");
+               case BT_SPECTRUM:
+                       DPRINTK("(for Piccolo/Spectrum)\n");
                        /* ### ueberall 0x22? */
                        /* ##vorher 1c MCLK select */
                        vga_wseq(regbase, CL_SEQR1F, 0x22);
@@ -1238,15 +1154,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                        vga_wseq(regbase, CL_SEQRF, 0xd0);
                        break;
 
-               case BT_SPECTRUM:
-                       DPRINTK("(for Spectrum)\n");
-                       /* ### ueberall 0x22? */
-                       /* ##vorher 1c MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
-                       /* evtl d0? avoid FIFO underruns..? */
-                       vga_wseq(regbase, CL_SEQRF, 0xb0);
-                       break;
-
                case BT_PICASSO4:
                case BT_ALPINE:
                case BT_GD5480:
@@ -1315,19 +1222,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                        break;
 
                case BT_PICCOLO:
-                       /* ### vorher 1c MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
-                       /* Fast Page-Mode writes */
-                       vga_wseq(regbase, CL_SEQRF, 0xb0);
-                       break;
-
                case BT_PICASSO:
-                       /* ### vorher 1c MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
-                       /* Fast Page-Mode writes */
-                       vga_wseq(regbase, CL_SEQRF, 0xb0);
-                       break;
-
                case BT_SPECTRUM:
                        /* ### vorher 1c MCLK select */
                        vga_wseq(regbase, CL_SEQR1F, 0x22);
@@ -1394,6 +1289,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                        break;
 
                case BT_PICCOLO:
+               case BT_SPECTRUM:
                        vga_wseq(regbase, CL_SEQR7, 0x87);
                        /* Fast Page-Mode writes */
                        vga_wseq(regbase, CL_SEQRF, 0xb0);
@@ -1409,14 +1305,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                        vga_wseq(regbase, CL_SEQR1F, 0x22);
                        break;
 
-               case BT_SPECTRUM:
-                       vga_wseq(regbase, CL_SEQR7, 0x87);
-                       /* Fast Page-Mode writes */
-                       vga_wseq(regbase, CL_SEQRF, 0xb0);
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
-                       break;
-
                case BT_PICASSO4:
                        vga_wseq(regbase, CL_SEQR7, 0x27);
 /*                     vga_wseq(regbase, CL_SEQR1F, 0x1c);  */
@@ -1482,6 +1370,7 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                        break;
 
                case BT_PICCOLO:
+               case BT_SPECTRUM:
                        vga_wseq(regbase, CL_SEQR7, 0x85);
                        /* Fast Page-Mode writes */
                        vga_wseq(regbase, CL_SEQRF, 0xb0);
@@ -1497,14 +1386,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
                        vga_wseq(regbase, CL_SEQR1F, 0x22);
                        break;
 
-               case BT_SPECTRUM:
-                       vga_wseq(regbase, CL_SEQR7, 0x85);
-                       /* Fast Page-Mode writes */
-                       vga_wseq(regbase, CL_SEQRF, 0xb0);
-                       /* MCLK select */
-                       vga_wseq(regbase, CL_SEQR1F, 0x22);
-                       break;
-
                case BT_PICASSO4:
                        vga_wseq(regbase, CL_SEQR7, 0x25);
 /*                     vga_wseq(regbase, CL_SEQR1F, 0x1c);  */
@@ -1627,9 +1508,6 @@ static int cirrusfb_set_par_foo(struct fb_info *info)
        DPRINTK("CL_SEQR1: %d\n", tmp);
 
        cinfo->currentmode = regs;
-       info->fix.type = regs.type;
-       info->fix.visual = regs.visual;
-       info->fix.line_length = regs.line_length;
 
        /* pan to requested offset */
        cirrusfb_pan_display(var, info);
@@ -1671,25 +1549,10 @@ static int cirrusfb_setcolreg(unsigned regno, unsigned red, unsigned green,
                    (green << info->var.green.offset) |
                    (blue << info->var.blue.offset);
 
-               switch (info->var.bits_per_pixel) {
-               case 8:
-                       cinfo->pseudo_palette[regno] = v;
-                       break;
-               case 16:
-                       cinfo->pseudo_palette[regno] = v;
-                       break;
-               case 24:
-               case 32:
-                       cinfo->pseudo_palette[regno] = v;
-                       break;
-               }
+               cinfo->pseudo_palette[regno] = v;
                return 0;
        }
 
-       cinfo->palette[regno].red = red;
-       cinfo->palette[regno].green = green;
-       cinfo->palette[regno].blue = blue;
-
        if (info->var.bits_per_pixel == 8)
                WClut(cinfo, regno, red >> 10, green >> 10, blue >> 10);
 
@@ -1725,7 +1588,7 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
        xoffset = var->xoffset * info->var.bits_per_pixel / 8;
        yoffset = var->yoffset;
 
-       base = yoffset * cinfo->currentmode.line_length + xoffset;
+       base = yoffset * info->fix.line_length + xoffset;
 
        if (info->var.bits_per_pixel == 1) {
                /* base is already correct */
@@ -1756,12 +1619,8 @@ static int cirrusfb_pan_display(struct fb_var_screeninfo *var,
        vga_wcrt(cinfo->regbase, CL_CRT1B, tmp2);
 
        /* construct bit 19 of screen start address */
-       if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19) {
-               tmp2 = 0;
-               if (base & 0x80000)
-                       tmp2 = 0x80;
-               vga_wcrt(cinfo->regbase, CL_CRT1D, tmp2);
-       }
+       if (cirrusfb_board_info[cinfo->btype].scrn_start_bit19)
+               vga_wcrt(cinfo->regbase, CL_CRT1D, (base >> 12) & 0x80);
 
        /* write pixel panning value to AR33; this does not quite work in 8bpp
         *
@@ -1848,8 +1707,9 @@ static int cirrusfb_blank(int blank_mode, struct fb_info *info)
 /****************************************************************************/
 /**** BEGIN Internal Routines ***********************************************/
 
-static void init_vgachip(struct cirrusfb_info *cinfo)
+static void init_vgachip(struct fb_info *info)
 {
+       struct cirrusfb_info *cinfo = info->par;
        const struct cirrusfb_board_info_rec *bi;
 
        DPRINTK("ENTER\n");
@@ -1903,7 +1763,8 @@ static void init_vgachip(struct cirrusfb_info *cinfo)
                break;
        }
 
-       assert(cinfo->size > 0); /* make sure RAM size set by this point */
+       /* make sure RAM size set by this point */
+       assert(info->screen_size > 0);
 
        /* the P4 is not fully initialized here; I rely on it having been */
        /* inited under AmigaOS already, which seems to work just fine    */
@@ -2089,7 +1950,7 @@ static void init_vgachip(struct cirrusfb_info *cinfo)
        WHDR(cinfo, 0); /* Hidden DAC register: - */
 
        printk(KERN_DEBUG "cirrusfb: This board has %ld bytes of DRAM memory\n",
-               cinfo->size);
+               info->screen_size);
        DPRINTK("EXIT\n");
        return;
 }
@@ -2150,38 +2011,15 @@ static void switch_monitor(struct cirrusfb_info *cinfo, int on)
 /* Linux 2.6-style  accelerated functions */
 /******************************************/
 
-static void cirrusfb_prim_fillrect(struct cirrusfb_info *cinfo,
-                                  const struct fb_fillrect *region)
-{
-       int m; /* bytes per pixel */
-       u32 color = (cinfo->info->fix.visual == FB_VISUAL_TRUECOLOR) ?
-               cinfo->pseudo_palette[region->color] : region->color;
-
-       if (cinfo->info->var.bits_per_pixel == 1) {
-               cirrusfb_RectFill(cinfo->regbase,
-                                 cinfo->info->var.bits_per_pixel,
-                                 region->dx / 8, region->dy,
-                                 region->width / 8, region->height,
-                                 color,
-                                 cinfo->currentmode.line_length);
-       } else {
-               m = (cinfo->info->var.bits_per_pixel + 7) / 8;
-               cirrusfb_RectFill(cinfo->regbase,
-                                 cinfo->info->var.bits_per_pixel,
-                                 region->dx * m, region->dy,
-                                 region->width * m, region->height,
-                                 color,
-                                 cinfo->currentmode.line_length);
-       }
-       return;
-}
-
 static void cirrusfb_fillrect(struct fb_info *info,
                              const struct fb_fillrect *region)
 {
-       struct cirrusfb_info *cinfo = info->par;
        struct fb_fillrect modded;
        int vxres, vyres;
+       struct cirrusfb_info *cinfo = info->par;
+       int m = info->var.bits_per_pixel;
+       u32 color = (info->fix.visual == FB_VISUAL_TRUECOLOR) ?
+               cinfo->pseudo_palette[region->color] : region->color;
 
        if (info->state != FBINFO_STATE_RUNNING)
                return;
@@ -2204,42 +2042,21 @@ static void cirrusfb_fillrect(struct fb_info *info,
        if (modded.dy + modded.height > vyres)
                modded.height = vyres - modded.dy;
 
-       cirrusfb_prim_fillrect(cinfo, &modded);
-}
-
-static void cirrusfb_prim_copyarea(struct cirrusfb_info *cinfo,
-                                  const struct fb_copyarea *area)
-{
-       int m; /* bytes per pixel */
-       if (cinfo->info->var.bits_per_pixel == 1) {
-               cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel,
-                               area->sx / 8, area->sy,
-                               area->dx / 8, area->dy,
-                               area->width / 8, area->height,
-                               cinfo->currentmode.line_length);
-       } else {
-               m = (cinfo->info->var.bits_per_pixel + 7) / 8;
-               cirrusfb_BitBLT(cinfo->regbase, cinfo->info->var.bits_per_pixel,
-                               area->sx * m, area->sy,
-                               area->dx * m, area->dy,
-                               area->width * m, area->height,
-                               cinfo->currentmode.line_length);
-       }
-       return;
+       cirrusfb_RectFill(cinfo->regbase,
+                         info->var.bits_per_pixel,
+                         (region->dx * m) / 8, region->dy,
+                         (region->width * m) / 8, region->height,
+                         color,
+                         info->fix.line_length);
 }
 
 static void cirrusfb_copyarea(struct fb_info *info,
                              const struct fb_copyarea *area)
 {
-       struct cirrusfb_info *cinfo = info->par;
        struct fb_copyarea modded;
        u32 vxres, vyres;
-       modded.sx = area->sx;
-       modded.sy = area->sy;
-       modded.dx = area->dx;
-       modded.dy = area->dy;
-       modded.width  = area->width;
-       modded.height = area->height;
+       struct cirrusfb_info *cinfo = info->par;
+       int m = info->var.bits_per_pixel;
 
        if (info->state != FBINFO_STATE_RUNNING)
                return;
@@ -2250,6 +2067,7 @@ static void cirrusfb_copyarea(struct fb_info *info,
 
        vxres = info->var.xres_virtual;
        vyres = info->var.yres_virtual;
+       memcpy(&modded, area, sizeof(struct fb_copyarea));
 
        if (!modded.width || !modded.height ||
           modded.sx >= vxres || modded.sy >= vyres ||
@@ -2265,7 +2083,12 @@ static void cirrusfb_copyarea(struct fb_info *info,
        if (modded.dy + modded.height > vyres)
                modded.height = vyres - modded.dy;
 
-       cirrusfb_prim_copyarea(cinfo, &modded);
+       cirrusfb_BitBLT(cinfo->regbase, info->var.bits_per_pixel,
+                       (area->sx * m) / 8, area->sy,
+                       (area->dx * m) / 8, area->dy,
+                       (area->width * m) / 8, area->height,
+                       info->fix.line_length);
+
 }
 
 static void cirrusfb_imageblit(struct fb_info *info,
@@ -2363,44 +2186,43 @@ static void get_pci_addrs(const struct pci_dev *pdev,
        DPRINTK("EXIT\n");
 }
 
-static void cirrusfb_pci_unmap(struct cirrusfb_info *cinfo)
+static void cirrusfb_pci_unmap(struct fb_info *info)
 {
+       struct cirrusfb_info *cinfo = info->par;
        struct pci_dev *pdev = cinfo->pdev;
 
-       iounmap(cinfo->fbmem);
+       iounmap(info->screen_base);
 #if 0 /* if system didn't claim this region, we would... */
        release_mem_region(0xA0000, 65535);
 #endif
        if (release_io_ports)
                release_region(0x3C0, 32);
        pci_release_regions(pdev);
-       framebuffer_release(cinfo->info);
 }
 #endif /* CONFIG_PCI */
 
 #ifdef CONFIG_ZORRO
-static void __devexit cirrusfb_zorro_unmap(struct cirrusfb_info *cinfo)
+static void __devexit cirrusfb_zorro_unmap(struct fb_info *info)
 {
+       struct cirrusfb_info *cinfo = info->par;
        zorro_release_device(cinfo->zdev);
 
        if (cinfo->btype == BT_PICASSO4) {
                cinfo->regbase -= 0x600000;
                iounmap((void *)cinfo->regbase);
-               iounmap((void *)cinfo->fbmem);
+               iounmap(info->screen_base);
        } else {
                if (zorro_resource_start(cinfo->zdev) > 0x01000000)
-                       iounmap((void *)cinfo->fbmem);
+                       iounmap(info->screen_base);
        }
-       framebuffer_release(cinfo->info);
 }
 #endif /* CONFIG_ZORRO */
 
-static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo)
+static int cirrusfb_set_fbinfo(struct fb_info *info)
 {
-       struct fb_info *info = cinfo->info;
+       struct cirrusfb_info *cinfo = info->par;
        struct fb_var_screeninfo *var = &info->var;
 
-       info->par = cinfo;
        info->pseudo_palette = cinfo->pseudo_palette;
        info->flags = FBINFO_DEFAULT
                    | FBINFO_HWACCEL_XPAN
@@ -2410,7 +2232,6 @@ static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo)
        if (noaccel)
                info->flags |= FBINFO_HWACCEL_DISABLED;
        info->fbops = &cirrusfb_ops;
-       info->screen_base = cinfo->fbmem;
        if (cinfo->btype == BT_GD5480) {
                if (var->bits_per_pixel == 16)
                        info->screen_base += 1 * MB_;
@@ -2424,19 +2245,15 @@ static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo)
 
        /* monochrome: only 1 memory plane */
        /* 8 bit and above: Use whole memory area */
-       info->fix.smem_start = cinfo->fbmem_phys;
-       info->fix.smem_len   =
-               (var->bits_per_pixel == 1) ? cinfo->size / 4 : cinfo->size;
-       info->fix.type       = cinfo->currentmode.type;
+       info->fix.smem_len   = info->screen_size;
+       if (var->bits_per_pixel == 1)
+               info->fix.smem_len /= 4;
        info->fix.type_aux   = 0;
-       info->fix.visual     = cinfo->currentmode.visual;
        info->fix.xpanstep   = 1;
        info->fix.ypanstep   = 1;
        info->fix.ywrapstep  = 0;
-       info->fix.line_length = cinfo->currentmode.line_length;
 
        /* FIXME: map region at 0xB8000 if available, fill in here */
-       info->fix.mmio_start = cinfo->fbregs_phys;
        info->fix.mmio_len   = 0;
        info->fix.accel = FB_ACCEL_NONE;
 
@@ -2445,24 +2262,23 @@ static int cirrusfb_set_fbinfo(struct cirrusfb_info *cinfo)
        return 0;
 }
 
-static int cirrusfb_register(struct cirrusfb_info *cinfo)
+static int cirrusfb_register(struct fb_info *info)
 {
-       struct fb_info *info;
+       struct cirrusfb_info *cinfo = info->par;
        int err;
-       cirrusfb_board_t btype;
+       enum cirrus_board btype;
 
        DPRINTK("ENTER\n");
 
        printk(KERN_INFO "cirrusfb: Driver for Cirrus Logic based "
                "graphic boards, v" CIRRUSFB_VERSION "\n");
 
-       info = cinfo->info;
        btype = cinfo->btype;
 
        /* sanity checks */
        assert(btype != BT_NONE);
 
-       DPRINTK("cirrusfb: (RAM start set to: 0x%p)\n", cinfo->fbmem);
+       DPRINTK("cirrusfb: (RAM start set to: 0x%p)\n", info->screen_base);
 
        /* Make pretend we've set the var so our structures are in a "good" */
        /* state, even though we haven't written the mode to the hw yet...  */
@@ -2477,7 +2293,7 @@ static int cirrusfb_register(struct cirrusfb_info *cinfo)
        }
 
        /* set all the vital stuff */
-       cirrusfb_set_fbinfo(cinfo);
+       cirrusfb_set_fbinfo(info);
 
        err = register_framebuffer(info);
        if (err < 0) {
@@ -2492,7 +2308,8 @@ static int cirrusfb_register(struct cirrusfb_info *cinfo)
 err_dealloc_cmap:
        fb_dealloc_cmap(&info->cmap);
 err_unmap_cirrusfb:
-       cinfo->unmap(cinfo);
+       cinfo->unmap(info);
+       framebuffer_release(info);
        return err;
 }
 
@@ -2506,7 +2323,8 @@ static void __devexit cirrusfb_cleanup(struct fb_info *info)
        unregister_framebuffer(info);
        fb_dealloc_cmap(&info->cmap);
        printk("Framebuffer unregistered\n");
-       cinfo->unmap(cinfo);
+       cinfo->unmap(info);
+       framebuffer_release(info);
 
        DPRINTK("EXIT\n");
 }
@@ -2517,7 +2335,7 @@ static int cirrusfb_pci_register(struct pci_dev *pdev,
 {
        struct cirrusfb_info *cinfo;
        struct fb_info *info;
-       cirrusfb_board_t btype;
+       enum cirrus_board btype;
        unsigned long board_addr, board_size;
        int ret;
 
@@ -2535,30 +2353,29 @@ static int cirrusfb_pci_register(struct pci_dev *pdev,
        }
 
        cinfo = info->par;
-       cinfo->info = info;
        cinfo->pdev = pdev;
-       cinfo->btype = btype = (cirrusfb_board_t) ent->driver_data;
+       cinfo->btype = btype = (enum cirrus_board) ent->driver_data;
 
-       DPRINTK(" Found PCI device, base address 0 is 0x%lx, btype set to %d\n",
+       DPRINTK(" Found PCI device, base address 0 is 0x%x, btype set to %d\n",
                pdev->resource[0].start, btype);
-       DPRINTK(" base address 1 is 0x%lx\n", pdev->resource[1].start);
+       DPRINTK(" base address 1 is 0x%x\n", pdev->resource[1].start);
 
        if (isPReP) {
                pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, 0x00000000);
 #ifdef CONFIG_PPC_PREP
-               get_prep_addrs(&board_addr, &cinfo->fbregs_phys);
+               get_prep_addrs(&board_addr, &info->fix.mmio_start);
 #endif
        /* PReP dies if we ioremap the IO registers, but it works w/out... */
-               cinfo->regbase = (char __iomem *) cinfo->fbregs_phys;
+               cinfo->regbase = (char __iomem *) info->fix.mmio_start;
        } else {
                DPRINTK("Attempt to get PCI info for Cirrus Graphics Card\n");
-               get_pci_addrs(pdev, &board_addr, &cinfo->fbregs_phys);
+               get_pci_addrs(pdev, &board_addr, &info->fix.mmio_start);
                /* FIXME: this forces VGA.  alternatives? */
                cinfo->regbase = NULL;
        }
 
        DPRINTK("Board address: 0x%lx, register address: 0x%lx\n",
-               board_addr, cinfo->fbregs_phys);
+               board_addr, info->fix.mmio_start);
 
        board_size = (btype == BT_GD5480) ?
                32 * MB_ : cirrusfb_get_memsize(cinfo->regbase);
@@ -2582,24 +2399,24 @@ static int cirrusfb_pci_register(struct pci_dev *pdev,
        if (request_region(0x3C0, 32, "cirrusfb"))
                release_io_ports = 1;
 
-       cinfo->fbmem = ioremap(board_addr, board_size);
-       if (!cinfo->fbmem) {
+       info->screen_base = ioremap(board_addr, board_size);
+       if (!info->screen_base) {
                ret = -EIO;
                goto err_release_legacy;
        }
 
-       cinfo->fbmem_phys = board_addr;
-       cinfo->size = board_size;
+       info->fix.smem_start = board_addr;
+       info->screen_size = board_size;
        cinfo->unmap = cirrusfb_pci_unmap;
 
-       printk(KERN_INFO " RAM (%lu kB) at 0xx%lx, ",
-               cinfo->size / KB_, board_addr);
-       printk(KERN_INFO "Cirrus Logic chipset on PCI bus\n");
+       printk(KERN_INFO "RAM (%lu kB) at 0x%lx, Cirrus "
+                       "Logic chipset on PCI bus\n",
+                       info->screen_size >> 10, board_addr);
        pci_set_drvdata(pdev, info);
 
-       ret = cirrusfb_register(cinfo);
+       ret = cirrusfb_register(info);
        if (ret)
-               iounmap(cinfo->fbmem);
+               iounmap(info->screen_base);
        return ret;
 
 err_release_legacy:
@@ -2647,7 +2464,7 @@ static int cirrusfb_zorro_register(struct zorro_dev *z,
 {
        struct cirrusfb_info *cinfo;
        struct fb_info *info;
-       cirrusfb_board_t btype;
+       enum cirrus_board btype;
        struct zorro_dev *z2 = NULL;
        unsigned long board_addr, board_size, size;
        int ret;
@@ -2667,17 +2484,15 @@ static int cirrusfb_zorro_register(struct zorro_dev *z,
        }
 
        cinfo = info->par;
-       cinfo->info = info;
        cinfo->btype = btype;
 
-       assert(z > 0);
-       assert(z2 >= 0);
+       assert(z);
        assert(btype != BT_NONE);
 
        cinfo->zdev = z;
        board_addr = zorro_resource_start(z);
        board_size = zorro_resource_len(z);
-       cinfo->size = size;
+       info->screen_size = size;
 
        if (!zorro_request_device(z, "cirrusfb")) {
                printk(KERN_ERR "cirrusfb: cannot reserve region 0x%lx, "
@@ -2705,27 +2520,27 @@ static int cirrusfb_zorro_register(struct zorro_dev *z,
                DPRINTK("cirrusfb: Virtual address for board set to: $%p\n",
                        cinfo->regbase);
                cinfo->regbase += 0x600000;
-               cinfo->fbregs_phys = board_addr + 0x600000;
+               info->fix.mmio_start = board_addr + 0x600000;
 
-               cinfo->fbmem_phys = board_addr + 16777216;
-               cinfo->fbmem = ioremap(cinfo->fbmem_phys, 16777216);
-               if (!cinfo->fbmem)
+               info->fix.smem_start = board_addr + 16777216;
+               info->screen_base = ioremap(info->fix.smem_start, 16777216);
+               if (!info->screen_base)
                        goto err_unmap_regbase;
        } else {
                printk(KERN_INFO " REG at $%lx\n",
                        (unsigned long) z2->resource.start);
 
-               cinfo->fbmem_phys = board_addr;
+               info->fix.smem_start = board_addr;
                if (board_addr > 0x01000000)
-                       cinfo->fbmem = ioremap(board_addr, board_size);
+                       info->screen_base = ioremap(board_addr, board_size);
                else
-                       cinfo->fbmem = (caddr_t) ZTWO_VADDR(board_addr);
-               if (!cinfo->fbmem)
+                       info->screen_base = (caddr_t) ZTWO_VADDR(board_addr);
+               if (!info->screen_base)
                        goto err_release_region;
 
                /* set address for REG area of board */
                cinfo->regbase = (caddr_t) ZTWO_VADDR(z2->resource.start);
-               cinfo->fbregs_phys = z2->resource.start;
+               info->fix.mmio_start = z2->resource.start;
 
                DPRINTK("cirrusfb: Virtual address for board set to: $%p\n",
                        cinfo->regbase);
@@ -2735,13 +2550,13 @@ static int cirrusfb_zorro_register(struct zorro_dev *z,
        printk(KERN_INFO "Cirrus Logic chipset on Zorro bus\n");
        zorro_set_drvdata(z, info);
 
-       ret = cirrusfb_register(cinfo);
+       ret = cirrusfb_register(info);
        if (ret) {
                if (btype == BT_PICASSO4) {
-                       iounmap(cinfo->fbmem);
+                       iounmap(info->screen_base);
                        iounmap(cinfo->regbase - 0x600000);
                } else if (board_addr > 0x01000000)
-                       iounmap(cinfo->fbmem);
+                       iounmap(info->screen_base);
        }
        return ret;
 
@@ -3279,7 +3094,7 @@ static void bestclock(long freq, long *best, long *nom,
                                }
                        }
                }
-               d = ((143181 * n) + f - 1) / f;
+               d = DIV_ROUND_UP(143181 * n, f);
                if ((d >= 7) && (d <= 63)) {
                        if (d > 31)
                                d = (d / 2) * 2;
@@ -3353,7 +3168,7 @@ void cirrusfb_dbg_print_byte(const char *name, unsigned char val)
 
 static
 void cirrusfb_dbg_print_regs(caddr_t regbase,
-                            cirrusfb_dbg_reg_class_t reg_class, ...)
+                            enum cirrusfb_dbg_reg_class reg_class, ...)
 {
        va_list list;
        unsigned char val = 0;