MLK-16928: drm: dcss: fix modesetting issues
authorLaurentiu Palcu <laurentiu.palcu@nxp.com>
Tue, 21 Nov 2017 13:00:28 +0000 (15:00 +0200)
committerLeonard Crestez <leonard.crestez@nxp.com>
Wed, 17 Apr 2019 23:51:34 +0000 (02:51 +0300)
DTG needs to be completely stopped before changing the display
resolution through modesetting. If DTG is not stopped, any change in
resolution could result in unpredictable results, like split screen,
etc.

This patch fixes that by introducing a completion signaling mechanism so
that we can signal the DRM CRTC when DCSS core is done stopping DTG.

Signed-off-by: Laurentiu Palcu <laurentiu.palcu@nxp.com>
drivers/gpu/drm/imx/dcss/dcss-crtc.c
drivers/gpu/imx/dcss/dcss-dtg.c
include/video/imx-dcss.h

index a305bf2..e2d110f 100644 (file)
@@ -35,6 +35,8 @@ struct dcss_crtc {
        int                     irq;
 
        struct drm_property *alpha;
+
+       struct completion disable_completion;
 };
 
 static void dcss_crtc_reset(struct drm_crtc *crtc)
@@ -173,7 +175,7 @@ static void dcss_crtc_atomic_enable(struct drm_crtc *crtc,
        pm_runtime_get_sync(dcss_crtc->dev->parent);
 
        dcss_ss_enable(dcss, true);
-       dcss_dtg_enable(dcss, true);
+       dcss_dtg_enable(dcss, true, NULL);
        dcss_ctxld_enable(dcss);
 
        crtc->enabled = true;
@@ -198,11 +200,14 @@ static void dcss_crtc_atomic_disable(struct drm_crtc *crtc,
        drm_crtc_vblank_off(crtc);
 
        dcss_ss_enable(dcss, false);
-       dcss_dtg_enable(dcss, false);
+       dcss_dtg_enable(dcss, false, &dcss_crtc->disable_completion);
        dcss_ctxld_enable(dcss);
 
        crtc->enabled = false;
 
+       wait_for_completion_timeout(&dcss_crtc->disable_completion,
+                                   msecs_to_jiffies(100));
+
        pm_runtime_mark_last_busy(dcss_crtc->dev->parent);
        pm_runtime_put_autosuspend(dcss_crtc->dev->parent);
 }
@@ -275,6 +280,8 @@ static int dcss_crtc_init(struct dcss_crtc *crtc,
                return crtc->irq;
        }
 
+       init_completion(&crtc->disable_completion);
+
        ret = devm_request_irq(crtc->dev, crtc->irq, dcss_crtc_irq_handler,
                               IRQF_TRIGGER_RISING, "dcss_drm", crtc);
        if (ret) {
index 7384dd5..570cc0a 100644 (file)
@@ -134,6 +134,13 @@ struct dcss_dtg_priv {
 
        u32 control_status;
        u32 alpha;
+
+       /*
+        * This will be passed on by DRM CRTC so that we can signal when DTG has
+        * been successfully stopped. Otherwise, any modesetting while DTG is
+        * still on may result in unpredictable behavior.
+        */
+       struct completion *dis_completion;
 };
 
 static void dcss_dtg_write(struct dcss_dtg_priv *dtg, u32 val, u32 ofs)
@@ -334,18 +341,23 @@ static void dcss_dtg_disable_callback(void *data)
                    dtg->base_reg + DCSS_DTG_TC_CONTROL_STATUS);
 
        dtg->in_use = false;
+
+       complete(dtg->dis_completion);
 }
 
-void dcss_dtg_enable(struct dcss_soc *dcss, bool en)
+void dcss_dtg_enable(struct dcss_soc *dcss, bool en,
+                    struct completion *dis_completion)
 {
        struct dcss_dtg_priv *dtg = dcss->dtg_priv;
 
        if (!en) {
                dcss->dcss_disable_callback = dcss_dtg_disable_callback;
+               dtg->dis_completion = dis_completion;
                return;
        }
 
        dcss->dcss_disable_callback = NULL;
+       dtg->dis_completion = NULL;
 
        dtg->control_status |= DTG_START;
 
index 690da53..fb1f6ae 100644 (file)
@@ -58,7 +58,8 @@ void dcss_dpr_format_set(struct dcss_soc *dcss, int ch_num, u32 pix_format);
 void dcss_dtg_sync_set(struct dcss_soc *dcss, struct videomode *vm);
 void dcss_dtg_plane_pos_set(struct dcss_soc *dcss, int ch_num,
                            int px, int py, int pw, int ph);
-void dcss_dtg_enable(struct dcss_soc *dcss, bool en);
+void dcss_dtg_enable(struct dcss_soc *dcss, bool en,
+                    struct completion *dis_completion);
 bool dcss_dtg_is_enabled(struct dcss_soc *dcss);
 void dcss_dtg_ch_enable(struct dcss_soc *dcss, int ch_num, bool en);
 void dcss_dtg_plane_alpha_set(struct dcss_soc *dcss, int ch_num,