]> err.no Git - linux-2.6/blobdiff - drivers/video/ffb.c
Merge branch 'merge' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
[linux-2.6] / drivers / video / ffb.c
index 949141bd44d44af445eeba4035b939f8c728f21f..4b520b573911f96d617935a2741898204b46b153 100644 (file)
@@ -336,14 +336,30 @@ struct ffb_dac {
        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 __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,8 +370,9 @@ struct ffb_par {
        unsigned long           physbase;
        unsigned long           fbsize;
 
-       int                     dac_rev;
        int                     board_type;
+
+       u32                     pseudo_palette[16];
 };
 
 static void FFBFifo(struct ffb_par *par, int n)
@@ -426,11 +443,12 @@ static void ffb_switch_from_graph(struct ffb_par *par)
        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);
 }
@@ -640,7 +658,7 @@ static int ffb_setcolreg(unsigned regno,
 {
        u32 value;
 
-       if (regno >= 256)
+       if (regno >= 16)
                return 1;
 
        red >>= 8;
@@ -664,18 +682,18 @@ ffb_blank(int blank, struct fb_info *info)
        struct ffb_par *par = (struct ffb_par *) info->par;
        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 FB_BLANK_UNBLANK: /* Unblanking */
-               upa_writel(0x6000, &dac->type);
-               tmp = (upa_readl(&dac->value) | 0x1);
-               upa_writel(0x6000, &dac->type);
-               upa_writel(tmp, &dac->value);
+               val |= FFB_DAC_TGEN_VIDE;
                par->flags &= ~FFB_FLAG_BLANKED;
                break;
 
@@ -683,13 +701,16 @@ ffb_blank(int blank, struct fb_info *info)
        case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
        case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
        case FB_BLANK_POWERDOWN: /* Poweroff */
-               upa_writel(0x6000, &dac->type);
-               tmp = (upa_readl(&dac->value) & ~0x1);
-               upa_writel(0x6000, &dac->type);
-               upa_writel(tmp, &dac->value);
+               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);
 
@@ -881,141 +902,149 @@ ffb_init_fix(struct fb_info *info)
        info->fix.accel = FB_ACCEL_SUN_CREATOR;
 }
 
-struct all_info {
-       struct fb_info info;
-       struct ffb_par par;
-       u32 pseudo_palette[256];
-};
-
-static int ffb_init_one(struct of_device *op)
+static int __devinit ffb_probe(struct of_device *op, const struct of_device_id *match)
 {
        struct device_node *dp = op->node;
        struct ffb_fbc __iomem *fbc;
        struct ffb_dac __iomem *dac;
-       struct all_info *all;
+       struct fb_info *info;
+       struct ffb_par *par;
+       u32 dac_pnum, dac_rev, dac_mrev;
        int err;
 
-       all = kzalloc(sizeof(*all), GFP_KERNEL);
-       if (!all)
-               return -ENOMEM;
+       info = framebuffer_alloc(sizeof(struct ffb_par), &op->dev);
 
-       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;
-       }
+       err = -ENOMEM;
+       if (!info)
+               goto out_err;
 
-       all->par.dac = of_ioremap(&op->resource[1], 0,
-                                 sizeof(struct ffb_dac), "ffb dac");
-       if (!all->par.dac) {
-               of_iounmap(all->par.fbc, sizeof(struct ffb_fbc));
-               kfree(all);
-               return -ENOMEM;
-       }
+       par = info->par;
 
-       all->par.rop_cache = FFB_ROP_NEW;
-       all->par.physbase = op->resource[0].start;
+       spin_lock_init(&par->lock);
+       par->fbc = of_ioremap(&op->resource[2], 0,
+                             sizeof(struct ffb_fbc), "ffb fbc");
+       if (!par->fbc)
+               goto out_release_fb;
+
+       par->dac = of_ioremap(&op->resource[1], 0,
+                             sizeof(struct ffb_dac), "ffb dac");
+       if (!par->dac)
+               goto out_unmap_fbc;
+
+       par->rop_cache = FFB_ROP_NEW;
+       par->physbase = op->resource[0].start;
 
        /* 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.par = &all->par;
-       all->info.pseudo_palette = all->pseudo_palette;
-
-       sbusfb_fill_var(&all->info.var, dp->node, 32);
-       all->par.fbsize = PAGE_ALIGN(all->info.var.xres *
-                                    all->info.var.yres *
-                                    4);
-       ffb_fixup_var_rgb(&all->info.var);
-
-       all->info.var.accel_flags = FB_ACCELF_TEXT;
+       info->flags = (FBINFO_DEFAULT |
+                      /* FBINFO_HWACCEL_COPYAREA | */
+                      FBINFO_HWACCEL_FILLRECT |
+                      FBINFO_HWACCEL_IMAGEBLIT);
+
+       info->fbops = &ffb_ops;
+
+       info->screen_base = (char *) par->physbase + FFB_DFB24_POFF;
+       info->pseudo_palette = par->pseudo_palette;
+
+       sbusfb_fill_var(&info->var, dp->node, 32);
+       par->fbsize = PAGE_ALIGN(info->var.xres * info->var.yres * 4);
+       ffb_fixup_var_rgb(&info->var);
+
+       info->var.accel_flags = FB_ACCELF_TEXT;
 
        if (!strcmp(dp->name, "SUNW,afb"))
-               all->par.flags |= FFB_FLAG_AFB;
+               par->flags |= FFB_FLAG_AFB;
 
-       all->par.board_type = of_getintprop_default(dp, "board_type", 0);
+       par->board_type = of_getintprop_default(dp, "board_type", 0);
 
-       fbc = all->par.fbc;
+       fbc = par->fbc;
        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 = par->dac;
+       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;
 
-       dac = all->par.dac;
-       upa_writel(0x8000, &dac->type);
-       all->par.dac_rev = upa_readl(&dac->value) >> 0x1c;
+       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 ((par->flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) {
+               par->flags &= ~FFB_FLAG_INVCURSOR;
+       } else {
+               if (dac_mrev < 3)
+                       par->flags |= FFB_FLAG_INVCURSOR;
+       }
+
+       ffb_switch_from_graph(par);
 
        /* Unblank it just to be sure.  When there are multiple
         * FFB/AFB cards in the system, or it is not the OBP
         * chosen console, it will have video outputs off in
         * the DAC.
         */
-       ffb_blank(0, &all->info);
-
-       if (fb_alloc_cmap(&all->info.cmap, 256, 0)) {
-               printk(KERN_ERR "ffb: Could not allocate color map.\n");
-               of_iounmap(all->par.fbc, sizeof(struct ffb_fbc));
-               of_iounmap(all->par.dac, sizeof(struct ffb_dac));
-               kfree(all);
-               return -ENOMEM;
-       }
+       ffb_blank(0, info);
 
-       ffb_init_fix(&all->info);
+       if (fb_alloc_cmap(&info->cmap, 256, 0))
+               goto out_unmap_dac;
 
-       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(all->par.fbc, sizeof(struct ffb_fbc));
-               of_iounmap(all->par.dac, sizeof(struct ffb_dac));
-               kfree(all);
-               return err;
-       }
+       ffb_init_fix(info);
 
-       dev_set_drvdata(&op->dev, all);
+       err = register_framebuffer(info);
+       if (err < 0)
+               goto out_dealloc_cmap;
 
-       printk("%s: %s at %016lx, type %d, DAC revision %d\n",
+       dev_set_drvdata(&op->dev, info);
+
+       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"),
-              all->par.physbase, all->par.board_type, all->par.dac_rev);
+              ((par->flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
+              par->physbase, par->board_type,
+              dac_pnum, dac_rev, dac_mrev);
 
        return 0;
-}
 
-static int __devinit ffb_probe(struct of_device *dev, const struct of_device_id *match)
-{
-       struct of_device *op = to_of_device(&dev->dev);
+out_dealloc_cmap:
+       fb_dealloc_cmap(&info->cmap);
+
+out_unmap_dac:
+       of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
+
+out_unmap_fbc:
+       of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
+
+out_release_fb:
+       framebuffer_release(info);
 
-       return ffb_init_one(op);
+out_err:
+       return err;
 }
 
-static int __devexit ffb_remove(struct of_device *dev)
+static int __devexit ffb_remove(struct of_device *op)
 {
-       struct all_info *all = dev_get_drvdata(&dev->dev);
+       struct fb_info *info = dev_get_drvdata(&op->dev);
+       struct ffb_par *par = info->par;
 
-       unregister_framebuffer(&all->info);
-       fb_dealloc_cmap(&all->info.cmap);
+       unregister_framebuffer(info);
+       fb_dealloc_cmap(&info->cmap);
 
-       of_iounmap(all->par.fbc, sizeof(struct ffb_fbc));
-       of_iounmap(all->par.dac, sizeof(struct ffb_dac));
+       of_iounmap(&op->resource[2], par->fbc, sizeof(struct ffb_fbc));
+       of_iounmap(&op->resource[1], par->dac, sizeof(struct ffb_dac));
 
-       kfree(all);
+       framebuffer_release(info);
 
-       dev_set_drvdata(&dev->dev, NULL);
+       dev_set_drvdata(&op->dev, NULL);
 
        return 0;
 }