fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / video / ffb.c
index 1f76131..1d4e835 100644 (file)
@@ -1,6 +1,6 @@
 /* ffb.c: Creator/Elite3D frame buffer driver
  *
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * Copyright (C) 2003, 2006 David S. Miller (davem@davemloft.net)
  * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
  *
  * Driver layout based loosely on tgafb.c, see that file for credits.
@@ -19,7 +19,8 @@
 
 #include <asm/io.h>
 #include <asm/upa.h>
-#include <asm/oplib.h>
+#include <asm/prom.h>
+#include <asm/of_device.h>
 #include <asm/fbio.h>
 
 #include "sbuslib.h"
@@ -37,9 +38,8 @@ static void ffb_imageblit(struct fb_info *, const struct fb_image *);
 static void ffb_fillrect(struct fb_info *, const struct fb_fillrect *);
 static void ffb_copyarea(struct fb_info *, const struct fb_copyarea *);
 static int ffb_sync(struct fb_info *);
-static int ffb_mmap(struct fb_info *, struct file *, struct vm_area_struct *);
-static int ffb_ioctl(struct inode *, struct file *, unsigned int,
-                    unsigned long, struct fb_info *);
+static int ffb_mmap(struct fb_info *, struct vm_area_struct *);
+static int ffb_ioctl(struct fb_info *, unsigned int, unsigned long);
 static int ffb_pan_display(struct fb_var_screeninfo *, struct fb_info *);
 
 /*
@@ -57,9 +57,9 @@ static struct fb_ops ffb_ops = {
        .fb_sync                = ffb_sync,
        .fb_mmap                = ffb_mmap,
        .fb_ioctl               = ffb_ioctl,
-
-       /* XXX Use FFB hw cursor once fb cursor API is better understood... */
-       .fb_cursor              = soft_cursor,
+#ifdef CONFIG_COMPAT
+       .fb_compat_ioctl        = sbusfb_compat_ioctl,
+#endif
 };
 
 /* Register layout and definitions */
@@ -185,165 +185,181 @@ static struct fb_ops ffb_ops = {
 
 struct ffb_fbc {
        /* Next vertex registers */
-       u32             xxx1[3];
-       volatile u32    alpha;
-       volatile u32    red;
-       volatile u32    green;
-       volatile u32    blue;
-       volatile u32    depth;
-       volatile u32    y;
-       volatile u32    x;
-       u32             xxx2[2];
-       volatile u32    ryf;
-       volatile u32    rxf;
-       u32             xxx3[2];
+       u32     xxx1[3];
+       u32     alpha;
+       u32     red;
+       u32     green;
+       u32     blue;
+       u32     depth;
+       u32     y;
+       u32     x;
+       u32     xxx2[2];
+       u32     ryf;
+       u32     rxf;
+       u32     xxx3[2];
        
-       volatile u32    dmyf;
-       volatile u32    dmxf;
-       u32             xxx4[2];
-       volatile u32    ebyi;
-       volatile u32    ebxi;
-       u32             xxx5[2];
-       volatile u32    by;
-       volatile u32    bx;
-       u32             dy;
-       u32             dx;
-       volatile u32    bh;
-       volatile u32    bw;
-       u32             xxx6[2];
+       u32     dmyf;
+       u32     dmxf;
+       u32     xxx4[2];
+       u32     ebyi;
+       u32     ebxi;
+       u32     xxx5[2];
+       u32     by;
+       u32     bx;
+       u32     dy;
+       u32     dx;
+       u32     bh;
+       u32     bw;
+       u32     xxx6[2];
        
-       u32             xxx7[32];
+       u32     xxx7[32];
        
        /* Setup unit vertex state register */
-       volatile u32    suvtx;
-       u32             xxx8[63];
+       u32     suvtx;
+       u32     xxx8[63];
        
        /* Control registers */
-       volatile u32    ppc;
-       volatile u32    wid;
-       volatile u32    fg;
-       volatile u32    bg;
-       volatile u32    consty;
-       volatile u32    constz;
-       volatile u32    xclip;
-       volatile u32    dcss;
-       volatile u32    vclipmin;
-       volatile u32    vclipmax;
-       volatile u32    vclipzmin;
-       volatile u32    vclipzmax;
-       volatile u32    dcsf;
-       volatile u32    dcsb;
-       volatile u32    dczf;
-       volatile u32    dczb;
+       u32     ppc;
+       u32     wid;
+       u32     fg;
+       u32     bg;
+       u32     consty;
+       u32     constz;
+       u32     xclip;
+       u32     dcss;
+       u32     vclipmin;
+       u32     vclipmax;
+       u32     vclipzmin;
+       u32     vclipzmax;
+       u32     dcsf;
+       u32     dcsb;
+       u32     dczf;
+       u32     dczb;
        
-       u32             xxx9;
-       volatile u32    blendc;
-       volatile u32    blendc1;
-       volatile u32    blendc2;
-       volatile u32    fbramitc;
-       volatile u32    fbc;
-       volatile u32    rop;
-       volatile u32    cmp;
-       volatile u32    matchab;
-       volatile u32    matchc;
-       volatile u32    magnab;
-       volatile u32    magnc;
-       volatile u32    fbcfg0;
-       volatile u32    fbcfg1;
-       volatile u32    fbcfg2;
-       volatile u32    fbcfg3;
+       u32     xxx9;
+       u32     blendc;
+       u32     blendc1;
+       u32     blendc2;
+       u32     fbramitc;
+       u32     fbc;
+       u32     rop;
+       u32     cmp;
+       u32     matchab;
+       u32     matchc;
+       u32     magnab;
+       u32     magnc;
+       u32     fbcfg0;
+       u32     fbcfg1;
+       u32     fbcfg2;
+       u32     fbcfg3;
        
-       u32             ppcfg;
-       volatile u32    pick;
-       volatile u32    fillmode;
-       volatile u32    fbramwac;
-       volatile u32    pmask;
-       volatile u32    xpmask;
-       volatile u32    ypmask;
-       volatile u32    zpmask;
-       volatile u32    clip0min;
-       volatile u32    clip0max;
-       volatile u32    clip1min;
-       volatile u32    clip1max;
-       volatile u32    clip2min;
-       volatile u32    clip2max;
-       volatile u32    clip3min;
-       volatile u32    clip3max;
+       u32     ppcfg;
+       u32     pick;
+       u32     fillmode;
+       u32     fbramwac;
+       u32     pmask;
+       u32     xpmask;
+       u32     ypmask;
+       u32     zpmask;
+       u32     clip0min;
+       u32     clip0max;
+       u32     clip1min;
+       u32     clip1max;
+       u32     clip2min;
+       u32     clip2max;
+       u32     clip3min;
+       u32     clip3max;
        
        /* New 3dRAM III support regs */
-       volatile u32    rawblend2;
-       volatile u32    rawpreblend;
-       volatile u32    rawstencil;
-       volatile u32    rawstencilctl;
-       volatile u32    threedram1;
-       volatile u32    threedram2;
-       volatile u32    passin;
-       volatile u32    rawclrdepth;
-       volatile u32    rawpmask;
-       volatile u32    rawcsrc;
-       volatile u32    rawmatch;
-       volatile u32    rawmagn;
-       volatile u32    rawropblend;
-       volatile u32    rawcmp;
-       volatile u32    rawwac;
-       volatile u32    fbramid;
+       u32     rawblend2;
+       u32     rawpreblend;
+       u32     rawstencil;
+       u32     rawstencilctl;
+       u32     threedram1;
+       u32     threedram2;
+       u32     passin;
+       u32     rawclrdepth;
+       u32     rawpmask;
+       u32     rawcsrc;
+       u32     rawmatch;
+       u32     rawmagn;
+       u32     rawropblend;
+       u32     rawcmp;
+       u32     rawwac;
+       u32     fbramid;
        
-       volatile u32    drawop;
-       u32             xxx10[2];
-       volatile u32    fontlpat;
-       u32             xxx11;
-       volatile u32    fontxy;
-       volatile u32    fontw;
-       volatile u32    fontinc;
-       volatile u32    font;
-       u32             xxx12[3];
-       volatile u32    blend2;
-       volatile u32    preblend;
-       volatile u32    stencil;
-       volatile u32    stencilctl;
-
-       u32             xxx13[4];       
-       volatile u32    dcss1;
-       volatile u32    dcss2;
-       volatile u32    dcss3;
-       volatile u32    widpmask;
-       volatile u32    dcs2;
-       volatile u32    dcs3;
-       volatile u32    dcs4;
-       u32             xxx14;
-       volatile u32    dcd2;
-       volatile u32    dcd3;
-       volatile u32    dcd4;
-       u32             xxx15;
+       u32     drawop;
+       u32     xxx10[2];
+       u32     fontlpat;
+       u32     xxx11;
+       u32     fontxy;
+       u32     fontw;
+       u32     fontinc;
+       u32     font;
+       u32     xxx12[3];
+       u32     blend2;
+       u32     preblend;
+       u32     stencil;
+       u32     stencilctl;
+
+       u32     xxx13[4];       
+       u32     dcss1;
+       u32     dcss2;
+       u32     dcss3;
+       u32     widpmask;
+       u32     dcs2;
+       u32     dcs3;
+       u32     dcs4;
+       u32     xxx14;
+       u32     dcd2;
+       u32     dcd3;
+       u32     dcd4;
+       u32     xxx15;
        
-       volatile u32    pattern[32];
+       u32     pattern[32];
        
-       u32             xxx16[256];
+       u32     xxx16[256];
        
-       volatile u32    devid;
-       u32             xxx17[63];
+       u32     devid;
+       u32     xxx17[63];
        
-       volatile u32    ucsr;
-       u32             xxx18[31];
+       u32     ucsr;
+       u32     xxx18[31];
        
-       volatile u32    mer;
+       u32     mer;
 };
 
 struct ffb_dac {
-       volatile u32    type;
-       volatile u32    value;
-       volatile u32    type2;
-       volatile u32    value2;
+       u32     type;
+       u32     value;
+       u32     type2;
+       u32     value2;
 };
 
+#define FFB_DAC_UCTRL  0x1001 /* User Control */
+#define  FFB_DAC_UCTRL_MANREV  0x00000f00 /* 4-bit Manufacturing Revision */
+#define  FFB_DAC_UCTRL_MANREV_SHIFT 8
+#define FFB_DAC_TGEN   0x6000 /* Timing Generator */
+#define  FFB_DAC_TGEN_VIDE     0x00000001 /* Video Enable */
+#define FFB_DAC_DID    0x8000 /* Device Identification */
+#define  FFB_DAC_DID_PNUM      0x0ffff000 /* Device Part Number */
+#define  FFB_DAC_DID_PNUM_SHIFT 12
+#define  FFB_DAC_DID_REV       0xf0000000 /* Device Revision */
+#define  FFB_DAC_DID_REV_SHIFT 28
+
+#define FFB_DAC_CUR_CTRL       0x100
+#define  FFB_DAC_CUR_CTRL_P0   0x00000001
+#define  FFB_DAC_CUR_CTRL_P1   0x00000002
+
 struct ffb_par {
        spinlock_t              lock;
-       struct ffb_fbc          *fbc;
-       struct ffb_dac          *dac;
+       struct ffb_fbc __iomem  *fbc;
+       struct ffb_dac __iomem  *dac;
 
        u32                     flags;
-#define FFB_FLAG_AFB           0x00000001
-#define FFB_FLAG_BLANKED       0x00000002
+#define FFB_FLAG_AFB           0x00000001 /* AFB m3 or m6 */
+#define FFB_FLAG_BLANKED       0x00000002 /* screen is blanked */
+#define FFB_FLAG_INVCURSOR     0x00000004 /* DAC has inverted cursor logic */
 
        u32                     fg_cache __attribute__((aligned (8)));
        u32                     bg_cache;
@@ -354,72 +370,12 @@ struct ffb_par {
        unsigned long           physbase;
        unsigned long           fbsize;
 
-       char                    name[64];
-       int                     prom_node;
-       int                     prom_parent_node;
-       int                     dac_rev;
        int                     board_type;
-       struct list_head        list;
 };
 
-#undef FFB_DO_DEBUG_LOG
-
-#ifdef FFB_DO_DEBUG_LOG
-#define FFB_DEBUG_LOG_ENTS     32
-static struct ffb_log {
-       int op;
-#define OP_FILLRECT    1
-#define OP_IMAGEBLIT   2
-
-       int depth, x, y, w, h;
-} ffb_debug_log[FFB_DEBUG_LOG_ENTS];
-static int ffb_debug_log_ent;
-
-static void ffb_do_log(unsigned long unused)
-{
-       int i;
-
-       for (i = 0; i < FFB_DEBUG_LOG_ENTS; i++) {
-               struct ffb_log *p = &ffb_debug_log[i];
-
-               printk("FFB_LOG: OP[%s] depth(%d) x(%d) y(%d) w(%d) h(%d)\n",
-                      (p->op == OP_FILLRECT ? "FILLRECT" : "IMAGEBLIT"),
-                      p->depth, p->x, p->y, p->w, p->h);
-       }
-}
-static struct timer_list ffb_log_timer =
-       TIMER_INITIALIZER(ffb_do_log, 0, 0);
-
-static void ffb_log(int op, int depth, int x, int y, int w, int h)
-{
-       if (ffb_debug_log_ent < FFB_DEBUG_LOG_ENTS) {
-               struct ffb_log *p = &ffb_debug_log[ffb_debug_log_ent];
-
-               if (ffb_debug_log_ent != 0 &&
-                   p[-1].op == op && p[-1].depth == depth)
-                       return;
-               p->op = op;
-               p->depth = depth;
-               p->x = x;
-               p->y = y;
-               p->w = w;
-               p->h = h;
-
-               if (++ffb_debug_log_ent == FFB_DEBUG_LOG_ENTS) {
-                       ffb_log_timer.expires = jiffies + 2;
-                       add_timer(&ffb_log_timer);
-               }
-       }
-}
-#else
-#define ffb_log(a,b,c,d,e,f)   do { } while(0)
-#endif
-
-#undef FORCE_WAIT_EVERY_ROP
-
 static void FFBFifo(struct ffb_par *par, int n)
 {
-       struct ffb_fbc *fbc;
+       struct ffb_fbc __iomem *fbc;
        int cache = par->fifo_cache;
 
        if (cache - n < 0) {
@@ -432,7 +388,7 @@ static void FFBFifo(struct ffb_par *par, int n)
 
 static void FFBWait(struct ffb_par *par)
 {
-       struct ffb_fbc *fbc;
+       struct ffb_fbc __iomem *fbc;
        int limit = 10000;
 
        fbc = par->fbc;
@@ -465,8 +421,8 @@ static __inline__ void ffb_rop(struct ffb_par *par, u32 rop)
 
 static void ffb_switch_from_graph(struct ffb_par *par)
 {
-       struct ffb_fbc *fbc = par->fbc;
-       struct ffb_dac *dac = par->dac;
+       struct ffb_fbc __iomem *fbc = par->fbc;
+       struct ffb_dac __iomem *dac = par->dac;
        unsigned long flags;
 
        spin_lock_irqsave(&par->lock, flags);
@@ -479,17 +435,18 @@ static void ffb_switch_from_graph(struct ffb_par *par)
        upa_writel(0x2000707f, &fbc->fbc);
        upa_writel(par->rop_cache, &fbc->rop);
        upa_writel(0xffffffff, &fbc->pmask);
-       upa_writel((0 << 16) | (32 << 0), &fbc->fontinc);
+       upa_writel((1 << 16) | (0 << 0), &fbc->fontinc);
        upa_writel(par->fg_cache, &fbc->fg);
        upa_writel(par->bg_cache, &fbc->bg);
        FFBWait(par);
 
        /* Disable cursor.  */
-       upa_writel(0x100, &dac->type2);
-       if (par->dac_rev <= 2)
+       upa_writel(FFB_DAC_CUR_CTRL, &dac->type2);
+       if (par->flags & FFB_FLAG_INVCURSOR)
                upa_writel(0, &dac->value2);
        else
-               upa_writel(3, &dac->value2);
+               upa_writel((FFB_DAC_CUR_CTRL_P0 |
+                           FFB_DAC_CUR_CTRL_P1), &dac->value2);
 
        spin_unlock_irqrestore(&par->lock, flags);
 }
@@ -519,14 +476,11 @@ static int ffb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
 static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
        struct ffb_par *par = (struct ffb_par *) info->par;
-       struct ffb_fbc *fbc = par->fbc;
+       struct ffb_fbc __iomem *fbc = par->fbc;
        unsigned long flags;
        u32 fg;
 
-       if (rect->rop != ROP_COPY && rect->rop != ROP_XOR)
-               BUG();
-
-       ffb_log(OP_FILLRECT, 0, rect->dx, rect->dy, rect->width, rect->height);
+       BUG_ON(rect->rop != ROP_COPY && rect->rop != ROP_XOR);
 
        fg = ((u32 *)info->pseudo_palette)[rect->color];
 
@@ -548,9 +502,6 @@ static void ffb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
        upa_writel(rect->dx, &fbc->bx);
        upa_writel(rect->height, &fbc->bh);
        upa_writel(rect->width, &fbc->bw);
-#ifdef FORCE_WAIT_EVERY_ROP
-       FFBWait(par);
-#endif
 
        spin_unlock_irqrestore(&par->lock, flags);
 }
@@ -568,11 +519,11 @@ static void
 ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area) 
 {
        struct ffb_par *par = (struct ffb_par *) info->par;
-       struct ffb_fbc *fbc = par->fbc;
+       struct ffb_fbc __iomem *fbc = par->fbc;
        unsigned long flags;
 
        if (area->dx != area->sx ||
-           area->dy == area->dy) {
+           area->dy == area->sy) {
                cfb_copyarea(info, area);
                return;
        }
@@ -604,15 +555,12 @@ ffb_copyarea(struct fb_info *info, const struct fb_copyarea *area)
 static void ffb_imageblit(struct fb_info *info, const struct fb_image *image)
 {
        struct ffb_par *par = (struct ffb_par *) info->par;
-       struct ffb_fbc *fbc = par->fbc;
+       struct ffb_fbc __iomem *fbc = par->fbc;
        const u8 *data = image->data;
        unsigned long flags;
        u32 fg, bg, xy;
        u64 fgbg;
-       int i, width;
-
-       ffb_log(OP_IMAGEBLIT, image->depth,
-               image->dx, image->dy, image->width, image->height);
+       int i, width, stride;
 
        if (image->depth > 1) {
                cfb_imageblit(info, image);
@@ -623,6 +571,8 @@ static void ffb_imageblit(struct fb_info *info, const struct fb_image *image)
        bg = ((u32 *)info->pseudo_palette)[image->bg_color];
        fgbg = ((u64) fg << 32) | (u64) bg;
        xy = (image->dy << 16) | image->dx;
+       width = image->width;
+       stride = ((width + 7) >> 3);
 
        spin_lock_irqsave(&par->lock, flags);
 
@@ -632,55 +582,49 @@ static void ffb_imageblit(struct fb_info *info, const struct fb_image *image)
                *(u64 *)&par->fg_cache = fgbg;
        }
 
-       ffb_rop(par, FFB_ROP_NEW);
+       if (width >= 32) {
+               FFBFifo(par, 1);
+               upa_writel(32, &fbc->fontw);
+       }
 
-       for (i = 0; i < image->height; i++) {
-               width = image->width;
+       while (width >= 32) {
+               const u8 *next_data = data + 4;
 
                FFBFifo(par, 1);
                upa_writel(xy, &fbc->fontxy);
-               xy += (1 << 16);
-
-               while (width >= 32) {
-                       u32 val;
-
-                       FFBFifo(par, 2);
-                       upa_writel(32, &fbc->fontw);
-
-                       val = ((u32)data[0] << 24) |
-                             ((u32)data[1] << 16) |
-                             ((u32)data[2] <<  8) |
-                             ((u32)data[3] <<  0);
+               xy += (32 << 0);
+
+               for (i = 0; i < image->height; i++) {
+                       u32 val = (((u32)data[0] << 24) |
+                                  ((u32)data[1] << 16) |
+                                  ((u32)data[2] <<  8) |
+                                  ((u32)data[3] <<  0));
+                       FFBFifo(par, 1);
                        upa_writel(val, &fbc->font);
 
-                       data += 4;
-                       width -= 32;
+                       data += stride;
                }
 
-               if (width) {
-                       u32 val;
-
-                       FFBFifo(par, 2);
-                       upa_writel(width, &fbc->fontw);
-                       if (width <= 8) {
-                               val = (u32) data[0] << 24;
-                               data += 1;
-                       } else if (width <= 16) {
-                               val = ((u32) data[0] << 24) |
-                                     ((u32) data[1] << 16);
-                               data += 2;
-                       } else {
-                               val = ((u32) data[0] << 24) |
-                                     ((u32) data[1] << 16) |
-                                     ((u32) data[2] <<  8);
-                               data += 3;
-                       }
+               data = next_data;
+               width -= 32;
+       }
+
+       if (width) {
+               FFBFifo(par, 2);
+               upa_writel(width, &fbc->fontw);
+               upa_writel(xy, &fbc->fontxy);
+
+               for (i = 0; i < image->height; i++) {
+                       u32 val = (((u32)data[0] << 24) |
+                                  ((u32)data[1] << 16) |
+                                  ((u32)data[2] <<  8) |
+                                  ((u32)data[3] <<  0));
+                       FFBFifo(par, 1);
                        upa_writel(val, &fbc->font);
+
+                       data += stride;
                }
        }
-#ifdef FORCE_WAIT_EVERY_ROP
-       FFBWait(par);
-#endif
 
        spin_unlock_irqrestore(&par->lock, flags);
 }
@@ -734,34 +678,37 @@ static int
 ffb_blank(int blank, struct fb_info *info)
 {
        struct ffb_par *par = (struct ffb_par *) info->par;
-       struct ffb_dac *dac = par->dac;
+       struct ffb_dac __iomem *dac = par->dac;
        unsigned long flags;
-       u32 tmp;
+       u32 val;
+       int i;
 
        spin_lock_irqsave(&par->lock, flags);
 
        FFBWait(par);
 
+       upa_writel(FFB_DAC_TGEN, &dac->type);
+       val = upa_readl(&dac->value);
        switch (blank) {
-       case 0: /* Unblanking */
-               upa_writel(0x6000, &dac->type);
-               tmp = (upa_readl(&dac->value) | 0x1);
-               upa_writel(0x6000, &dac->type);
-               upa_writel(tmp, &dac->value);
+       case FB_BLANK_UNBLANK: /* Unblanking */
+               val |= FFB_DAC_TGEN_VIDE;
                par->flags &= ~FFB_FLAG_BLANKED;
                break;
 
-       case 1: /* Normal blanking */
-       case 2: /* VESA blank (vsync off) */
-       case 3: /* VESA blank (hsync off) */
-       case 4: /* Poweroff */
-               upa_writel(0x6000, &dac->type);
-               tmp = (upa_readl(&dac->value) & ~0x1);
-               upa_writel(0x6000, &dac->type);
-               upa_writel(tmp, &dac->value);
+       case FB_BLANK_NORMAL: /* Normal blanking */
+       case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
+       case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
+       case FB_BLANK_POWERDOWN: /* Poweroff */
+               val &= ~FFB_DAC_TGEN_VIDE;
                par->flags |= FFB_FLAG_BLANKED;
                break;
        }
+       upa_writel(FFB_DAC_TGEN, &dac->type);
+       upa_writel(val, &dac->value);
+       for (i = 0; i < 10; i++) {
+               upa_writel(FFB_DAC_TGEN, &dac->type);
+               upa_readl(&dac->value);
+       }
 
        spin_unlock_irqrestore(&par->lock, flags);
 
@@ -907,7 +854,7 @@ static struct sbus_mmap_map ffb_mmap_map[] = {
        { .size = 0 }
 };
 
-static int ffb_mmap(struct fb_info *info, struct file *file, struct vm_area_struct *vma)
+static int ffb_mmap(struct fb_info *info, struct vm_area_struct *vma)
 {
        struct ffb_par *par = (struct ffb_par *)info->par;
 
@@ -916,8 +863,7 @@ static int ffb_mmap(struct fb_info *info, struct file *file, struct vm_area_stru
                                  0, vma);
 }
 
-static int ffb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-                    unsigned long arg, struct fb_info *info)
+static int ffb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
 {
        struct ffb_par *par = (struct ffb_par *) info->par;
 
@@ -954,87 +900,58 @@ ffb_init_fix(struct fb_info *info)
        info->fix.accel = FB_ACCEL_SUN_CREATOR;
 }
 
-static int ffb_apply_upa_parent_ranges(int parent,
-                                      struct linux_prom64_registers *regs)
-{
-       struct linux_prom64_ranges ranges[PROMREG_MAX];
-       char name[128];
-       int len, i;
-
-       prom_getproperty(parent, "name", name, sizeof(name));
-       if (strcmp(name, "upa") != 0)
-               return 0;
-
-       len = prom_getproperty(parent, "ranges", (void *) ranges, sizeof(ranges));
-       if (len <= 0)
-               return 1;
-
-       len /= sizeof(struct linux_prom64_ranges);
-       for (i = 0; i < len; i++) {
-               struct linux_prom64_ranges *rng = &ranges[i];
-               u64 phys_addr = regs->phys_addr;
-
-               if (phys_addr >= rng->ot_child_base &&
-                   phys_addr < (rng->ot_child_base + rng->or_size)) {
-                       regs->phys_addr -= rng->ot_child_base;
-                       regs->phys_addr += rng->ot_parent_base;
-                       return 0;
-               }
-       }
-
-       return 1;
-}
-
 struct all_info {
        struct fb_info info;
        struct ffb_par par;
        u32 pseudo_palette[256];
-       struct list_head list;
 };
-static LIST_HEAD(ffb_list);
 
-static void ffb_init_one(int node, int parent)
+static int ffb_init_one(struct of_device *op)
 {
-       struct linux_prom64_registers regs[2*PROMREG_MAX];
-       struct ffb_fbc *fbc;
-       struct ffb_dac *dac;
+       struct device_node *dp = op->node;
+       struct ffb_fbc __iomem *fbc;
+       struct ffb_dac __iomem *dac;
        struct all_info *all;
+       int err;
+       u32 dac_pnum, dac_rev, dac_mrev;
 
-       if (prom_getproperty(node, "reg", (void *) regs, sizeof(regs)) <= 0) {
-               printk("ffb: Cannot get reg device node property.\n");
-               return;
-       }
+       all = kzalloc(sizeof(*all), GFP_KERNEL);
+       if (!all)
+               return -ENOMEM;
 
-       if (ffb_apply_upa_parent_ranges(parent, &regs[0])) {
-               printk("ffb: Cannot apply parent ranges to regs.\n");
-               return;
+       spin_lock_init(&all->par.lock);
+       all->par.fbc = of_ioremap(&op->resource[2], 0,
+                                 sizeof(struct ffb_fbc), "ffb fbc");
+       if (!all->par.fbc) {
+               kfree(all);
+               return -ENOMEM;
        }
 
-       all = kmalloc(sizeof(*all), GFP_KERNEL);
-       if (!all) {
-               printk(KERN_ERR "ffb: Cannot allocate memory.\n");
-               return;
+       all->par.dac = of_ioremap(&op->resource[1], 0,
+                                 sizeof(struct ffb_dac), "ffb dac");
+       if (!all->par.dac) {
+               of_iounmap(&op->resource[2],
+                          all->par.fbc, sizeof(struct ffb_fbc));
+               kfree(all);
+               return -ENOMEM;
        }
-       memset(all, 0, sizeof(*all));
-
-       INIT_LIST_HEAD(&all->list);     
 
-       spin_lock_init(&all->par.lock);
-       all->par.fbc = (struct ffb_fbc *)(regs[0].phys_addr + FFB_FBC_REGS_POFF);
-       all->par.dac = (struct ffb_dac *)(regs[0].phys_addr + FFB_DAC_POFF);
        all->par.rop_cache = FFB_ROP_NEW;
-       all->par.physbase = regs[0].phys_addr;
-       all->par.prom_node = node;
-       all->par.prom_parent_node = parent;
+       all->par.physbase = op->resource[0].start;
 
-       all->info.flags = FBINFO_FLAG_DEFAULT;
+       /* Don't mention copyarea, so SCROLL_REDRAW is always
+        * used.  It is the fastest on this chip.
+        */
+       all->info.flags = (FBINFO_DEFAULT |
+                          /* FBINFO_HWACCEL_COPYAREA | */
+                          FBINFO_HWACCEL_FILLRECT |
+                          FBINFO_HWACCEL_IMAGEBLIT);
        all->info.fbops = &ffb_ops;
        all->info.screen_base = (char *) all->par.physbase + FFB_DFB24_POFF;
-       all->info.currcon = -1;
        all->info.par = &all->par;
        all->info.pseudo_palette = all->pseudo_palette;
 
-       sbusfb_fill_var(&all->info.var, all->par.prom_node, 32);
+       sbusfb_fill_var(&all->info.var, dp->node, 32);
        all->par.fbsize = PAGE_ALIGN(all->info.var.xres *
                                     all->info.var.yres *
                                     4);
@@ -1042,27 +959,40 @@ static void ffb_init_one(int node, int parent)
 
        all->info.var.accel_flags = FB_ACCELF_TEXT;
 
-       prom_getstring(node, "name", all->par.name, sizeof(all->par.name));
-       if (!strcmp(all->par.name, "SUNW,afb"))
+       if (!strcmp(dp->name, "SUNW,afb"))
                all->par.flags |= FFB_FLAG_AFB;
 
-       all->par.board_type = prom_getintdefault(node, "board_type", 0);
+       all->par.board_type = of_getintprop_default(dp, "board_type", 0);
 
        fbc = all->par.fbc;
-       if((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
+       if ((upa_readl(&fbc->ucsr) & FFB_UCSR_ALL_ERRORS) != 0)
                upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
 
-       ffb_switch_from_graph(&all->par);
-
        dac = all->par.dac;
-       upa_writel(0x8000, &dac->type);
-       all->par.dac_rev = upa_readl(&dac->value) >> 0x1c;
+       upa_writel(FFB_DAC_DID, &dac->type);
+       dac_pnum = upa_readl(&dac->value);
+       dac_rev = (dac_pnum & FFB_DAC_DID_REV) >> FFB_DAC_DID_REV_SHIFT;
+       dac_pnum = (dac_pnum & FFB_DAC_DID_PNUM) >> FFB_DAC_DID_PNUM_SHIFT;
+
+       upa_writel(FFB_DAC_UCTRL, &dac->type);
+       dac_mrev = upa_readl(&dac->value);
+       dac_mrev = (dac_mrev & FFB_DAC_UCTRL_MANREV) >>
+               FFB_DAC_UCTRL_MANREV_SHIFT;
 
        /* Elite3D has different DAC revision numbering, and no DAC revisions
-        * have the reversed meaning of cursor enable.
+        * have the reversed meaning of cursor enable.  Otherwise, Pacifica 1
+        * ramdacs with manufacturing revision less than 3 have inverted
+        * cursor logic.  We identify Pacifica 1 as not Pacifica 2, the
+        * latter having a part number value of 0x236e.
         */
-       if (all->par.flags & FFB_FLAG_AFB)
-               all->par.dac_rev = 10;
+       if ((all->par.flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) {
+               all->par.flags &= ~FFB_FLAG_INVCURSOR;
+       } else {
+               if (dac_mrev < 3)
+                       all->par.flags |= FFB_FLAG_INVCURSOR;
+       }
+
+       ffb_switch_from_graph(&all->par);
 
        /* Unblank it just to be sure.  When there are multiple
         * FFB/AFB cards in the system, or it is not the OBP
@@ -1073,78 +1003,99 @@ static void ffb_init_one(int node, int parent)
 
        if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
                printk(KERN_ERR "ffb: Could not allocate color map.\n");
+               of_iounmap(&op->resource[2],
+                          all->par.fbc, sizeof(struct ffb_fbc));
+               of_iounmap(&op->resource[1],
+                          all->par.dac, sizeof(struct ffb_dac));
                kfree(all);
-               return;
+               return -ENOMEM;
        }
 
        ffb_init_fix(&all->info);
 
-       if (register_framebuffer(&all->info) < 0) {
+       err = register_framebuffer(&all->info);
+       if (err < 0) {
                printk(KERN_ERR "ffb: Could not register framebuffer.\n");
                fb_dealloc_cmap(&all->info.cmap);
+               of_iounmap(&op->resource[2],
+                          all->par.fbc, sizeof(struct ffb_fbc));
+               of_iounmap(&op->resource[1],
+                          all->par.dac, sizeof(struct ffb_dac));
                kfree(all);
-               return;
+               return err;
        }
 
-       list_add(&all->list, &ffb_list);
+       dev_set_drvdata(&op->dev, all);
 
-       printk("ffb: %s at %016lx type %d DAC %d\n",
+       printk("%s: %s at %016lx, type %d, "
+              "DAC pnum[%x] rev[%d] manuf_rev[%d]\n",
+              dp->full_name,
               ((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
-              regs[0].phys_addr, all->par.board_type, all->par.dac_rev);
+              all->par.physbase, all->par.board_type,
+              dac_pnum, dac_rev, dac_mrev);
+
+       return 0;
 }
 
-static void ffb_scan_siblings(int root)
+static int __devinit ffb_probe(struct of_device *dev, const struct of_device_id *match)
 {
-       int node, child;
-
-       child = prom_getchild(root);
-       for (node = prom_searchsiblings(child, "SUNW,ffb"); node;
-            node = prom_searchsiblings(prom_getsibling(node), "SUNW,ffb"))
-               ffb_init_one(node, root);
-       for (node = prom_searchsiblings(child, "SUNW,afb"); node;
-            node = prom_searchsiblings(prom_getsibling(node), "SUNW,afb"))
-               ffb_init_one(node, root);
+       struct of_device *op = to_of_device(&dev->dev);
+
+       return ffb_init_one(op);
 }
 
-int __init ffb_init(void)
+static int __devexit ffb_remove(struct of_device *op)
 {
-       int root;
+       struct all_info *all = dev_get_drvdata(&op->dev);
 
-       ffb_scan_siblings(prom_root_node);
+       unregister_framebuffer(&all->info);
+       fb_dealloc_cmap(&all->info.cmap);
 
-       root = prom_getchild(prom_root_node);
-       for (root = prom_searchsiblings(root, "upa"); root;
-            root = prom_searchsiblings(prom_getsibling(root), "upa"))
-               ffb_scan_siblings(root);
+       of_iounmap(&op->resource[2], all->par.fbc, sizeof(struct ffb_fbc));
+       of_iounmap(&op->resource[1], all->par.dac, sizeof(struct ffb_dac));
+
+       kfree(all);
+
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }
 
-void __exit ffb_exit(void)
-{
-       struct list_head *pos, *tmp;
+static struct of_device_id ffb_match[] = {
+       {
+               .name = "SUNW,ffb",
+       },
+       {
+               .name = "SUNW,afb",
+       },
+       {},
+};
+MODULE_DEVICE_TABLE(of, ffb_match);
 
-       list_for_each_safe(pos, tmp, &ffb_list) {
-               struct all_info *all = list_entry(pos, typeof(*all), list);
+static struct of_platform_driver ffb_driver = {
+       .name           = "ffb",
+       .match_table    = ffb_match,
+       .probe          = ffb_probe,
+       .remove         = __devexit_p(ffb_remove),
+};
 
-               unregister_framebuffer(&all->info);
-               fb_dealloc_cmap(&all->info.cmap);
-               kfree(all);
-       }
+int __init ffb_init(void)
+{
+       if (fb_get_options("ffb", NULL))
+               return -ENODEV;
+
+       return of_register_driver(&ffb_driver, &of_bus_type);
 }
 
-int __init
-ffb_setup(char *arg)
+void __exit ffb_exit(void)
 {
-       /* No cmdline options yet... */
-       return 0;
+       of_unregister_driver(&ffb_driver);
 }
 
-#ifdef MODULE
 module_init(ffb_init);
 module_exit(ffb_exit);
-#endif
 
 MODULE_DESCRIPTION("framebuffer driver for Creator/Elite3D chipsets");
-MODULE_AUTHOR("David S. Miller <davem@redhat.com>");
+MODULE_AUTHOR("David S. Miller <davem@davemloft.net>");
+MODULE_VERSION("2.0");
 MODULE_LICENSE("GPL");