Commit 37db9a34 authored by David S. Miller's avatar David S. Miller

[VIDEO] ffb: Fix two DAC handling bugs.

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: default avatarDavid S. Miller <davem@davemloft.net>
parent 74e61dee
...@@ -336,14 +336,30 @@ struct ffb_dac { ...@@ -336,14 +336,30 @@ struct ffb_dac {
u32 value2; 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 { struct ffb_par {
spinlock_t lock; spinlock_t lock;
struct ffb_fbc __iomem *fbc; struct ffb_fbc __iomem *fbc;
struct ffb_dac __iomem *dac; struct ffb_dac __iomem *dac;
u32 flags; u32 flags;
#define FFB_FLAG_AFB 0x00000001 #define FFB_FLAG_AFB 0x00000001 /* AFB m3 or m6 */
#define FFB_FLAG_BLANKED 0x00000002 #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 fg_cache __attribute__((aligned (8)));
u32 bg_cache; u32 bg_cache;
...@@ -354,7 +370,6 @@ struct ffb_par { ...@@ -354,7 +370,6 @@ struct ffb_par {
unsigned long physbase; unsigned long physbase;
unsigned long fbsize; unsigned long fbsize;
int dac_rev;
int board_type; int board_type;
}; };
...@@ -426,11 +441,12 @@ static void ffb_switch_from_graph(struct ffb_par *par) ...@@ -426,11 +441,12 @@ static void ffb_switch_from_graph(struct ffb_par *par)
FFBWait(par); FFBWait(par);
/* Disable cursor. */ /* Disable cursor. */
upa_writel(0x100, &dac->type2); upa_writel(FFB_DAC_CUR_CTRL, &dac->type2);
if (par->dac_rev <= 2) if (par->flags & FFB_FLAG_INVCURSOR)
upa_writel(0, &dac->value2); upa_writel(0, &dac->value2);
else 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); spin_unlock_irqrestore(&par->lock, flags);
} }
...@@ -664,18 +680,18 @@ ffb_blank(int blank, struct fb_info *info) ...@@ -664,18 +680,18 @@ ffb_blank(int blank, struct fb_info *info)
struct ffb_par *par = (struct ffb_par *) info->par; struct ffb_par *par = (struct ffb_par *) info->par;
struct ffb_dac __iomem *dac = par->dac; struct ffb_dac __iomem *dac = par->dac;
unsigned long flags; unsigned long flags;
u32 tmp; u32 val;
int i;
spin_lock_irqsave(&par->lock, flags); spin_lock_irqsave(&par->lock, flags);
FFBWait(par); FFBWait(par);
upa_writel(FFB_DAC_TGEN, &dac->type);
val = upa_readl(&dac->value);
switch (blank) { switch (blank) {
case FB_BLANK_UNBLANK: /* Unblanking */ case FB_BLANK_UNBLANK: /* Unblanking */
upa_writel(0x6000, &dac->type); val |= FFB_DAC_TGEN_VIDE;
tmp = (upa_readl(&dac->value) | 0x1);
upa_writel(0x6000, &dac->type);
upa_writel(tmp, &dac->value);
par->flags &= ~FFB_FLAG_BLANKED; par->flags &= ~FFB_FLAG_BLANKED;
break; break;
...@@ -683,13 +699,16 @@ ffb_blank(int blank, struct fb_info *info) ...@@ -683,13 +699,16 @@ ffb_blank(int blank, struct fb_info *info)
case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */ case FB_BLANK_VSYNC_SUSPEND: /* VESA blank (vsync off) */
case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */ case FB_BLANK_HSYNC_SUSPEND: /* VESA blank (hsync off) */
case FB_BLANK_POWERDOWN: /* Poweroff */ case FB_BLANK_POWERDOWN: /* Poweroff */
upa_writel(0x6000, &dac->type); val &= ~FFB_DAC_TGEN_VIDE;
tmp = (upa_readl(&dac->value) & ~0x1);
upa_writel(0x6000, &dac->type);
upa_writel(tmp, &dac->value);
par->flags |= FFB_FLAG_BLANKED; par->flags |= FFB_FLAG_BLANKED;
break; 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); spin_unlock_irqrestore(&par->lock, flags);
...@@ -894,6 +913,7 @@ static int ffb_init_one(struct of_device *op) ...@@ -894,6 +913,7 @@ static int ffb_init_one(struct of_device *op)
struct ffb_dac __iomem *dac; struct ffb_dac __iomem *dac;
struct all_info *all; struct all_info *all;
int err; int err;
u32 dac_pnum, dac_rev, dac_mrev;
all = kzalloc(sizeof(*all), GFP_KERNEL); all = kzalloc(sizeof(*all), GFP_KERNEL);
if (!all) if (!all)
...@@ -948,17 +968,31 @@ static int ffb_init_one(struct of_device *op) ...@@ -948,17 +968,31 @@ static int ffb_init_one(struct of_device *op)
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); upa_writel(FFB_UCSR_ALL_ERRORS, &fbc->ucsr);
ffb_switch_from_graph(&all->par);
dac = all->par.dac; dac = all->par.dac;
upa_writel(0x8000, &dac->type); upa_writel(FFB_DAC_DID, &dac->type);
all->par.dac_rev = upa_readl(&dac->value) >> 0x1c; 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 /* 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) if ((all->par.flags & FFB_FLAG_AFB) || dac_pnum == 0x236e) {
all->par.dac_rev = 10; 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 /* Unblank it just to be sure. When there are multiple
* FFB/AFB cards in the system, or it is not the OBP * FFB/AFB cards in the system, or it is not the OBP
...@@ -993,10 +1027,12 @@ static int ffb_init_one(struct of_device *op) ...@@ -993,10 +1027,12 @@ static int ffb_init_one(struct of_device *op)
dev_set_drvdata(&op->dev, all); dev_set_drvdata(&op->dev, all);
printk("%s: %s at %016lx, type %d, DAC revision %d\n", printk("%s: %s at %016lx, type %d, "
"DAC pnum[%x] rev[%d] manuf_rev[%d]\n",
dp->full_name, dp->full_name,
((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"), ((all->par.flags & FFB_FLAG_AFB) ? "AFB" : "FFB"),
all->par.physbase, all->par.board_type, all->par.dac_rev); all->par.physbase, all->par.board_type,
dac_pnum, dac_rev, dac_mrev);
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment