Hello,
The recent changes to the rcar-du driver to fix a page flip handling race condition changed the order of which vblanks and page flips are handled, resulting in incorrect timestamps being reported in the vblan events. Correct this by handling vblank events in the same completion handler as page flips.
Compared to v2 patch 3/4 is completely rewritten with a new approach, as the previous one caused flip timeouts for a currently unknown reason. This version now uses the vertical blanking interrupt to handle the CRTC stop race regardless of the generation of the SoC.
As a result drm_atomic_helper_wait_for_vblanks() can't be used anymore to wait for completion of a page flip or CRTC disable. I've thus included the previously posted patch "drm: rcar-du: Wait for flip completion instead of vblank in commit tail" in this series.
I still plan to investigate why the original version caused issues, as I believe it went in the right direction. For now this series should do, as it doesn't introduce any hack and passes all tests properly.
Kieran Bingham (1): drm: rcar-du: Repair vblank for DRM page flips using the VSP
Laurent Pinchart (3): drm: rcar-du: Use the VBK interrupt for vblank events drm: rcar-du: Wait for flip completion instead of vblank in commit tail drm: rcar-du: Fix race condition when disabling planes at CRTC stop
drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 66 +++++++++++++++++++++++++++----- drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 10 +++++ drivers/gpu/drm/rcar-du/rcar_du_kms.c | 2 +- drivers/gpu/drm/rcar-du/rcar_du_vsp.c | 8 +++- drivers/media/platform/vsp1/vsp1_drm.c | 5 ++- drivers/media/platform/vsp1/vsp1_drm.h | 2 +- drivers/media/platform/vsp1/vsp1_pipe.c | 20 +++++----- drivers/media/platform/vsp1/vsp1_pipe.h | 2 +- drivers/media/platform/vsp1/vsp1_video.c | 6 ++- include/media/vsp1.h | 2 +- 10 files changed, 95 insertions(+), 28 deletions(-)
When implementing support for interlaced modes, the driver switched from reporting vblank events on the vertical blanking (VBK) interrupt to the frame end interrupt (FRM). This incorrectly divided the reported refresh rate by two. Fix it by moving back to the VBK interrupt.
Fixes: 906eff7fcada ("drm: rcar-du: Implement support for interlaced modes") Signed-off-by: Laurent Pinchart laurent.pinchart+renesas@ideasonboard.com Reviewed-by: Kieran Bingham kieran.bingham+renesas@ideasonboard.com --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 98cf446391dc..17fd1cd5212c 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -698,7 +698,7 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg) status = rcar_du_crtc_read(rcrtc, DSSR); rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
- if (status & DSSR_FRM) { + if (status & DSSR_VBK) { drm_crtc_handle_vblank(&rcrtc->crtc);
if (rcdu->info->gen < 3)
Page flips can take more than one vertical blanking to complete if arming the page flips races with the vertical blanking interrupt. Waiting for one vblank to complete the atomic commit in the commit tail handler is thus incorrect, and can lead to framebuffers being released while still being scanned out.
Fix this by waiting for flip completion instead, using the drm_atomic_helper_wait_for_flip_done() helper.
Fixes: 0d230422d256 ("drm: rcar-du: Register a completion callback with VSP1") Signed-off-by: Laurent Pinchart laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/rcar-du/rcar_du_kms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index b91257dee98f..221e22922396 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -262,7 +262,7 @@ static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state) drm_atomic_helper_commit_modeset_enables(dev, old_state);
drm_atomic_helper_commit_hw_done(old_state); - drm_atomic_helper_wait_for_vblanks(dev, old_state); + drm_atomic_helper_wait_for_flip_done(dev, old_state);
drm_atomic_helper_cleanup_planes(dev, old_state); }
Hi Laurent,
On 29/07/17 22:08, Laurent Pinchart wrote:
Page flips can take more than one vertical blanking to complete if arming the page flips races with the vertical blanking interrupt. Waiting for one vblank to complete the atomic commit in the commit tail handler is thus incorrect, and can lead to framebuffers being released while still being scanned out.
Fix this by waiting for flip completion instead, using the drm_atomic_helper_wait_for_flip_done() helper.
Fixes: 0d230422d256 ("drm: rcar-du: Register a completion callback with VSP1") Signed-off-by: Laurent Pinchart laurent.pinchart+renesas@ideasonboard.com
drivers/gpu/drm/rcar-du/rcar_du_kms.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c index b91257dee98f..221e22922396 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c @@ -262,7 +262,7 @@ static void rcar_du_atomic_commit_tail(struct drm_atomic_state *old_state) drm_atomic_helper_commit_modeset_enables(dev, old_state);
drm_atomic_helper_commit_hw_done(old_state);
- drm_atomic_helper_wait_for_vblanks(dev, old_state);
- drm_atomic_helper_wait_for_flip_done(dev, old_state);
Ahh yes, that makes sense!
Reviewed-by: Kieran Bingham kieran.bingham+renesas@ideasonboard.com
drm_atomic_helper_cleanup_planes(dev, old_state); }
When stopping the CRTC the driver must disable all planes and wait for the change to take effect at the next vblank. Merely calling drm_crtc_wait_one_vblank() is not enough, as the function doesn't include any mechanism to handle the race with vblank interrupts.
Replace the drm_crtc_wait_one_vblank() call with a manual mechanism that handles the vblank interrupt race.
Signed-off-by: Laurent Pinchart laurent.pinchart+renesas@ideasonboard.com --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 58 ++++++++++++++++++++++++++++++---- drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 8 +++++ 2 files changed, 60 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 17fd1cd5212c..6e5bd0b92dfa 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -490,23 +490,51 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) rcar_du_group_start_stop(rcrtc->group, true); }
+static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc) +{ + struct rcar_du_device *rcdu = rcrtc->group->dev; + struct drm_crtc *crtc = &rcrtc->crtc; + u32 status; + + /* Make sure vblank interrupts are enabled. */ + drm_crtc_vblank_get(crtc); + + /* + * Disable planes and calculate how many vertical blanking interrupts we + * have to wait for. If a vertical blanking interrupt has been triggered + * but not processed yet, we don't know whether it occurred before or + * after the planes got disabled. We thus have to wait for two vblank + * interrupts in that case. + */ + spin_lock_irq(&rcrtc->vblank_lock); + rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0); + status = rcar_du_crtc_read(rcrtc, DSSR); + rcrtc->vblank_count = status & DSSR_VBK ? 2 : 1; + spin_unlock_irq(&rcrtc->vblank_lock); + + if (!wait_event_timeout(rcrtc->vblank_wait, rcrtc->vblank_count == 0, + msecs_to_jiffies(100))) + dev_warn(rcdu->dev, "vertical blanking timeout\n"); + + drm_crtc_vblank_put(crtc); +} + static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) { struct drm_crtc *crtc = &rcrtc->crtc;
/* * Disable all planes and wait for the change to take effect. This is - * required as the DSnPR registers are updated on vblank, and no vblank - * will occur once the CRTC is stopped. Disabling planes when starting - * the CRTC thus wouldn't be enough as it would start scanning out - * immediately from old frame buffers until the next vblank. + * required as the plane enable registers are updated on vblank, and no + * vblank will occur once the CRTC is stopped. Disabling planes when + * starting the CRTC thus wouldn't be enough as it would start scanning + * out immediately from old frame buffers until the next vblank. * * This increases the CRTC stop delay, especially when multiple CRTCs * are stopped in one operation as we now wait for one vblank per CRTC. * Whether this can be improved needs to be researched. */ - rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0); - drm_crtc_wait_one_vblank(crtc); + rcar_du_crtc_disable_planes(rcrtc);
/* * Disable vertical blanking interrupt reporting. We first need to wait @@ -695,10 +723,26 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg) irqreturn_t ret = IRQ_NONE; u32 status;
+ spin_lock(&rcrtc->vblank_lock); + status = rcar_du_crtc_read(rcrtc, DSSR); rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
if (status & DSSR_VBK) { + /* + * Wake up the vblank wait if the counter reaches 0. This must + * be protected by the vblank_lock to avoid races in + * rcar_du_crtc_disable_planes(). + */ + if (rcrtc->vblank_count) { + if (--rcrtc->vblank_count == 0) + wake_up(&rcrtc->vblank_wait); + } + } + + spin_unlock(&rcrtc->vblank_lock); + + if (status & DSSR_VBK) { drm_crtc_handle_vblank(&rcrtc->crtc);
if (rcdu->info->gen < 3) @@ -756,6 +800,8 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index) }
init_waitqueue_head(&rcrtc->flip_wait); + init_waitqueue_head(&rcrtc->vblank_wait); + spin_lock_init(&rcrtc->vblank_lock);
rcrtc->group = rgrp; rcrtc->mmio_offset = mmio_offsets[index]; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 3cc376826592..065b91f5b1d9 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -15,6 +15,7 @@ #define __RCAR_DU_CRTC_H__
#include <linux/mutex.h> +#include <linux/spinlock.h> #include <linux/wait.h>
#include <drm/drmP.h> @@ -33,6 +34,9 @@ struct rcar_du_vsp; * @initialized: whether the CRTC has been initialized and clocks enabled * @event: event to post when the pending page flip completes * @flip_wait: wait queue used to signal page flip completion + * @vblank_lock: protects vblank_wait and vblank_count + * @vblank_wait: wait queue used to signal vertical blanking + * @vblank_count: number of vertical blanking interrupts to wait for * @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC * @group: CRTC group this CRTC belongs to * @vsp: VSP feeding video to this CRTC @@ -50,6 +54,10 @@ struct rcar_du_crtc { struct drm_pending_vblank_event *event; wait_queue_head_t flip_wait;
+ spinlock_t vblank_lock; + wait_queue_head_t vblank_wait; + unsigned int vblank_count; + unsigned int outputs;
struct rcar_du_group *group;
Hi Laurent,
On 29/07/17 22:08, Laurent Pinchart wrote:
When stopping the CRTC the driver must disable all planes and wait for the change to take effect at the next vblank. Merely calling drm_crtc_wait_one_vblank() is not enough, as the function doesn't include any mechanism to handle the race with vblank interrupts.
Replace the drm_crtc_wait_one_vblank() call with a manual mechanism that handles the vblank interrupt race.
This looks like a nasty hidden race (though I understand I unintentionally helped make it more prominent :D )
Fix looks good to me.
Signed-off-by: Laurent Pinchart laurent.pinchart+renesas@ideasonboard.com
Reviewed-by: Kieran Bingham kieran.bingham+renesas@ideasonboard.com
drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 58 ++++++++++++++++++++++++++++++---- drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 8 +++++ 2 files changed, 60 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 17fd1cd5212c..6e5bd0b92dfa 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -490,23 +490,51 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) rcar_du_group_start_stop(rcrtc->group, true); }
+static void rcar_du_crtc_disable_planes(struct rcar_du_crtc *rcrtc) +{
- struct rcar_du_device *rcdu = rcrtc->group->dev;
- struct drm_crtc *crtc = &rcrtc->crtc;
- u32 status;
- /* Make sure vblank interrupts are enabled. */
- drm_crtc_vblank_get(crtc);
- /*
* Disable planes and calculate how many vertical blanking interrupts we
* have to wait for. If a vertical blanking interrupt has been triggered
* but not processed yet, we don't know whether it occurred before or
* after the planes got disabled. We thus have to wait for two vblank
* interrupts in that case.
*/
- spin_lock_irq(&rcrtc->vblank_lock);
- rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
- status = rcar_du_crtc_read(rcrtc, DSSR);
- rcrtc->vblank_count = status & DSSR_VBK ? 2 : 1;
- spin_unlock_irq(&rcrtc->vblank_lock);
- if (!wait_event_timeout(rcrtc->vblank_wait, rcrtc->vblank_count == 0,
msecs_to_jiffies(100)))
dev_warn(rcdu->dev, "vertical blanking timeout\n");
- drm_crtc_vblank_put(crtc);
+}
static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) { struct drm_crtc *crtc = &rcrtc->crtc;
/* * Disable all planes and wait for the change to take effect. This is
* required as the DSnPR registers are updated on vblank, and no vblank
* will occur once the CRTC is stopped. Disabling planes when starting
* the CRTC thus wouldn't be enough as it would start scanning out
* immediately from old frame buffers until the next vblank.
* required as the plane enable registers are updated on vblank, and no
* vblank will occur once the CRTC is stopped. Disabling planes when
* starting the CRTC thus wouldn't be enough as it would start scanning
* out immediately from old frame buffers until the next vblank.
*/
- This increases the CRTC stop delay, especially when multiple CRTCs
- are stopped in one operation as we now wait for one vblank per CRTC.
- Whether this can be improved needs to be researched.
- rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0);
- drm_crtc_wait_one_vblank(crtc);
rcar_du_crtc_disable_planes(rcrtc);
/*
- Disable vertical blanking interrupt reporting. We first need to wait
@@ -695,10 +723,26 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg) irqreturn_t ret = IRQ_NONE; u32 status;
spin_lock(&rcrtc->vblank_lock);
status = rcar_du_crtc_read(rcrtc, DSSR); rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
if (status & DSSR_VBK) {
/*
* Wake up the vblank wait if the counter reaches 0. This must
* be protected by the vblank_lock to avoid races in
* rcar_du_crtc_disable_planes().
*/
if (rcrtc->vblank_count) {
if (--rcrtc->vblank_count == 0)
wake_up(&rcrtc->vblank_wait);
}
}
spin_unlock(&rcrtc->vblank_lock);
if (status & DSSR_VBK) { drm_crtc_handle_vblank(&rcrtc->crtc);
if (rcdu->info->gen < 3)
@@ -756,6 +800,8 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index) }
init_waitqueue_head(&rcrtc->flip_wait);
init_waitqueue_head(&rcrtc->vblank_wait);
spin_lock_init(&rcrtc->vblank_lock);
rcrtc->group = rgrp; rcrtc->mmio_offset = mmio_offsets[index];
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 3cc376826592..065b91f5b1d9 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -15,6 +15,7 @@ #define __RCAR_DU_CRTC_H__
#include <linux/mutex.h> +#include <linux/spinlock.h> #include <linux/wait.h>
#include <drm/drmP.h> @@ -33,6 +34,9 @@ struct rcar_du_vsp;
- @initialized: whether the CRTC has been initialized and clocks enabled
- @event: event to post when the pending page flip completes
- @flip_wait: wait queue used to signal page flip completion
- @vblank_lock: protects vblank_wait and vblank_count
- @vblank_wait: wait queue used to signal vertical blanking
- @vblank_count: number of vertical blanking interrupts to wait for
- @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC
- @group: CRTC group this CRTC belongs to
- @vsp: VSP feeding video to this CRTC
@@ -50,6 +54,10 @@ struct rcar_du_crtc { struct drm_pending_vblank_event *event; wait_queue_head_t flip_wait;
spinlock_t vblank_lock;
wait_queue_head_t vblank_wait;
unsigned int vblank_count;
unsigned int outputs;
struct rcar_du_group *group;
From: Kieran Bingham kieran.bingham+renesas@ideasonboard.com
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 --- Changes compared to v2:
- Enable the VBK interrupt when using the VSP as patch 3/4 now needs it
Changes compared to v1:
- Don't enable the VBK interrupt when using the VSP --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 8 +++++--- drivers/gpu/drm/rcar-du/rcar_du_crtc.h | 2 ++ drivers/gpu/drm/rcar-du/rcar_du_vsp.c | 8 ++++++-- drivers/media/platform/vsp1/vsp1_drm.c | 5 +++-- drivers/media/platform/vsp1/vsp1_drm.h | 2 +- drivers/media/platform/vsp1/vsp1_pipe.c | 20 ++++++++++---------- drivers/media/platform/vsp1/vsp1_pipe.h | 2 +- drivers/media/platform/vsp1/vsp1_video.c | 6 +++++- include/media/vsp1.h | 2 +- 9 files changed, 34 insertions(+), 21 deletions(-)
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 6e5bd0b92dfa..301ea1a8018e 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -690,6 +690,7 @@ static int rcar_du_crtc_enable_vblank(struct drm_crtc *crtc)
rcar_du_crtc_write(rcrtc, DSRCR, DSRCR_VBCL); rcar_du_crtc_set(rcrtc, DIER, DIER_VBE); + rcrtc->vblank_enable = true;
return 0; } @@ -699,6 +700,7 @@ static void rcar_du_crtc_disable_vblank(struct drm_crtc *crtc) struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
rcar_du_crtc_clr(rcrtc, DIER, DIER_VBE); + rcrtc->vblank_enable = false; }
static const struct drm_crtc_funcs crtc_funcs = { @@ -743,10 +745,10 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg) spin_unlock(&rcrtc->vblank_lock);
if (status & DSSR_VBK) { - drm_crtc_handle_vblank(&rcrtc->crtc); - - if (rcdu->info->gen < 3) + if (rcdu->info->gen < 3) { + drm_crtc_handle_vblank(&rcrtc->crtc); rcar_du_crtc_finish_page_flip(rcrtc); + }
ret = IRQ_HANDLED; } diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h index 065b91f5b1d9..fdc2bf99bda1 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h @@ -32,6 +32,7 @@ struct rcar_du_vsp; * @mmio_offset: offset of the CRTC registers in the DU MMIO block * @index: CRTC software and hardware index * @initialized: whether the CRTC has been initialized and clocks enabled + * @vblank_enable: whether vblank events are enabled on this CRTC * @event: event to post when the pending page flip completes * @flip_wait: wait queue used to signal page flip completion * @vblank_lock: protects vblank_wait and vblank_count @@ -51,6 +52,7 @@ struct rcar_du_crtc { unsigned int index; bool initialized;
+ bool vblank_enable; struct drm_pending_vblank_event *event; wait_queue_head_t flip_wait;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c index e43b065e141a..6de6be3d9090 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c @@ -31,11 +31,15 @@ #include "rcar_du_kms.h" #include "rcar_du_vsp.h"
-static void rcar_du_vsp_complete(void *private) +static void rcar_du_vsp_complete(void *private, bool completed) { struct rcar_du_crtc *crtc = private;
- rcar_du_crtc_finish_page_flip(crtc); + if (crtc->vblank_enable) + drm_crtc_handle_vblank(&crtc->crtc); + + if (completed) + rcar_du_crtc_finish_page_flip(crtc); }
void rcar_du_vsp_enable(struct rcar_du_crtc *crtc) 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. */ diff --git a/include/media/vsp1.h b/include/media/vsp1.h index c8fc868fb0f2..68a8abe4fac5 100644 --- a/include/media/vsp1.h +++ b/include/media/vsp1.h @@ -34,7 +34,7 @@ struct vsp1_du_lif_config { unsigned int width; unsigned int height;
- void (*callback)(void *); + void (*callback)(void *, bool); void *callback_data; };
dri-devel@lists.freedesktop.org