aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Yushchenko2022-01-20 09:15:30 +0100
committerMauro Carvalho Chehab2022-02-17 10:28:42 +0100
commitc7cfc7b90e25468c98dfb1082474644f2a3e2df7 (patch)
tree4254fb6e36ca74a5dddd027549e7d05b6169dbc3
parent53c264544dfce30f7741a2b1e78f90d046e5d8ff (diff)
media: vsp1: mask interrupts before enabling
VSP hardware could be used (e.g. by the bootloader) before driver load, and some interrupts could be left in enabled and pending state. In this case, setting up VSP interrupt handler without masking interrupts before causes interrupt handler to be immediately called (and crash due to null vsp->info dereference). Fix that by explicitly masking all interrupts before setting the interrupt handler. To do so, have to set the interrupt handler later, after hw revision is already detected and number of interrupts to mask gets known. Based on patch by Koji Matsuoka <koji.matsuoka.xm@renesas.com> included in the Renesas BSP kernel. Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com> Reviewed-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
-rw-r--r--drivers/media/platform/vsp1/vsp1_drv.c37
1 files changed, 29 insertions, 8 deletions
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index e5b865dca111..502c7d9d6890 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -550,6 +550,16 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
return 0;
}
+static void vsp1_mask_all_interrupts(struct vsp1_device *vsp1)
+{
+ unsigned int i;
+
+ for (i = 0; i < vsp1->info->lif_count; ++i)
+ vsp1_write(vsp1, VI6_DISP_IRQ_ENB(i), 0);
+ for (i = 0; i < vsp1->info->wpf_count; ++i)
+ vsp1_write(vsp1, VI6_WPF_IRQ_ENB(i), 0);
+}
+
/*
* vsp1_device_get - Acquire the VSP1 device
*
@@ -817,13 +827,6 @@ static int vsp1_probe(struct platform_device *pdev)
if (irq < 0)
return irq;
- ret = devm_request_irq(&pdev->dev, irq, vsp1_irq_handler,
- IRQF_SHARED, dev_name(&pdev->dev), vsp1);
- if (ret < 0) {
- dev_err(&pdev->dev, "failed to request IRQ\n");
- return ret;
- }
-
/* FCP (optional). */
fcp_node = of_parse_phandle(pdev->dev.of_node, "renesas,fcp", 0);
if (fcp_node) {
@@ -853,7 +856,6 @@ static int vsp1_probe(struct platform_device *pdev)
goto done;
vsp1->version = vsp1_read(vsp1, VI6_IP_VERSION);
- vsp1_device_put(vsp1);
for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) {
if ((vsp1->version & VI6_IP_VERSION_MODEL_MASK) ==
@@ -866,12 +868,31 @@ static int vsp1_probe(struct platform_device *pdev)
if (!vsp1->info) {
dev_err(&pdev->dev, "unsupported IP version 0x%08x\n",
vsp1->version);
+ vsp1_device_put(vsp1);
ret = -ENXIO;
goto done;
}
dev_dbg(&pdev->dev, "IP version 0x%08x\n", vsp1->version);
+ /*
+ * Previous use of the hardware (e.g. by the bootloader) could leave
+ * some interrupts enabled and pending.
+ *
+ * TODO: Investigate if this shouldn't be better handled by using the
+ * device reset provided by the CPG.
+ */
+ vsp1_mask_all_interrupts(vsp1);
+
+ vsp1_device_put(vsp1);
+
+ ret = devm_request_irq(&pdev->dev, irq, vsp1_irq_handler,
+ IRQF_SHARED, dev_name(&pdev->dev), vsp1);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request IRQ\n");
+ goto done;
+ }
+
/* Instantiate entities. */
ret = vsp1_create_entities(vsp1);
if (ret < 0) {