diff options
author | Stefan Agner <stefan.agner@toradex.com> | 2015-06-11 09:25:04 +0200 |
---|---|---|
committer | Stefan Agner <stefan.agner@toradex.com> | 2015-06-11 09:25:04 +0200 |
commit | 85f663301364d015738e9cc7c77bd8c550262df0 (patch) | |
tree | abbb65813e915b60ed90c86a7af65249bb348ef6 | |
parent | 62c593f704e0b2f05db5b4e53fa3911a86f6f575 (diff) |
video: fsl-dcu-fb: remove underrun interrupt handlingtoradex_vf_4.0
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.
-rw-r--r-- | drivers/video/fbdev/fsl-dcu-fb.c | 48 |
1 files changed, 9 insertions, 39 deletions
diff --git a/drivers/video/fbdev/fsl-dcu-fb.c b/drivers/video/fbdev/fsl-dcu-fb.c index d442c41b1298..844c6d4efa51 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) @@ -946,26 +944,6 @@ static void uninstall_framebuffer(struct fb_info *info) fb_dealloc_cmap(&info->cmap); } -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; -} - #ifdef CONFIG_PM_RUNTIME static int fsl_dcu_runtime_suspend(struct device *dev) { @@ -1099,13 +1077,6 @@ static int fsl_dcu_probe(struct platform_device *pdev) return -EINVAL; } - ret = devm_request_irq(&pdev->dev, dcufb->irq, fsl_dcu_irq, - 0, DRIVER_NAME, dcufb); - if (ret) { - dev_err(&pdev->dev, "could not request irq\n"); - goto failed_ioremap; - } - /* Put TCON in bypass mode, so the input signals from DCU are passed * through TCON unchanged */ ret = bypass_tcon(pdev->dev.of_node); @@ -1173,7 +1144,6 @@ failed_alloc_framebuffer: failed_getclock: failed_bypasstcon: free_irq(dcufb->irq, dcufb); -failed_ioremap: return ret; } |