drm: rcar-du: Register a completion callback with VSP1
Currently we process page flip events on every display interrupt,
however this does not take into consideration the processing time needed
by the VSP1 utilised in the pipeline.
Register a callback with the VSP driver to obtain completion events, and
track them so that we only perform page flips when the full display
pipeline has completed for the frame.
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
---
v2:
- Utilise drm_crtc_vblank_count() as a frame identifier instead of the
user space flip event.
- Commit message completely re-worded for patch re-work.
- drm_crtc_handle_vblank() re-instated in event of rcrtc->pending
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 7391dd9..4900e01 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -328,7 +328,7 @@ static bool rcar_du_crtc_page_flip_pending(struct rcar_du_crtc *rcrtc)
bool pending;
spin_lock_irqsave(&dev->event_lock, flags);
- pending = rcrtc->event != NULL;
+ pending = (rcrtc->event != NULL) || (rcrtc->pending);
spin_unlock_irqrestore(&dev->event_lock, flags);
return pending;
@@ -579,6 +579,12 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
if (status & DSSR_FRM) {
drm_crtc_handle_vblank(&rcrtc->crtc);
+
+ if (rcrtc->pending) {
+ trace_printk("VBlank loss due to VSP Overrun\n");
+ return IRQ_HANDLED;
+ }
+
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 a719481..c35691d 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -47,6 +47,7 @@ struct rcar_du_crtc {
struct drm_pending_vblank_event *event;
wait_queue_head_t flip_wait;
+ unsigned long pending;
unsigned int outputs;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
index 9736b228..230ca10 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vsp.c
@@ -28,6 +28,17 @@
#include "rcar_du_kms.h"
#include "rcar_du_vsp.h"
+static void rcar_du_vsp_complete(void *private, void *data)
+{
+ struct rcar_du_crtc *crtc = (struct rcar_du_crtc *)private;
+ unsigned long completed = (uintptr_t)data;
+
+ if (completed) {
+ WARN_ON(crtc->pending != completed);
+ crtc->pending = 0;
+ }
+}
+
void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
{
const struct drm_display_mode *mode = &crtc->crtc.state->adjusted_mode;
@@ -35,6 +46,8 @@ void rcar_du_vsp_enable(struct rcar_du_crtc *crtc)
struct vsp1_du_lif_config cfg = {
.width = mode->hdisplay,
.height = mode->vdisplay,
+ .callback = rcar_du_vsp_complete,
+ .callback_data = crtc,
};
struct rcar_du_plane_state state = {
.state = {
@@ -85,7 +98,15 @@ void rcar_du_vsp_atomic_begin(struct rcar_du_crtc *crtc)
void rcar_du_vsp_atomic_flush(struct rcar_du_crtc *crtc)
{
- vsp1_du_atomic_flush(crtc->vsp->vsp, NULL);
+ WARN(crtc->pending, "Queuing frame before VSP completion\n");
+
+ /*
+ * Use the current vblank count as a unique tracking value for each
+ * frame processed by the VSP.
+ */
+ crtc->pending = drm_crtc_vblank_count(&crtc->crtc);
+
+ vsp1_du_atomic_flush(crtc->vsp->vsp, (void *)crtc->pending);
}
/* Keep the two tables in sync. */