Commit 5e0594fd authored by Kieran Bingham's avatar Kieran Bingham Committed by Laurent Pinchart
Browse files

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: d503a43a ("drm: rcar-du: Register a completion callback with VSP1")
Signed-off-by: default avatarKieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Acked-by: default avatarMauro Carvalho Chehab <mchehab@s-opensource.com>
parent 641307df
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -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) {
		if (rcdu->info->gen < 3) {
			drm_crtc_handle_vblank(&rcrtc->crtc);

		if (rcdu->info->gen < 3)
			rcar_du_crtc_finish_page_flip(rcrtc);
		}

		ret = IRQ_HANDLED;
	}
+2 −0
Original line number Diff line number Diff line
@@ -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;

+6 −2
Original line number Diff line number Diff line
@@ -31,10 +31,14 @@
#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;

	if (crtc->vblank_enable)
		drm_crtc_handle_vblank(&crtc->crtc);

	if (completed)
		rcar_du_crtc_finish_page_flip(crtc);
}

+3 −2
Original line number Diff line number Diff line
@@ -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);
}

/* -----------------------------------------------------------------------------
+1 −1
Original line number Diff line number Diff line
@@ -29,7 +29,7 @@ struct vsp1_drm_pipeline {
	bool enabled;

	/* Frame synchronisation */
	void (*du_complete)(void *);
	void (*du_complete)(void *, bool);
	void *du_private;
};

Loading