drivers/gpu/drm/mediatek/mtk_crtc.c | 31 ++++++++++++++++++++++++++++ drivers/gpu/drm/mediatek/mtk_crtc.h | 1 + drivers/gpu/drm/mediatek/mtk_plane.c | 5 +++++ 3 files changed, 37 insertions(+)
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: 119f5173628a ("drm/mediatek: Add DRM Driver for Mediatek SoC MT8173.")
Signed-off-by: Jason-JH Lin <jason-jh.lin@mediatek.com>
Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_crtc.c | 31 ++++++++++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_crtc.h | 1 +
drivers/gpu/drm/mediatek/mtk_plane.c | 5 +++++
3 files changed, 37 insertions(+)
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index 8f6fba4217ec..0c856cc679de 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -719,6 +719,37 @@ 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)
+{
+ 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));
+}
+
void mtk_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane,
struct drm_atomic_state *state)
{
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.h b/drivers/gpu/drm/mediatek/mtk_crtc.h
index 388e900b6f4d..828f109b83e7 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.h
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.h
@@ -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);
diff --git a/drivers/gpu/drm/mediatek/mtk_plane.c b/drivers/gpu/drm/mediatek/mtk_plane.c
index 655106bbb76d..59edbe26f01e 100644
--- a/drivers/gpu/drm/mediatek/mtk_plane.c
+++ b/drivers/gpu/drm/mediatek/mtk_plane.c
@@ -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,
--
2.43.0
On Tue, 2025-06-24 at 19:31 +0800, Jason-JH Lin wrote:
> 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: 119f5173628a ("drm/mediatek: Add DRM Driver for Mediatek SoC MT8173.")
This patch looks good to me, so
Reviewed-by: CK Hu <ck.hu@mediatek.com>
But fixes patch is not correct.
In "drm/mediatek: Add DRM Driver for Mediatek SoC MT8173.", it does not support cmdq.
The first patch to support cmdq is 2f965be7f900 "drm/mediatek: apply CMDQ control flow"
I would change fixes tag when I apply this patch.
> Signed-off-by: Jason-JH Lin <jason-jh.lin@mediatek.com>
> Reviewed-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
> drivers/gpu/drm/mediatek/mtk_crtc.c | 31 ++++++++++++++++++++++++++++
> drivers/gpu/drm/mediatek/mtk_crtc.h | 1 +
> drivers/gpu/drm/mediatek/mtk_plane.c | 5 +++++
> 3 files changed, 37 insertions(+)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
> index 8f6fba4217ec..0c856cc679de 100644
> --- a/drivers/gpu/drm/mediatek/mtk_crtc.c
> +++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
> @@ -719,6 +719,37 @@ 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)
> +{
> + 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));
> +}
> +
> void mtk_crtc_async_update(struct drm_crtc *crtc, struct drm_plane *plane,
> struct drm_atomic_state *state)
> {
> diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.h b/drivers/gpu/drm/mediatek/mtk_crtc.h
> index 388e900b6f4d..828f109b83e7 100644
> --- a/drivers/gpu/drm/mediatek/mtk_crtc.h
> +++ b/drivers/gpu/drm/mediatek/mtk_crtc.h
> @@ -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);
> diff --git a/drivers/gpu/drm/mediatek/mtk_plane.c b/drivers/gpu/drm/mediatek/mtk_plane.c
> index 655106bbb76d..59edbe26f01e 100644
> --- a/drivers/gpu/drm/mediatek/mtk_plane.c
> +++ b/drivers/gpu/drm/mediatek/mtk_plane.c
> @@ -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,
> --
> 2.43.0
>
>
On Wed, 2025-06-25 at 06:54 +0000, CK Hu (胡俊光) wrote:
> On Tue, 2025-06-24 at 19:31 +0800, Jason-JH Lin wrote:
> > 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: 119f5173628a ("drm/mediatek: Add DRM Driver for Mediatek SoC
> > MT8173.")
>
> This patch looks good to me, so
>
> Reviewed-by: CK Hu <ck.hu@mediatek.com>
>
> But fixes patch is not correct.
> In "drm/mediatek: Add DRM Driver for Mediatek SoC MT8173.", it does
> not support cmdq.
> The first patch to support cmdq is 2f965be7f900 "drm/mediatek: apply
> CMDQ control flow"
> I would change fixes tag when I apply this patch.
>
Thank you very much!
Regards,
Jason-JH Lin
> > Signed-off-by: Jason-JH Lin <jason-jh.lin@mediatek.com>
> > Reviewed-by: AngeloGioacchino Del Regno
> > <angelogioacchino.delregno@collabora.com>
Hi, Jason:
Jason-JH Lin (林睿祥) <Jason-JH.Lin@mediatek.com> 於 2025年6月25日 週三 下午3:40寫道:
>
> On Wed, 2025-06-25 at 06:54 +0000, CK Hu (胡俊光) wrote:
> > On Tue, 2025-06-24 at 19:31 +0800, Jason-JH Lin wrote:
> > > 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: 119f5173628a ("drm/mediatek: Add DRM Driver for Mediatek SoC
> > > MT8173.")
> >
> > This patch looks good to me, so
> >
> > Reviewed-by: CK Hu <ck.hu@mediatek.com>
> >
> > But fixes patch is not correct.
> > In "drm/mediatek: Add DRM Driver for Mediatek SoC MT8173.", it does
> > not support cmdq.
> > The first patch to support cmdq is 2f965be7f900 "drm/mediatek: apply
> > CMDQ control flow"
> > I would change fixes tag when I apply this patch.
> >
>
> Thank you very much!
>
> Regards,
> Jason-JH Lin
Applied to mediatek-drm-fixes [1], thanks.
[1] https://git.kernel.org/pub/scm/linux/kernel/git/chunkuang.hu/linux.git/log/?h=mediatek-drm-fixes
Regards,
Chun-Kuang.
>
> > > Signed-off-by: Jason-JH Lin <jason-jh.lin@mediatek.com>
> > > Reviewed-by: AngeloGioacchino Del Regno
> > > <angelogioacchino.delregno@collabora.com>
>
© 2016 - 2026 Red Hat, Inc.