drm/msm/disp/dpu: wait for extra vsync till timing engine status is disabled
authorVinod Polimera <quic_vpolimer@quicinc.com>
Thu, 2 Mar 2023 16:33:09 +0000 (22:03 +0530)
committerDmitry Baryshkov <dmitry.baryshkov@linaro.org>
Mon, 13 Mar 2023 01:43:49 +0000 (04:43 +0300)
There can be a race between timing gen disable and vblank irq. The
wait post timing gen disable may return early but intf disable sequence
might not be completed. Ensure that, intf status is disabled before
we retire the function.

Signed-off-by: Vinod Polimera <quic_vpolimer@quicinc.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Patchwork: https://patchwork.freedesktop.org/patch/524727/
Link: https://lore.kernel.org/r/1677774797-31063-7-git-send-email-quic_vpolimer@quicinc.com
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
drivers/gpu/drm/msm/disp/dpu1/dpu_encoder_phys_vid.c

index 48c48106b16a00710e77467d767cabae88ab7881..03960848dba63a6f005be47382377cc923640dec 100644 (file)
@@ -523,6 +523,7 @@ static void dpu_encoder_phys_vid_disable(struct dpu_encoder_phys *phys_enc)
 {
        unsigned long lock_flags;
        int ret;
+       struct intf_status intf_status = {0};
 
        if (!phys_enc->parent || !phys_enc->parent->dev) {
                DPU_ERROR("invalid encoder/device\n");
@@ -567,6 +568,26 @@ static void dpu_encoder_phys_vid_disable(struct dpu_encoder_phys *phys_enc)
                }
        }
 
+       if (phys_enc->hw_intf && phys_enc->hw_intf->ops.get_status)
+               phys_enc->hw_intf->ops.get_status(phys_enc->hw_intf, &intf_status);
+
+       /*
+        * Wait for a vsync if timing en status is on after timing engine
+        * is disabled.
+        */
+       if (intf_status.is_en && dpu_encoder_phys_vid_is_master(phys_enc)) {
+               spin_lock_irqsave(phys_enc->enc_spinlock, lock_flags);
+               dpu_encoder_phys_inc_pending(phys_enc);
+               spin_unlock_irqrestore(phys_enc->enc_spinlock, lock_flags);
+               ret = dpu_encoder_phys_vid_wait_for_vblank(phys_enc);
+               if (ret) {
+                       atomic_set(&phys_enc->pending_kickoff_cnt, 0);
+                       DRM_ERROR("wait disable failed: id:%u intf:%d ret:%d\n",
+                                 DRMID(phys_enc->parent),
+                                 phys_enc->hw_intf->idx - INTF_0, ret);
+               }
+       }
+
        phys_enc->enable_state = DPU_ENC_DISABLED;
 }