diff options
author | Stefan Agner <stefan.agner@toradex.com> | 2015-06-11 09:25:04 +0200 |
---|---|---|
committer | Stefan Agner <stefan.agner@toradex.com> | 2015-07-01 15:04:34 +0200 |
commit | 1668362effee27780c7eeace482681265cb1e3f3 (patch) | |
tree | e34f427e8b0e8fe42b3f608e63a59f42e55004c9 /drivers/video | |
parent | 3d392402aea0db20ed99b1cc4fb51254ef0c4948 (diff) |
video: fsl-dcu-fb: remove underrun interrupt handling
The current buffer underrun interrupt handling seems bogus in
multiple ways: Disabling and reenabling the controller seems a
questionable procedure and is also not documented. Furthermore,
to apply a DCU mode, a register transfer would be necessary
(UPDATE_MODE).
The current implementation probably even introduce races: If
a underrun happens just when enabling the controller (which has
been observed to happen quite often during initialization), the
register could still be in transfer mode. A write to a register
could still be transferred in this situation, which might lead
that the DCU off mode is transferred. Since the interrupt handler
does not initiate another register transfer, the controller would
stay off in this situation...
Rare conditions have been observed in which the controller ends
up in test mode. The race condition outlined above describes a
sequence in which the controller ends up beeing disabled. However,
before cd586e4cf9dc ("video: fsl-dcu-fb: fix operating mode off)
the DCU state off and test have been mixed up, hence this patch
could in fact fix that issue.
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/fbdev/fsl-dcu-fb.c | 32 |
1 files changed, 10 insertions, 22 deletions
diff --git a/drivers/video/fbdev/fsl-dcu-fb.c b/drivers/video/fbdev/fsl-dcu-fb.c index 88aa3f9bb4d0..471a8fd995b1 100644 --- a/drivers/video/fbdev/fsl-dcu-fb.c +++ b/drivers/video/fbdev/fsl-dcu-fb.c @@ -740,24 +740,22 @@ static void reset_layers(struct dcu_fb_data *dcufb) static int fsl_dcu_open(struct fb_info *info, int user) { struct mfb_info *mfbi = info->par; - struct dcu_fb_data *dcufb = mfbi->parent; - u32 int_mask = readl(dcufb->reg_base + DCU_INT_MASK); - int ret = 0; + int ret; mfbi->index = info->node; - mfbi->count++; - if (mfbi->count == 1) { - fsl_dcu_check_var(&info->var, info); + if (mfbi->count == 0) { + ret = fsl_dcu_check_var(&info->var, info); + if (ret < 0) + return ret; + ret = fsl_dcu_set_par(info); if (ret < 0) - mfbi->count--; - else - writel(int_mask & ~DCU_INT_MASK_UNDRUN, - dcufb->reg_base + DCU_INT_MASK); + return ret; } + mfbi->count++; - return ret; + return 0; } static int fsl_dcu_release(struct fb_info *info, int user) @@ -950,19 +948,9 @@ static irqreturn_t fsl_dcu_irq(int irq, void *dev_id) { struct dcu_fb_data *dcufb = dev_id; unsigned int status = readl(dcufb->reg_base + DCU_INT_STATUS); - u32 dcu_mode; - - if (status & DCU_INT_STATUS_UNDRUN) { - dcu_mode = readl(dcufb->reg_base + DCU_DCU_MODE); - dcu_mode &= ~DCU_MODE_DCU_MODE_MASK; - writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_OFF), - dcufb->reg_base + DCU_DCU_MODE); - udelay(1); - writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_NORMAL), - dcufb->reg_base + DCU_DCU_MODE); - } writel(status, dcufb->reg_base + DCU_INT_STATUS); + return IRQ_HANDLED; } |