summaryrefslogtreecommitdiff
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-06-11 09:25:04 +0200
commit85f663301364d015738e9cc7c77bd8c550262df0 (patch)
treeabbb65813e915b60ed90c86a7af65249bb348ef6
parent62c593f704e0b2f05db5b4e53fa3911a86f6f575 (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.c48
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 d442c41..844c6d4 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;
}