]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
[VIDEO] ffb: Fix two DAC handling bugs.
authorDavid S. Miller <davem@davemloft.net>
Mon, 2 Apr 2007 23:50:31 +0000 (01:50 +0200)
committerAdrian Bunk <bunk@stusta.de>
Mon, 2 Apr 2007 23:50:31 +0000 (01:50 +0200)
The determination of whether the DAC has inverted cursor logic is
broken, import the version checks the X.org driver uses to fix this.

Next, when we change the timing generator, borrow code from X.org that
does 10 NOP reads of the timing generator register afterwards to make
sure the video-enable transition occurs cleanly.

Finally, use macros for the DAC registers and fields in order to
provide documentation for the next person who reads this code.

Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Adrian Bunk <bunk@stusta.de>
drivers/video/ffb.c

index 9c9b21d469a1e7c76c1f3eac8ffb4ae9e4b6d6bd..c35ceaf6b2a14b65d08adcdfcb41af17e3043c5c 100644 (file)
@@ -335,14 +335,30 @@ struct ffb_dac {
        volatile 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;
 
        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;
@@ -356,7 +372,6 @@ struct ffb_par {
        char                    name[64];
        int                     prom_node;
        int                     prom_parent_node;
-       int                     dac_rev;
        int                     board_type;
 };
 
@@ -428,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);
 }
@@ -667,18 +683,18 @@ ffb_blank(int blank, struct fb_info *info)
        struct ffb_par *par = (struct ffb_par *) info->par;
        struct ffb_dac *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;
 
@@ -686,13 +702,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);
 
@@ -929,6 +948,7 @@ static void ffb_init_one(int node, int parent)
        struct ffb_fbc *fbc;
        struct ffb_dac *dac;
        struct all_info *all;
+       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");
@@ -987,17 +1007,31 @@ static void ffb_init_one(int node, int parent)
        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
@@ -1023,9 +1057,11 @@ static void ffb_init_one(int node, int parent)
 
        list_add(&all->list, &ffb_list);
 
-       printk("ffb: %s at %016lx type %d DAC %d\n",
+       printk("ffb: %s at %016lx type %d, "
+              "DAC pnum[%x] rev[%d] manuf_rev[%d]\n",
               ((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
-              regs[0].phys_addr, all->par.board_type, all->par.dac_rev);
+              regs[0].phys_addr, all->par.board_type,
+              dac_pnum, dac_rev, dac_mrev);
 }
 
 static void ffb_scan_siblings(int root)