summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
authorStefan Agner <stefan.agner@toradex.com>2015-06-11 09:25:04 +0200
committerStefan Agner <stefan.agner@toradex.com>2015-07-01 15:04:34 +0200
commit1668362effee27780c7eeace482681265cb1e3f3 (patch)
treee34f427e8b0e8fe42b3f608e63a59f42e55004c9 /drivers/video
parent3d392402aea0db20ed99b1cc4fb51254ef0c4948 (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.c32
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;
}