MLK-22653-4 drm/imx: dpu: crtc: Precisely send vbland event if CRTC is active
authorLiu Ying <victor.liu@nxp.com>
Mon, 23 Sep 2019 03:22:42 +0000 (11:22 +0800)
committerLiu Ying <victor.liu@nxp.com>
Thu, 26 Sep 2019 01:44:18 +0000 (09:44 +0800)
If CRTC is active, we should send vblank event in vblank
interrupt handler to make sure it's sent precisely.  This
patch caches the event to be sent at dpu_crtc->event in
the ->atomic_enable() and the ->atomic_flush() callbacks
and finally sends it out in dpu_vbl_irq_handler().  Since
we rely on the interrupt handler to send the event, we
call drm_crtc_vblank_get() to get a vblank refcount to
guarantee the interrupt is enabled when caching the event
in dpu_crtc_queue_state_event() and call drm_crtc_vblank_put()
to drop a vblank refcount in the interrupt handler.

Signed-off-by: Liu Ying <victor.liu@nxp.com>
(cherry picked from commit c5f325790615eb16fe5a448e4b0afa122a33c23e)

drivers/gpu/drm/imx/dpu/dpu-crtc.c
drivers/gpu/drm/imx/dpu/dpu-crtc.h

index a6f11ed..eb124d4 100644 (file)
@@ -45,6 +45,20 @@ alloc_dpu_plane_states(struct dpu_crtc *dpu_crtc)
        return states;
 }
 
+static void dpu_crtc_queue_state_event(struct drm_crtc *crtc)
+{
+       struct dpu_crtc *dpu_crtc = to_dpu_crtc(crtc);
+
+       spin_lock_irq(&crtc->dev->event_lock);
+       if (crtc->state->event) {
+               WARN_ON(drm_crtc_vblank_get(crtc));
+               WARN_ON(dpu_crtc->event);
+               dpu_crtc->event = crtc->state->event;
+               crtc->state->event = NULL;
+       }
+       spin_unlock_irq(&crtc->dev->event_lock);
+}
+
 struct dpu_plane_state **
 crtc_state_get_dpu_plane_states(struct drm_crtc_state *state)
 {
@@ -240,13 +254,7 @@ static void dpu_crtc_atomic_enable(struct drm_crtc *crtc,
                disable_irq(aux_dpu_crtc->dec_shdld_irq);
        }
 
-       if (crtc->state->event) {
-               spin_lock_irq(&crtc->dev->event_lock);
-               drm_crtc_send_vblank_event(crtc, crtc->state->event);
-               spin_unlock_irq(&crtc->dev->event_lock);
-
-               crtc->state->event = NULL;
-       }
+       dpu_crtc_queue_state_event(crtc);
 
        if (dcstate->use_pc) {
                framegen_wait_for_secondary_syncup(dpu_crtc->m_fg);
@@ -313,13 +321,12 @@ static void dpu_crtc_atomic_disable(struct drm_crtc *crtc,
 
        drm_crtc_vblank_off(crtc);
 
+       spin_lock_irq(&crtc->dev->event_lock);
        if (crtc->state->event && !crtc->state->active) {
-               spin_lock_irq(&crtc->dev->event_lock);
                drm_crtc_send_vblank_event(crtc, crtc->state->event);
-               spin_unlock_irq(&crtc->dev->event_lock);
-
                crtc->state->event = NULL;
        }
+       spin_unlock_irq(&crtc->dev->event_lock);
 }
 
 static void dpu_drm_crtc_reset(struct drm_crtc *crtc)
@@ -431,8 +438,18 @@ static const struct drm_crtc_funcs dpu_crtc_funcs = {
 static irqreturn_t dpu_vbl_irq_handler(int irq, void *dev_id)
 {
        struct dpu_crtc *dpu_crtc = dev_id;
+       struct drm_crtc *crtc = &dpu_crtc->base;
+       unsigned long flags;
 
-       drm_crtc_handle_vblank(&dpu_crtc->base);
+       drm_crtc_handle_vblank(crtc);
+
+       spin_lock_irqsave(&crtc->dev->event_lock, flags);
+       if (dpu_crtc->event) {
+               drm_crtc_send_vblank_event(crtc, dpu_crtc->event);
+               dpu_crtc->event = NULL;
+               drm_crtc_vblank_put(crtc);
+       }
+       spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
 
        return IRQ_HANDLED;
 }
@@ -772,13 +789,7 @@ static void dpu_crtc_atomic_flush(struct drm_crtc *crtc,
                        }
                }
 
-               if (crtc->state->event) {
-                       spin_lock_irq(&crtc->dev->event_lock);
-                       drm_crtc_send_vblank_event(crtc, crtc->state->event);
-                       spin_unlock_irq(&crtc->dev->event_lock);
-
-                       crtc->state->event = NULL;
-               }
+               dpu_crtc_queue_state_event(crtc);
        } else if (!crtc->state->active) {
                if (old_dcstate->use_pc) {
                        if (extdst_is_master(ed)) {
index dfa04d9..51a5737 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef _DPU_CRTC_H_
 #define _DPU_CRTC_H_
 
+#include <drm/drm_vblank.h>
 #include <video/dpu.h>
 #include "dpu-plane.h"
 #include "imx-drm.h"
@@ -77,6 +78,8 @@ struct dpu_crtc {
        struct completion       crc_shdld_done;
        struct completion       aux_crc_done;
 
+       struct drm_pending_vblank_event *event;
+
        u32                     crc_red;
        u32                     crc_green;
        u32                     crc_blue;