media: renesas: vsp1: Align VSPD startup to HW manual
Commit Message
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(-)
@@ -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;
@@ -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)
@@ -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);