]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/mediatek: Add wait_event_timeout when disabling plane
authorJason-JH Lin <jason-jh.lin@mediatek.com>
Tue, 24 Jun 2025 11:31:41 +0000 (19:31 +0800)
committerChun-Kuang Hu <chunkuang.hu@kernel.org>
Thu, 17 Jul 2025 23:18:53 +0000 (23:18 +0000)
Our hardware registers are set through GCE, not by the CPU.
DRM might assume the hardware is disabled immediately after calling
atomic_disable() of drm_plane, but it is only truly disabled after the
GCE IRQ is triggered.

Additionally, the cursor plane in DRM uses async_commit, so DRM will
not wait for vblank and will free the buffer immediately after calling
atomic_disable().

To prevent the framebuffer from being freed before the layer disable
settings are configured into the hardware, which can cause an IOMMU
fault error, a wait_event_timeout has been added to wait for the
ddp_cmdq_cb() callback,indicating that the GCE IRQ has been triggered.

Fixes: 2f965be7f900 ("drm/mediatek: apply CMDQ control flow")
Signed-off-by: Jason-JH Lin <jason-jh.lin@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Reviewed-by: CK Hu <ck.hu@mediatek.com>
Link: https://patchwork.kernel.org/project/linux-mediatek/patch/20250624113223.443274-1-jason-jh.lin@mediatek.com/
Signed-off-by: Chun-Kuang Hu <chunkuang.hu@kernel.org>
drivers/gpu/drm/mediatek/mtk_crtc.c
drivers/gpu/drm/mediatek/mtk_crtc.h
drivers/gpu/drm/mediatek/mtk_plane.c

index 8f6fba4217ece5b0c29dbfc1a724fc4606b8604a..6916c8925b412bdc840f8ab2e7179f486382155a 100644 (file)
@@ -719,6 +719,39 @@ int mtk_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane,
        return 0;
 }
 
+void mtk_crtc_plane_disable(struct drm_crtc *crtc, struct drm_plane *plane)
+{
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+       struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
+       struct mtk_plane_state *plane_state = to_mtk_plane_state(plane->state);
+       int i;
+
+       /* no need to wait for disabling the plane by CPU */
+       if (!mtk_crtc->cmdq_client.chan)
+               return;
+
+       if (!mtk_crtc->enabled)
+               return;
+
+       /* set pending plane state to disabled */
+       for (i = 0; i < mtk_crtc->layer_nr; i++) {
+               struct drm_plane *mtk_plane = &mtk_crtc->planes[i];
+               struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(mtk_plane->state);
+
+               if (mtk_plane->index == plane->index) {
+                       memcpy(mtk_plane_state, plane_state, sizeof(*plane_state));
+                       break;
+               }
+       }
+       mtk_crtc_update_config(mtk_crtc, false);
+
+       /* wait for planes to be disabled by CMDQ */
+       wait_event_timeout(mtk_crtc->cb_blocking_queue,
+                          mtk_crtc->cmdq_vblank_cnt == 0,
+                          msecs_to_jiffies(500));
+#endif
+}
+
 void mtk_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane,
                           struct drm_atomic_state *state)
 {
index 388e900b6f4ded1b4047838f670fd18ee0700e54..828f109b83e78ff00de6d69d860b9b8eb081be33 100644 (file)
@@ -21,6 +21,7 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
                    unsigned int num_conn_routes);
 int mtk_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane,
                         struct mtk_plane_state *state);
+void mtk_crtc_plane_disable(struct drm_crtc *crtc, struct drm_plane *plane);
 void mtk_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane,
                           struct drm_atomic_state *plane_state);
 struct device *mtk_crtc_dma_dev_get(struct drm_crtc *crtc);
index 655106bbb76d3300edb71fa027591b2f943bbe68..59edbe26f01ee3d56f353867eca07a7fdcba261b 100644 (file)
@@ -285,9 +285,14 @@ static void mtk_plane_atomic_disable(struct drm_plane *plane,
        struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
                                                                           plane);
        struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(new_state);
+       struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state,
+                                                                          plane);
+
        mtk_plane_state->pending.enable = false;
        wmb(); /* Make sure the above parameter is set before update */
        mtk_plane_state->pending.dirty = true;
+
+       mtk_crtc_plane_disable(old_state->crtc, plane);
 }
 
 static void mtk_plane_atomic_update(struct drm_plane *plane,