diff mbox series

media: renesas: vsp1: Align VSPD startup to HW manual

Message ID 20230216094205.151375-1-tomi.valkeinen+renesas@ideasonboard.com
State New
Headers show
Series media: renesas: vsp1: Align VSPD startup to HW manual | expand

Commit Message

Tomi Valkeinen Feb. 16, 2023, 9:42 a.m. UTC
From: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>

The hardware manual states that after setting VI6_CMD0.STRCMD to 1, we
need to wait until VI6_DISP0_IRQ_STA.DST is set before proceeding. The
driver is missing this wait.

Add the wait with readl_poll_timeout, because:
1) The VI6_DISP0_IRQ_STA.DST bit is usually set more or less immediately
   after setting the VI6_CMD0.STRCMD (i.e. the first test passes).
2) While we have an interrupt handler, we never enable nor handle the
   VI6_DISP0_IRQ interrupts.

Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
---
 .../media/platform/renesas/vsp1/vsp1_drm.c    | 19 ++++++++++++++++++-
 .../media/platform/renesas/vsp1/vsp1_pipe.c   |  7 ++++++-
 .../media/platform/renesas/vsp1/vsp1_pipe.h   |  2 +-
 3 files changed, 25 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drm.c b/drivers/media/platform/renesas/vsp1/vsp1_drm.c
index 5da1bc991750..767ebab65114 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_drm.c
@@ -9,6 +9,7 @@ 
 
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
+#include <linux/iopoll.h>
 #include <linux/slab.h>
 
 #include <media/media-entity.h>
@@ -648,7 +649,9 @@  int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
 	struct vsp1_pipeline *pipe;
 	unsigned long flags;
 	unsigned int i;
+	bool started;
 	int ret;
+	u32 v;
 
 	if (pipe_index >= vsp1->info->lif_count)
 		return -EINVAL;
@@ -757,11 +760,25 @@  int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
 	if (ret < 0)
 		return ret;
 
+	/* Clear VI6_DISP_IRQ_STA_DST flag */
+	v = vsp1_read(vsp1, VI6_DISP_IRQ_STA(pipe->output->entity.index));
+	vsp1_write(vsp1, VI6_DISP_IRQ_STA(pipe->output->entity.index),
+		   ~v & VI6_DISP_IRQ_STA_DST);
+
 	/* Start the pipeline. */
 	spin_lock_irqsave(&pipe->irqlock, flags);
-	vsp1_pipeline_run(pipe);
+	started = vsp1_pipeline_run(pipe);
 	spin_unlock_irqrestore(&pipe->irqlock, flags);
 
+	if (started) {
+		/* Wait for VI6_DISP_IRQ_STA_DST flag */
+		ret = readl_poll_timeout(vsp1->mmio + VI6_DISP_IRQ_STA(pipe->output->entity.index),
+			v, v & VI6_DISP_IRQ_STA_DST, 1,  100 * USEC_PER_MSEC);
+		if (ret)
+			dev_warn(vsp1->dev,
+				 "Timeout waiting for VI6_DISP_IRQ_STA_DST\n");
+	}
+
 	dev_dbg(vsp1->dev, "%s: pipeline enabled\n", __func__);
 
 	return 0;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c
index f8093ba9539e..87f97d2d5773 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c
@@ -302,17 +302,22 @@  void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
 }
 
 /* Must be called with the pipe irqlock held. */
-void vsp1_pipeline_run(struct vsp1_pipeline *pipe)
+bool vsp1_pipeline_run(struct vsp1_pipeline *pipe)
 {
 	struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+	bool started = false;
 
 	if (pipe->state == VSP1_PIPELINE_STOPPED) {
 		vsp1_write(vsp1, VI6_CMD(pipe->output->entity.index),
 			   VI6_CMD_STRCMD);
 		pipe->state = VSP1_PIPELINE_RUNNING;
+
+		started = true;
 	}
 
 	pipe->buffers_ready = 0;
+
+	return started;
 }
 
 bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe)
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_pipe.h b/drivers/media/platform/renesas/vsp1/vsp1_pipe.h
index 674b5748d929..5a7b38efa67a 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/renesas/vsp1/vsp1_pipe.h
@@ -155,7 +155,7 @@  struct vsp1_pipeline {
 void vsp1_pipeline_reset(struct vsp1_pipeline *pipe);
 void vsp1_pipeline_init(struct vsp1_pipeline *pipe);
 
-void vsp1_pipeline_run(struct vsp1_pipeline *pipe);
+bool vsp1_pipeline_run(struct vsp1_pipeline *pipe);
 bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe);
 int vsp1_pipeline_stop(struct vsp1_pipeline *pipe);
 bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe);