summaryrefslogtreecommitdiff
path: root/drivers/media/platform/vsp1
diff options
context:
space:
mode:
authorKieran Bingham <kieran.bingham+renesas@ideasonboard.com>2017-06-30 15:14:11 +0300
committerLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>2017-08-03 16:17:30 +0300
commit5e0594fd77e0d4dfd728898814da43a065094ae0 (patch)
treeab79391d344d8582ff3c8f955f7015adf0c7cf57 /drivers/media/platform/vsp1
parent641307df71fe77d7b38a477067495ede05d47295 (diff)
downloadlinux-5e0594fd77e0d4dfd728898814da43a065094ae0.tar.xz
drm: rcar-du: Repair vblank for DRM page flips using the VSP
The driver recently switched from handling page flip completion in the DU vertical blanking handler to the VSP frame end handler to fix a race condition. This unfortunately resulted in incorrect timestamps in the vertical blanking events sent to userspace as vertical blanking is now handled after sending the event. To fix this we must reverse the order of the two operations. The easiest way is to handle vertical blanking in the VSP frame end handler before sending the event. The VSP frame end interrupt occurs approximately 50µs earlier than the DU frame end interrupt, but this should not cause any undue harm. As we need to handle vertical blanking even when page flip completion is delayed, the VSP driver now needs to call the frame end completion callback unconditionally, with a new argument to report whether page flip has completed. With this new scheme the DU vertical blanking interrupt isn't needed anymore, so we can stop enabling it. Fixes: d503a43ac06a ("drm: rcar-du: Register a completion callback with VSP1") Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> Acked-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Diffstat (limited to 'drivers/media/platform/vsp1')
-rw-r--r--drivers/media/platform/vsp1/vsp1_drm.c5
-rw-r--r--drivers/media/platform/vsp1/vsp1_drm.h2
-rw-r--r--drivers/media/platform/vsp1/vsp1_pipe.c20
-rw-r--r--drivers/media/platform/vsp1/vsp1_pipe.h2
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c6
5 files changed, 20 insertions, 15 deletions
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index 7791d7b5a743..4dfbeac8f42c 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -32,12 +32,13 @@
* Interrupt Handling
*/
-static void vsp1_du_pipeline_frame_end(struct vsp1_pipeline *pipe)
+static void vsp1_du_pipeline_frame_end(struct vsp1_pipeline *pipe,
+ bool completed)
{
struct vsp1_drm_pipeline *drm_pipe = to_vsp1_drm_pipeline(pipe);
if (drm_pipe->du_complete)
- drm_pipe->du_complete(drm_pipe->du_private);
+ drm_pipe->du_complete(drm_pipe->du_private, completed);
}
/* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_drm.h b/drivers/media/platform/vsp1/vsp1_drm.h
index fca553ddd184..1cd9db785bf7 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.h
+++ b/drivers/media/platform/vsp1/vsp1_drm.h
@@ -29,7 +29,7 @@ struct vsp1_drm_pipeline {
bool enabled;
/* Frame synchronisation */
- void (*du_complete)(void *);
+ void (*du_complete)(void *, bool);
void *du_private;
};
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c
index 9bb961298af2..4f4b732df84b 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/vsp1/vsp1_pipe.c
@@ -335,16 +335,12 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
if (pipe == NULL)
return;
+ /*
+ * If the DL commit raced with the frame end interrupt, the commit ends
+ * up being postponed by one frame. @completed represents whether the
+ * active frame was finished or postponed.
+ */
completed = vsp1_dlm_irq_frame_end(pipe->output->dlm);
- if (!completed) {
- /*
- * If the DL commit raced with the frame end interrupt, the
- * commit ends up being postponed by one frame. Return
- * immediately without calling the pipeline's frame end handler
- * or incrementing the sequence number.
- */
- return;
- }
if (pipe->hgo)
vsp1_hgo_frame_end(pipe->hgo);
@@ -352,8 +348,12 @@ void vsp1_pipeline_frame_end(struct vsp1_pipeline *pipe)
if (pipe->hgt)
vsp1_hgt_frame_end(pipe->hgt);
+ /*
+ * Regardless of frame completion we still need to notify the pipe
+ * frame_end to account for vblank events.
+ */
if (pipe->frame_end)
- pipe->frame_end(pipe);
+ pipe->frame_end(pipe, completed);
pipe->sequence++;
}
diff --git a/drivers/media/platform/vsp1/vsp1_pipe.h b/drivers/media/platform/vsp1/vsp1_pipe.h
index 91a784a13422..c5d01a365370 100644
--- a/drivers/media/platform/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/vsp1/vsp1_pipe.h
@@ -91,7 +91,7 @@ struct vsp1_pipeline {
enum vsp1_pipeline_state state;
wait_queue_head_t wq;
- void (*frame_end)(struct vsp1_pipeline *pipe);
+ void (*frame_end)(struct vsp1_pipeline *pipe, bool completed);
struct mutex lock;
struct kref kref;
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 84139affb871..e9f5dcb8fae5 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -440,13 +440,17 @@ static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
vsp1_pipeline_run(pipe);
}
-static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe)
+static void vsp1_video_pipeline_frame_end(struct vsp1_pipeline *pipe,
+ bool completed)
{
struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
enum vsp1_pipeline_state state;
unsigned long flags;
unsigned int i;
+ /* M2M Pipelines should never call here with an incomplete frame. */
+ WARN_ON_ONCE(!completed);
+
spin_lock_irqsave(&pipe->irqlock, flags);
/* Complete buffers on all video nodes. */