* [PATCH 01/42] drm/mediatek: Rename OVL format naming
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-02 7:30 ` CK Hu (胡俊光)
2026-07-01 12:20 ` [PATCH 02/42] drm/mediatek: Export OVL formats definitions and format conversion API AngeloGioacchino Del Regno
` (40 subsequent siblings)
41 siblings, 1 reply; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel, Paul-pl Chen
From: Paul-pl Chen <paul-pl.chen@mediatek.com>
Rename format arrays from mt8173_formats[] to mt8173_ovl_formats[]
to explicitly indicate that these format definitions are specific
to OVL (Overlay) components.
This naming improvement is necessary because MT8196 introduces new
display components (EXDMA, BLENDER, OUTPROC) that support different
format capabilities than OVL. Without clear naming, it becomes
ambiguous which formats apply to which component type.
Examples of format differences between components:
- EXDMA supports 10-bit RGB formats that some OVL variants don't
- BLENDER has different YUV handling requirements
- Component-specific format conversion capabilities vary
The explicit naming:
- Prevents confusion when debugging format-related issues
- Makes it immediately clear which component a format array belongs to
- Improves code searchability (grep for "ovl_formats")
- Follows consistent naming convention for component-specific definitions
- Prepares for adding exdma_formats[], blender_formats[] arrays
This is a preparatory patch for MT8196 component support, which
requires clear distinction between OVL formats and EXDMA/BLENDER
formats to avoid applying incorrect format configurations.
Signed-off-by: Paul-pl Chen <paul-pl.chen@mediatek.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 36 ++++++++++++-------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index c4b5a262fa8a..87c2b5e6d6b0 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -101,7 +101,7 @@ static inline bool is_10bit_rgb(u32 fmt)
return false;
}
-static const u32 mt8173_formats[] = {
+static const u32 mt8173_ovl_formats[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_BGRX8888,
@@ -115,7 +115,7 @@ static const u32 mt8173_formats[] = {
DRM_FORMAT_YUYV,
};
-static const u32 mt8195_formats[] = {
+static const u32 mt8195_ovl_formats[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB2101010,
@@ -673,8 +673,8 @@ static const struct mtk_disp_ovl_data mt2701_ovl_driver_data = {
.gmc_bits = 8,
.layer_nr = 4,
.fmt_rgb565_is_0 = false,
- .formats = mt8173_formats,
- .num_formats = ARRAY_SIZE(mt8173_formats),
+ .formats = mt8173_ovl_formats,
+ .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
};
static const struct mtk_disp_ovl_data mt8167_ovl_driver_data = {
@@ -683,8 +683,8 @@ static const struct mtk_disp_ovl_data mt8167_ovl_driver_data = {
.layer_nr = 4,
.fmt_rgb565_is_0 = true,
.smi_id_en = true,
- .formats = mt8173_formats,
- .num_formats = ARRAY_SIZE(mt8173_formats),
+ .formats = mt8173_ovl_formats,
+ .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
};
static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = {
@@ -692,8 +692,8 @@ static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = {
.gmc_bits = 8,
.layer_nr = 4,
.fmt_rgb565_is_0 = true,
- .formats = mt8173_formats,
- .num_formats = ARRAY_SIZE(mt8173_formats),
+ .formats = mt8173_ovl_formats,
+ .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
};
static const struct mtk_disp_ovl_data mt8183_ovl_driver_data = {
@@ -701,8 +701,8 @@ static const struct mtk_disp_ovl_data mt8183_ovl_driver_data = {
.gmc_bits = 10,
.layer_nr = 4,
.fmt_rgb565_is_0 = true,
- .formats = mt8173_formats,
- .num_formats = ARRAY_SIZE(mt8173_formats),
+ .formats = mt8173_ovl_formats,
+ .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
};
static const struct mtk_disp_ovl_data mt8183_ovl_2l_driver_data = {
@@ -710,8 +710,8 @@ static const struct mtk_disp_ovl_data mt8183_ovl_2l_driver_data = {
.gmc_bits = 10,
.layer_nr = 2,
.fmt_rgb565_is_0 = true,
- .formats = mt8173_formats,
- .num_formats = ARRAY_SIZE(mt8173_formats),
+ .formats = mt8173_ovl_formats,
+ .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
};
static const struct mtk_disp_ovl_data mt8192_ovl_driver_data = {
@@ -723,8 +723,8 @@ static const struct mtk_disp_ovl_data mt8192_ovl_driver_data = {
.blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
BIT(DRM_MODE_BLEND_COVERAGE) |
BIT(DRM_MODE_BLEND_PIXEL_NONE),
- .formats = mt8173_formats,
- .num_formats = ARRAY_SIZE(mt8173_formats),
+ .formats = mt8173_ovl_formats,
+ .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
};
static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = {
@@ -736,8 +736,8 @@ static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = {
.blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
BIT(DRM_MODE_BLEND_COVERAGE) |
BIT(DRM_MODE_BLEND_PIXEL_NONE),
- .formats = mt8173_formats,
- .num_formats = ARRAY_SIZE(mt8173_formats),
+ .formats = mt8173_ovl_formats,
+ .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
};
static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = {
@@ -750,8 +750,8 @@ static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = {
.blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
BIT(DRM_MODE_BLEND_COVERAGE) |
BIT(DRM_MODE_BLEND_PIXEL_NONE),
- .formats = mt8195_formats,
- .num_formats = ARRAY_SIZE(mt8195_formats),
+ .formats = mt8195_ovl_formats,
+ .num_formats = ARRAY_SIZE(mt8195_ovl_formats),
.supports_clrfmt_ext = true,
};
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 01/42] drm/mediatek: Rename OVL format naming
2026-07-01 12:20 ` [PATCH 01/42] drm/mediatek: Rename OVL format naming AngeloGioacchino Del Regno
@ 2026-07-02 7:30 ` CK Hu (胡俊光)
0 siblings, 0 replies; 52+ messages in thread
From: CK Hu (胡俊光) @ 2026-07-02 7:30 UTC (permalink / raw)
To: AngeloGioacchino Del Regno, chunkuang.hu@kernel.org
Cc: robh@kernel.org, tzimmermann@suse.de, simona@ffwll.ch,
mripard@kernel.org, kernel@collabora.com,
linux-mediatek@lists.infradead.org,
maarten.lankhorst@linux.intel.com,
dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
conor+dt@kernel.org, devicetree@vger.kernel.org,
krzk+dt@kernel.org, Paul-pl Chen (陳柏霖),
p.zabel@pengutronix.de, airlied@gmail.com,
Justin Yeh (葉英茂), matthias.bgg@gmail.com,
linux-arm-kernel@lists.infradead.org,
Jason-JH Lin (林睿祥)
On Wed, 2026-07-01 at 14:20 +0200, AngeloGioacchino Del Regno wrote:
> From: Paul-pl Chen <paul-pl.chen@mediatek.com>
>
> Rename format arrays from mt8173_formats[] to mt8173_ovl_formats[]
> to explicitly indicate that these format definitions are specific
> to OVL (Overlay) components.
>
> This naming improvement is necessary because MT8196 introduces new
> display components (EXDMA, BLENDER, OUTPROC) that support different
> format capabilities than OVL. Without clear naming, it becomes
> ambiguous which formats apply to which component type.
>
> Examples of format differences between components:
> - EXDMA supports 10-bit RGB formats that some OVL variants don't
> - BLENDER has different YUV handling requirements
> - Component-specific format conversion capabilities vary
>
> The explicit naming:
> - Prevents confusion when debugging format-related issues
> - Makes it immediately clear which component a format array belongs to
> - Improves code searchability (grep for "ovl_formats")
> - Follows consistent naming convention for component-specific definitions
> - Prepares for adding exdma_formats[], blender_formats[] arrays
>
> This is a preparatory patch for MT8196 component support, which
> requires clear distinction between OVL formats and EXDMA/BLENDER
> formats to avoid applying incorrect format configurations.
Reviewed-by: CK Hu <ck.hu@mediatek.com>
>
> Signed-off-by: Paul-pl Chen <paul-pl.chen@mediatek.com>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
> drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 36 ++++++++++++-------------
> 1 file changed, 18 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> index c4b5a262fa8a..87c2b5e6d6b0 100644
> --- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> +++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
> @@ -101,7 +101,7 @@ static inline bool is_10bit_rgb(u32 fmt)
> return false;
> }
>
> -static const u32 mt8173_formats[] = {
> +static const u32 mt8173_ovl_formats[] = {
> DRM_FORMAT_XRGB8888,
> DRM_FORMAT_ARGB8888,
> DRM_FORMAT_BGRX8888,
> @@ -115,7 +115,7 @@ static const u32 mt8173_formats[] = {
> DRM_FORMAT_YUYV,
> };
>
> -static const u32 mt8195_formats[] = {
> +static const u32 mt8195_ovl_formats[] = {
> DRM_FORMAT_XRGB8888,
> DRM_FORMAT_ARGB8888,
> DRM_FORMAT_XRGB2101010,
> @@ -673,8 +673,8 @@ static const struct mtk_disp_ovl_data mt2701_ovl_driver_data = {
> .gmc_bits = 8,
> .layer_nr = 4,
> .fmt_rgb565_is_0 = false,
> - .formats = mt8173_formats,
> - .num_formats = ARRAY_SIZE(mt8173_formats),
> + .formats = mt8173_ovl_formats,
> + .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
> };
>
> static const struct mtk_disp_ovl_data mt8167_ovl_driver_data = {
> @@ -683,8 +683,8 @@ static const struct mtk_disp_ovl_data mt8167_ovl_driver_data = {
> .layer_nr = 4,
> .fmt_rgb565_is_0 = true,
> .smi_id_en = true,
> - .formats = mt8173_formats,
> - .num_formats = ARRAY_SIZE(mt8173_formats),
> + .formats = mt8173_ovl_formats,
> + .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
> };
>
> static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = {
> @@ -692,8 +692,8 @@ static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = {
> .gmc_bits = 8,
> .layer_nr = 4,
> .fmt_rgb565_is_0 = true,
> - .formats = mt8173_formats,
> - .num_formats = ARRAY_SIZE(mt8173_formats),
> + .formats = mt8173_ovl_formats,
> + .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
> };
>
> static const struct mtk_disp_ovl_data mt8183_ovl_driver_data = {
> @@ -701,8 +701,8 @@ static const struct mtk_disp_ovl_data mt8183_ovl_driver_data = {
> .gmc_bits = 10,
> .layer_nr = 4,
> .fmt_rgb565_is_0 = true,
> - .formats = mt8173_formats,
> - .num_formats = ARRAY_SIZE(mt8173_formats),
> + .formats = mt8173_ovl_formats,
> + .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
> };
>
> static const struct mtk_disp_ovl_data mt8183_ovl_2l_driver_data = {
> @@ -710,8 +710,8 @@ static const struct mtk_disp_ovl_data mt8183_ovl_2l_driver_data = {
> .gmc_bits = 10,
> .layer_nr = 2,
> .fmt_rgb565_is_0 = true,
> - .formats = mt8173_formats,
> - .num_formats = ARRAY_SIZE(mt8173_formats),
> + .formats = mt8173_ovl_formats,
> + .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
> };
>
> static const struct mtk_disp_ovl_data mt8192_ovl_driver_data = {
> @@ -723,8 +723,8 @@ static const struct mtk_disp_ovl_data mt8192_ovl_driver_data = {
> .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
> BIT(DRM_MODE_BLEND_COVERAGE) |
> BIT(DRM_MODE_BLEND_PIXEL_NONE),
> - .formats = mt8173_formats,
> - .num_formats = ARRAY_SIZE(mt8173_formats),
> + .formats = mt8173_ovl_formats,
> + .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
> };
>
> static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = {
> @@ -736,8 +736,8 @@ static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = {
> .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
> BIT(DRM_MODE_BLEND_COVERAGE) |
> BIT(DRM_MODE_BLEND_PIXEL_NONE),
> - .formats = mt8173_formats,
> - .num_formats = ARRAY_SIZE(mt8173_formats),
> + .formats = mt8173_ovl_formats,
> + .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
> };
>
> static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = {
> @@ -750,8 +750,8 @@ static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = {
> .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
> BIT(DRM_MODE_BLEND_COVERAGE) |
> BIT(DRM_MODE_BLEND_PIXEL_NONE),
> - .formats = mt8195_formats,
> - .num_formats = ARRAY_SIZE(mt8195_formats),
> + .formats = mt8195_ovl_formats,
> + .num_formats = ARRAY_SIZE(mt8195_ovl_formats),
> .supports_clrfmt_ext = true,
> };
>
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 02/42] drm/mediatek: Export OVL formats definitions and format conversion API
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 01/42] drm/mediatek: Rename OVL format naming AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-02 9:36 ` CK Hu (胡俊光)
2026-07-01 12:20 ` [PATCH 03/42] drm/mediatek: Export OVL Blend function AngeloGioacchino Del Regno
` (39 subsequent siblings)
41 siblings, 1 reply; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel, Nancy Lin,
Paul-pl Chen
From: Nancy Lin <nancy.lin@mediatek.com>
In upcoming SoCs, the OVL component will be divided into multiple
smaller hardware units to enhance flexibility. To facilitate this
transition, the OVL format definitions and format conversion API
should be exported for reuse across these units.
Signed-off-by: Nancy Lin <nancy.lin@mediatek.com>
Signed-off-by: Paul-pl Chen <paul-pl.chen@mediatek.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 192 ++++++++++++++----------
drivers/gpu/drm/mediatek/mtk_disp_ovl.h | 19 +++
2 files changed, 132 insertions(+), 79 deletions(-)
create mode 100644 drivers/gpu/drm/mediatek/mtk_disp_ovl.h
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 87c2b5e6d6b0..9ded20202191 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -4,7 +4,6 @@
*/
#include <drm/drm_blend.h>
-#include <drm/drm_fourcc.h>
#include <drm/drm_framebuffer.h>
#include <linux/clk.h>
@@ -18,6 +17,7 @@
#include "mtk_crtc.h"
#include "mtk_ddp_comp.h"
#include "mtk_disp_drv.h"
+#include "mtk_disp_ovl.h"
#include "mtk_drm_drv.h"
#define DISP_REG_OVL_INTEN 0x0004
@@ -62,22 +62,16 @@
/* OVL_CON_RGB_SWAP works only if OVL_CON_CLRFMT_MAN is enabled */
#define OVL_CON_RGB_SWAP BIT(25)
-#define OVL_CON_CLRFMT_RGB (1 << 12)
-#define OVL_CON_CLRFMT_ARGB8888 (2 << 12)
-#define OVL_CON_CLRFMT_RGBA8888 (3 << 12)
-#define OVL_CON_CLRFMT_ABGR8888 (OVL_CON_CLRFMT_ARGB8888 | OVL_CON_BYTE_SWAP)
-#define OVL_CON_CLRFMT_BGRA8888 (OVL_CON_CLRFMT_RGBA8888 | OVL_CON_BYTE_SWAP)
-#define OVL_CON_CLRFMT_UYVY (4 << 12)
-#define OVL_CON_CLRFMT_YUYV (5 << 12)
-#define OVL_CON_MTX_YUV_TO_RGB (6 << 16)
-#define OVL_CON_CLRFMT_PARGB8888 ((3 << 12) | OVL_CON_CLRFMT_MAN)
-#define OVL_CON_CLRFMT_PABGR8888 (OVL_CON_CLRFMT_PARGB8888 | OVL_CON_RGB_SWAP)
-#define OVL_CON_CLRFMT_PBGRA8888 (OVL_CON_CLRFMT_PARGB8888 | OVL_CON_BYTE_SWAP)
-#define OVL_CON_CLRFMT_PRGBA8888 (OVL_CON_CLRFMT_PABGR8888 | OVL_CON_BYTE_SWAP)
-#define OVL_CON_CLRFMT_RGB565(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \
- 0 : OVL_CON_CLRFMT_RGB)
-#define OVL_CON_CLRFMT_RGB888(ovl) ((ovl)->data->fmt_rgb565_is_0 ? \
- OVL_CON_CLRFMT_RGB : 0)
+#define OVL_CON_CLRFMT_SHIFT (12)
+#define OVL_CON_CLRFMT_RGB565(shift) (0 << (shift))
+#define OVL_CON_CLRFMT_RGB888(shift) (1 << (shift))
+#define OVL_CON_CLRFMT_ARGB8888(shift) (2 << (shift))
+#define OVL_CON_CLRFMT_RGBA8888(shift) (3 << (shift))
+#define OVL_CON_CLRFMT_UYVY(shift) (4 << (shift))
+#define OVL_CON_CLRFMT_YUYV(shift) (5 << (shift))
+#define OVL_CON_MTX_YUV_TO_RGB (6 << 16)
+#define OVL_CON_CLRFMT_PARGB8888(shift, man) ((3 << (shift)) | (man))
+
#define OVL_CON_AEN BIT(8)
#define OVL_CON_ALPHA 0xff
#define OVL_CON_VIRT_FLIP BIT(9)
@@ -85,21 +79,6 @@
#define OVL_COLOR_ALPHA GENMASK(31, 24)
-static inline bool is_10bit_rgb(u32 fmt)
-{
- switch (fmt) {
- case DRM_FORMAT_XRGB2101010:
- case DRM_FORMAT_ARGB2101010:
- case DRM_FORMAT_RGBX1010102:
- case DRM_FORMAT_RGBA1010102:
- case DRM_FORMAT_XBGR2101010:
- case DRM_FORMAT_ABGR2101010:
- case DRM_FORMAT_BGRX1010102:
- case DRM_FORMAT_BGRA1010102:
- return true;
- }
- return false;
-}
static const u32 mt8173_ovl_formats[] = {
DRM_FORMAT_XRGB8888,
@@ -115,7 +94,9 @@ static const u32 mt8173_ovl_formats[] = {
DRM_FORMAT_YUYV,
};
-static const u32 mt8195_ovl_formats[] = {
+static const size_t mt8173_ovl_formats_len = ARRAY_SIZE(mt8173_ovl_formats);
+
+const u32 mt8195_ovl_formats[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_XRGB2101010,
@@ -139,6 +120,8 @@ static const u32 mt8195_ovl_formats[] = {
DRM_FORMAT_YUYV,
};
+const size_t mt8195_ovl_formats_len = ARRAY_SIZE(mt8195_ovl_formats);
+
struct mtk_disp_ovl_data {
unsigned int addr;
unsigned int gmc_bits;
@@ -168,6 +151,22 @@ struct mtk_disp_ovl {
void *vblank_cb_data;
};
+bool mtk_ovl_is_10bit_rgb(unsigned int fmt)
+{
+ switch (fmt) {
+ case DRM_FORMAT_XRGB2101010:
+ case DRM_FORMAT_ARGB2101010:
+ case DRM_FORMAT_RGBX1010102:
+ case DRM_FORMAT_RGBA1010102:
+ case DRM_FORMAT_XBGR2101010:
+ case DRM_FORMAT_ABGR2101010:
+ case DRM_FORMAT_BGRX1010102:
+ case DRM_FORMAT_BGRA1010102:
+ return true;
+ }
+ return false;
+}
+
static irqreturn_t mtk_disp_ovl_irq_handler(int irq, void *dev_id)
{
struct mtk_disp_ovl *priv = dev_id;
@@ -303,7 +302,7 @@ static void mtk_ovl_set_bit_depth(struct device *dev, int idx, u32 format,
if (!ovl->data->supports_clrfmt_ext)
return;
- if (is_10bit_rgb(format))
+ if (mtk_ovl_is_10bit_rgb(format))
bit_depth = OVL_CON_CLRFMT_10_BIT;
mtk_ddp_write_mask(cmdq_pkt, OVL_CON_CLRFMT_BIT_DEPTH(bit_depth, idx),
@@ -402,70 +401,97 @@ void mtk_ovl_layer_off(struct device *dev, unsigned int idx,
DISP_REG_OVL_RDMA_CTRL(idx));
}
-static unsigned int mtk_ovl_fmt_convert(struct mtk_disp_ovl *ovl,
- struct mtk_plane_state *state)
+unsigned int mtk_ovl_fmt_convert(unsigned int fmt, unsigned int blend_mode,
+ bool fmt_rgb565_is_0, bool color_convert,
+ u8 clrfmt_shift, u32 clrfmt_man, u32 byte_swap, u32 rgb_swap)
{
- unsigned int fmt = state->pending.format;
- unsigned int blend_mode = DRM_MODE_BLEND_COVERAGE;
-
- /*
- * For the platforms where OVL_CON_CLRFMT_MAN is defined in the hardware data sheet
- * and supports premultiplied color formats, such as OVL_CON_CLRFMT_PARGB8888.
- *
- * Check blend_modes in the driver data to see if premultiplied mode is supported.
- * If not, use coverage mode instead to set it to the supported color formats.
- *
- * Current DRM assumption is that alpha is default premultiplied, so the bitmask of
- * blend_modes must include BIT(DRM_MODE_BLEND_PREMULTI). Otherwise, mtk_plane_init()
- * will get an error return from drm_plane_create_blend_mode_property() and
- * state->base.pixel_blend_mode should not be used.
- */
- if (ovl->data->blend_modes & BIT(DRM_MODE_BLEND_PREMULTI))
- blend_mode = state->base.pixel_blend_mode;
+ unsigned int con = 0;
+ bool need_byte_swap = false, need_rgb_swap = false;
switch (fmt) {
default:
case DRM_FORMAT_RGB565:
- return OVL_CON_CLRFMT_RGB565(ovl);
+ con = fmt_rgb565_is_0 ?
+ OVL_CON_CLRFMT_RGB565(clrfmt_shift) : OVL_CON_CLRFMT_RGB888(clrfmt_shift);
+ break;
case DRM_FORMAT_BGR565:
- return OVL_CON_CLRFMT_RGB565(ovl) | OVL_CON_BYTE_SWAP;
+ con = fmt_rgb565_is_0 ?
+ OVL_CON_CLRFMT_RGB565(clrfmt_shift) : OVL_CON_CLRFMT_RGB888(clrfmt_shift);
+ need_byte_swap = true; /* RGB565 -> BGR565 */
+ break;
case DRM_FORMAT_RGB888:
- return OVL_CON_CLRFMT_RGB888(ovl);
+ con = fmt_rgb565_is_0 ?
+ OVL_CON_CLRFMT_RGB888(clrfmt_shift) : OVL_CON_CLRFMT_RGB565(clrfmt_shift);
+ break;
case DRM_FORMAT_BGR888:
- return OVL_CON_CLRFMT_RGB888(ovl) | OVL_CON_BYTE_SWAP;
+ con = fmt_rgb565_is_0 ?
+ OVL_CON_CLRFMT_RGB888(clrfmt_shift) : OVL_CON_CLRFMT_RGB565(clrfmt_shift);
+ need_byte_swap = true; /* RGB888 -> BGR888 */
+ break;
case DRM_FORMAT_RGBX8888:
case DRM_FORMAT_RGBA8888:
case DRM_FORMAT_RGBX1010102:
case DRM_FORMAT_RGBA1010102:
- return blend_mode == DRM_MODE_BLEND_COVERAGE ?
- OVL_CON_CLRFMT_RGBA8888 :
- OVL_CON_CLRFMT_PRGBA8888;
+ if (blend_mode == DRM_MODE_BLEND_COVERAGE) {
+ con = OVL_CON_CLRFMT_RGBA8888(clrfmt_shift);
+ } else {
+ con = OVL_CON_CLRFMT_PARGB8888(clrfmt_shift, clrfmt_man);
+ need_byte_swap = true; /* PARGB8888 -> PBGRA8888 */
+ need_rgb_swap = true; /* PBGRA8888 -> PRGBA8888 */
+ }
+ break;
case DRM_FORMAT_BGRX8888:
case DRM_FORMAT_BGRA8888:
case DRM_FORMAT_BGRX1010102:
case DRM_FORMAT_BGRA1010102:
- return blend_mode == DRM_MODE_BLEND_COVERAGE ?
- OVL_CON_CLRFMT_BGRA8888 :
- OVL_CON_CLRFMT_PBGRA8888;
+ if (blend_mode == DRM_MODE_BLEND_COVERAGE) {
+ con = OVL_CON_CLRFMT_RGBA8888(clrfmt_shift);
+ need_byte_swap = true; /* RGB8888 -> BGR8888 */
+ } else {
+ con = OVL_CON_CLRFMT_PARGB8888(clrfmt_shift, clrfmt_man);
+ need_byte_swap = true; /* PARGB8888 -> PBGRA8888 */
+ }
+ break;
case DRM_FORMAT_XRGB8888:
case DRM_FORMAT_ARGB8888:
case DRM_FORMAT_XRGB2101010:
case DRM_FORMAT_ARGB2101010:
- return blend_mode == DRM_MODE_BLEND_COVERAGE ?
- OVL_CON_CLRFMT_ARGB8888 :
- OVL_CON_CLRFMT_PARGB8888;
+ if (blend_mode == DRM_MODE_BLEND_COVERAGE)
+ con = OVL_CON_CLRFMT_ARGB8888(clrfmt_shift);
+ else
+ con = OVL_CON_CLRFMT_PARGB8888(clrfmt_shift, clrfmt_man);
+ break;
case DRM_FORMAT_XBGR8888:
case DRM_FORMAT_ABGR8888:
case DRM_FORMAT_XBGR2101010:
case DRM_FORMAT_ABGR2101010:
- return blend_mode == DRM_MODE_BLEND_COVERAGE ?
- OVL_CON_CLRFMT_ABGR8888 :
- OVL_CON_CLRFMT_PABGR8888;
+ if (blend_mode == DRM_MODE_BLEND_COVERAGE) {
+ con = OVL_CON_CLRFMT_ARGB8888(clrfmt_shift);
+ need_rgb_swap = true; /* ARGB8888 -> ABGR8888 */
+ } else {
+ con = OVL_CON_CLRFMT_PARGB8888(clrfmt_shift, clrfmt_man);
+ need_rgb_swap = true; /* PARGB8888 -> PABGR8888 */
+ }
+ break;
case DRM_FORMAT_UYVY:
- return OVL_CON_CLRFMT_UYVY | OVL_CON_MTX_YUV_TO_RGB;
+ con = OVL_CON_CLRFMT_UYVY(clrfmt_shift);
+ if (color_convert)
+ con |= OVL_CON_MTX_YUV_TO_RGB;
+ break;
case DRM_FORMAT_YUYV:
- return OVL_CON_CLRFMT_YUYV | OVL_CON_MTX_YUV_TO_RGB;
+ con = OVL_CON_CLRFMT_YUYV(clrfmt_shift);
+ if (color_convert)
+ con |= OVL_CON_MTX_YUV_TO_RGB;
+ break;
}
+
+ if (need_byte_swap)
+ con |= byte_swap;
+
+ if (need_rgb_swap)
+ con |= rgb_swap;
+
+ return con;
}
static void mtk_ovl_afbc_layer_config(struct mtk_disp_ovl *ovl,
@@ -512,7 +538,15 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
return;
}
- con = mtk_ovl_fmt_convert(ovl, state);
+ if (ovl->data->blend_modes & BIT(DRM_MODE_BLEND_PREMULTI))
+ con = mtk_ovl_fmt_convert(fmt, blend_mode,
+ ovl->data->fmt_rgb565_is_0, true, OVL_CON_CLRFMT_SHIFT,
+ OVL_CON_CLRFMT_MAN, OVL_CON_BYTE_SWAP, OVL_CON_RGB_SWAP);
+ else
+ con = mtk_ovl_fmt_convert(fmt, DRM_MODE_BLEND_COVERAGE,
+ ovl->data->fmt_rgb565_is_0, true, OVL_CON_CLRFMT_SHIFT,
+ OVL_CON_CLRFMT_MAN, OVL_CON_BYTE_SWAP, OVL_CON_RGB_SWAP);
+
if (state->base.fb) {
con |= state->base.alpha & OVL_CON_ALPHA;
@@ -674,7 +708,7 @@ static const struct mtk_disp_ovl_data mt2701_ovl_driver_data = {
.layer_nr = 4,
.fmt_rgb565_is_0 = false,
.formats = mt8173_ovl_formats,
- .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
+ .num_formats = mt8173_ovl_formats_len,
};
static const struct mtk_disp_ovl_data mt8167_ovl_driver_data = {
@@ -693,7 +727,7 @@ static const struct mtk_disp_ovl_data mt8173_ovl_driver_data = {
.layer_nr = 4,
.fmt_rgb565_is_0 = true,
.formats = mt8173_ovl_formats,
- .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
+ .num_formats = mt8173_ovl_formats_len,
};
static const struct mtk_disp_ovl_data mt8183_ovl_driver_data = {
@@ -702,7 +736,7 @@ static const struct mtk_disp_ovl_data mt8183_ovl_driver_data = {
.layer_nr = 4,
.fmt_rgb565_is_0 = true,
.formats = mt8173_ovl_formats,
- .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
+ .num_formats = mt8173_ovl_formats_len,
};
static const struct mtk_disp_ovl_data mt8183_ovl_2l_driver_data = {
@@ -711,7 +745,7 @@ static const struct mtk_disp_ovl_data mt8183_ovl_2l_driver_data = {
.layer_nr = 2,
.fmt_rgb565_is_0 = true,
.formats = mt8173_ovl_formats,
- .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
+ .num_formats = mt8173_ovl_formats_len,
};
static const struct mtk_disp_ovl_data mt8192_ovl_driver_data = {
@@ -724,7 +758,7 @@ static const struct mtk_disp_ovl_data mt8192_ovl_driver_data = {
BIT(DRM_MODE_BLEND_COVERAGE) |
BIT(DRM_MODE_BLEND_PIXEL_NONE),
.formats = mt8173_ovl_formats,
- .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
+ .num_formats = mt8173_ovl_formats_len,
};
static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = {
@@ -737,7 +771,7 @@ static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = {
BIT(DRM_MODE_BLEND_COVERAGE) |
BIT(DRM_MODE_BLEND_PIXEL_NONE),
.formats = mt8173_ovl_formats,
- .num_formats = ARRAY_SIZE(mt8173_ovl_formats),
+ .num_formats = mt8173_ovl_formats_len,
};
static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = {
@@ -751,7 +785,7 @@ static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = {
BIT(DRM_MODE_BLEND_COVERAGE) |
BIT(DRM_MODE_BLEND_PIXEL_NONE),
.formats = mt8195_ovl_formats,
- .num_formats = ARRAY_SIZE(mt8195_ovl_formats),
+ .num_formats = mt8195_ovl_formats_len,
.supports_clrfmt_ext = true,
};
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.h b/drivers/gpu/drm/mediatek/mtk_disp_ovl.h
new file mode 100644
index 000000000000..919498496bb6
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ */
+
+#ifndef __MTK_DISP_OVL_H__
+#define __MTK_DISP_OVL_H__
+
+#include <drm/drm_fourcc.h>
+
+extern const u32 mt8195_ovl_formats[];
+extern const size_t mt8195_ovl_formats_len;
+
+bool mtk_ovl_is_10bit_rgb(unsigned int fmt);
+unsigned int mtk_ovl_fmt_convert(unsigned int fmt, unsigned int blend_mode,
+ bool fmt_rgb565_is_0, bool color_convert,
+ u8 clrfmt_shift, u32 clrfmt_man, u32 byte_swap, u32 rgb_swap);
+
+#endif
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 02/42] drm/mediatek: Export OVL formats definitions and format conversion API
2026-07-01 12:20 ` [PATCH 02/42] drm/mediatek: Export OVL formats definitions and format conversion API AngeloGioacchino Del Regno
@ 2026-07-02 9:36 ` CK Hu (胡俊光)
0 siblings, 0 replies; 52+ messages in thread
From: CK Hu (胡俊光) @ 2026-07-02 9:36 UTC (permalink / raw)
To: AngeloGioacchino Del Regno, chunkuang.hu@kernel.org
Cc: robh@kernel.org, tzimmermann@suse.de, simona@ffwll.ch,
mripard@kernel.org, kernel@collabora.com,
linux-mediatek@lists.infradead.org,
maarten.lankhorst@linux.intel.com,
dri-devel@lists.freedesktop.org, linux-kernel@vger.kernel.org,
conor+dt@kernel.org, devicetree@vger.kernel.org,
krzk+dt@kernel.org, Paul-pl Chen (陳柏霖),
p.zabel@pengutronix.de, Nancy Lin (林欣螢),
airlied@gmail.com, Justin Yeh (葉英茂),
matthias.bgg@gmail.com, linux-arm-kernel@lists.infradead.org,
Jason-JH Lin (林睿祥)
On Wed, 2026-07-01 at 14:20 +0200, AngeloGioacchino Del Regno wrote:
> From: Nancy Lin <nancy.lin@mediatek.com>
>
> In upcoming SoCs, the OVL component will be divided into multiple
> smaller hardware units to enhance flexibility. To facilitate this
> transition, the OVL format definitions and format conversion API
> should be exported for reuse across these units.
>
> Signed-off-by: Nancy Lin <nancy.lin@mediatek.com>
> Signed-off-by: Paul-pl Chen <paul-pl.chen@mediatek.com>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
[snip]
>
> -static unsigned int mtk_ovl_fmt_convert(struct mtk_disp_ovl *ovl,
> - struct mtk_plane_state *state)
> +unsigned int mtk_ovl_fmt_convert(unsigned int fmt, unsigned int blend_mode,
> + bool fmt_rgb565_is_0, bool color_convert,
> + u8 clrfmt_shift, u32 clrfmt_man, u32 byte_swap, u32 rgb_swap)
> {
> - unsigned int fmt = state->pending.format;
> - unsigned int blend_mode = DRM_MODE_BLEND_COVERAGE;
> -
> - /*
> - * For the platforms where OVL_CON_CLRFMT_MAN is defined in the hardware data sheet
> - * and supports premultiplied color formats, such as OVL_CON_CLRFMT_PARGB8888.
> - *
> - * Check blend_modes in the driver data to see if premultiplied mode is supported.
> - * If not, use coverage mode instead to set it to the supported color formats.
> - *
> - * Current DRM assumption is that alpha is default premultiplied, so the bitmask of
> - * blend_modes must include BIT(DRM_MODE_BLEND_PREMULTI). Otherwise, mtk_plane_init()
> - * will get an error return from drm_plane_create_blend_mode_property() and
> - * state->base.pixel_blend_mode should not be used.
> - */
> - if (ovl->data->blend_modes & BIT(DRM_MODE_BLEND_PREMULTI))
> - blend_mode = state->base.pixel_blend_mode;
> + unsigned int con = 0;
> + bool need_byte_swap = false, need_rgb_swap = false;
>
> switch (fmt) {
> default:
> case DRM_FORMAT_RGB565:
> - return OVL_CON_CLRFMT_RGB565(ovl);
> + con = fmt_rgb565_is_0 ?
> + OVL_CON_CLRFMT_RGB565(clrfmt_shift) : OVL_CON_CLRFMT_RGB888(clrfmt_shift);
> + break;
One more indent.
> case DRM_FORMAT_BGR565:
> - return OVL_CON_CLRFMT_RGB565(ovl) | OVL_CON_BYTE_SWAP;
> + con = fmt_rgb565_is_0 ?
> + OVL_CON_CLRFMT_RGB565(clrfmt_shift) : OVL_CON_CLRFMT_RGB888(clrfmt_shift);
> + need_byte_swap = true; /* RGB565 -> BGR565 */
> + break;
> case DRM_FORMAT_RGB888:
> - return OVL_CON_CLRFMT_RGB888(ovl);
> + con = fmt_rgb565_is_0 ?
> + OVL_CON_CLRFMT_RGB888(clrfmt_shift) : OVL_CON_CLRFMT_RGB565(clrfmt_shift);
> + break;
> case DRM_FORMAT_BGR888:
> - return OVL_CON_CLRFMT_RGB888(ovl) | OVL_CON_BYTE_SWAP;
> + con = fmt_rgb565_is_0 ?
> + OVL_CON_CLRFMT_RGB888(clrfmt_shift) : OVL_CON_CLRFMT_RGB565(clrfmt_shift);
> + need_byte_swap = true; /* RGB888 -> BGR888 */
> + break;
> case DRM_FORMAT_RGBX8888:
> case DRM_FORMAT_RGBA8888:
> case DRM_FORMAT_RGBX1010102:
> case DRM_FORMAT_RGBA1010102:
> - return blend_mode == DRM_MODE_BLEND_COVERAGE ?
> - OVL_CON_CLRFMT_RGBA8888 :
> - OVL_CON_CLRFMT_PRGBA8888;
> + if (blend_mode == DRM_MODE_BLEND_COVERAGE) {
> + con = OVL_CON_CLRFMT_RGBA8888(clrfmt_shift);
> + } else {
> + con = OVL_CON_CLRFMT_PARGB8888(clrfmt_shift, clrfmt_man);
> + need_byte_swap = true; /* PARGB8888 -> PBGRA8888 */
> + need_rgb_swap = true; /* PBGRA8888 -> PRGBA8888 */
> + }
> + break;
> case DRM_FORMAT_BGRX8888:
> case DRM_FORMAT_BGRA8888:
> case DRM_FORMAT_BGRX1010102:
> case DRM_FORMAT_BGRA1010102:
> - return blend_mode == DRM_MODE_BLEND_COVERAGE ?
> - OVL_CON_CLRFMT_BGRA8888 :
> - OVL_CON_CLRFMT_PBGRA8888;
> + if (blend_mode == DRM_MODE_BLEND_COVERAGE) {
> + con = OVL_CON_CLRFMT_RGBA8888(clrfmt_shift);
> + need_byte_swap = true; /* RGB8888 -> BGR8888 */
/* RGBA8888 -> BGRA8888 */
Regards,
CK
> + } else {
> + con = OVL_CON_CLRFMT_PARGB8888(clrfmt_shift, clrfmt_man);
> + need_byte_swap = true; /* PARGB8888 -> PBGRA8888 */
> + }
> + break;
> case DRM_FORMAT_XRGB8888:
> case DRM_FORMAT_ARGB8888:
> case DRM_FORMAT_XRGB2101010:
> case DRM_FORMAT_ARGB2101010:
> - return blend_mode == DRM_MODE_BLEND_COVERAGE ?
> - OVL_CON_CLRFMT_ARGB8888 :
> - OVL_CON_CLRFMT_PARGB8888;
> + if (blend_mode == DRM_MODE_BLEND_COVERAGE)
> + con = OVL_CON_CLRFMT_ARGB8888(clrfmt_shift);
> + else
> + con = OVL_CON_CLRFMT_PARGB8888(clrfmt_shift, clrfmt_man);
> + break;
> case DRM_FORMAT_XBGR8888:
> case DRM_FORMAT_ABGR8888:
> case DRM_FORMAT_XBGR2101010:
> case DRM_FORMAT_ABGR2101010:
> - return blend_mode == DRM_MODE_BLEND_COVERAGE ?
> - OVL_CON_CLRFMT_ABGR8888 :
> - OVL_CON_CLRFMT_PABGR8888;
> + if (blend_mode == DRM_MODE_BLEND_COVERAGE) {
> + con = OVL_CON_CLRFMT_ARGB8888(clrfmt_shift);
> + need_rgb_swap = true; /* ARGB8888 -> ABGR8888 */
> + } else {
> + con = OVL_CON_CLRFMT_PARGB8888(clrfmt_shift, clrfmt_man);
> + need_rgb_swap = true; /* PARGB8888 -> PABGR8888 */
> + }
> + break;
> case DRM_FORMAT_UYVY:
> - return OVL_CON_CLRFMT_UYVY | OVL_CON_MTX_YUV_TO_RGB;
> + con = OVL_CON_CLRFMT_UYVY(clrfmt_shift);
> + if (color_convert)
> + con |= OVL_CON_MTX_YUV_TO_RGB;
> + break;
> case DRM_FORMAT_YUYV:
> - return OVL_CON_CLRFMT_YUYV | OVL_CON_MTX_YUV_TO_RGB;
> + con = OVL_CON_CLRFMT_YUYV(clrfmt_shift);
> + if (color_convert)
> + con |= OVL_CON_MTX_YUV_TO_RGB;
> + break;
> }
> +
> + if (need_byte_swap)
> + con |= byte_swap;
> +
> + if (need_rgb_swap)
> + con |= rgb_swap;
> +
> + return con;
> }
>
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 03/42] drm/mediatek: Export OVL Blend function
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 01/42] drm/mediatek: Rename OVL format naming AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 02/42] drm/mediatek: Export OVL formats definitions and format conversion API AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 04/42] drm/mediatek: Move mtk_ddp_comp_type enumeration to mtk-mmsys.h AngeloGioacchino Del Regno
` (38 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel, Paul-pl Chen,
Nancy Lin
From: Paul-pl Chen <paul-pl.chen@mediatek.com>
For the new BLENDER component, the OVL ignore pixel alpha logic
should be exported as a function and reused it.
Signed-off-by: Nancy Lin <nancy.lin@mediatek.com>
Signed-off-by: Paul-pl Chen <paul-pl.chen@mediatek.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 68 +++++++++++++++++--------
drivers/gpu/drm/mediatek/mtk_disp_ovl.h | 8 +++
2 files changed, 56 insertions(+), 20 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 9ded20202191..fa4607304acb 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -215,6 +215,23 @@ void mtk_ovl_disable_vblank(struct device *dev)
writel_relaxed(0x0, ovl->regs + DISP_REG_OVL_INTEN);
}
+bool mtk_ovl_is_ignore_pixel_alpha(struct mtk_plane_state *state, unsigned int blend_mode)
+{
+ if (!state->base.fb)
+ return false;
+
+ /*
+ * Although the alpha channel can be ignored, CONST_BLD must be enabled
+ * for XRGB format, otherwise OVL will still read the value from memory.
+ * For RGB888 related formats, whether CONST_BLD is enabled or not won't
+ * affect the result. Therefore we use !has_alpha as the condition.
+ */
+ if (blend_mode == DRM_MODE_BLEND_PIXEL_NONE || !state->base.fb->format->has_alpha)
+ return true;
+
+ return false;
+}
+
u32 mtk_ovl_get_blend_modes(struct device *dev)
{
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
@@ -401,6 +418,29 @@ void mtk_ovl_layer_off(struct device *dev, unsigned int idx,
DISP_REG_OVL_RDMA_CTRL(idx));
}
+unsigned int mtk_ovl_get_blend_mode(struct mtk_plane_state *state, unsigned int blend_modes)
+{
+ unsigned int blend_mode = DRM_MODE_BLEND_COVERAGE;
+
+ /*
+ * For the platforms where OVL_CON_CLRFMT_MAN is defined in the hardware data sheet
+ * and supports premultiplied color formats, such as OVL_CON_CLRFMT_PARGB888
+ * and supports premultiplied color formats, such as OVL_CON_CLRFMT_PARGB8888.
+ *
+ * Check blend_modes in the driver data to see if premultiplied mode is supported.
+ * If not, use coverage mode instead to set it to the supported color formats.
+ *
+ * Current DRM assumption is that alpha is default premultiplied, so the bitmask of
+ * blend_modes must include BIT(DRM_MODE_BLEND_PREMULTI). Otherwise, mtk_plane_init()
+ * will get an error return from drm_plane_create_blend_mode_property() and
+ * state->base.pixel_blend_mode should not be used.
+ */
+ if (blend_modes & BIT(DRM_MODE_BLEND_PREMULTI))
+ blend_mode = state->base.pixel_blend_mode;
+
+ return blend_mode;
+}
+
unsigned int mtk_ovl_fmt_convert(unsigned int fmt, unsigned int blend_mode,
bool fmt_rgb565_is_0, bool color_convert,
u8 clrfmt_shift, u32 clrfmt_man, u32 byte_swap, u32 rgb_swap)
@@ -529,7 +569,7 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
unsigned int rotation = pending->rotation;
unsigned int offset = (pending->y << 16) | pending->x;
unsigned int src_size = (pending->height << 16) | pending->width;
- unsigned int blend_mode = state->base.pixel_blend_mode;
+ unsigned int blend_mode = mtk_ovl_get_blend_mode(state, ovl->data->blend_modes);
unsigned int ignore_pixel_alpha = 0;
unsigned int con;
@@ -554,17 +594,8 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
* For blend_modes supported SoCs, always enable alpha blending.
* For blend_modes unsupported SoCs, enable alpha blending when has_alpha is set.
*/
- if (blend_mode || state->base.fb->format->has_alpha)
+ if (state->base.pixel_blend_mode || state->base.fb->format->has_alpha)
con |= OVL_CON_AEN;
-
- /*
- * Although the alpha channel can be ignored, CONST_BLD must be enabled
- * for XRGB format, otherwise OVL will still read the value from memory.
- * For RGB888 related formats, whether CONST_BLD is enabled or not won't
- * affect the result. Therefore we use !has_alpha as the condition.
- */
- if (blend_mode == DRM_MODE_BLEND_PIXEL_NONE || !state->base.fb->format->has_alpha)
- ignore_pixel_alpha = OVL_CONST_BLEND;
}
/*
@@ -590,6 +621,9 @@ void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
mtk_ddp_write_relaxed(cmdq_pkt, con, &ovl->cmdq_reg, ovl->regs,
DISP_REG_OVL_CON(idx));
+
+ if (mtk_ovl_is_ignore_pixel_alpha(state, blend_mode))
+ ignore_pixel_alpha = OVL_CONST_BLEND;
mtk_ddp_write_relaxed(cmdq_pkt, pitch_lsb | ignore_pixel_alpha,
&ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_PITCH(idx));
mtk_ddp_write_relaxed(cmdq_pkt, src_size, &ovl->cmdq_reg, ovl->regs,
@@ -754,9 +788,7 @@ static const struct mtk_disp_ovl_data mt8192_ovl_driver_data = {
.layer_nr = 4,
.fmt_rgb565_is_0 = true,
.smi_id_en = true,
- .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
- BIT(DRM_MODE_BLEND_COVERAGE) |
- BIT(DRM_MODE_BLEND_PIXEL_NONE),
+ .blend_modes = MTK_OVL_SUPPORT_BLEND_MODES,
.formats = mt8173_ovl_formats,
.num_formats = mt8173_ovl_formats_len,
};
@@ -767,9 +799,7 @@ static const struct mtk_disp_ovl_data mt8192_ovl_2l_driver_data = {
.layer_nr = 2,
.fmt_rgb565_is_0 = true,
.smi_id_en = true,
- .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
- BIT(DRM_MODE_BLEND_COVERAGE) |
- BIT(DRM_MODE_BLEND_PIXEL_NONE),
+ .blend_modes = MTK_OVL_SUPPORT_BLEND_MODES,
.formats = mt8173_ovl_formats,
.num_formats = mt8173_ovl_formats_len,
};
@@ -781,9 +811,7 @@ static const struct mtk_disp_ovl_data mt8195_ovl_driver_data = {
.fmt_rgb565_is_0 = true,
.smi_id_en = true,
.supports_afbc = true,
- .blend_modes = BIT(DRM_MODE_BLEND_PREMULTI) |
- BIT(DRM_MODE_BLEND_COVERAGE) |
- BIT(DRM_MODE_BLEND_PIXEL_NONE),
+ .blend_modes = MTK_OVL_SUPPORT_BLEND_MODES,
.formats = mt8195_ovl_formats,
.num_formats = mt8195_ovl_formats_len,
.supports_clrfmt_ext = true,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.h b/drivers/gpu/drm/mediatek/mtk_disp_ovl.h
index 919498496bb6..419c2136006c 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.h
@@ -6,12 +6,20 @@
#ifndef __MTK_DISP_OVL_H__
#define __MTK_DISP_OVL_H__
+#include <drm/drm_blend.h>
#include <drm/drm_fourcc.h>
+#define MTK_OVL_SUPPORT_BLEND_MODES \
+ (BIT(DRM_MODE_BLEND_PREMULTI) | \
+ BIT(DRM_MODE_BLEND_COVERAGE) | \
+ BIT(DRM_MODE_BLEND_PIXEL_NONE))
+
extern const u32 mt8195_ovl_formats[];
extern const size_t mt8195_ovl_formats_len;
bool mtk_ovl_is_10bit_rgb(unsigned int fmt);
+bool mtk_ovl_is_ignore_pixel_alpha(struct mtk_plane_state *state, unsigned int blend_mode);
+unsigned int mtk_ovl_get_blend_mode(struct mtk_plane_state *state, unsigned int blend_modes);
unsigned int mtk_ovl_fmt_convert(unsigned int fmt, unsigned int blend_mode,
bool fmt_rgb565_is_0, bool color_convert,
u8 clrfmt_shift, u32 clrfmt_man, u32 byte_swap, u32 rgb_swap);
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 04/42] drm/mediatek: Move mtk_ddp_comp_type enumeration to mtk-mmsys.h
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (2 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 03/42] drm/mediatek: Export OVL Blend function AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 05/42] drm/mediatek: Rename all display component type to have DISP_ prefix AngeloGioacchino Del Regno
` (37 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In preparation for a major refactoring of MMSYS, MUTEX and of
mediatek-drm, move the mtk_ddp_comp_type enumeration to the
mtk-mmsys.h header, as this will be shared between multiple
MediaTek multimedia related drivers.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 25 ------------------
include/linux/soc/mediatek/mtk-mmsys.h | 34 +++++++++++++++++++++++++
2 files changed, 34 insertions(+), 25 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index 99bf1e1015da..bbc66072fe6b 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -22,31 +22,6 @@ struct mtk_plane_state;
struct drm_crtc_state;
struct drm_dsc_config;
-enum mtk_ddp_comp_type {
- MTK_DISP_AAL,
- MTK_DISP_BLS,
- MTK_DISP_CCORR,
- MTK_DISP_COLOR,
- MTK_DISP_DITHER,
- MTK_DISP_DSC,
- MTK_DISP_GAMMA,
- MTK_DISP_MERGE,
- MTK_DISP_MUTEX,
- MTK_DISP_OD,
- MTK_DISP_OVL,
- MTK_DISP_OVL_2L,
- MTK_DISP_OVL_ADAPTOR,
- MTK_DISP_POSTMASK,
- MTK_DISP_PWM,
- MTK_DISP_RDMA,
- MTK_DISP_UFOE,
- MTK_DISP_WDMA,
- MTK_DPI,
- MTK_DP_INTF,
- MTK_DSI,
- MTK_DDP_COMP_TYPE_MAX,
-};
-
struct mtk_ddp_comp;
struct cmdq_pkt;
struct mtk_ddp_comp_funcs {
diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h
index 4885b065b849..3ddfdeac658d 100644
--- a/include/linux/soc/mediatek/mtk-mmsys.h
+++ b/include/linux/soc/mediatek/mtk-mmsys.h
@@ -84,6 +84,40 @@ enum mtk_ddp_comp_id {
DDP_COMPONENT_ID_MAX,
};
+enum mtk_ddp_comp_type {
+ /* DISP Components */
+ MTK_DISP_AAL,
+ MTK_DISP_BLS,
+ MTK_DISP_CCORR,
+ MTK_DISP_COLOR,
+ MTK_DISP_DITHER,
+ MTK_DISP_DSC,
+ MTK_DISP_ETHDR_MIXER,
+ MTK_DISP_GAMMA,
+ MTK_DISP_MERGE,
+ MTK_DISP_MUTEX,
+ MTK_DISP_OD,
+ MTK_DISP_OVL,
+ MTK_DISP_OVL_2L,
+ MTK_DISP_OVL_ADAPTOR,
+ MTK_DISP_PADDING,
+ MTK_DISP_POSTMASK,
+ MTK_DISP_PWM,
+ MTK_DISP_RDMA,
+ MTK_DISP_UFOE,
+ MTK_DISP_WDMA,
+
+ /* MDP Components */
+ MTK_DISP_MDP_RDMA,
+
+ /* Keep Display outputs at the end for readability */
+ MTK_DPI,
+ MTK_DP_INTF,
+ MTK_DSI,
+
+ MTK_DDP_COMP_TYPE_MAX
+};
+
void mtk_mmsys_ddp_connect(struct device *dev,
enum mtk_ddp_comp_id cur,
enum mtk_ddp_comp_id next);
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 05/42] drm/mediatek: Rename all display component type to have DISP_ prefix
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (3 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 04/42] drm/mediatek: Move mtk_ddp_comp_type enumeration to mtk-mmsys.h AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 06/42] drm/mediatek: Use hashtable for components discovery and registration AngeloGioacchino Del Regno
` (36 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
The mtk_ddp_comp_type enumeration will end up containing both the
Display Controller and Media Data Path Controller components: this
is because those can be interconnected together (as in, using MDP
components in Display Controller paths is possible!) and because
both MMSYS and MuteX are managing both of those in practically the
same way.
Rename all of the Display Controller related HW components in the
list to always have a "DISP_" prefix.
This includes components that are in the MDP Controller instead,
and the strategy here is for some of those to also have the same
DISP_ prefix, so that:
- Display Controller specific components have a DISP_ prefix
- Example: MTK_DISP_(NAME)
- MDP Controller components that can be interconnected to the
Display Controller will have both DISP_ and MDP_ prefixes
- Example: MTK_DISP_MDP_(NAME)
- MDP Controller components that are exclusive to MDP and can
not be interconnected with Display Controller will only have
an MDP_ prefix but not a DISP_ prefix
- Example: MTK_MDP_(NAME).
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 28 +++++++++----------
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 36 ++++++++++++-------------
include/linux/soc/mediatek/mtk-mmsys.h | 6 ++---
3 files changed, 35 insertions(+), 35 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index 94b356da6de7..a6c1815ffa39 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -423,9 +423,9 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_RDMA] = "rdma",
[MTK_DISP_UFOE] = "ufoe",
[MTK_DISP_WDMA] = "wdma",
- [MTK_DP_INTF] = "dp-intf",
- [MTK_DPI] = "dpi",
- [MTK_DSI] = "dsi",
+ [MTK_DISP_DP_INTF] = "dp-intf",
+ [MTK_DISP_DPI] = "dpi",
+ [MTK_DISP_DSI] = "dsi",
};
struct mtk_ddp_comp_match {
@@ -442,17 +442,17 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_DRM_ID_MAX]
[DDP_COMPONENT_COLOR0] = { MTK_DISP_COLOR, 0, &ddp_color },
[DDP_COMPONENT_COLOR1] = { MTK_DISP_COLOR, 1, &ddp_color },
[DDP_COMPONENT_DITHER0] = { MTK_DISP_DITHER, 0, &ddp_dither },
- [DDP_COMPONENT_DP_INTF0] = { MTK_DP_INTF, 0, &ddp_dpi },
- [DDP_COMPONENT_DP_INTF1] = { MTK_DP_INTF, 1, &ddp_dpi },
- [DDP_COMPONENT_DPI0] = { MTK_DPI, 0, &ddp_dpi },
- [DDP_COMPONENT_DPI1] = { MTK_DPI, 1, &ddp_dpi },
+ [DDP_COMPONENT_DP_INTF0] = { MTK_DISP_DP_INTF, 0, &ddp_dpi },
+ [DDP_COMPONENT_DP_INTF1] = { MTK_DISP_DP_INTF, 1, &ddp_dpi },
+ [DDP_COMPONENT_DPI0] = { MTK_DISP_DPI, 0, &ddp_dpi },
+ [DDP_COMPONENT_DPI1] = { MTK_DISP_DPI, 1, &ddp_dpi },
[DDP_COMPONENT_DRM_OVL_ADAPTOR] = { MTK_DISP_OVL_ADAPTOR, 0, &ddp_ovl_adaptor },
[DDP_COMPONENT_DSC0] = { MTK_DISP_DSC, 0, &ddp_dsc },
[DDP_COMPONENT_DSC1] = { MTK_DISP_DSC, 1, &ddp_dsc },
- [DDP_COMPONENT_DSI0] = { MTK_DSI, 0, &ddp_dsi },
- [DDP_COMPONENT_DSI1] = { MTK_DSI, 1, &ddp_dsi },
- [DDP_COMPONENT_DSI2] = { MTK_DSI, 2, &ddp_dsi },
- [DDP_COMPONENT_DSI3] = { MTK_DSI, 3, &ddp_dsi },
+ [DDP_COMPONENT_DSI0] = { MTK_DISP_DSI, 0, &ddp_dsi },
+ [DDP_COMPONENT_DSI1] = { MTK_DISP_DSI, 1, &ddp_dsi },
+ [DDP_COMPONENT_DSI2] = { MTK_DISP_DSI, 2, &ddp_dsi },
+ [DDP_COMPONENT_DSI3] = { MTK_DISP_DSI, 3, &ddp_dsi },
[DDP_COMPONENT_GAMMA] = { MTK_DISP_GAMMA, 0, &ddp_gamma },
[DDP_COMPONENT_MERGE0] = { MTK_DISP_MERGE, 0, &ddp_merge },
[DDP_COMPONENT_MERGE1] = { MTK_DISP_MERGE, 1, &ddp_merge },
@@ -659,9 +659,9 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, struct mtk_d
type == MTK_DISP_PWM ||
type == MTK_DISP_RDMA ||
type == MTK_DISP_WDMA ||
- type == MTK_DPI ||
- type == MTK_DP_INTF ||
- type == MTK_DSI)
+ type == MTK_DISP_DPI ||
+ type == MTK_DISP_DP_INTF ||
+ type == MTK_DISP_DSI)
return 0;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index e54f0654f2f9..9c6dfc1e384b 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -801,35 +801,35 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
{ .compatible = "mediatek,mt8173-disp-wdma",
.data = (void *)MTK_DISP_WDMA },
{ .compatible = "mediatek,mt2701-dpi",
- .data = (void *)MTK_DPI },
+ .data = (void *)MTK_DISP_DPI },
{ .compatible = "mediatek,mt8167-dsi",
- .data = (void *)MTK_DSI },
+ .data = (void *)MTK_DISP_DSI },
{ .compatible = "mediatek,mt8173-dpi",
- .data = (void *)MTK_DPI },
+ .data = (void *)MTK_DISP_DPI },
{ .compatible = "mediatek,mt8183-dpi",
- .data = (void *)MTK_DPI },
+ .data = (void *)MTK_DISP_DPI },
{ .compatible = "mediatek,mt8186-dpi",
- .data = (void *)MTK_DPI },
+ .data = (void *)MTK_DISP_DPI },
{ .compatible = "mediatek,mt8188-dp-intf",
- .data = (void *)MTK_DP_INTF },
+ .data = (void *)MTK_DISP_DP_INTF },
{ .compatible = "mediatek,mt8192-dpi",
- .data = (void *)MTK_DPI },
+ .data = (void *)MTK_DISP_DPI },
{ .compatible = "mediatek,mt8195-dp-intf",
- .data = (void *)MTK_DP_INTF },
+ .data = (void *)MTK_DISP_DP_INTF },
{ .compatible = "mediatek,mt8195-dpi",
- .data = (void *)MTK_DPI },
+ .data = (void *)MTK_DISP_DPI },
{ .compatible = "mediatek,mt2701-dsi",
- .data = (void *)MTK_DSI },
+ .data = (void *)MTK_DISP_DSI },
{ .compatible = "mediatek,mt8173-dsi",
- .data = (void *)MTK_DSI },
+ .data = (void *)MTK_DISP_DSI },
{ .compatible = "mediatek,mt8183-dsi",
- .data = (void *)MTK_DSI },
+ .data = (void *)MTK_DISP_DSI },
{ .compatible = "mediatek,mt8186-dsi",
- .data = (void *)MTK_DSI },
+ .data = (void *)MTK_DISP_DSI },
{ .compatible = "mediatek,mt8188-dsi",
- .data = (void *)MTK_DSI },
+ .data = (void *)MTK_DISP_DSI },
{ .compatible = "mediatek,mt8196-dsi",
- .data = (void *)MTK_DSI },
+ .data = (void *)MTK_DISP_DSI },
{ }
};
@@ -1176,9 +1176,9 @@ static int mtk_drm_probe(struct platform_device *pdev)
comp_type == MTK_DISP_OVL_ADAPTOR ||
comp_type == MTK_DISP_RDMA ||
comp_type == MTK_DISP_WDMA ||
- comp_type == MTK_DP_INTF ||
- comp_type == MTK_DPI ||
- comp_type == MTK_DSI) {
+ comp_type == MTK_DISP_DP_INTF ||
+ comp_type == MTK_DISP_DPI ||
+ comp_type == MTK_DISP_DSI) {
dev_info(dev, "Adding component match for %pOF\n",
node);
drm_of_component_match_add(dev, &match, component_compare_of,
diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h
index 3ddfdeac658d..bbdd0b01927d 100644
--- a/include/linux/soc/mediatek/mtk-mmsys.h
+++ b/include/linux/soc/mediatek/mtk-mmsys.h
@@ -111,9 +111,9 @@ enum mtk_ddp_comp_type {
MTK_DISP_MDP_RDMA,
/* Keep Display outputs at the end for readability */
- MTK_DPI,
- MTK_DP_INTF,
- MTK_DSI,
+ MTK_DISP_DPI,
+ MTK_DISP_DP_INTF,
+ MTK_DISP_DSI,
MTK_DDP_COMP_TYPE_MAX
};
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 06/42] drm/mediatek: Use hashtable for components discovery and registration
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (4 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 05/42] drm/mediatek: Rename all display component type to have DISP_ prefix AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 07/42] drm/mediatek: ddp_comp: Move internal component register in function AngeloGioacchino Del Regno
` (35 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
As a preparation for refactoring the concept of hardware component
identification, search, and final usage, remove the ddp_comp array
of components and replace it with a hashtable, indexed by ID.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_crtc.c | 44 ++++++++++++++++-------
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 48 ++++++++++++++++++-------
drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 23 +++++++++++-
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 7 ++--
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 2 +-
5 files changed, 94 insertions(+), 30 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index f39f197057a7..3f4d6ab1bfc2 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -725,8 +725,12 @@ static void mtk_crtc_update_output(struct drm_crtc *crtc,
crtc_state->connectors_changed, encoder_mask, crtc_index);
for (i = 0; i < mtk_crtc->num_conn_routes; i++) {
- unsigned int comp_id = mtk_crtc->conn_routes[i].route_ddp;
- struct mtk_ddp_comp *comp = &priv->ddp_comp[comp_id];
+ const struct mtk_drm_route *conn_route = &mtk_crtc->conn_routes[i];
+ struct mtk_ddp_comp *comp;
+
+ comp = mtk_ddp_comp_find_by_id(&priv->hlist, conn_route->route_ddp);
+ if (!comp)
+ continue;
if (comp->encoder_index >= 0 &&
(encoder_mask & BIT(comp->encoder_index))) {
@@ -1028,10 +1032,11 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
{
struct mtk_drm_private *priv = drm_dev->dev_private;
struct device *dev = drm_dev->dev;
+ struct mtk_ddp_comp *dma_comp;
struct mtk_crtc *mtk_crtc;
unsigned int num_comp_planes = 0;
int ret;
- int i;
+ int i, j;
bool has_ctm = false;
uint gamma_lut_size = 0;
struct drm_crtc *tmp;
@@ -1051,7 +1056,7 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
struct mtk_ddp_comp *comp;
node = priv->comp_node[comp_id];
- comp = &priv->ddp_comp[comp_id];
+ comp = mtk_ddp_comp_find_by_id(&priv->hlist, comp_id);
/* Not all drm components have a DTS device node, such as ovl_adaptor,
* which is the drm bring up sub driver
@@ -1063,7 +1068,7 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
return 0;
}
- if (!comp->dev) {
+ if (!comp || !comp->dev) {
dev_err(dev, "Component %pOF not initialized\n", node);
return -ENODEV;
}
@@ -1089,12 +1094,17 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
return ret;
}
- for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
+ for (i = 0, j = 0; i < mtk_crtc->ddp_comp_nr; i++, j++) {
unsigned int comp_id = path[i];
struct mtk_ddp_comp *comp;
- comp = &priv->ddp_comp[comp_id];
- mtk_crtc->ddp_comp[i] = comp;
+ comp = mtk_ddp_comp_find_by_id(&priv->hlist, comp_id);
+ if (!comp) {
+ j--;
+ dev_dbg(dev, "Cannot find component %d.\n", comp_id);
+ continue;
+ }
+ mtk_crtc->ddp_comp[j] = comp;
if (comp->funcs) {
if (comp->funcs->gamma_set && comp->funcs->gamma_get_lut_size) {
@@ -1131,7 +1141,14 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
* In the case of ovl_adaptor sub driver, it needs to use the
* dma_dev_get function to get representative dma dev.
*/
- mtk_crtc->dma_dev = mtk_ddp_comp_dma_dev_get(&priv->ddp_comp[path[0]]);
+ dma_comp = mtk_ddp_comp_find_by_id(&priv->hlist, path[0]);
+ if (dma_comp == NULL) {
+ dev_err(dev, "Could not find appropriate DMA device!\n");
+ return -EINVAL;
+ }
+
+ mtk_crtc->dma_dev = mtk_ddp_comp_dma_dev_get(dma_comp);
+ dev_dbg(dev, "Using DMA device %pOF\n", mtk_crtc->dma_dev->of_node);
ret = mtk_crtc_init(drm_dev, mtk_crtc, crtc_i);
if (ret < 0)
@@ -1188,17 +1205,18 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
for (i = 0; i < num_conn_routes; i++) {
unsigned int comp_id = conn_routes[i].route_ddp;
struct device_node *node = priv->comp_node[comp_id];
- struct mtk_ddp_comp *comp = &priv->ddp_comp[comp_id];
+ struct mtk_ddp_comp *comp = mtk_ddp_comp_find_by_id(&priv->hlist, comp_id);
- if (!comp->dev) {
+ if (!comp || !comp->dev) {
dev_dbg(dev, "comp_id:%d, Component %pOF not initialized\n",
comp_id, node);
/* mark encoder_index to -1, if route comp device is not enabled */
- comp->encoder_index = -1;
+ if (comp)
+ comp->encoder_index = -1;
continue;
}
- mtk_ddp_comp_encoder_index_set(&priv->ddp_comp[comp_id]);
+ mtk_ddp_comp_encoder_index_set(comp);
}
mtk_crtc->num_conn_routes = num_conn_routes;
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index a6c1815ffa39..d716fd9f8a70 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -480,10 +480,24 @@ static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_DRM_ID_MAX]
[DDP_COMPONENT_WDMA1] = { MTK_DISP_WDMA, 1, &ddp_wdma },
};
+static bool mtk_ddp_find_comp_dev_in_table(const struct mtk_drm_comp_list *hlist,
+ const unsigned int comp_id,
+ struct device *dev)
+{
+ struct mtk_ddp_comp *ddp_comp;
+
+ hash_for_each_possible(hlist->ddp_list, ddp_comp, lnode, comp_id) {
+ if (ddp_comp->dev == dev)
+ return true;
+ }
+
+ return false;
+}
+
static bool mtk_ddp_comp_find(struct device *dev,
const unsigned int *path,
unsigned int path_len,
- struct mtk_ddp_comp *ddp_comp)
+ const struct mtk_drm_comp_list *hlist)
{
unsigned int i;
@@ -491,7 +505,7 @@ static bool mtk_ddp_comp_find(struct device *dev,
return false;
for (i = 0U; i < path_len; i++)
- if (dev == ddp_comp[path[i]].dev)
+ if (mtk_ddp_find_comp_dev_in_table(hlist, path[i], dev))
return true;
return false;
@@ -500,7 +514,7 @@ static bool mtk_ddp_comp_find(struct device *dev,
static int mtk_ddp_comp_find_in_route(struct device *dev,
const struct mtk_drm_route *routes,
unsigned int num_routes,
- struct mtk_ddp_comp *ddp_comp)
+ const struct mtk_drm_comp_list *hlist)
{
unsigned int i;
@@ -508,7 +522,7 @@ static int mtk_ddp_comp_find_in_route(struct device *dev,
return -EINVAL;
for (i = 0; i < num_routes; i++)
- if (dev == ddp_comp[routes[i].route_ddp].dev)
+ if (mtk_ddp_find_comp_dev_in_table(hlist, routes[i].route_ddp, dev))
return BIT(routes[i].crtc_id);
return -ENODEV;
@@ -566,7 +580,7 @@ int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev)
priv_n->comp_node)) {
if (mtk_ddp_comp_find(dev, data->main_path,
data->main_len,
- priv_n->ddp_comp))
+ &priv_n->hlist))
return BIT(i);
i++;
}
@@ -575,7 +589,7 @@ int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev)
priv_n->comp_node)) {
if (mtk_ddp_comp_find(dev, data->ext_path,
data->ext_len,
- priv_n->ddp_comp))
+ &priv_n->hlist))
return BIT(i);
i++;
}
@@ -584,7 +598,7 @@ int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev)
priv_n->comp_node)) {
if (mtk_ddp_comp_find(dev, data->third_path,
data->third_len,
- priv_n->ddp_comp))
+ &priv_n->hlist))
return BIT(i);
i++;
}
@@ -593,7 +607,7 @@ int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev)
ret = mtk_ddp_comp_find_in_route(dev,
private->data->conn_routes,
private->data->num_conn_routes,
- private->ddp_comp);
+ &private->hlist);
if (ret < 0)
DRM_INFO("Failed to find comp in ddp table, ret = %d\n", ret);
@@ -615,10 +629,12 @@ static void mtk_ddp_comp_clk_put(void *_clk)
clk_put(clk);
}
-int mtk_ddp_comp_init(struct device *dev, struct device_node *node, struct mtk_ddp_comp *comp,
+int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
+ struct mtk_drm_comp_list *hlist,
unsigned int comp_id)
{
struct platform_device *comp_pdev;
+ struct mtk_ddp_comp *comp;
enum mtk_ddp_comp_type type;
struct mtk_ddp_comp_dev *priv;
int ret;
@@ -626,6 +642,10 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, struct mtk_d
if (comp_id >= DDP_COMPONENT_DRM_ID_MAX)
return -EINVAL;
+ comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
+ if (!comp)
+ return -ENOMEM;
+
type = mtk_ddp_matches[comp_id].type;
comp->id = comp_id;
@@ -633,8 +653,10 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, struct mtk_d
/* Not all drm components have a DTS device node, such as ovl_adaptor,
* which is the drm bring up sub driver
*/
- if (!node)
- return 0;
+ if (!node) {
+ comp->dev = dev;
+ goto end;
+ }
comp_pdev = of_find_device_by_node(node);
if (!comp_pdev) {
@@ -662,7 +684,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, struct mtk_d
type == MTK_DISP_DPI ||
type == MTK_DISP_DP_INTF ||
type == MTK_DISP_DSI)
- return 0;
+ goto end;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -687,6 +709,8 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node, struct mtk_d
#endif
platform_set_drvdata(comp_pdev, priv);
+end:
+ hash_add(hlist->ddp_list, &comp->lnode, comp->id);
return 0;
}
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index bbc66072fe6b..4203eecb2a7b 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -6,6 +6,7 @@
#ifndef MTK_DDP_COMP_H
#define MTK_DDP_COMP_H
+#include <linux/hashtable.h>
#include <linux/io.h>
#include <linux/pm_runtime.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
@@ -24,6 +25,11 @@ struct drm_dsc_config;
struct mtk_ddp_comp;
struct cmdq_pkt;
+
+struct mtk_drm_comp_list {
+ DECLARE_HASHTABLE(ddp_list, 8);
+};
+
struct mtk_ddp_comp_funcs {
int (*power_on)(struct device *dev);
void (*power_off)(struct device *dev);
@@ -75,6 +81,8 @@ struct mtk_ddp_comp {
unsigned int id;
int encoder_index;
const struct mtk_ddp_comp_funcs *funcs;
+
+ struct hlist_node lnode;
};
static inline int mtk_ddp_comp_power_on(struct mtk_ddp_comp *comp)
@@ -331,10 +339,23 @@ static inline void mtk_ddp_comp_encoder_index_set(struct mtk_ddp_comp *comp)
comp->encoder_index = (int)comp->funcs->encoder_index(comp->dev);
}
+static inline struct mtk_ddp_comp
+*mtk_ddp_comp_find_by_id(struct mtk_drm_comp_list *hlist,
+ const unsigned int id)
+{
+ struct mtk_ddp_comp *ddp_comp;
+
+ hash_for_each_possible(hlist->ddp_list, ddp_comp, lnode, id)
+ return ddp_comp;
+
+ return NULL;
+}
+
int mtk_ddp_comp_get_id(struct device_node *node,
enum mtk_ddp_comp_type comp_type);
int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev);
-int mtk_ddp_comp_init(struct device *dev, struct device_node *comp_node, struct mtk_ddp_comp *comp,
+int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
+ struct mtk_drm_comp_list *hlist,
unsigned int comp_id);
enum mtk_ddp_comp_type mtk_ddp_comp_get_type(unsigned int comp_id);
void mtk_ddp_write(struct cmdq_pkt *cmdq_pkt, unsigned int value,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 9c6dfc1e384b..e956e1966b86 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -1086,6 +1086,8 @@ static int mtk_drm_probe(struct platform_device *pdev)
if (!mtk_drm_data)
return -EINVAL;
+ hash_init(private->hlist.ddp_list);
+
/* Try to build the display pipeline from devicetree graphs */
if (of_graph_is_present(phandle)) {
dev_dbg(dev, "Building display pipeline for MMSYS %u\n",
@@ -1116,8 +1118,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
PLATFORM_DEVID_AUTO,
(void *)private->mmsys_dev,
sizeof(*private->mmsys_dev));
- private->ddp_comp[DDP_COMPONENT_DRM_OVL_ADAPTOR].dev = &ovl_adaptor->dev;
- mtk_ddp_comp_init(dev, NULL, &private->ddp_comp[DDP_COMPONENT_DRM_OVL_ADAPTOR],
+ mtk_ddp_comp_init(&ovl_adaptor->dev, NULL, &private->hlist,
DDP_COMPONENT_DRM_OVL_ADAPTOR);
component_match_add(dev, &match, compare_dev, &ovl_adaptor->dev);
}
@@ -1185,7 +1186,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
node);
}
- ret = mtk_ddp_comp_init(dev, node, &private->ddp_comp[comp_id], comp_id);
+ ret = mtk_ddp_comp_init(dev, node, &private->hlist, comp_id);
if (ret) {
of_node_put(node);
goto err_node;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index 8b5c51d93f72..a171126d580e 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -60,8 +60,8 @@ struct mtk_drm_private {
struct device_node *mutex_node;
struct device *mutex_dev;
struct device *mmsys_dev;
+ struct mtk_drm_comp_list hlist;
struct device_node *comp_node[DDP_COMPONENT_DRM_ID_MAX];
- struct mtk_ddp_comp ddp_comp[DDP_COMPONENT_DRM_ID_MAX];
struct mtk_mmsys_driver_data *data;
struct drm_atomic_commit *suspend_state;
unsigned int mbox_index;
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 07/42] drm/mediatek: ddp_comp: Move internal component register in function
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (5 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 06/42] drm/mediatek: Use hashtable for components discovery and registration AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 08/42] drm/mediatek: De-duplicate internal component checks AngeloGioacchino Del Regno
` (34 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In preparation for adding an helper serving the purpose of finally
removing duplicated code to check for internal/simple components,
and for improving human readability in the up coming refactoring,
move the internal/simple component registration logic to its own
mtk_ddp_comp_init_internal_comp() function.
This brings no functional changes.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 55 +++++++++++++++----------
1 file changed, 33 insertions(+), 22 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index d716fd9f8a70..2ba2123238b3 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -629,6 +629,38 @@ static void mtk_ddp_comp_clk_put(void *_clk)
clk_put(clk);
}
+static int mtk_ddp_comp_init_internal_comp(struct device *dev, struct device *comp_dev)
+{
+ struct device_node *comp_node = comp_dev->of_node;
+ struct mtk_ddp_comp_dev *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->regs = devm_of_iomap(dev, comp_node, 0, NULL);
+ if (IS_ERR(priv->regs))
+ return PTR_ERR(priv->regs);
+
+ priv->clk = of_clk_get(comp_node, 0);
+ if (IS_ERR(priv->clk))
+ return PTR_ERR(priv->clk);
+
+ ret = devm_add_action_or_reset(dev, mtk_ddp_comp_clk_put, priv->clk);
+ if (ret)
+ return ret;
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ ret = cmdq_dev_get_client_reg(comp_dev, &priv->cmdq_reg, 0);
+ if (ret)
+ dev_dbg(comp_dev, "get mediatek,gce-client-reg fail!\n");
+#endif
+ dev_set_drvdata(comp_dev, priv);
+
+ return 0;
+};
+
int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
struct mtk_drm_comp_list *hlist,
unsigned int comp_id)
@@ -636,7 +668,6 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
struct platform_device *comp_pdev;
struct mtk_ddp_comp *comp;
enum mtk_ddp_comp_type type;
- struct mtk_ddp_comp_dev *priv;
int ret;
if (comp_id >= DDP_COMPONENT_DRM_ID_MAX)
@@ -686,29 +717,9 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
type == MTK_DISP_DSI)
goto end;
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
-
- priv->regs = devm_of_iomap(dev, node, 0, NULL);
- if (IS_ERR(priv->regs))
- return PTR_ERR(priv->regs);
-
- priv->clk = of_clk_get(node, 0);
- if (IS_ERR(priv->clk))
- return PTR_ERR(priv->clk);
-
- ret = devm_add_action_or_reset(dev, mtk_ddp_comp_clk_put, priv->clk);
+ ret = mtk_ddp_comp_init_internal_comp(dev, comp->dev);
if (ret)
return ret;
-
-#if IS_REACHABLE(CONFIG_MTK_CMDQ)
- ret = cmdq_dev_get_client_reg(comp->dev, &priv->cmdq_reg, 0);
- if (ret)
- dev_dbg(comp->dev, "get mediatek,gce-client-reg fail!\n");
-#endif
-
- platform_set_drvdata(comp_pdev, priv);
end:
hash_add(hlist->ddp_list, &comp->lnode, comp->id);
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 08/42] drm/mediatek: De-duplicate internal component checks
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (6 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 07/42] drm/mediatek: ddp_comp: Move internal component register in function AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 09/42] drm/mediatek: Introduce and use path/comp definition structures AngeloGioacchino Del Regno
` (33 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Both mtk_ddp_comp and mtk_drm_drv are performing similar checks
to distinguish components that have an external driver from ones
that don't - with the exception of mtk_ddp_comp also checking if
the component is related to a backlight driver.
Create helper functions in the main component management driver
mtk_ddp_comp, one to check if the currently checked component is
internal/simple, and one (static, internal to mtk_ddp_comp only)
to check if it is a backlight related one.
Since the amount of internal/simple components is lower than the
amount of ones having a specific driver, and since it is expected
that most of (if not all) of any new hardware support will need a
specific driver as well, the helpers are doing an inverted check
compared to what the code was doing before, as both mtk_ddp_comp
and mtk_drm_drv were checking for external component explicitly,
while now they're doing the same, but checking if NOT internal.
Also, while at it, for the OVL_ADAPTOR components case, instead
of checking for MTK_DISP_OVL_ADAPTOR, call the already provided
mtk_ovl_adaptor_is_comp_present() function to check for this type
of component.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 47 ++++++++++++++-----------
drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 1 +
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 16 ++-------
3 files changed, 30 insertions(+), 34 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index 2ba2123238b3..f7103e20abe5 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -629,6 +629,27 @@ static void mtk_ddp_comp_clk_put(void *_clk)
clk_put(clk);
}
+static bool mtk_ddp_comp_is_backlight_comp(enum mtk_ddp_comp_type type)
+{
+ return type == MTK_DISP_BLS || type == MTK_DISP_PWM;
+}
+
+bool mtk_ddp_comp_is_internal_comp(enum mtk_ddp_comp_type type)
+{
+ switch (type) {
+ case MTK_DISP_DITHER:
+ case MTK_DISP_OD:
+ case MTK_DISP_POSTMASK:
+ case MTK_DISP_RSZ:
+ case MTK_DISP_UFOE:
+ return true;
+ default:
+ break;
+ };
+
+ return false;
+}
+
static int mtk_ddp_comp_init_internal_comp(struct device *dev, struct device *comp_dev)
{
struct device_node *comp_node = comp_dev->of_node;
@@ -700,26 +721,12 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
if (ret)
return ret;
- if (type == MTK_DISP_AAL ||
- type == MTK_DISP_BLS ||
- type == MTK_DISP_CCORR ||
- type == MTK_DISP_COLOR ||
- type == MTK_DISP_DSC ||
- type == MTK_DISP_GAMMA ||
- type == MTK_DISP_MERGE ||
- type == MTK_DISP_OVL ||
- type == MTK_DISP_OVL_2L ||
- type == MTK_DISP_PWM ||
- type == MTK_DISP_RDMA ||
- type == MTK_DISP_WDMA ||
- type == MTK_DISP_DPI ||
- type == MTK_DISP_DP_INTF ||
- type == MTK_DISP_DSI)
- goto end;
-
- ret = mtk_ddp_comp_init_internal_comp(dev, comp->dev);
- if (ret)
- return ret;
+ /* If there's no external driver for this component, allocate and init now */
+ if (mtk_ddp_comp_is_internal_comp(type) || mtk_ddp_comp_is_backlight_comp(type)) {
+ ret = mtk_ddp_comp_init_internal_comp(dev, comp->dev);
+ if (ret)
+ return ret;
+ }
end:
hash_add(hlist->ddp_list, &comp->lnode, comp->id);
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index 4203eecb2a7b..58a06add1368 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -351,6 +351,7 @@ static inline struct mtk_ddp_comp
return NULL;
}
+bool mtk_ddp_comp_is_internal_comp(enum mtk_ddp_comp_type type);
int mtk_ddp_comp_get_id(struct device_node *node,
enum mtk_ddp_comp_type comp_type);
int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index e956e1966b86..18683aee61ff 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -1166,20 +1166,8 @@ static int mtk_drm_probe(struct platform_device *pdev)
* blocks have separate component platform drivers and initialize their own
* DDP component structure. The others are initialized here.
*/
- if (comp_type == MTK_DISP_AAL ||
- comp_type == MTK_DISP_CCORR ||
- comp_type == MTK_DISP_COLOR ||
- comp_type == MTK_DISP_DSC ||
- comp_type == MTK_DISP_GAMMA ||
- comp_type == MTK_DISP_MERGE ||
- comp_type == MTK_DISP_OVL ||
- comp_type == MTK_DISP_OVL_2L ||
- comp_type == MTK_DISP_OVL_ADAPTOR ||
- comp_type == MTK_DISP_RDMA ||
- comp_type == MTK_DISP_WDMA ||
- comp_type == MTK_DISP_DP_INTF ||
- comp_type == MTK_DISP_DPI ||
- comp_type == MTK_DISP_DSI) {
+ if (!mtk_ddp_comp_is_internal_comp(comp_type) &&
+ !mtk_ovl_adaptor_is_comp_present(node)) {
dev_info(dev, "Adding component match for %pOF\n",
node);
drm_of_component_match_add(dev, &match, component_compare_of,
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 09/42] drm/mediatek: Introduce and use path/comp definition structures
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (7 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 08/42] drm/mediatek: De-duplicate internal component checks AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 10/42] drm/mediatek: Create new mtk_drm_legacy and move deprecated code AngeloGioacchino Del Regno
` (32 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In preparation for a bigger restructuring of Display Controller
HW sub-component handing and path building, introduce two new
mtk_drm_comp_definition and mtk_drm_path definition structures,
meant to replace all of the {main,ext,third}_path pointers and
supportive length variables.
Obviously, also change all of the functions that were previously
using the old path array pointers to use the new structures.
This made possible to loop through the path definition structures,
shortening various code paths and hence improving readability but,
as a nice side effect, now it is possible to easily extend the
maximum number of outputs that are supported by the driver.
Of course, even though that could be done by simply extending the
already present mtk_crtc_path enumeration (which now also indexes
the mtk_drm_path_definition array in mtk_mmsys_driver_data), doing
so will increase the memory footprint for all platforms (even the
ones with a single output): this is currently left unresolved, but
this change makes performing a future optimization to add dynamic
CRTC output indexing(/numbers) way easier than before.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_crtc.c | 21 +-
drivers/gpu/drm/mediatek/mtk_crtc.h | 4 +-
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 51 +--
drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 2 +
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 573 +++++++++++++-----------
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 17 +-
6 files changed, 359 insertions(+), 309 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index 3f4d6ab1bfc2..5e243550d35e 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -1,6 +1,8 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2015 MediaTek Inc.
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
#include <linux/clk.h>
@@ -1025,12 +1027,13 @@ struct device *mtk_crtc_dma_dev_get(struct drm_crtc *crtc)
return mtk_crtc->dma_dev;
}
-int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
- unsigned int path_len, int priv_data_index,
+int mtk_crtc_create(struct drm_device *drm_dev,
+ enum mtk_crtc_path path_sel, int priv_data_index,
const struct mtk_drm_route *conn_routes,
unsigned int num_conn_routes)
{
struct mtk_drm_private *priv = drm_dev->dev_private;
+ const struct mtk_drm_path_definition *output_path;
struct device *dev = drm_dev->dev;
struct mtk_ddp_comp *dma_comp;
struct mtk_crtc *mtk_crtc;
@@ -1042,16 +1045,14 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
struct drm_crtc *tmp;
int crtc_i = 0;
- if (!path)
- return 0;
-
priv = priv->all_drm_private[priv_data_index];
+ output_path = &priv->data->output_paths[path_sel];
drm_for_each_crtc(tmp, drm_dev)
crtc_i++;
- for (i = 0; i < path_len; i++) {
- enum mtk_ddp_comp_id comp_id = path[i];
+ for (i = 0; i < output_path[i].len; i++) {
+ enum mtk_ddp_comp_id comp_id = output_path->comp[i].type;
struct device_node *node;
struct mtk_ddp_comp *comp;
@@ -1079,7 +1080,7 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
return -ENOMEM;
mtk_crtc->mmsys_dev = priv->mmsys_dev;
- mtk_crtc->ddp_comp_nr = path_len;
+ mtk_crtc->ddp_comp_nr = output_path->len;
mtk_crtc->ddp_comp = devm_kcalloc(dev,
mtk_crtc->ddp_comp_nr + (conn_routes ? 1 : 0),
sizeof(*mtk_crtc->ddp_comp),
@@ -1095,7 +1096,7 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
}
for (i = 0, j = 0; i < mtk_crtc->ddp_comp_nr; i++, j++) {
- unsigned int comp_id = path[i];
+ unsigned int comp_id = output_path->comp[i].type;
struct mtk_ddp_comp *comp;
comp = mtk_ddp_comp_find_by_id(&priv->hlist, comp_id);
@@ -1141,7 +1142,7 @@ int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
* In the case of ovl_adaptor sub driver, it needs to use the
* dma_dev_get function to get representative dma dev.
*/
- dma_comp = mtk_ddp_comp_find_by_id(&priv->hlist, path[0]);
+ dma_comp = mtk_ddp_comp_find_by_id(&priv->hlist, output_path->comp[0].type);
if (dma_comp == NULL) {
dev_err(dev, "Could not find appropriate DMA device!\n");
return -EINVAL;
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.h b/drivers/gpu/drm/mediatek/mtk_crtc.h
index a6b8697cca97..5a18b6bfa06b 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.h
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.h
@@ -15,8 +15,8 @@
#define MTK_MIN_BPC 3
void mtk_crtc_commit(struct drm_crtc *crtc);
-int mtk_crtc_create(struct drm_device *drm_dev, const unsigned int *path,
- unsigned int path_len, int priv_data_index,
+int mtk_crtc_create(struct drm_device *drm_dev,
+ enum mtk_crtc_path path_sel, int priv_data_index,
const struct mtk_drm_route *conn_routes,
unsigned int num_conn_routes);
int mtk_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane,
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index f7103e20abe5..b0d38646ca03 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -495,17 +495,13 @@ static bool mtk_ddp_find_comp_dev_in_table(const struct mtk_drm_comp_list *hlist
}
static bool mtk_ddp_comp_find(struct device *dev,
- const unsigned int *path,
- unsigned int path_len,
+ const struct mtk_drm_path_definition *output_path,
const struct mtk_drm_comp_list *hlist)
{
unsigned int i;
- if (path == NULL)
- return false;
-
- for (i = 0U; i < path_len; i++)
- if (mtk_ddp_find_comp_dev_in_table(hlist, path[i], dev))
+ for (i = 0U; i < output_path->len; i++)
+ if (mtk_ddp_find_comp_dev_in_table(hlist, output_path->comp[i].type, dev))
return true;
return false;
@@ -528,21 +524,17 @@ static int mtk_ddp_comp_find_in_route(struct device *dev,
return -ENODEV;
}
-static bool mtk_ddp_path_available(const unsigned int *path,
- unsigned int path_len,
+static bool mtk_ddp_path_available(const struct mtk_drm_path_definition *output_path,
struct device_node **comp_node)
{
unsigned int i;
- if (!path || !path_len)
- return false;
-
- for (i = 0U; i < path_len; i++) {
+ for (i = 0U; i < output_path->len; i++) {
/* OVL_ADAPTOR doesn't have a device node */
- if (path[i] == DDP_COMPONENT_DRM_OVL_ADAPTOR)
+ if (output_path->comp[i].type == DDP_COMPONENT_DRM_OVL_ADAPTOR)
continue;
- if (!comp_node[path[i]])
+ if (!comp_node[output_path->comp[i].type])
return false;
}
@@ -576,31 +568,14 @@ int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev)
priv_n = private->all_drm_private[j];
data = priv_n->data;
- if (mtk_ddp_path_available(data->main_path, data->main_len,
- priv_n->comp_node)) {
- if (mtk_ddp_comp_find(dev, data->main_path,
- data->main_len,
- &priv_n->hlist))
- return BIT(i);
- i++;
- }
-
- if (mtk_ddp_path_available(data->ext_path, data->ext_len,
- priv_n->comp_node)) {
- if (mtk_ddp_comp_find(dev, data->ext_path,
- data->ext_len,
- &priv_n->hlist))
- return BIT(i);
- i++;
- }
+ for (i = 0; i < MAX_CRTC; i++) {
+ if (!data->output_paths[i].len)
+ continue;
- if (mtk_ddp_path_available(data->third_path, data->third_len,
- priv_n->comp_node)) {
- if (mtk_ddp_comp_find(dev, data->third_path,
- data->third_len,
- &priv_n->hlist))
+ ret = mtk_ddp_comp_find(dev, &data->output_paths[i],
+ &priv_n->hlist);
+ if (ret)
return BIT(i);
- i++;
}
}
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index 58a06add1368..76a2b649516d 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -15,6 +15,8 @@
#include <drm/drm_modes.h>
+#define MTK_DISP_CONTROLLER_MAX_COMP_PER_PATH 24
+
struct device;
struct device_node;
struct drm_crtc;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 18683aee61ff..09c7d038348d 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -2,6 +2,10 @@
/*
* Copyright (c) 2015 MediaTek Inc.
* Author: YT SHEN <yt.shen@mediatek.com>
+ *
+ * Major rework
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
#include <linux/aperture.h>
@@ -59,239 +63,326 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = {
.atomic_commit = drm_atomic_helper_commit,
};
-static const unsigned int mt2701_mtk_ddp_main[] = {
- DDP_COMPONENT_OVL0,
- DDP_COMPONENT_RDMA0,
- DDP_COMPONENT_COLOR0,
- DDP_COMPONENT_BLS,
- DDP_COMPONENT_DSI0,
+static const struct mtk_drm_comp_definition mt2701_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_BLS },
+ { DDP_COMPONENT_DSI0 },
};
-static const unsigned int mt2701_mtk_ddp_ext[] = {
- DDP_COMPONENT_RDMA1,
- DDP_COMPONENT_DPI0,
+static const struct mtk_drm_comp_definition mt2701_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_RDMA1 },
+ { DDP_COMPONENT_DPI0 },
};
-static const unsigned int mt7623_mtk_ddp_main[] = {
- DDP_COMPONENT_OVL0,
- DDP_COMPONENT_RDMA0,
- DDP_COMPONENT_COLOR0,
- DDP_COMPONENT_BLS,
- DDP_COMPONENT_DPI0,
+struct mtk_drm_path_definition mt2701_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt2701_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt2701_mtk_ddp_main),
+ },
+ [CRTC_EXT] = {
+ .comp = mt2701_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt2701_mtk_ddp_ext),
+ },
};
-static const unsigned int mt7623_mtk_ddp_ext[] = {
- DDP_COMPONENT_RDMA1,
- DDP_COMPONENT_DSI0,
+static const struct mtk_drm_comp_definition mt2712_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_OD0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_DPI0 },
+ { DDP_COMPONENT_PWM0 },
};
-static const unsigned int mt2712_mtk_ddp_main[] = {
- DDP_COMPONENT_OVL0,
- DDP_COMPONENT_COLOR0,
- DDP_COMPONENT_AAL0,
- DDP_COMPONENT_OD0,
- DDP_COMPONENT_RDMA0,
- DDP_COMPONENT_DPI0,
- DDP_COMPONENT_PWM0,
+static const struct mtk_drm_comp_definition mt2712_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_OVL1 },
+ { DDP_COMPONENT_COLOR1 },
+ { DDP_COMPONENT_AAL1 },
+ { DDP_COMPONENT_OD1 },
+ { DDP_COMPONENT_RDMA1 },
+ { DDP_COMPONENT_DPI1 },
+ { DDP_COMPONENT_PWM1 },
};
-static const unsigned int mt2712_mtk_ddp_ext[] = {
- DDP_COMPONENT_OVL1,
- DDP_COMPONENT_COLOR1,
- DDP_COMPONENT_AAL1,
- DDP_COMPONENT_OD1,
- DDP_COMPONENT_RDMA1,
- DDP_COMPONENT_DPI1,
- DDP_COMPONENT_PWM1,
+static const struct mtk_drm_comp_definition mt2712_mtk_ddp_third[] = {
+ { DDP_COMPONENT_RDMA2 },
+ { DDP_COMPONENT_DSI3 },
+ { DDP_COMPONENT_PWM2 },
};
-static const unsigned int mt2712_mtk_ddp_third[] = {
- DDP_COMPONENT_RDMA2,
- DDP_COMPONENT_DSI3,
- DDP_COMPONENT_PWM2,
+struct mtk_drm_path_definition mt2712_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt2712_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt2712_mtk_ddp_main),
+ },
+ [CRTC_EXT] = {
+ .comp = mt2712_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt2712_mtk_ddp_ext),
+ },
+ [CRTC_THIRD] = {
+ .comp = mt2712_mtk_ddp_third,
+ .len = ARRAY_SIZE(mt2712_mtk_ddp_third),
+ },
};
-static unsigned int mt8167_mtk_ddp_main[] = {
- DDP_COMPONENT_OVL0,
- DDP_COMPONENT_COLOR0,
- DDP_COMPONENT_CCORR,
- DDP_COMPONENT_AAL0,
- DDP_COMPONENT_GAMMA,
- DDP_COMPONENT_DITHER0,
- DDP_COMPONENT_RDMA0,
- DDP_COMPONENT_DSI0,
+static const struct mtk_drm_comp_definition mt7623_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_BLS },
+ { DDP_COMPONENT_DPI0 },
};
-static const unsigned int mt8173_mtk_ddp_main[] = {
- DDP_COMPONENT_OVL0,
- DDP_COMPONENT_COLOR0,
- DDP_COMPONENT_AAL0,
- DDP_COMPONENT_OD0,
- DDP_COMPONENT_RDMA0,
- DDP_COMPONENT_UFOE,
- DDP_COMPONENT_DSI0,
- DDP_COMPONENT_PWM0,
+static const struct mtk_drm_comp_definition mt7623_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_RDMA1 },
+ { DDP_COMPONENT_DSI0 },
};
-static const unsigned int mt8173_mtk_ddp_ext[] = {
- DDP_COMPONENT_OVL1,
- DDP_COMPONENT_COLOR1,
- DDP_COMPONENT_GAMMA,
- DDP_COMPONENT_RDMA1,
- DDP_COMPONENT_DPI0,
+struct mtk_drm_path_definition mt7623_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt7623_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt7623_mtk_ddp_main),
+ },
+ [CRTC_EXT] = {
+ .comp = mt7623_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt7623_mtk_ddp_ext),
+ },
};
-static const unsigned int mt8183_mtk_ddp_main[] = {
- DDP_COMPONENT_OVL0,
- DDP_COMPONENT_OVL_2L0,
- DDP_COMPONENT_RDMA0,
- DDP_COMPONENT_COLOR0,
- DDP_COMPONENT_CCORR,
- DDP_COMPONENT_AAL0,
- DDP_COMPONENT_GAMMA,
- DDP_COMPONENT_DITHER0,
- DDP_COMPONENT_DSI0,
+static const struct mtk_drm_comp_definition mt8167_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_CCORR },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_GAMMA },
+ { DDP_COMPONENT_DITHER0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_DSI0 },
};
-static const unsigned int mt8183_mtk_ddp_ext[] = {
- DDP_COMPONENT_OVL_2L1,
- DDP_COMPONENT_RDMA1,
- DDP_COMPONENT_DPI0,
+struct mtk_drm_path_definition mt8167_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt8167_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt8167_mtk_ddp_main),
+ },
};
-static const unsigned int mt8186_mtk_ddp_main[] = {
- DDP_COMPONENT_OVL0,
- DDP_COMPONENT_RDMA0,
- DDP_COMPONENT_COLOR0,
- DDP_COMPONENT_CCORR,
- DDP_COMPONENT_AAL0,
- DDP_COMPONENT_GAMMA,
- DDP_COMPONENT_POSTMASK0,
- DDP_COMPONENT_DITHER0,
- DDP_COMPONENT_DSI0,
+static const struct mtk_drm_comp_definition mt8173_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_OD0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_UFOE },
+ { DDP_COMPONENT_DSI0 },
+ { DDP_COMPONENT_PWM0 },
};
-static const unsigned int mt8186_mtk_ddp_ext[] = {
- DDP_COMPONENT_OVL_2L0,
- DDP_COMPONENT_RDMA1,
- DDP_COMPONENT_DPI0,
+static const struct mtk_drm_comp_definition mt8173_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_OVL1 },
+ { DDP_COMPONENT_COLOR1 },
+ { DDP_COMPONENT_GAMMA },
+ { DDP_COMPONENT_RDMA1 },
+ { DDP_COMPONENT_DPI0 },
};
-static const unsigned int mt8188_mtk_ddp_main[] = {
- DDP_COMPONENT_OVL0,
- DDP_COMPONENT_RDMA0,
- DDP_COMPONENT_COLOR0,
- DDP_COMPONENT_CCORR,
- DDP_COMPONENT_AAL0,
- DDP_COMPONENT_GAMMA,
- DDP_COMPONENT_POSTMASK0,
- DDP_COMPONENT_DITHER0,
+struct mtk_drm_path_definition mt8173_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt8173_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt8173_mtk_ddp_main),
+ },
+ [CRTC_EXT] = {
+ .comp = mt8173_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt8173_mtk_ddp_ext),
+ },
};
-static const struct mtk_drm_route mt8188_mtk_ddp_main_routes[] = {
- {0, DDP_COMPONENT_DP_INTF0},
- {0, DDP_COMPONENT_DSI0},
+static const struct mtk_drm_comp_definition mt8183_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_OVL_2L0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_CCORR },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_GAMMA },
+ { DDP_COMPONENT_DITHER0 },
+ { DDP_COMPONENT_DSI0 },
+};
+
+static const struct mtk_drm_comp_definition mt8183_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_OVL_2L1 },
+ { DDP_COMPONENT_RDMA1 },
+ { DDP_COMPONENT_DPI0 },
+};
+
+struct mtk_drm_path_definition mt8183_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt8183_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt8183_mtk_ddp_main),
+ },
+ [CRTC_EXT] = {
+ .comp = mt8183_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt8183_mtk_ddp_ext),
+ },
};
-static const unsigned int mt8192_mtk_ddp_main[] = {
- DDP_COMPONENT_OVL0,
- DDP_COMPONENT_OVL_2L0,
- DDP_COMPONENT_RDMA0,
- DDP_COMPONENT_COLOR0,
- DDP_COMPONENT_CCORR,
- DDP_COMPONENT_AAL0,
- DDP_COMPONENT_GAMMA,
- DDP_COMPONENT_POSTMASK0,
- DDP_COMPONENT_DITHER0,
- DDP_COMPONENT_DSI0,
+static const struct mtk_drm_comp_definition mt8186_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_CCORR },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_GAMMA },
+ { DDP_COMPONENT_POSTMASK0 },
+ { DDP_COMPONENT_DITHER0 },
+ { DDP_COMPONENT_DSI0 },
};
-static const unsigned int mt8192_mtk_ddp_ext[] = {
- DDP_COMPONENT_OVL_2L2,
- DDP_COMPONENT_RDMA4,
- DDP_COMPONENT_DPI0,
+static const struct mtk_drm_comp_definition mt8186_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_OVL_2L0 },
+ { DDP_COMPONENT_RDMA1 },
+ { DDP_COMPONENT_DPI0 },
};
-static const unsigned int mt8195_mtk_ddp_main[] = {
- DDP_COMPONENT_OVL0,
- DDP_COMPONENT_RDMA0,
- DDP_COMPONENT_COLOR0,
- DDP_COMPONENT_CCORR,
- DDP_COMPONENT_AAL0,
- DDP_COMPONENT_GAMMA,
- DDP_COMPONENT_DITHER0,
- DDP_COMPONENT_DSC0,
- DDP_COMPONENT_MERGE0,
- DDP_COMPONENT_DP_INTF0,
+struct mtk_drm_path_definition mt8186_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt8186_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt8186_mtk_ddp_main),
+ },
+ [CRTC_EXT] = {
+ .comp = mt8186_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt8186_mtk_ddp_ext),
+ },
};
-static const unsigned int mt8195_mtk_ddp_ext[] = {
- DDP_COMPONENT_DRM_OVL_ADAPTOR,
- DDP_COMPONENT_MERGE5,
- DDP_COMPONENT_DP_INTF1,
+static const struct mtk_drm_comp_definition mt8188_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_CCORR },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_GAMMA },
+ { DDP_COMPONENT_POSTMASK0 },
+ { DDP_COMPONENT_DITHER0 },
+};
+
+struct mtk_drm_path_definition mt8188_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt8188_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt8188_mtk_ddp_main),
+ },
+};
+
+static const struct mtk_drm_comp_definition mt8192_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_OVL_2L0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_CCORR },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_GAMMA },
+ { DDP_COMPONENT_POSTMASK0 },
+ { DDP_COMPONENT_DITHER0 },
+ { DDP_COMPONENT_DSI0 },
+};
+
+static const struct mtk_drm_comp_definition mt8192_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_OVL_2L2 },
+ { DDP_COMPONENT_RDMA4 },
+ { DDP_COMPONENT_DPI0 },
+};
+
+struct mtk_drm_path_definition mt8192_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt8192_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt8192_mtk_ddp_main),
+ },
+ [CRTC_EXT] = {
+ .comp = mt8192_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt8192_mtk_ddp_ext),
+ },
+};
+
+static const struct mtk_drm_comp_definition mt8195_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_CCORR },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_GAMMA },
+ { DDP_COMPONENT_DITHER0 },
+ { DDP_COMPONENT_DSC0 },
+ { DDP_COMPONENT_MERGE0 },
+ { DDP_COMPONENT_DP_INTF0 },
+};
+
+static const struct mtk_drm_comp_definition mt8195_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_DRM_OVL_ADAPTOR },
+ { DDP_COMPONENT_MERGE5 },
+ { DDP_COMPONENT_DP_INTF1 },
+};
+
+struct mtk_drm_path_definition mt8195_vdo0_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt8195_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt8195_mtk_ddp_main),
+ },
+};
+
+struct mtk_drm_path_definition mt8195_vdo1_legacy_paths[MAX_CRTC] = {
+ [CRTC_EXT] = {
+ .comp = mt8195_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt8195_mtk_ddp_ext),
+ },
};
static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
- .main_path = mt2701_mtk_ddp_main,
- .main_len = ARRAY_SIZE(mt2701_mtk_ddp_main),
- .ext_path = mt2701_mtk_ddp_ext,
- .ext_len = ARRAY_SIZE(mt2701_mtk_ddp_ext),
+ .output_paths = mt2701_legacy_paths,
.shadow_register = true,
.mmsys_dev_num = 1,
};
-static const struct mtk_mmsys_driver_data mt7623_mmsys_driver_data = {
- .main_path = mt7623_mtk_ddp_main,
- .main_len = ARRAY_SIZE(mt7623_mtk_ddp_main),
- .ext_path = mt7623_mtk_ddp_ext,
- .ext_len = ARRAY_SIZE(mt7623_mtk_ddp_ext),
- .shadow_register = true,
+static const struct mtk_mmsys_driver_data mt2712_mmsys_driver_data = {
+ .output_paths = mt2712_legacy_paths,
.mmsys_dev_num = 1,
};
-static const struct mtk_mmsys_driver_data mt2712_mmsys_driver_data = {
- .main_path = mt2712_mtk_ddp_main,
- .main_len = ARRAY_SIZE(mt2712_mtk_ddp_main),
- .ext_path = mt2712_mtk_ddp_ext,
- .ext_len = ARRAY_SIZE(mt2712_mtk_ddp_ext),
- .third_path = mt2712_mtk_ddp_third,
- .third_len = ARRAY_SIZE(mt2712_mtk_ddp_third),
+static const struct mtk_mmsys_driver_data mt7623_mmsys_driver_data = {
+ .output_paths = mt7623_legacy_paths,
+ .shadow_register = true,
.mmsys_dev_num = 1,
};
static const struct mtk_mmsys_driver_data mt8167_mmsys_driver_data = {
- .main_path = mt8167_mtk_ddp_main,
- .main_len = ARRAY_SIZE(mt8167_mtk_ddp_main),
+ .output_paths = mt8167_legacy_paths,
.mmsys_dev_num = 1,
};
static const struct mtk_mmsys_driver_data mt8173_mmsys_driver_data = {
- .main_path = mt8173_mtk_ddp_main,
- .main_len = ARRAY_SIZE(mt8173_mtk_ddp_main),
- .ext_path = mt8173_mtk_ddp_ext,
- .ext_len = ARRAY_SIZE(mt8173_mtk_ddp_ext),
+ .output_paths = mt8173_legacy_paths,
.mmsys_dev_num = 1,
};
static const struct mtk_mmsys_driver_data mt8183_mmsys_driver_data = {
- .main_path = mt8183_mtk_ddp_main,
- .main_len = ARRAY_SIZE(mt8183_mtk_ddp_main),
- .ext_path = mt8183_mtk_ddp_ext,
- .ext_len = ARRAY_SIZE(mt8183_mtk_ddp_ext),
+ .output_paths = mt8183_legacy_paths,
.mmsys_dev_num = 1,
};
static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = {
- .main_path = mt8186_mtk_ddp_main,
- .main_len = ARRAY_SIZE(mt8186_mtk_ddp_main),
- .ext_path = mt8186_mtk_ddp_ext,
- .ext_len = ARRAY_SIZE(mt8186_mtk_ddp_ext),
+ .output_paths = mt8186_legacy_paths,
.mmsys_dev_num = 1,
};
+static const struct mtk_drm_route mt8188_mtk_ddp_main_routes[] = {
+ { 0, DDP_COMPONENT_DP_INTF0 },
+ { 0, DDP_COMPONENT_DSI0 },
+};
+
static const struct mtk_mmsys_driver_data mt8188_vdosys0_driver_data = {
- .main_path = mt8188_mtk_ddp_main,
- .main_len = ARRAY_SIZE(mt8188_mtk_ddp_main),
+ .output_paths = mt8188_legacy_paths,
.conn_routes = mt8188_mtk_ddp_main_routes,
.num_conn_routes = ARRAY_SIZE(mt8188_mtk_ddp_main_routes),
.mmsys_dev_num = 2,
@@ -301,16 +392,12 @@ static const struct mtk_mmsys_driver_data mt8188_vdosys0_driver_data = {
};
static const struct mtk_mmsys_driver_data mt8192_mmsys_driver_data = {
- .main_path = mt8192_mtk_ddp_main,
- .main_len = ARRAY_SIZE(mt8192_mtk_ddp_main),
- .ext_path = mt8192_mtk_ddp_ext,
- .ext_len = ARRAY_SIZE(mt8192_mtk_ddp_ext),
+ .output_paths = mt8192_legacy_paths,
.mmsys_dev_num = 1,
};
static const struct mtk_mmsys_driver_data mt8195_vdosys0_driver_data = {
- .main_path = mt8195_mtk_ddp_main,
- .main_len = ARRAY_SIZE(mt8195_mtk_ddp_main),
+ .output_paths = mt8195_vdo0_legacy_paths,
.mmsys_dev_num = 2,
.max_width = 8191,
.min_width = 1,
@@ -318,8 +405,7 @@ static const struct mtk_mmsys_driver_data mt8195_vdosys0_driver_data = {
};
static const struct mtk_mmsys_driver_data mt8195_vdosys1_driver_data = {
- .ext_path = mt8195_mtk_ddp_ext,
- .ext_len = ARRAY_SIZE(mt8195_mtk_ddp_ext),
+ .output_paths = mt8195_vdo1_legacy_paths,
.mmsys_id = 1,
.mmsys_dev_num = 2,
.max_width = 8191,
@@ -384,6 +470,7 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
int i, j;
for_each_child_of_node(phandle->parent, node) {
+ const struct mtk_drm_path_definition *output_path;
struct platform_device *pdev;
of_id = of_match_node(mtk_drm_of_ids, node);
@@ -404,12 +491,14 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
if (!temp_drm_priv)
continue;
- if (temp_drm_priv->data->main_len)
- all_drm_priv[CRTC_MAIN] = temp_drm_priv;
- else if (temp_drm_priv->data->ext_len)
- all_drm_priv[CRTC_EXT] = temp_drm_priv;
- else if (temp_drm_priv->data->third_len)
- all_drm_priv[CRTC_THIRD] = temp_drm_priv;
+ for (i = 0; i < MAX_CRTC; i++) {
+ output_path = &temp_drm_priv->data->output_paths[i];
+
+ if (!output_path->len)
+ continue;
+
+ all_drm_priv[i] = temp_drm_priv;
+ }
if (temp_drm_priv->mtk_drm_bound)
cnt++;
@@ -433,27 +522,23 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
static bool mtk_drm_find_mmsys_comp(struct mtk_drm_private *private, int comp_id)
{
- const struct mtk_mmsys_driver_data *drv_data = private->data;
- int i;
+ const struct mtk_mmsys_driver_data *data = private->data;
+ int i, j;
- if (drv_data->main_path)
- for (i = 0; i < drv_data->main_len; i++)
- if (drv_data->main_path[i] == comp_id)
- return true;
+ for (i = 0; i < MAX_CRTC; i++) {
+ const struct mtk_drm_path_definition *output_path = &data->output_paths[i];
- if (drv_data->ext_path)
- for (i = 0; i < drv_data->ext_len; i++)
- if (drv_data->ext_path[i] == comp_id)
- return true;
+ for (j = 0; j < output_path->len; j++) {
+ if (output_path->comp[j].type != comp_id)
+ continue;
- if (drv_data->third_path)
- for (i = 0; i < drv_data->third_len; i++)
- if (drv_data->third_path[i] == comp_id)
- return true;
+ return true;
+ }
+ }
- if (drv_data->num_conn_routes)
- for (i = 0; i < drv_data->num_conn_routes; i++)
- if (drv_data->conn_routes[i].route_ddp == comp_id)
+ if (data->num_conn_routes)
+ for (i = 0; i < data->num_conn_routes; i++)
+ if (data->conn_routes[i].route_ddp == comp_id)
return true;
return false;
@@ -525,30 +610,15 @@ static int mtk_drm_kms_init(struct drm_device *drm)
if (priv_n->data->min_height)
drm->mode_config.min_height = priv_n->data->min_height;
- if (i == CRTC_MAIN && priv_n->data->main_len) {
- ret = mtk_crtc_create(drm, priv_n->data->main_path,
- priv_n->data->main_len, j,
- priv_n->data->conn_routes,
- priv_n->data->num_conn_routes);
- if (ret)
- goto err_component_unbind;
-
+ if (!priv_n->data->output_paths[i].len)
continue;
- } else if (i == CRTC_EXT && priv_n->data->ext_len) {
- ret = mtk_crtc_create(drm, priv_n->data->ext_path,
- priv_n->data->ext_len, j, NULL, 0);
- if (ret)
- goto err_component_unbind;
- continue;
- } else if (i == CRTC_THIRD && priv_n->data->third_len) {
- ret = mtk_crtc_create(drm, priv_n->data->third_path,
- priv_n->data->third_len, j, NULL, 0);
- if (ret)
- goto err_component_unbind;
+ ret = mtk_crtc_create(drm, i, j,
+ priv_n->data->conn_routes,
+ priv_n->data->num_conn_routes);
- continue;
- }
+ if (ret)
+ goto err_component_unbind;
}
}
@@ -847,7 +917,8 @@ static int mtk_drm_of_get_ddp_comp_type(struct device_node *node, enum mtk_ddp_c
static int mtk_drm_of_get_ddp_ep_cid(struct device_node *node,
int output_port, enum mtk_crtc_path crtc_path,
- struct device_node **next, unsigned int *cid)
+ struct device_node **next,
+ struct mtk_drm_comp_definition *comp_def)
{
struct device_node *ep_dev_node, *ep_out;
enum mtk_ddp_comp_type comp_type;
@@ -875,7 +946,7 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device_node *node,
ret = mtk_drm_of_get_ddp_comp_type(ep_dev_node, &comp_type);
if (ret) {
if (mtk_ovl_adaptor_is_comp_present(ep_dev_node)) {
- *cid = (unsigned int)DDP_COMPONENT_DRM_OVL_ADAPTOR;
+ comp_def->type = DDP_COMPONENT_DRM_OVL_ADAPTOR;
return 0;
}
return ret;
@@ -886,7 +957,7 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device_node *node,
return ret;
/* All ok! Pass the Component ID to the caller. */
- *cid = (unsigned int)ret;
+ comp_def->type = ret;
return 0;
}
@@ -895,8 +966,7 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device_node *node,
* mtk_drm_of_ddp_path_build_one - Build a Display HW Pipeline for a CRTC Path
* @dev: The mediatek-drm device
* @cpath: CRTC Path relative to a VDO or MMSYS
- * @out_path: Pointer to an array that will contain the new pipeline
- * @out_path_len: Number of entries in the pipeline array
+ * @out_path: Pointer to the structure that will contain the new pipeline
*
* MediaTek SoCs can use different DDP hardware pipelines (or paths) depending
* on the board-specific desired display configuration; this function walks
@@ -910,20 +980,19 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device_node *node,
* * %-ENOMEM - Failure to allocate pipeline array to pass to the caller
*/
static int mtk_drm_of_ddp_path_build_one(struct device *dev, enum mtk_crtc_path cpath,
- const unsigned int **out_path,
- unsigned int *out_path_len)
+ struct mtk_drm_path_definition *out_path)
{
+ struct mtk_drm_comp_definition temp_path[MTK_DISP_CONTROLLER_MAX_COMP_PER_PATH];
struct device_node *next = NULL, *prev, *vdo = dev->parent->of_node;
- unsigned int temp_path[DDP_COMPONENT_DRM_ID_MAX] = { 0 };
- unsigned int *final_ddp_path;
- unsigned short int idx = 0;
bool ovl_adaptor_comp_added = false;
+ unsigned short int idx = 0;
+ size_t final_comp_sz;
int ret;
/* Get the first entry for the temp_path array */
ret = mtk_drm_of_get_ddp_ep_cid(vdo, 0, cpath, &next, &temp_path[idx]);
if (ret) {
- if (next && temp_path[idx] == DDP_COMPONENT_DRM_OVL_ADAPTOR) {
+ if (next && temp_path[idx].type == DDP_COMPONENT_DRM_OVL_ADAPTOR) {
dev_dbg(dev, "Adding OVL Adaptor for %pOF\n", next);
ovl_adaptor_comp_added = true;
} else {
@@ -957,7 +1026,7 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, enum mtk_crtc_path
* to probe that component master driver of which only one instance
* is needed and possible.
*/
- if (temp_path[idx] == DDP_COMPONENT_DRM_OVL_ADAPTOR) {
+ if (temp_path[idx].type == DDP_COMPONENT_DRM_OVL_ADAPTOR) {
if (!ovl_adaptor_comp_added)
ovl_adaptor_comp_added = true;
else
@@ -973,7 +1042,7 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, enum mtk_crtc_path
return ret;
/* If the last entry is not a final display output, the configuration is wrong */
- switch (temp_path[idx - 1]) {
+ switch (temp_path[idx - 1].type) {
case DDP_COMPONENT_DP_INTF0:
case DDP_COMPONENT_DP_INTF1:
case DDP_COMPONENT_DPI0:
@@ -985,30 +1054,31 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, enum mtk_crtc_path
break;
default:
dev_err(dev, "Invalid display hw pipeline. Last component: %d (ret=%d)\n",
- temp_path[idx - 1], ret);
+ temp_path[idx - 1].type, ret);
return -EINVAL;
}
- final_ddp_path = devm_kmemdup(dev, temp_path, idx * sizeof(temp_path[0]), GFP_KERNEL);
- if (!final_ddp_path)
+ /* Pipeline built! */
+ out_path->len = idx;
+ final_comp_sz = out_path->len * sizeof(out_path->comp[0]);
+ out_path->comp = devm_kmemdup(dev, temp_path, final_comp_sz, GFP_KERNEL);
+ if (!out_path->comp)
return -ENOMEM;
dev_dbg(dev, "Display HW Pipeline built with %d components.\n", idx);
- /* Pipeline built! */
- *out_path = final_ddp_path;
- *out_path_len = idx;
-
return 0;
}
static int mtk_drm_of_ddp_path_build(struct device *dev, struct device_node *node,
struct mtk_mmsys_driver_data *data)
{
+ struct mtk_drm_path_definition *output_paths;
struct device_node *ep_node;
struct of_endpoint of_ep;
bool output_present[MAX_CRTC] = { false };
- int ret;
+ u8 num_outputs_present = 0;
+ int i, ret;
for_each_endpoint_of_node(node, ep_node) {
ret = of_graph_parse_endpoint(ep_node, &of_ep);
@@ -1024,33 +1094,30 @@ static int mtk_drm_of_ddp_path_build(struct device *dev, struct device_node *nod
}
output_present[of_ep.id] = true;
+ num_outputs_present++;
}
+ if (ret == 0 && num_outputs_present == 0)
+ ret = dev_err_probe(dev, -ENXIO, "No display outputs found.\n");
if (ret) {
of_node_put(ep_node);
return ret;
}
- if (output_present[CRTC_MAIN]) {
- ret = mtk_drm_of_ddp_path_build_one(dev, CRTC_MAIN,
- &data->main_path, &data->main_len);
- if (ret && ret != -ENODEV)
- return ret;
- }
+ /* This can be optimized after making CRTC numbers dynamic */
+ output_paths = devm_kcalloc(dev, MAX_CRTC, sizeof(*output_paths), GFP_KERNEL);
+ if (!output_paths)
+ return -ENOMEM;
- if (output_present[CRTC_EXT]) {
- ret = mtk_drm_of_ddp_path_build_one(dev, CRTC_EXT,
- &data->ext_path, &data->ext_len);
- if (ret && ret != -ENODEV)
- return ret;
- }
+ for (i = 0; i < MAX_CRTC; i++) {
+ if (!output_present[i])
+ continue;
- if (output_present[CRTC_THIRD]) {
- ret = mtk_drm_of_ddp_path_build_one(dev, CRTC_THIRD,
- &data->third_path, &data->third_len);
+ ret = mtk_drm_of_ddp_path_build_one(dev, i, &output_paths[i]);
if (ret && ret != -ENODEV)
return ret;
}
+ data->output_paths = output_paths;
return 0;
}
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index a171126d580e..7dc208669c2e 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -33,13 +33,18 @@ struct mtk_drm_route {
const unsigned int route_ddp;
};
+struct mtk_drm_comp_definition {
+ enum mtk_ddp_comp_id type;
+};
+
+struct mtk_drm_path_definition {
+ const struct mtk_drm_comp_definition *comp;
+ u8 len;
+};
+
struct mtk_mmsys_driver_data {
- const unsigned int *main_path;
- unsigned int main_len;
- const unsigned int *ext_path;
- unsigned int ext_len;
- const unsigned int *third_path;
- unsigned int third_len;
+ struct mtk_drm_path_definition *output_paths;
+ u8 num_output_paths;
const struct mtk_drm_route *conn_routes;
unsigned int num_conn_routes;
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 10/42] drm/mediatek: Create new mtk_drm_legacy and move deprecated code
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (8 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 09/42] drm/mediatek: Introduce and use path/comp definition structures AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 11/42] drm/mediatek: Add support for MuteX trigger-sources parsing AngeloGioacchino Del Regno
` (31 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Since mediatek-drm shifted from hardcoded per-SoC-per-Board path
definitions for the display controller to devicetree graph based
path building, the first ones are used less and less, and those
are also decreasing ease of code browsability (hence, readability)
in the mtk_drm_drv.c file.
This means that those big arrays are almost irrelevant now (for
modern code, of course).
Seen the need to keep compatibility with older devicetrees, then,
move all of the deprecated arrays in new mtk_drm_legacy files and
add a big warning to those, explaining that no new SoCs must be
implemented like so, and making it clear that it shall exclusively
contain legacy and deprecated code.
Also, especially with the restructuring work that is currently in
progress (with MuteX finally getting trigger-sources support and
other changes that will follow), it is expected to see more code
being moved in the mtk_drm_legacy territory.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/Makefile | 1 +
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 277 +------------------
drivers/gpu/drm/mediatek/mtk_drm_legacy.c | 309 ++++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_drm_legacy.h | 28 ++
4 files changed, 339 insertions(+), 276 deletions(-)
create mode 100644 drivers/gpu/drm/mediatek/mtk_drm_legacy.c
create mode 100644 drivers/gpu/drm/mediatek/mtk_drm_legacy.h
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index 8079962597c8..f40ad5565716 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -13,6 +13,7 @@ mediatek-drm-y := mtk_crtc.o \
mtk_disp_rdma.o \
mtk_disp_wdma.o \
mtk_drm_drv.o \
+ mtk_drm_legacy.o \
mtk_dsi.o \
mtk_dpi.o \
mtk_ethdr.o \
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 09c7d038348d..1396cbc65627 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -35,6 +35,7 @@
#include "mtk_ddp_comp.h"
#include "mtk_disp_drv.h"
#include "mtk_drm_drv.h"
+#include "mtk_drm_legacy.h"
#define DRIVER_NAME "mediatek"
#define DRIVER_DESC "Mediatek SoC DRM"
@@ -63,282 +64,6 @@ static const struct drm_mode_config_funcs mtk_drm_mode_config_funcs = {
.atomic_commit = drm_atomic_helper_commit,
};
-static const struct mtk_drm_comp_definition mt2701_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_BLS },
- { DDP_COMPONENT_DSI0 },
-};
-
-static const struct mtk_drm_comp_definition mt2701_mtk_ddp_ext[] = {
- { DDP_COMPONENT_RDMA1 },
- { DDP_COMPONENT_DPI0 },
-};
-
-struct mtk_drm_path_definition mt2701_legacy_paths[MAX_CRTC] = {
- [CRTC_MAIN] = {
- .comp = mt2701_mtk_ddp_main,
- .len = ARRAY_SIZE(mt2701_mtk_ddp_main),
- },
- [CRTC_EXT] = {
- .comp = mt2701_mtk_ddp_ext,
- .len = ARRAY_SIZE(mt2701_mtk_ddp_ext),
- },
-};
-
-static const struct mtk_drm_comp_definition mt2712_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_OD0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_DPI0 },
- { DDP_COMPONENT_PWM0 },
-};
-
-static const struct mtk_drm_comp_definition mt2712_mtk_ddp_ext[] = {
- { DDP_COMPONENT_OVL1 },
- { DDP_COMPONENT_COLOR1 },
- { DDP_COMPONENT_AAL1 },
- { DDP_COMPONENT_OD1 },
- { DDP_COMPONENT_RDMA1 },
- { DDP_COMPONENT_DPI1 },
- { DDP_COMPONENT_PWM1 },
-};
-
-static const struct mtk_drm_comp_definition mt2712_mtk_ddp_third[] = {
- { DDP_COMPONENT_RDMA2 },
- { DDP_COMPONENT_DSI3 },
- { DDP_COMPONENT_PWM2 },
-};
-
-struct mtk_drm_path_definition mt2712_legacy_paths[MAX_CRTC] = {
- [CRTC_MAIN] = {
- .comp = mt2712_mtk_ddp_main,
- .len = ARRAY_SIZE(mt2712_mtk_ddp_main),
- },
- [CRTC_EXT] = {
- .comp = mt2712_mtk_ddp_ext,
- .len = ARRAY_SIZE(mt2712_mtk_ddp_ext),
- },
- [CRTC_THIRD] = {
- .comp = mt2712_mtk_ddp_third,
- .len = ARRAY_SIZE(mt2712_mtk_ddp_third),
- },
-};
-
-static const struct mtk_drm_comp_definition mt7623_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_BLS },
- { DDP_COMPONENT_DPI0 },
-};
-
-static const struct mtk_drm_comp_definition mt7623_mtk_ddp_ext[] = {
- { DDP_COMPONENT_RDMA1 },
- { DDP_COMPONENT_DSI0 },
-};
-
-struct mtk_drm_path_definition mt7623_legacy_paths[MAX_CRTC] = {
- [CRTC_MAIN] = {
- .comp = mt7623_mtk_ddp_main,
- .len = ARRAY_SIZE(mt7623_mtk_ddp_main),
- },
- [CRTC_EXT] = {
- .comp = mt7623_mtk_ddp_ext,
- .len = ARRAY_SIZE(mt7623_mtk_ddp_ext),
- },
-};
-
-static const struct mtk_drm_comp_definition mt8167_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_CCORR },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_GAMMA },
- { DDP_COMPONENT_DITHER0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_DSI0 },
-};
-
-struct mtk_drm_path_definition mt8167_legacy_paths[MAX_CRTC] = {
- [CRTC_MAIN] = {
- .comp = mt8167_mtk_ddp_main,
- .len = ARRAY_SIZE(mt8167_mtk_ddp_main),
- },
-};
-
-static const struct mtk_drm_comp_definition mt8173_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_OD0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_UFOE },
- { DDP_COMPONENT_DSI0 },
- { DDP_COMPONENT_PWM0 },
-};
-
-static const struct mtk_drm_comp_definition mt8173_mtk_ddp_ext[] = {
- { DDP_COMPONENT_OVL1 },
- { DDP_COMPONENT_COLOR1 },
- { DDP_COMPONENT_GAMMA },
- { DDP_COMPONENT_RDMA1 },
- { DDP_COMPONENT_DPI0 },
-};
-
-struct mtk_drm_path_definition mt8173_legacy_paths[MAX_CRTC] = {
- [CRTC_MAIN] = {
- .comp = mt8173_mtk_ddp_main,
- .len = ARRAY_SIZE(mt8173_mtk_ddp_main),
- },
- [CRTC_EXT] = {
- .comp = mt8173_mtk_ddp_ext,
- .len = ARRAY_SIZE(mt8173_mtk_ddp_ext),
- },
-};
-
-static const struct mtk_drm_comp_definition mt8183_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_OVL_2L0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_CCORR },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_GAMMA },
- { DDP_COMPONENT_DITHER0 },
- { DDP_COMPONENT_DSI0 },
-};
-
-static const struct mtk_drm_comp_definition mt8183_mtk_ddp_ext[] = {
- { DDP_COMPONENT_OVL_2L1 },
- { DDP_COMPONENT_RDMA1 },
- { DDP_COMPONENT_DPI0 },
-};
-
-struct mtk_drm_path_definition mt8183_legacy_paths[MAX_CRTC] = {
- [CRTC_MAIN] = {
- .comp = mt8183_mtk_ddp_main,
- .len = ARRAY_SIZE(mt8183_mtk_ddp_main),
- },
- [CRTC_EXT] = {
- .comp = mt8183_mtk_ddp_ext,
- .len = ARRAY_SIZE(mt8183_mtk_ddp_ext),
- },
-};
-
-static const struct mtk_drm_comp_definition mt8186_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_CCORR },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_GAMMA },
- { DDP_COMPONENT_POSTMASK0 },
- { DDP_COMPONENT_DITHER0 },
- { DDP_COMPONENT_DSI0 },
-};
-
-static const struct mtk_drm_comp_definition mt8186_mtk_ddp_ext[] = {
- { DDP_COMPONENT_OVL_2L0 },
- { DDP_COMPONENT_RDMA1 },
- { DDP_COMPONENT_DPI0 },
-};
-
-struct mtk_drm_path_definition mt8186_legacy_paths[MAX_CRTC] = {
- [CRTC_MAIN] = {
- .comp = mt8186_mtk_ddp_main,
- .len = ARRAY_SIZE(mt8186_mtk_ddp_main),
- },
- [CRTC_EXT] = {
- .comp = mt8186_mtk_ddp_ext,
- .len = ARRAY_SIZE(mt8186_mtk_ddp_ext),
- },
-};
-
-static const struct mtk_drm_comp_definition mt8188_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_CCORR },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_GAMMA },
- { DDP_COMPONENT_POSTMASK0 },
- { DDP_COMPONENT_DITHER0 },
-};
-
-struct mtk_drm_path_definition mt8188_legacy_paths[MAX_CRTC] = {
- [CRTC_MAIN] = {
- .comp = mt8188_mtk_ddp_main,
- .len = ARRAY_SIZE(mt8188_mtk_ddp_main),
- },
-};
-
-static const struct mtk_drm_comp_definition mt8192_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_OVL_2L0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_CCORR },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_GAMMA },
- { DDP_COMPONENT_POSTMASK0 },
- { DDP_COMPONENT_DITHER0 },
- { DDP_COMPONENT_DSI0 },
-};
-
-static const struct mtk_drm_comp_definition mt8192_mtk_ddp_ext[] = {
- { DDP_COMPONENT_OVL_2L2 },
- { DDP_COMPONENT_RDMA4 },
- { DDP_COMPONENT_DPI0 },
-};
-
-struct mtk_drm_path_definition mt8192_legacy_paths[MAX_CRTC] = {
- [CRTC_MAIN] = {
- .comp = mt8192_mtk_ddp_main,
- .len = ARRAY_SIZE(mt8192_mtk_ddp_main),
- },
- [CRTC_EXT] = {
- .comp = mt8192_mtk_ddp_ext,
- .len = ARRAY_SIZE(mt8192_mtk_ddp_ext),
- },
-};
-
-static const struct mtk_drm_comp_definition mt8195_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_CCORR },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_GAMMA },
- { DDP_COMPONENT_DITHER0 },
- { DDP_COMPONENT_DSC0 },
- { DDP_COMPONENT_MERGE0 },
- { DDP_COMPONENT_DP_INTF0 },
-};
-
-static const struct mtk_drm_comp_definition mt8195_mtk_ddp_ext[] = {
- { DDP_COMPONENT_DRM_OVL_ADAPTOR },
- { DDP_COMPONENT_MERGE5 },
- { DDP_COMPONENT_DP_INTF1 },
-};
-
-struct mtk_drm_path_definition mt8195_vdo0_legacy_paths[MAX_CRTC] = {
- [CRTC_MAIN] = {
- .comp = mt8195_mtk_ddp_main,
- .len = ARRAY_SIZE(mt8195_mtk_ddp_main),
- },
-};
-
-struct mtk_drm_path_definition mt8195_vdo1_legacy_paths[MAX_CRTC] = {
- [CRTC_EXT] = {
- .comp = mt8195_mtk_ddp_ext,
- .len = ARRAY_SIZE(mt8195_mtk_ddp_ext),
- },
-};
-
static const struct mtk_mmsys_driver_data mt2701_mmsys_driver_data = {
.output_paths = mt2701_legacy_paths,
.shadow_register = true,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_legacy.c b/drivers/gpu/drm/mediatek/mtk_drm_legacy.c
new file mode 100644
index 000000000000..623e510de9ff
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_drm_legacy.c
@@ -0,0 +1,309 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Compatibility layer for legacy mediatek-drm
+ *
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ *
+ * All (or most of) MediaTek SoCs released since around year 2014 onwards
+ * have got a new Multimedia System (and Display Controller) architecture,
+ * featuring an extreme flexibility on the connection of all of the various
+ * multimedia-related hardware components (or sub-IPs).
+ *
+ * Many different boards based on those SoCs are using different displays,
+ * different outputs, hence wildly different display pipelines: for this,
+ * a solution based on a devicetree graph (OF Graph) was chosen for setting
+ * up the correct pipeline for each device.
+ *
+ * However, removing the hardcoded display controller paths would break all
+ * of the devices using the new display driver on an old devicetree.
+ *
+ * This compatibility layer makes possible to keep the display controller
+ * functionality working when a board/device:
+ * - Uses an old devicetree with no OF Graph; and
+ * - Uses a new kernel with the new mediatek-drm graph-based pipeline
+ * building code.
+ *
+ * ** WARNING **
+ * This exists only to avoid ABI breakages and no new SoC should ever be
+ * added to this file.
+ */
+
+#include "mtk_drm_drv.h"
+#include "mtk_drm_legacy.h"
+
+static const struct mtk_drm_comp_definition mt2701_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_BLS },
+ { DDP_COMPONENT_DSI0 },
+};
+
+static const struct mtk_drm_comp_definition mt2701_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_RDMA1 },
+ { DDP_COMPONENT_DPI0 },
+};
+
+struct mtk_drm_path_definition mt2701_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt2701_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt2701_mtk_ddp_main),
+ },
+ [CRTC_EXT] = {
+ .comp = mt2701_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt2701_mtk_ddp_ext),
+ },
+};
+
+static const struct mtk_drm_comp_definition mt2712_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_OD0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_DPI0 },
+ { DDP_COMPONENT_PWM0 },
+};
+
+static const struct mtk_drm_comp_definition mt2712_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_OVL1 },
+ { DDP_COMPONENT_COLOR1 },
+ { DDP_COMPONENT_AAL1 },
+ { DDP_COMPONENT_OD1 },
+ { DDP_COMPONENT_RDMA1 },
+ { DDP_COMPONENT_DPI1 },
+ { DDP_COMPONENT_PWM1 },
+};
+
+static const struct mtk_drm_comp_definition mt2712_mtk_ddp_third[] = {
+ { DDP_COMPONENT_RDMA2 },
+ { DDP_COMPONENT_DSI3 },
+ { DDP_COMPONENT_PWM2 },
+};
+
+struct mtk_drm_path_definition mt2712_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt2712_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt2712_mtk_ddp_main),
+ },
+ [CRTC_EXT] = {
+ .comp = mt2712_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt2712_mtk_ddp_ext),
+ },
+ [CRTC_THIRD] = {
+ .comp = mt2712_mtk_ddp_third,
+ .len = ARRAY_SIZE(mt2712_mtk_ddp_third),
+ },
+};
+
+static const struct mtk_drm_comp_definition mt7623_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_BLS },
+ { DDP_COMPONENT_DPI0 },
+};
+
+static const struct mtk_drm_comp_definition mt7623_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_RDMA1 },
+ { DDP_COMPONENT_DSI0 },
+};
+
+struct mtk_drm_path_definition mt7623_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt7623_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt7623_mtk_ddp_main),
+ },
+ [CRTC_EXT] = {
+ .comp = mt7623_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt7623_mtk_ddp_ext),
+ },
+};
+
+static const struct mtk_drm_comp_definition mt8167_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_CCORR },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_GAMMA },
+ { DDP_COMPONENT_DITHER0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_DSI0 },
+};
+
+struct mtk_drm_path_definition mt8167_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt8167_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt8167_mtk_ddp_main),
+ },
+};
+
+static const struct mtk_drm_comp_definition mt8173_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_OD0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_UFOE },
+ { DDP_COMPONENT_DSI0 },
+ { DDP_COMPONENT_PWM0 },
+};
+
+static const struct mtk_drm_comp_definition mt8173_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_OVL1 },
+ { DDP_COMPONENT_COLOR1 },
+ { DDP_COMPONENT_GAMMA },
+ { DDP_COMPONENT_RDMA1 },
+ { DDP_COMPONENT_DPI0 },
+};
+
+struct mtk_drm_path_definition mt8173_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt8173_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt8173_mtk_ddp_main),
+ },
+ [CRTC_EXT] = {
+ .comp = mt8173_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt8173_mtk_ddp_ext),
+ },
+};
+
+static const struct mtk_drm_comp_definition mt8183_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_OVL_2L0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_CCORR },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_GAMMA },
+ { DDP_COMPONENT_DITHER0 },
+ { DDP_COMPONENT_DSI0 },
+};
+
+static const struct mtk_drm_comp_definition mt8183_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_OVL_2L1 },
+ { DDP_COMPONENT_RDMA1 },
+ { DDP_COMPONENT_DPI0 },
+};
+
+struct mtk_drm_path_definition mt8183_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt8183_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt8183_mtk_ddp_main),
+ },
+ [CRTC_EXT] = {
+ .comp = mt8183_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt8183_mtk_ddp_ext),
+ },
+};
+
+static const struct mtk_drm_comp_definition mt8186_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_CCORR },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_GAMMA },
+ { DDP_COMPONENT_POSTMASK0 },
+ { DDP_COMPONENT_DITHER0 },
+ { DDP_COMPONENT_DSI0 },
+};
+
+static const struct mtk_drm_comp_definition mt8186_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_OVL_2L0 },
+ { DDP_COMPONENT_RDMA1 },
+ { DDP_COMPONENT_DPI0 },
+};
+
+struct mtk_drm_path_definition mt8186_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt8186_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt8186_mtk_ddp_main),
+ },
+ [CRTC_EXT] = {
+ .comp = mt8186_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt8186_mtk_ddp_ext),
+ },
+};
+
+static const struct mtk_drm_comp_definition mt8188_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_CCORR },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_GAMMA },
+ { DDP_COMPONENT_POSTMASK0 },
+ { DDP_COMPONENT_DITHER0 },
+};
+
+struct mtk_drm_path_definition mt8188_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt8188_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt8188_mtk_ddp_main),
+ },
+};
+
+static const struct mtk_drm_comp_definition mt8192_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_OVL_2L0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_CCORR },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_GAMMA },
+ { DDP_COMPONENT_POSTMASK0 },
+ { DDP_COMPONENT_DITHER0 },
+ { DDP_COMPONENT_DSI0 },
+};
+
+static const struct mtk_drm_comp_definition mt8192_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_OVL_2L2 },
+ { DDP_COMPONENT_RDMA4 },
+ { DDP_COMPONENT_DPI0 },
+};
+
+struct mtk_drm_path_definition mt8192_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt8192_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt8192_mtk_ddp_main),
+ },
+ [CRTC_EXT] = {
+ .comp = mt8192_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt8192_mtk_ddp_ext),
+ },
+};
+
+static const struct mtk_drm_comp_definition mt8195_mtk_ddp_main[] = {
+ { DDP_COMPONENT_OVL0 },
+ { DDP_COMPONENT_RDMA0 },
+ { DDP_COMPONENT_COLOR0 },
+ { DDP_COMPONENT_CCORR },
+ { DDP_COMPONENT_AAL0 },
+ { DDP_COMPONENT_GAMMA },
+ { DDP_COMPONENT_DITHER0 },
+ { DDP_COMPONENT_DSC0 },
+ { DDP_COMPONENT_MERGE0 },
+ { DDP_COMPONENT_DP_INTF0 },
+};
+
+static const struct mtk_drm_comp_definition mt8195_mtk_ddp_ext[] = {
+ { DDP_COMPONENT_DRM_OVL_ADAPTOR },
+ { DDP_COMPONENT_MERGE5 },
+ { DDP_COMPONENT_DP_INTF1 },
+};
+
+struct mtk_drm_path_definition mt8195_vdo0_legacy_paths[MAX_CRTC] = {
+ [CRTC_MAIN] = {
+ .comp = mt8195_mtk_ddp_main,
+ .len = ARRAY_SIZE(mt8195_mtk_ddp_main),
+ },
+};
+
+struct mtk_drm_path_definition mt8195_vdo1_legacy_paths[MAX_CRTC] = {
+ [CRTC_EXT] = {
+ .comp = mt8195_mtk_ddp_ext,
+ .len = ARRAY_SIZE(mt8195_mtk_ddp_ext),
+ },
+};
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_legacy.h b/drivers/gpu/drm/mediatek/mtk_drm_legacy.h
new file mode 100644
index 000000000000..a87741ec0dcd
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_drm_legacy.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Support for legacy mediatek-drm display paths
+ *
+ * Please read mtk_drm_legacy.c for more information.
+ *
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#ifndef MTK_DRM_LEGACY_H
+#define MTK_DRM_LEGACY_H
+
+struct mtk_drm_path_definition;
+
+extern struct mtk_drm_path_definition mt2701_legacy_paths[];
+extern struct mtk_drm_path_definition mt2712_legacy_paths[];
+extern struct mtk_drm_path_definition mt7623_legacy_paths[];
+extern struct mtk_drm_path_definition mt8167_legacy_paths[];
+extern struct mtk_drm_path_definition mt8173_legacy_paths[];
+extern struct mtk_drm_path_definition mt8183_legacy_paths[];
+extern struct mtk_drm_path_definition mt8186_legacy_paths[];
+extern struct mtk_drm_path_definition mt8188_legacy_paths[];
+extern struct mtk_drm_path_definition mt8192_legacy_paths[];
+extern struct mtk_drm_path_definition mt8195_vdo0_legacy_paths[];
+extern struct mtk_drm_path_definition mt8195_vdo1_legacy_paths[];
+
+#endif /* MTK_DRM_LEGACY_H */
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 11/42] drm/mediatek: Add support for MuteX trigger-sources parsing
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (9 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 10/42] drm/mediatek: Create new mtk_drm_legacy and move deprecated code AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 12/42] drm/mediatek: ovl_adaptor: Add special MERGE component check AngeloGioacchino Del Regno
` (30 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Add support for getting the Mute-X trigger source ID from the
devicetree of each component requiring one.
In order to retain compatibility with older devicetrees that are
not specifying one, add a hardcoded table of Mute-X IDs in the
mtk_drm_legacy code, and inject all of the hardcoded identifiers
during initialization in mtk_drm_drv if the MediaTek Mute-X node
does not have #trigger-source-cells as this implies that the
driver is surely dealing with an old devicetree.
While at it, also migrate the mtk_disp_ovl_adaptor registration
mechanism to mtk_drm_legacy and change its platform data to get
a struct mtk_drm_private instead of mmsys_dev: this is done in
order to get a handle to the MuteX node in OVL_ADAPTOR, which
purpose is to get the legacy trigger IDs through, again, tables
in mtk_drm_legacy.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 19 +
drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 2 +
.../gpu/drm/mediatek/mtk_disp_ovl_adaptor.c | 17 +-
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 28 +-
drivers/gpu/drm/mediatek/mtk_drm_legacy.c | 567 ++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_drm_legacy.h | 8 +
6 files changed, 621 insertions(+), 20 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index b0d38646ca03..f45588ae7342 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -604,6 +604,21 @@ static void mtk_ddp_comp_clk_put(void *_clk)
clk_put(clk);
}
+int mtk_ddp_comp_get_mutex_trigger(struct device_node *node, unsigned int index)
+{
+ struct fwnode_reference_args mutex_trigger;
+ int ret;
+
+ ret = fwnode_property_get_reference_args(of_fwnode_handle(node),
+ "trigger-sources",
+ "#trigger-source-cells",
+ 0, index, &mutex_trigger);
+ if (ret < 0)
+ return ret;
+
+ return mutex_trigger.args[0];
+}
+
static bool mtk_ddp_comp_is_backlight_comp(enum mtk_ddp_comp_type type)
{
return type == MTK_DISP_BLS || type == MTK_DISP_PWM;
@@ -696,6 +711,10 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
if (ret)
return ret;
+ ret = mtk_ddp_comp_get_mutex_trigger(node, 0);
+ if (ret >= 0)
+ comp->mtx_trig_id = ret;
+
/* If there's no external driver for this component, allocate and init now */
if (mtk_ddp_comp_is_internal_comp(type) || mtk_ddp_comp_is_backlight_comp(type)) {
ret = mtk_ddp_comp_init_internal_comp(dev, comp->dev);
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index 76a2b649516d..5206445b7157 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -81,6 +81,7 @@ struct mtk_ddp_comp {
struct device *dev;
int irq;
unsigned int id;
+ u8 mtx_trig_id;
int encoder_index;
const struct mtk_ddp_comp_funcs *funcs;
@@ -360,6 +361,7 @@ int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev);
int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
struct mtk_drm_comp_list *hlist,
unsigned int comp_id);
+int mtk_ddp_comp_get_mutex_trigger(struct device_node *node, unsigned int index);
enum mtk_ddp_comp_type mtk_ddp_comp_get_type(unsigned int comp_id);
void mtk_ddp_write(struct cmdq_pkt *cmdq_pkt, unsigned int value,
struct cmdq_client_reg *cmdq_reg, void __iomem *regs,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
index c0af3e3b51d5..ed9a2e35ba8a 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
@@ -20,6 +20,7 @@
#include "mtk_ddp_comp.h"
#include "mtk_disp_drv.h"
#include "mtk_drm_drv.h"
+#include "mtk_drm_legacy.h"
#include "mtk_ethdr.h"
#define MTK_OVL_ADAPTOR_RDMA_MAX_WIDTH 1920
@@ -68,6 +69,7 @@ struct ovl_adaptor_comp_match {
struct mtk_disp_ovl_adaptor {
struct device *ovl_adaptor_comp[OVL_ADAPTOR_ID_MAX];
struct device *mmsys_dev;
+ u8 mtx_trig_ids[OVL_ADAPTOR_ID_MAX];
bool children_bound;
};
@@ -534,7 +536,8 @@ static void ovl_adaptor_put_device(void *_dev)
put_device(dev);
}
-static int ovl_adaptor_comp_init(struct device *dev, struct component_match **match)
+static int ovl_adaptor_comp_init(struct device *dev, struct device_node *mutex_node,
+ struct component_match **match)
{
struct mtk_disp_ovl_adaptor *priv = dev_get_drvdata(dev);
struct device_node *parent;
@@ -544,7 +547,9 @@ static int ovl_adaptor_comp_init(struct device *dev, struct component_match **ma
for_each_child_of_node_scoped(parent, node) {
enum mtk_ovl_adaptor_comp_type type;
+ enum mtk_ddp_comp_id ddp_type;
int id, ret;
+ u8 mtx_id;
ret = ovl_adaptor_of_get_ddp_comp_type(node, &type);
if (ret)
@@ -563,6 +568,10 @@ static int ovl_adaptor_comp_init(struct device *dev, struct component_match **ma
continue;
}
+ ddp_type = comp_matches[id].comp_id;
+ mtx_id = mtk_drm_legacy_get_ovl_adaptor_mutex_trig_id(ddp_type,
+ mutex_node);
+
comp_pdev = of_find_device_by_node(node);
if (!comp_pdev)
return -EPROBE_DEFER;
@@ -573,6 +582,7 @@ static int ovl_adaptor_comp_init(struct device *dev, struct component_match **ma
return ret;
priv->ovl_adaptor_comp[id] = &comp_pdev->dev;
+ priv->mtx_trig_ids[id] = mtx_id;
drm_of_component_match_add(dev, match, component_compare_of, node);
dev_dbg(dev, "Adding component match for %pOF\n", node);
@@ -634,6 +644,7 @@ static const struct component_master_ops mtk_disp_ovl_adaptor_master_ops = {
static int mtk_disp_ovl_adaptor_probe(struct platform_device *pdev)
{
+ struct mtk_drm_private *drm_private = pdev->dev.platform_data;
struct mtk_disp_ovl_adaptor *priv;
struct device *dev = &pdev->dev;
struct component_match *match = NULL;
@@ -645,11 +656,11 @@ static int mtk_disp_ovl_adaptor_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
- ret = ovl_adaptor_comp_init(dev, &match);
+ ret = ovl_adaptor_comp_init(dev, drm_private->mutex_node, &match);
if (ret < 0)
return ret;
- priv->mmsys_dev = pdev->dev.platform_data;
+ priv->mmsys_dev = drm_private->mmsys_dev;
component_master_add_with_match(dev, &mtk_disp_ovl_adaptor_master_ops, match);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 1396cbc65627..cdff5edd09da 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -409,11 +409,6 @@ static const struct drm_driver mtk_drm_driver = {
.minor = DRIVER_MINOR,
};
-static int compare_dev(struct device *dev, void *data)
-{
- return dev == (struct device *)data;
-}
-
static int mtk_drm_bind(struct device *dev)
{
struct mtk_drm_private *private = dev_get_drvdata(dev);
@@ -856,7 +851,6 @@ static int mtk_drm_probe(struct platform_device *pdev)
struct mtk_mmsys_driver_data *mtk_drm_data;
struct device_node *node;
struct component_match *match = NULL;
- struct platform_device *ovl_adaptor;
int ret;
int i;
@@ -904,17 +898,6 @@ static int mtk_drm_probe(struct platform_device *pdev)
if (!private->all_drm_private)
return -ENOMEM;
- /* Bringup ovl_adaptor */
- if (mtk_drm_find_mmsys_comp(private, DDP_COMPONENT_DRM_OVL_ADAPTOR)) {
- ovl_adaptor = platform_device_register_data(dev, "mediatek-disp-ovl-adaptor",
- PLATFORM_DEVID_AUTO,
- (void *)private->mmsys_dev,
- sizeof(*private->mmsys_dev));
- mtk_ddp_comp_init(&ovl_adaptor->dev, NULL, &private->hlist,
- DDP_COMPONENT_DRM_OVL_ADAPTOR);
- component_match_add(dev, &match, compare_dev, &ovl_adaptor->dev);
- }
-
/* Iterate over sibling DISP function blocks */
for_each_child_of_node(phandle->parent, node) {
enum mtk_ddp_comp_type comp_type;
@@ -979,6 +962,17 @@ static int mtk_drm_probe(struct platform_device *pdev)
goto err_node;
}
+ /* If mtk-mutex is not a trigger source, this is an old devicetree */
+ if (!of_property_present(private->mutex_node, "#trigger-source-cells")) {
+ ret = mtk_drm_legacy_inject_mutex_trig_ids(&private->hlist, private->mutex_node);
+ if (ret)
+ return ret;
+ }
+
+ /* Bringup ovl_adaptor */
+ if (mtk_drm_find_mmsys_comp(private, DDP_COMPONENT_DRM_OVL_ADAPTOR))
+ mtk_drm_legacy_ovl_adaptor_probe(dev, private, &match);
+
pm_runtime_enable(dev);
platform_set_drvdata(pdev, private);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_legacy.c b/drivers/gpu/drm/mediatek/mtk_drm_legacy.c
index 623e510de9ff..d6e3ab7e08ba 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_legacy.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_legacy.c
@@ -29,9 +29,224 @@
* added to this file.
*/
+#include <linux/component.h>
+#include <linux/of.h>
+
#include "mtk_drm_drv.h"
#include "mtk_drm_legacy.h"
+#define MT2701_MUTEX_MOD_DISP_OVL 3
+#define MT2701_MUTEX_MOD_DISP_WDMA 6
+#define MT2701_MUTEX_MOD_DISP_COLOR 7
+#define MT2701_MUTEX_MOD_DISP_BLS 9
+#define MT2701_MUTEX_MOD_DISP_RDMA0 10
+#define MT2701_MUTEX_MOD_DISP_RDMA1 12
+
+#define MT2712_MUTEX_MOD_DISP_PWM2 10
+#define MT2712_MUTEX_MOD_DISP_OVL0 11
+#define MT2712_MUTEX_MOD_DISP_OVL1 12
+#define MT2712_MUTEX_MOD_DISP_RDMA0 13
+#define MT2712_MUTEX_MOD_DISP_RDMA1 14
+#define MT2712_MUTEX_MOD_DISP_RDMA2 15
+#define MT2712_MUTEX_MOD_DISP_WDMA0 16
+#define MT2712_MUTEX_MOD_DISP_WDMA1 17
+#define MT2712_MUTEX_MOD_DISP_COLOR0 18
+#define MT2712_MUTEX_MOD_DISP_COLOR1 19
+#define MT2712_MUTEX_MOD_DISP_AAL0 20
+#define MT2712_MUTEX_MOD_DISP_UFOE 22
+#define MT2712_MUTEX_MOD_DISP_PWM0 23
+#define MT2712_MUTEX_MOD_DISP_PWM1 24
+#define MT2712_MUTEX_MOD_DISP_OD0 25
+#define MT2712_MUTEX_MOD2_DISP_AAL1 33
+#define MT2712_MUTEX_MOD2_DISP_OD1 34
+
+#define MT6893_MUTEX_MOD_DISP_OVL0 0
+#define MT6893_MUTEX_MOD_DISP_OVL0_2L 1
+#define MT6893_MUTEX_MOD_DISP_RDMA0 2
+#define MT6893_MUTEX_MOD_DISP_WDMA0 3
+#define MT6893_MUTEX_MOD_DISP_COLOR0 4
+#define MT6893_MUTEX_MOD_DISP_CCORR0 5
+#define MT6893_MUTEX_MOD_DISP_AAL0 6
+#define MT6893_MUTEX_MOD_DISP_GAMMA0 7
+#define MT6893_MUTEX_MOD_DISP_DITHER0 8
+#define MT6893_MUTEX_MOD_DISP_DSI0 9
+#define MT6893_MUTEX_MOD_DISP_PWM0 11
+#define MT6893_MUTEX_MOD_DISP_OVL1 12
+#define MT6893_MUTEX_MOD_DISP_OVL1_2L 13
+#define MT6893_MUTEX_MOD_DISP_RDMA1 14
+#define MT6893_MUTEX_MOD_DISP_WDMA1 15
+#define MT6893_MUTEX_MOD_DISP_COLOR1 16
+#define MT6893_MUTEX_MOD_DISP_AAL1 18
+#define MT6893_MUTEX_MOD_DISP_DITHER1 20
+#define MT6893_MUTEX_MOD_DISP_DSI1 21
+#define MT6893_MUTEX_MOD_DISP_OVL2 23
+#define MT6893_MUTEX_MOD_DISP_POSTMASK0 25
+#define MT6893_MUTEX_MOD_DISP_MERGE0 27
+#define MT6893_MUTEX_MOD_DISP_MERGE1 28
+#define MT6893_MUTEX_MOD_DISP_DSC0 29
+#define MT6893_MUTEX_MOD_DISP_DP 31
+#define MT6893_MUTEX_MOD_DISP_RDMA4 34
+
+#define MT8167_MUTEX_MOD_DISP_PWM 1
+#define MT8167_MUTEX_MOD_DISP_OVL0 6
+#define MT8167_MUTEX_MOD_DISP_OVL1 7
+#define MT8167_MUTEX_MOD_DISP_RDMA0 8
+#define MT8167_MUTEX_MOD_DISP_RDMA1 9
+#define MT8167_MUTEX_MOD_DISP_WDMA0 10
+#define MT8167_MUTEX_MOD_DISP_CCORR 11
+#define MT8167_MUTEX_MOD_DISP_COLOR 12
+#define MT8167_MUTEX_MOD_DISP_AAL 13
+#define MT8167_MUTEX_MOD_DISP_GAMMA 14
+#define MT8167_MUTEX_MOD_DISP_DITHER 15
+#define MT8167_MUTEX_MOD_DISP_UFOE 16
+
+#define MT8173_MUTEX_MOD_DISP_OVL0 11
+#define MT8173_MUTEX_MOD_DISP_OVL1 12
+#define MT8173_MUTEX_MOD_DISP_RDMA0 13
+#define MT8173_MUTEX_MOD_DISP_RDMA1 14
+#define MT8173_MUTEX_MOD_DISP_RDMA2 15
+#define MT8173_MUTEX_MOD_DISP_WDMA0 16
+#define MT8173_MUTEX_MOD_DISP_WDMA1 17
+#define MT8173_MUTEX_MOD_DISP_COLOR0 18
+#define MT8173_MUTEX_MOD_DISP_COLOR1 19
+#define MT8173_MUTEX_MOD_DISP_AAL 20
+#define MT8173_MUTEX_MOD_DISP_GAMMA 21
+#define MT8173_MUTEX_MOD_DISP_UFOE 22
+#define MT8173_MUTEX_MOD_DISP_PWM0 23
+#define MT8173_MUTEX_MOD_DISP_PWM1 24
+#define MT8173_MUTEX_MOD_DISP_OD 25
+
+#define MT8183_MUTEX_MOD_DISP_RDMA0 0
+#define MT8183_MUTEX_MOD_DISP_RDMA1 1
+#define MT8183_MUTEX_MOD_DISP_OVL0 9
+#define MT8183_MUTEX_MOD_DISP_OVL0_2L 10
+#define MT8183_MUTEX_MOD_DISP_OVL1_2L 11
+#define MT8183_MUTEX_MOD_DISP_WDMA0 12
+#define MT8183_MUTEX_MOD_DISP_COLOR0 13
+#define MT8183_MUTEX_MOD_DISP_CCORR0 14
+#define MT8183_MUTEX_MOD_DISP_AAL0 15
+#define MT8183_MUTEX_MOD_DISP_GAMMA0 16
+#define MT8183_MUTEX_MOD_DISP_DITHER0 17
+
+#define MT8186_MUTEX_MOD_DISP_OVL0 0
+#define MT8186_MUTEX_MOD_DISP_OVL0_2L 1
+#define MT8186_MUTEX_MOD_DISP_RDMA0 2
+#define MT8186_MUTEX_MOD_DISP_COLOR0 4
+#define MT8186_MUTEX_MOD_DISP_CCORR0 5
+#define MT8186_MUTEX_MOD_DISP_AAL0 7
+#define MT8186_MUTEX_MOD_DISP_GAMMA0 8
+#define MT8186_MUTEX_MOD_DISP_POSTMASK0 9
+#define MT8186_MUTEX_MOD_DISP_DITHER0 10
+#define MT8186_MUTEX_MOD_DISP_RDMA1 17
+
+#define MT8188_MUTEX_MOD_DISP_OVL0 0
+#define MT8188_MUTEX_MOD_DISP_WDMA0 1
+#define MT8188_MUTEX_MOD_DISP_RDMA0 2
+#define MT8188_MUTEX_MOD_DISP_COLOR0 3
+#define MT8188_MUTEX_MOD_DISP_CCORR0 4
+#define MT8188_MUTEX_MOD_DISP_AAL0 5
+#define MT8188_MUTEX_MOD_DISP_GAMMA0 6
+#define MT8188_MUTEX_MOD_DISP_DITHER0 7
+#define MT8188_MUTEX_MOD_DISP_DSI0 8
+#define MT8188_MUTEX_MOD_DISP_DSC_WRAP0_CORE0 9
+#define MT8188_MUTEX_MOD_DISP_VPP_MERGE 20
+#define MT8188_MUTEX_MOD_DISP_DP_INTF0 21
+#define MT8188_MUTEX_MOD_DISP_POSTMASK0 24
+#define MT8188_MUTEX_MOD2_DISP_PWM0 33
+
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA0 0
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA1 1
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA2 2
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA3 3
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA4 4
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA5 5
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA6 6
+#define MT8188_MUTEX_MOD_DISP1_MDP_RDMA7 7
+#define MT8188_MUTEX_MOD_DISP1_PADDING0 8
+#define MT8188_MUTEX_MOD_DISP1_PADDING1 9
+#define MT8188_MUTEX_MOD_DISP1_PADDING2 10
+#define MT8188_MUTEX_MOD_DISP1_PADDING3 11
+#define MT8188_MUTEX_MOD_DISP1_PADDING4 12
+#define MT8188_MUTEX_MOD_DISP1_PADDING5 13
+#define MT8188_MUTEX_MOD_DISP1_PADDING6 14
+#define MT8188_MUTEX_MOD_DISP1_PADDING7 15
+#define MT8188_MUTEX_MOD_DISP1_VPP_MERGE0 20
+#define MT8188_MUTEX_MOD_DISP1_VPP_MERGE1 21
+#define MT8188_MUTEX_MOD_DISP1_VPP_MERGE2 22
+#define MT8188_MUTEX_MOD_DISP1_VPP_MERGE3 23
+#define MT8188_MUTEX_MOD_DISP1_VPP_MERGE4 24
+#define MT8188_MUTEX_MOD_DISP1_DISP_MIXER 30
+#define MT8188_MUTEX_MOD_DISP1_DPI1 38
+#define MT8188_MUTEX_MOD_DISP1_DP_INTF1 39
+
+#define MT8192_MUTEX_MOD_DISP_OVL0 0
+#define MT8192_MUTEX_MOD_DISP_OVL0_2L 1
+#define MT8192_MUTEX_MOD_DISP_RDMA0 2
+#define MT8192_MUTEX_MOD_DISP_COLOR0 4
+#define MT8192_MUTEX_MOD_DISP_CCORR0 5
+#define MT8192_MUTEX_MOD_DISP_AAL0 6
+#define MT8192_MUTEX_MOD_DISP_GAMMA0 7
+#define MT8192_MUTEX_MOD_DISP_POSTMASK0 8
+#define MT8192_MUTEX_MOD_DISP_DITHER0 9
+#define MT8192_MUTEX_MOD_DISP_OVL2_2L 16
+#define MT8192_MUTEX_MOD_DISP_RDMA4 17
+
+#define MT8195_MUTEX_MOD_DISP_OVL0 0
+#define MT8195_MUTEX_MOD_DISP_WDMA0 1
+#define MT8195_MUTEX_MOD_DISP_RDMA0 2
+#define MT8195_MUTEX_MOD_DISP_COLOR0 3
+#define MT8195_MUTEX_MOD_DISP_CCORR0 4
+#define MT8195_MUTEX_MOD_DISP_AAL0 5
+#define MT8195_MUTEX_MOD_DISP_GAMMA0 6
+#define MT8195_MUTEX_MOD_DISP_DITHER0 7
+#define MT8195_MUTEX_MOD_DISP_DSI0 8
+#define MT8195_MUTEX_MOD_DISP_DSC_WRAP0_CORE0 9
+#define MT8195_MUTEX_MOD_DISP_VPP_MERGE 20
+#define MT8195_MUTEX_MOD_DISP_DP_INTF0 21
+#define MT8195_MUTEX_MOD_DISP_PWM0 27
+
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA0 0
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA1 1
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA2 2
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA3 3
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA4 4
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA5 5
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA6 6
+#define MT8195_MUTEX_MOD_DISP1_MDP_RDMA7 7
+#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE0 8
+#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE1 9
+#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE2 10
+#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE3 11
+#define MT8195_MUTEX_MOD_DISP1_VPP_MERGE4 12
+#define MT8195_MUTEX_MOD_DISP1_DISP_MIXER 18
+#define MT8195_MUTEX_MOD_DISP1_DPI0 25
+#define MT8195_MUTEX_MOD_DISP1_DPI1 26
+#define MT8195_MUTEX_MOD_DISP1_DP_INTF0 27
+
+#define MT8365_MUTEX_MOD_DISP_OVL0 7
+#define MT8365_MUTEX_MOD_DISP_OVL0_2L 8
+#define MT8365_MUTEX_MOD_DISP_RDMA0 9
+#define MT8365_MUTEX_MOD_DISP_RDMA1 10
+#define MT8365_MUTEX_MOD_DISP_WDMA0 11
+#define MT8365_MUTEX_MOD_DISP_COLOR0 12
+#define MT8365_MUTEX_MOD_DISP_CCORR 13
+#define MT8365_MUTEX_MOD_DISP_AAL 14
+#define MT8365_MUTEX_MOD_DISP_GAMMA 15
+#define MT8365_MUTEX_MOD_DISP_DITHER 16
+#define MT8365_MUTEX_MOD_DISP_DSI0 17
+#define MT8365_MUTEX_MOD_DISP_PWM0 20
+#define MT8365_MUTEX_MOD_DISP_DPI0 22
+
+struct mtk_drm_legacy_mtx_pairs {
+ struct mtk_drm_comp_definition comp;
+ u8 mtx_trig_id;
+};
+
+struct mtk_drm_legacy_mtx_data {
+ const struct mtk_drm_legacy_mtx_pairs *pairs;
+ u8 num_pairs;
+};
+
static const struct mtk_drm_comp_definition mt2701_mtk_ddp_main[] = {
{ DDP_COMPONENT_OVL0 },
{ DDP_COMPONENT_RDMA0 },
@@ -307,3 +522,355 @@ struct mtk_drm_path_definition mt8195_vdo1_legacy_paths[MAX_CRTC] = {
.len = ARRAY_SIZE(mt8195_mtk_ddp_ext),
},
};
+
+static const struct mtk_drm_legacy_mtx_pairs mt2701_legacy_mtx_trig_ids[] = {
+ { { DDP_COMPONENT_BLS }, MT2701_MUTEX_MOD_DISP_BLS },
+ { { DDP_COMPONENT_COLOR0 }, MT2701_MUTEX_MOD_DISP_COLOR },
+ { { DDP_COMPONENT_OVL0 }, MT2701_MUTEX_MOD_DISP_OVL },
+ { { DDP_COMPONENT_RDMA0 }, MT2701_MUTEX_MOD_DISP_RDMA0 },
+ { { DDP_COMPONENT_RDMA1 }, MT2701_MUTEX_MOD_DISP_RDMA1 },
+ { { DDP_COMPONENT_WDMA0 }, MT2701_MUTEX_MOD_DISP_WDMA },
+};
+
+const struct mtk_drm_legacy_mtx_data mt2701_legacy_mtx_data = {
+ .pairs = mt2701_legacy_mtx_trig_ids,
+ .num_pairs = ARRAY_SIZE(mt2701_legacy_mtx_trig_ids)
+};
+
+static const struct mtk_drm_legacy_mtx_pairs mt2712_legacy_mtx_trig_ids[] = {
+ { { DDP_COMPONENT_AAL0 }, MT2712_MUTEX_MOD_DISP_AAL0 },
+ { { DDP_COMPONENT_AAL1 }, MT2712_MUTEX_MOD2_DISP_AAL1 },
+ { { DDP_COMPONENT_COLOR0 }, MT2712_MUTEX_MOD_DISP_COLOR0 },
+ { { DDP_COMPONENT_COLOR1 }, MT2712_MUTEX_MOD_DISP_COLOR1 },
+ { { DDP_COMPONENT_OD0 }, MT2712_MUTEX_MOD_DISP_OD0 },
+ { { DDP_COMPONENT_OD1 }, MT2712_MUTEX_MOD2_DISP_OD1 },
+ { { DDP_COMPONENT_OVL0 }, MT2712_MUTEX_MOD_DISP_OVL0 },
+ { { DDP_COMPONENT_OVL1 }, MT2712_MUTEX_MOD_DISP_OVL1 },
+ { { DDP_COMPONENT_PWM0 }, MT2712_MUTEX_MOD_DISP_PWM0 },
+ { { DDP_COMPONENT_PWM1 }, MT2712_MUTEX_MOD_DISP_PWM1 },
+ { { DDP_COMPONENT_PWM2 }, MT2712_MUTEX_MOD_DISP_PWM2 },
+ { { DDP_COMPONENT_RDMA0 }, MT2712_MUTEX_MOD_DISP_RDMA0 },
+ { { DDP_COMPONENT_RDMA1 }, MT2712_MUTEX_MOD_DISP_RDMA1 },
+ { { DDP_COMPONENT_RDMA2 }, MT2712_MUTEX_MOD_DISP_RDMA2 },
+ { { DDP_COMPONENT_UFOE }, MT2712_MUTEX_MOD_DISP_UFOE },
+ { { DDP_COMPONENT_WDMA0 }, MT2712_MUTEX_MOD_DISP_WDMA0 },
+ { { DDP_COMPONENT_WDMA1 }, MT2712_MUTEX_MOD_DISP_WDMA1 },
+};
+
+const struct mtk_drm_legacy_mtx_data mt2712_legacy_mtx_data = {
+ .pairs = mt2712_legacy_mtx_trig_ids,
+ .num_pairs = ARRAY_SIZE(mt2712_legacy_mtx_trig_ids)
+};
+
+static const struct mtk_drm_legacy_mtx_pairs mt6893_legacy_mtx_trig_ids[] = {
+ { { DDP_COMPONENT_AAL0 }, MT6893_MUTEX_MOD_DISP_AAL0 },
+ { { DDP_COMPONENT_AAL1 }, MT6893_MUTEX_MOD_DISP_AAL1 },
+ { { DDP_COMPONENT_CCORR }, MT6893_MUTEX_MOD_DISP_CCORR0 },
+ { { DDP_COMPONENT_COLOR0 }, MT6893_MUTEX_MOD_DISP_COLOR0 },
+ { { DDP_COMPONENT_COLOR1 }, MT6893_MUTEX_MOD_DISP_COLOR1 },
+ { { DDP_COMPONENT_DITHER0 }, MT6893_MUTEX_MOD_DISP_DITHER0 },
+ { { DDP_COMPONENT_DITHER1 }, MT6893_MUTEX_MOD_DISP_DITHER1 },
+ { { DDP_COMPONENT_DP_INTF0 }, MT6893_MUTEX_MOD_DISP_DP },
+ { { DDP_COMPONENT_DSC0 }, MT6893_MUTEX_MOD_DISP_DSC0 },
+ { { DDP_COMPONENT_DSI0 }, MT6893_MUTEX_MOD_DISP_DSI0 },
+ { { DDP_COMPONENT_DSI1 }, MT6893_MUTEX_MOD_DISP_DSI1 },
+ { { DDP_COMPONENT_GAMMA }, MT6893_MUTEX_MOD_DISP_GAMMA0 },
+ { { DDP_COMPONENT_MERGE1 }, MT6893_MUTEX_MOD_DISP_MERGE1 },
+ { { DDP_COMPONENT_OVL0 }, MT6893_MUTEX_MOD_DISP_OVL0 },
+ { { DDP_COMPONENT_OVL1 }, MT6893_MUTEX_MOD_DISP_OVL1 },
+ { { DDP_COMPONENT_OVL_2L0 }, MT6893_MUTEX_MOD_DISP_OVL0_2L },
+ { { DDP_COMPONENT_OVL_2L1 }, MT6893_MUTEX_MOD_DISP_OVL1_2L },
+ { { DDP_COMPONENT_OVL_2L2 }, MT6893_MUTEX_MOD_DISP_OVL2 },
+ { { DDP_COMPONENT_POSTMASK0 }, MT6893_MUTEX_MOD_DISP_POSTMASK0 },
+ { { DDP_COMPONENT_PWM0 }, MT6893_MUTEX_MOD_DISP_PWM0 },
+ { { DDP_COMPONENT_RDMA0 }, MT6893_MUTEX_MOD_DISP_RDMA0 },
+ { { DDP_COMPONENT_RDMA1 }, MT6893_MUTEX_MOD_DISP_RDMA1 },
+ { { DDP_COMPONENT_RDMA4 }, MT6893_MUTEX_MOD_DISP_RDMA4 },
+ { { DDP_COMPONENT_WDMA0 }, MT6893_MUTEX_MOD_DISP_WDMA0 },
+ { { DDP_COMPONENT_WDMA1 }, MT6893_MUTEX_MOD_DISP_WDMA1 },
+};
+
+const struct mtk_drm_legacy_mtx_data mt6893_legacy_mtx_data = {
+ .pairs = mt6893_legacy_mtx_trig_ids,
+ .num_pairs = ARRAY_SIZE(mt6893_legacy_mtx_trig_ids)
+};
+
+static const struct mtk_drm_legacy_mtx_pairs mt8167_legacy_mtx_trig_ids[] = {
+ { { DDP_COMPONENT_AAL0 }, MT8167_MUTEX_MOD_DISP_AAL },
+ { { DDP_COMPONENT_CCORR }, MT8167_MUTEX_MOD_DISP_CCORR },
+ { { DDP_COMPONENT_COLOR0 }, MT8167_MUTEX_MOD_DISP_COLOR },
+ { { DDP_COMPONENT_DITHER0 }, MT8167_MUTEX_MOD_DISP_DITHER },
+ { { DDP_COMPONENT_GAMMA }, MT8167_MUTEX_MOD_DISP_GAMMA },
+ { { DDP_COMPONENT_OVL0 }, MT8167_MUTEX_MOD_DISP_OVL0 },
+ { { DDP_COMPONENT_OVL1 }, MT8167_MUTEX_MOD_DISP_OVL1 },
+ { { DDP_COMPONENT_PWM0 }, MT8167_MUTEX_MOD_DISP_PWM },
+ { { DDP_COMPONENT_RDMA0 }, MT8167_MUTEX_MOD_DISP_RDMA0 },
+ { { DDP_COMPONENT_RDMA1 }, MT8167_MUTEX_MOD_DISP_RDMA1 },
+ { { DDP_COMPONENT_UFOE }, MT8167_MUTEX_MOD_DISP_UFOE },
+ { { DDP_COMPONENT_WDMA0 }, MT8167_MUTEX_MOD_DISP_WDMA0 },
+};
+
+const struct mtk_drm_legacy_mtx_data mt8167_legacy_mtx_data = {
+ .pairs = mt8167_legacy_mtx_trig_ids,
+ .num_pairs = ARRAY_SIZE(mt8167_legacy_mtx_trig_ids)
+};
+
+static const struct mtk_drm_legacy_mtx_pairs mt8173_legacy_mtx_trig_ids[] = {
+ { { DDP_COMPONENT_AAL0 }, MT8173_MUTEX_MOD_DISP_AAL },
+ { { DDP_COMPONENT_COLOR0 }, MT8173_MUTEX_MOD_DISP_COLOR0 },
+ { { DDP_COMPONENT_COLOR1 }, MT8173_MUTEX_MOD_DISP_COLOR1 },
+ { { DDP_COMPONENT_GAMMA }, MT8173_MUTEX_MOD_DISP_GAMMA },
+ { { DDP_COMPONENT_OD0 }, MT8173_MUTEX_MOD_DISP_OD },
+ { { DDP_COMPONENT_OVL0 }, MT8173_MUTEX_MOD_DISP_OVL0 },
+ { { DDP_COMPONENT_OVL1 }, MT8173_MUTEX_MOD_DISP_OVL1 },
+ { { DDP_COMPONENT_PWM0 }, MT8173_MUTEX_MOD_DISP_PWM0 },
+ { { DDP_COMPONENT_PWM1 }, MT8173_MUTEX_MOD_DISP_PWM1 },
+ { { DDP_COMPONENT_RDMA0 }, MT8173_MUTEX_MOD_DISP_RDMA0 },
+ { { DDP_COMPONENT_RDMA1 }, MT8173_MUTEX_MOD_DISP_RDMA1 },
+ { { DDP_COMPONENT_RDMA2 }, MT8173_MUTEX_MOD_DISP_RDMA2 },
+ { { DDP_COMPONENT_UFOE }, MT8173_MUTEX_MOD_DISP_UFOE },
+ { { DDP_COMPONENT_WDMA0 }, MT8173_MUTEX_MOD_DISP_WDMA0 },
+ { { DDP_COMPONENT_WDMA1 }, MT8173_MUTEX_MOD_DISP_WDMA1 },
+};
+
+const struct mtk_drm_legacy_mtx_data mt8173_legacy_mtx_data = {
+ .pairs = mt8173_legacy_mtx_trig_ids,
+ .num_pairs = ARRAY_SIZE(mt8173_legacy_mtx_trig_ids)
+};
+
+static const struct mtk_drm_legacy_mtx_pairs mt8183_legacy_mtx_trig_ids[] = {
+ { { DDP_COMPONENT_AAL0 }, MT8183_MUTEX_MOD_DISP_AAL0 },
+ { { DDP_COMPONENT_CCORR }, MT8183_MUTEX_MOD_DISP_CCORR0 },
+ { { DDP_COMPONENT_COLOR0 }, MT8183_MUTEX_MOD_DISP_COLOR0 },
+ { { DDP_COMPONENT_DITHER0 }, MT8183_MUTEX_MOD_DISP_DITHER0 },
+ { { DDP_COMPONENT_GAMMA }, MT8183_MUTEX_MOD_DISP_GAMMA0 },
+ { { DDP_COMPONENT_OVL0 }, MT8183_MUTEX_MOD_DISP_OVL0 },
+ { { DDP_COMPONENT_OVL_2L0 }, MT8183_MUTEX_MOD_DISP_OVL0_2L },
+ { { DDP_COMPONENT_OVL_2L1 }, MT8183_MUTEX_MOD_DISP_OVL1_2L },
+ { { DDP_COMPONENT_RDMA0 }, MT8183_MUTEX_MOD_DISP_RDMA0 },
+ { { DDP_COMPONENT_RDMA1 }, MT8183_MUTEX_MOD_DISP_RDMA1 },
+ { { DDP_COMPONENT_WDMA0 }, MT8183_MUTEX_MOD_DISP_WDMA0 },
+};
+
+const struct mtk_drm_legacy_mtx_data mt8183_legacy_mtx_data = {
+ .pairs = mt8183_legacy_mtx_trig_ids,
+ .num_pairs = ARRAY_SIZE(mt8183_legacy_mtx_trig_ids)
+};
+
+static const struct mtk_drm_legacy_mtx_pairs mt8186_legacy_mtx_trig_ids[] = {
+ { { DDP_COMPONENT_AAL0 }, MT8186_MUTEX_MOD_DISP_AAL0 },
+ { { DDP_COMPONENT_CCORR }, MT8186_MUTEX_MOD_DISP_CCORR0 },
+ { { DDP_COMPONENT_COLOR0 }, MT8186_MUTEX_MOD_DISP_COLOR0 },
+ { { DDP_COMPONENT_DITHER0 }, MT8186_MUTEX_MOD_DISP_DITHER0 },
+ { { DDP_COMPONENT_GAMMA }, MT8186_MUTEX_MOD_DISP_GAMMA0 },
+ { { DDP_COMPONENT_OVL0 }, MT8186_MUTEX_MOD_DISP_OVL0 },
+ { { DDP_COMPONENT_OVL_2L0 }, MT8186_MUTEX_MOD_DISP_OVL0_2L },
+ { { DDP_COMPONENT_POSTMASK0 }, MT8186_MUTEX_MOD_DISP_POSTMASK0 },
+ { { DDP_COMPONENT_RDMA0 }, MT8186_MUTEX_MOD_DISP_RDMA0 },
+ { { DDP_COMPONENT_RDMA1 }, MT8186_MUTEX_MOD_DISP_RDMA1 },
+};
+
+const struct mtk_drm_legacy_mtx_data mt8186_legacy_mtx_data = {
+ .pairs = mt8186_legacy_mtx_trig_ids,
+ .num_pairs = ARRAY_SIZE(mt8186_legacy_mtx_trig_ids)
+};
+
+static const struct mtk_drm_legacy_mtx_pairs mt8188_legacy_mtx_trig_ids[] = {
+ { { DDP_COMPONENT_OVL0 }, MT8188_MUTEX_MOD_DISP_OVL0 },
+ { { DDP_COMPONENT_WDMA0 }, MT8188_MUTEX_MOD_DISP_WDMA0 },
+ { { DDP_COMPONENT_RDMA0 }, MT8188_MUTEX_MOD_DISP_RDMA0 },
+ { { DDP_COMPONENT_COLOR0 }, MT8188_MUTEX_MOD_DISP_COLOR0 },
+ { { DDP_COMPONENT_CCORR }, MT8188_MUTEX_MOD_DISP_CCORR0 },
+ { { DDP_COMPONENT_AAL0 }, MT8188_MUTEX_MOD_DISP_AAL0 },
+ { { DDP_COMPONENT_GAMMA }, MT8188_MUTEX_MOD_DISP_GAMMA0 },
+ { { DDP_COMPONENT_POSTMASK0 }, MT8188_MUTEX_MOD_DISP_POSTMASK0 },
+ { { DDP_COMPONENT_DITHER0 }, MT8188_MUTEX_MOD_DISP_DITHER0 },
+ { { DDP_COMPONENT_MERGE0 }, MT8188_MUTEX_MOD_DISP_VPP_MERGE },
+ { { DDP_COMPONENT_DSC0 }, MT8188_MUTEX_MOD_DISP_DSC_WRAP0_CORE0 },
+ { { DDP_COMPONENT_DSI0 }, MT8188_MUTEX_MOD_DISP_DSI0 },
+ { { DDP_COMPONENT_PWM0 }, MT8188_MUTEX_MOD2_DISP_PWM0 },
+ { { DDP_COMPONENT_DP_INTF0 }, MT8188_MUTEX_MOD_DISP_DP_INTF0 },
+ { { DDP_COMPONENT_DP_INTF1 }, MT8188_MUTEX_MOD_DISP1_DP_INTF1 },
+ { { DDP_COMPONENT_DPI1 }, MT8188_MUTEX_MOD_DISP1_DPI1 },
+ { { DDP_COMPONENT_ETHDR_MIXER }, MT8188_MUTEX_MOD_DISP1_DISP_MIXER },
+ { { DDP_COMPONENT_MDP_RDMA0 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA0 },
+ { { DDP_COMPONENT_MDP_RDMA1 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA1 },
+ { { DDP_COMPONENT_MDP_RDMA2 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA2 },
+ { { DDP_COMPONENT_MDP_RDMA3 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA3 },
+ { { DDP_COMPONENT_MDP_RDMA4 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA4 },
+ { { DDP_COMPONENT_MDP_RDMA5 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA5 },
+ { { DDP_COMPONENT_MDP_RDMA6 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA6 },
+ { { DDP_COMPONENT_MDP_RDMA7 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA7 },
+ { { DDP_COMPONENT_PADDING0 }, MT8188_MUTEX_MOD_DISP1_PADDING0 },
+ { { DDP_COMPONENT_PADDING1 }, MT8188_MUTEX_MOD_DISP1_PADDING1 },
+ { { DDP_COMPONENT_PADDING2 }, MT8188_MUTEX_MOD_DISP1_PADDING2 },
+ { { DDP_COMPONENT_PADDING3 }, MT8188_MUTEX_MOD_DISP1_PADDING3 },
+ { { DDP_COMPONENT_PADDING4 }, MT8188_MUTEX_MOD_DISP1_PADDING4 },
+ { { DDP_COMPONENT_PADDING5 }, MT8188_MUTEX_MOD_DISP1_PADDING5 },
+ { { DDP_COMPONENT_PADDING6 }, MT8188_MUTEX_MOD_DISP1_PADDING6 },
+ { { DDP_COMPONENT_PADDING7 }, MT8188_MUTEX_MOD_DISP1_PADDING7 },
+ { { DDP_COMPONENT_MERGE1 }, MT8188_MUTEX_MOD_DISP1_VPP_MERGE0 },
+ { { DDP_COMPONENT_MERGE2 }, MT8188_MUTEX_MOD_DISP1_VPP_MERGE1 },
+ { { DDP_COMPONENT_MERGE3 }, MT8188_MUTEX_MOD_DISP1_VPP_MERGE2 },
+ { { DDP_COMPONENT_MERGE4 }, MT8188_MUTEX_MOD_DISP1_VPP_MERGE3 },
+ { { DDP_COMPONENT_MERGE5 }, MT8188_MUTEX_MOD_DISP1_VPP_MERGE4 },
+};
+
+const struct mtk_drm_legacy_mtx_data mt8188_legacy_mtx_data = {
+ .pairs = mt8188_legacy_mtx_trig_ids,
+ .num_pairs = ARRAY_SIZE(mt8188_legacy_mtx_trig_ids)
+};
+
+static const struct mtk_drm_legacy_mtx_pairs mt8192_legacy_mtx_trig_ids[] = {
+ { { DDP_COMPONENT_AAL0 }, MT8192_MUTEX_MOD_DISP_AAL0 },
+ { { DDP_COMPONENT_CCORR }, MT8192_MUTEX_MOD_DISP_CCORR0 },
+ { { DDP_COMPONENT_COLOR0 }, MT8192_MUTEX_MOD_DISP_COLOR0 },
+ { { DDP_COMPONENT_DITHER0 }, MT8192_MUTEX_MOD_DISP_DITHER0 },
+ { { DDP_COMPONENT_GAMMA }, MT8192_MUTEX_MOD_DISP_GAMMA0 },
+ { { DDP_COMPONENT_POSTMASK0 }, MT8192_MUTEX_MOD_DISP_POSTMASK0 },
+ { { DDP_COMPONENT_OVL0 }, MT8192_MUTEX_MOD_DISP_OVL0 },
+ { { DDP_COMPONENT_OVL_2L0 }, MT8192_MUTEX_MOD_DISP_OVL0_2L },
+ { { DDP_COMPONENT_OVL_2L2 }, MT8192_MUTEX_MOD_DISP_OVL2_2L },
+ { { DDP_COMPONENT_RDMA0 }, MT8192_MUTEX_MOD_DISP_RDMA0 },
+ { { DDP_COMPONENT_RDMA4 }, MT8192_MUTEX_MOD_DISP_RDMA4 },
+};
+
+const struct mtk_drm_legacy_mtx_data mt8192_legacy_mtx_data = {
+ .pairs = mt8192_legacy_mtx_trig_ids,
+ .num_pairs = ARRAY_SIZE(mt8192_legacy_mtx_trig_ids)
+};
+
+static const struct mtk_drm_legacy_mtx_pairs mt8195_legacy_mtx_trig_ids[] = {
+ { { DDP_COMPONENT_OVL0 }, MT8195_MUTEX_MOD_DISP_OVL0 },
+ { { DDP_COMPONENT_WDMA0 }, MT8195_MUTEX_MOD_DISP_WDMA0 },
+ { { DDP_COMPONENT_RDMA0 }, MT8195_MUTEX_MOD_DISP_RDMA0 },
+ { { DDP_COMPONENT_COLOR0 }, MT8195_MUTEX_MOD_DISP_COLOR0 },
+ { { DDP_COMPONENT_CCORR }, MT8195_MUTEX_MOD_DISP_CCORR0 },
+ { { DDP_COMPONENT_AAL0 }, MT8195_MUTEX_MOD_DISP_AAL0 },
+ { { DDP_COMPONENT_GAMMA }, MT8195_MUTEX_MOD_DISP_GAMMA0 },
+ { { DDP_COMPONENT_DITHER0 }, MT8195_MUTEX_MOD_DISP_DITHER0 },
+ { { DDP_COMPONENT_MERGE0 }, MT8195_MUTEX_MOD_DISP_VPP_MERGE },
+ { { DDP_COMPONENT_DSC0 }, MT8195_MUTEX_MOD_DISP_DSC_WRAP0_CORE0 },
+ { { DDP_COMPONENT_DSI0 }, MT8195_MUTEX_MOD_DISP_DSI0 },
+ { { DDP_COMPONENT_PWM0 }, MT8195_MUTEX_MOD_DISP_PWM0 },
+ { { DDP_COMPONENT_DP_INTF0 }, MT8195_MUTEX_MOD_DISP_DP_INTF0 },
+ { { DDP_COMPONENT_MDP_RDMA0 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA0 },
+ { { DDP_COMPONENT_MDP_RDMA1 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA1 },
+ { { DDP_COMPONENT_MDP_RDMA2 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA2 },
+ { { DDP_COMPONENT_MDP_RDMA3 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA3 },
+ { { DDP_COMPONENT_MDP_RDMA4 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA4 },
+ { { DDP_COMPONENT_MDP_RDMA5 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA5 },
+ { { DDP_COMPONENT_MDP_RDMA6 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA6 },
+ { { DDP_COMPONENT_MDP_RDMA7 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA7 },
+ { { DDP_COMPONENT_MERGE1 }, MT8195_MUTEX_MOD_DISP1_VPP_MERGE0 },
+ { { DDP_COMPONENT_MERGE2 }, MT8195_MUTEX_MOD_DISP1_VPP_MERGE1 },
+ { { DDP_COMPONENT_MERGE3 }, MT8195_MUTEX_MOD_DISP1_VPP_MERGE2 },
+ { { DDP_COMPONENT_MERGE4 }, MT8195_MUTEX_MOD_DISP1_VPP_MERGE3 },
+ { { DDP_COMPONENT_ETHDR_MIXER }, MT8195_MUTEX_MOD_DISP1_DISP_MIXER },
+ { { DDP_COMPONENT_MERGE5 }, MT8195_MUTEX_MOD_DISP1_VPP_MERGE4 },
+ { { DDP_COMPONENT_DP_INTF1 }, MT8195_MUTEX_MOD_DISP1_DP_INTF0 },
+};
+
+const struct mtk_drm_legacy_mtx_data mt8195_legacy_mtx_data = {
+ .pairs = mt8195_legacy_mtx_trig_ids,
+ .num_pairs = ARRAY_SIZE(mt8195_legacy_mtx_trig_ids)
+};
+
+static const struct mtk_drm_legacy_mtx_pairs mt8365_legacy_mtx_trig_ids[] = {
+ { { DDP_COMPONENT_AAL0 }, MT8365_MUTEX_MOD_DISP_AAL },
+ { { DDP_COMPONENT_CCORR }, MT8365_MUTEX_MOD_DISP_CCORR },
+ { { DDP_COMPONENT_COLOR0 }, MT8365_MUTEX_MOD_DISP_COLOR0 },
+ { { DDP_COMPONENT_DITHER0 }, MT8365_MUTEX_MOD_DISP_DITHER },
+ { { DDP_COMPONENT_DPI0 }, MT8365_MUTEX_MOD_DISP_DPI0 },
+ { { DDP_COMPONENT_DSI0 }, MT8365_MUTEX_MOD_DISP_DSI0 },
+ { { DDP_COMPONENT_GAMMA }, MT8365_MUTEX_MOD_DISP_GAMMA },
+ { { DDP_COMPONENT_OVL0 }, MT8365_MUTEX_MOD_DISP_OVL0 },
+ { { DDP_COMPONENT_OVL_2L0 }, MT8365_MUTEX_MOD_DISP_OVL0_2L },
+ { { DDP_COMPONENT_PWM0 }, MT8365_MUTEX_MOD_DISP_PWM0 },
+ { { DDP_COMPONENT_RDMA0 }, MT8365_MUTEX_MOD_DISP_RDMA0 },
+ { { DDP_COMPONENT_RDMA1 }, MT8365_MUTEX_MOD_DISP_RDMA1 },
+ { { DDP_COMPONENT_WDMA0 }, MT8365_MUTEX_MOD_DISP_WDMA0 },
+};
+
+const struct mtk_drm_legacy_mtx_data mt8365_legacy_mtx_data = {
+ .pairs = mt8365_legacy_mtx_trig_ids,
+ .num_pairs = ARRAY_SIZE(mt8365_legacy_mtx_trig_ids)
+};
+
+static const struct of_device_id mtk_drm_legacy_mtk_mutex_match[] = {
+ { .compatible = "mediatek,mt2701-disp-mutex", .data = &mt2701_legacy_mtx_data },
+ { .compatible = "mediatek,mt2712-disp-mutex", .data = &mt2712_legacy_mtx_data },
+ { .compatible = "mediatek,mt6795-disp-mutex", .data = &mt8173_legacy_mtx_data },
+ { .compatible = "mediatek.mt6893-disp-mutex", .data = &mt6893_legacy_mtx_data },
+ { .compatible = "mediatek,mt8167-disp-mutex", .data = &mt8167_legacy_mtx_data },
+ { .compatible = "mediatek,mt8173-disp-mutex", .data = &mt8173_legacy_mtx_data },
+ { .compatible = "mediatek,mt8183-disp-mutex", .data = &mt8183_legacy_mtx_data },
+ { .compatible = "mediatek,mt8186-disp-mutex", .data = &mt8186_legacy_mtx_data },
+ { .compatible = "mediatek,mt8188-disp-mutex", .data = &mt8188_legacy_mtx_data },
+ { .compatible = "mediatek,mt8192-disp-mutex", .data = &mt8192_legacy_mtx_data },
+ { .compatible = "mediatek,mt8195-disp-mutex", .data = &mt8195_legacy_mtx_data },
+ { .compatible = "mediatek,mt8365-disp-mutex", .data = &mt8365_legacy_mtx_data },
+ { /* sentinel */ },
+};
+
+int mtk_drm_legacy_inject_mutex_trig_ids(struct mtk_drm_comp_list *hlist,
+ struct device_node *mutex_node)
+{
+ struct mtk_drm_legacy_mtx_data *data;
+ const struct of_device_id *of_id;
+ struct mtk_ddp_comp *ddp_comp;
+ int i;
+
+ of_id = of_match_node(mtk_drm_legacy_mtk_mutex_match, mutex_node);
+ if (!of_id)
+ return -ENODEV;
+
+ data = (struct mtk_drm_legacy_mtx_data *)of_id->data;
+
+ for (i = 0; i < data->num_pairs; i++) {
+ const struct mtk_drm_comp_definition *comp = &data->pairs[i].comp;
+
+ hash_for_each_possible(hlist->ddp_list, ddp_comp, lnode, comp->type)
+ ddp_comp->mtx_trig_id = data->pairs[i].mtx_trig_id;
+ }
+
+ return 0;
+}
+
+u8 mtk_drm_legacy_get_ovl_adaptor_mutex_trig_id(enum mtk_ddp_comp_id ddp_type,
+ struct device_node *mutex_node)
+{
+ struct mtk_drm_legacy_mtx_data *data;
+ const struct of_device_id *of_id;
+ int i;
+
+ of_id = of_match_node(mtk_drm_legacy_mtk_mutex_match, mutex_node);
+ if (!of_id)
+ return 0;
+
+ data = (struct mtk_drm_legacy_mtx_data *)of_id->data;
+
+ for (i = 0; i < data->num_pairs; i++) {
+ const struct mtk_drm_comp_definition *comp = &data->pairs[i].comp;
+
+ if (ddp_type != comp->type)
+ continue;
+
+ return data->pairs[i].mtx_trig_id;
+ }
+
+ return 0;
+}
+
+void mtk_drm_legacy_ovl_adaptor_probe(struct device *dev, struct mtk_drm_private *priv,
+ struct component_match **match)
+{
+ struct platform_device *ovl_adaptor;
+
+ ovl_adaptor = platform_device_register_data(dev, "mediatek-disp-ovl-adaptor",
+ PLATFORM_DEVID_AUTO,
+ (void *)priv, sizeof(*priv));
+
+ mtk_ddp_comp_init(&ovl_adaptor->dev, NULL, &priv->hlist, DDP_COMPONENT_DRM_OVL_ADAPTOR);
+ component_match_add(dev, match, component_compare_dev, &ovl_adaptor->dev);
+}
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_legacy.h b/drivers/gpu/drm/mediatek/mtk_drm_legacy.h
index a87741ec0dcd..45bcf2674628 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_legacy.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_legacy.h
@@ -25,4 +25,12 @@ extern struct mtk_drm_path_definition mt8192_legacy_paths[];
extern struct mtk_drm_path_definition mt8195_vdo0_legacy_paths[];
extern struct mtk_drm_path_definition mt8195_vdo1_legacy_paths[];
+int mtk_drm_legacy_inject_mutex_trig_ids(struct mtk_drm_comp_list *hlist,
+ struct device_node *mutex_node);
+u8 mtk_drm_legacy_get_ovl_adaptor_mutex_trig_id(enum mtk_ddp_comp_id ddp_type,
+ struct device_node *mutex_node);
+
+void mtk_drm_legacy_ovl_adaptor_probe(struct device *dev, struct mtk_drm_private *priv,
+ struct component_match **match);
+
#endif /* MTK_DRM_LEGACY_H */
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 12/42] drm/mediatek: ovl_adaptor: Add special MERGE component check
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (10 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 11/42] drm/mediatek: Add support for MuteX trigger-sources parsing AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 13/42] drm/mediatek: mtk_hdmi_v2: Don't warn on RPM active during detach AngeloGioacchino Del Regno
` (29 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
On the legacy ovl_adaptor for MT8195 and MT8188, four MERGE IPs
from VPPSYS are used, and those shall be exclusive to the OVL
Adaptor driver.
For this reason, add a branch in mtk_ovl_adaptor_is_comp_present()
to check if the component that is being checked is MERGE and, if
so, iterate through the list of component matches to understand if
it is one of those that must be exclusive to OVL Adaptor.
This resolves a corner case happening when mediatek-drm retries to
probe after a probe deferral, where all MERGE components would get
added to both "normal" and OVL Adaptor pipelines.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
index ed9a2e35ba8a..bbf1d8ccda05 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
@@ -519,6 +519,17 @@ bool mtk_ovl_adaptor_is_comp_present(struct device_node *node)
if (type >= OVL_ADAPTOR_TYPE_NUM)
return false;
+ /* Check if this is one of the MERGE components used in OVL Adaptor */
+ if (type == OVL_ADAPTOR_TYPE_MERGE) {
+ int id = of_alias_get_id(node, private_comp_stem[type]);
+
+ for (int i = OVL_ADAPTOR_MERGE0; i <= OVL_ADAPTOR_MERGE3; i++)
+ if (comp_matches[i].alias_id == id)
+ return true;
+
+ return false;
+ }
+
/*
* In the context of mediatek-drm, ETHDR, MDP_RDMA and Padding are
* used exclusively by OVL Adaptor: if this component is not one of
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 13/42] drm/mediatek: mtk_hdmi_v2: Don't warn on RPM active during detach
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (11 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 12/42] drm/mediatek: ovl_adaptor: Add special MERGE component check AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 14/42] drm/mediatek: Add support for hardware multi-stage layers AngeloGioacchino Del Regno
` (28 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
The Runtime PM may be active during bridge .detach() and this
happens especially at boot, when probe deferrals in the display
controller driver happen.
Even though it looks safe to assume that RPM has to be inactive
at that time, this happens to be true only if the DDC was to be
handled internally (like before .hpd_{en,dis}able() existed).
At this point in time, this driver uses HPD callbacks, and for
HPD to actually work it is necessary to raise the RPM refcount
to wake up the entire HDMI IP: since it's not granted that the
HPD or other children of the HDMI node are disabled during the
display controller probe sequence, the WARN at bridge .detach()
time may trigger (and will do that when mediatek-drm defers),
unnecessarily bloating the kernel log, as the RPM refcount will
be decreased anyway when removing the driver.
This is why the WARN(pm_runtime_active()) check during detach
is simply a development stage leftover: remove it!
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_hdmi_v2.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c
index 7bbf463056c9..0cc80e80ae26 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c
@@ -995,8 +995,6 @@ static void mtk_hdmi_v2_bridge_detach(struct drm_bridge *bridge)
{
struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
- WARN_ON(pm_runtime_active(hdmi->dev));
-
/* The controller is already powered off, just disable irq here */
disable_irq(hdmi->irq);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 14/42] drm/mediatek: Add support for hardware multi-stage layers
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (12 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 13/42] drm/mediatek: mtk_hdmi_v2: Don't warn on RPM active during detach AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 15/42] drm/mediatek: mtk_crtc: Complete documentation for struct mtk_crtc AngeloGioacchino Del Regno
` (27 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In preparation for adding support for newer, more complex, display
controllers like the ones found in the MediaTek Kompanio Ultra and
Genio Pro 5100 (MT8196/MT8894), add support for multi-stage layers
as in newer hardware, there is a special strategy using multiple
hardware components of one (or multiple) display controller(s) to
form one single layer.
Multi-stage layers are one more step towards extra flexibility of
the Display Subsystem, making it possible to change capabilities
of Display Controller Pipelines depending on the final application
of a board: for example, one board may choose to use fewer layers
per pipeline to achieve more pipelines (more concurrent outputs),
or more layers to achieve less, but more capable (as in offloading
and in achievable bandwidth) concurrent outputs.
This currently adds boilerplate to support this hardware, but does
not yet implement the IP-specific support for MT8196/8894, which
will be done after all preparation is done.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_crtc.c | 304 ++++++++++++------
drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 15 +-
drivers/gpu/drm/mediatek/mtk_disp_drv.h | 12 +-
drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 12 +-
.../gpu/drm/mediatek/mtk_disp_ovl_adaptor.c | 2 +-
drivers/gpu/drm/mediatek/mtk_disp_rdma.c | 9 +-
drivers/gpu/drm/mediatek/mtk_disp_wdma.c | 2 +-
7 files changed, 246 insertions(+), 110 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index 5e243550d35e..8656b56618a2 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -8,6 +8,7 @@
#include <linux/clk.h>
#include <linux/dma-mapping.h>
#include <linux/mailbox_controller.h>
+#include <linux/minmax.h>
#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
@@ -28,12 +29,24 @@
#include "mtk_drm_drv.h"
#include "mtk_plane.h"
+/*
+ * struct mtk_crtc_hw_layer - MediaTek specific layer structure
+ * @plane: DRM Plane
+ * @layer_stages: HW Components layer stage indices to form one full layer/plane
+ * @layer_stages_nr: Number of layer stages in array
+ */
+struct mtk_crtc_hw_layer {
+ struct drm_plane plane;
+ u8 *layer_stages;
+ u8 layer_stages_nr;
+};
+
/*
* struct mtk_crtc - MediaTek specific crtc structure.
* @base: crtc object.
* @enabled: records whether crtc_enable succeeded
- * @planes: array of 4 drm_plane structures, one for each overlay plane
- * @pending_planes: whether any plane has pending changes to be applied
+ * @hwlayers: Array of mtk_crtc_hw_layer structures, one for each overlay plane
+ * @hwlayer_nr: Number of hwlayers
* @mmsys_dev: pointer to the mmsys device for configuration registers
* @mutex: handle to one of the ten disp_mutex streams
* @ddp_comp_nr: number of components in ddp_comp
@@ -48,8 +61,8 @@ struct mtk_crtc {
bool pending_needs_vblank;
struct drm_pending_vblank_event *event;
- struct drm_plane *planes;
- unsigned int layer_nr;
+ struct mtk_crtc_hw_layer *hwlayers;
+ unsigned int hwlayer_nr;
bool pending_planes;
bool pending_async_planes;
@@ -254,29 +267,6 @@ static void mtk_crtc_ddp_clk_disable(struct mtk_crtc *mtk_crtc)
mtk_ddp_comp_clk_disable(mtk_crtc->ddp_comp[i]);
}
-static
-struct mtk_ddp_comp *mtk_ddp_comp_for_plane(struct drm_crtc *crtc,
- struct drm_plane *plane,
- unsigned int *local_layer)
-{
- struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
- struct mtk_ddp_comp *comp;
- int i, count = 0;
- unsigned int local_index = plane - mtk_crtc->planes;
-
- for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
- comp = mtk_crtc->ddp_comp[i];
- if (local_index < (count + mtk_ddp_comp_layer_nr(comp))) {
- *local_layer = local_index - count;
- return comp;
- }
- count += mtk_ddp_comp_layer_nr(comp);
- }
-
- WARN(1, "Failed to find component for plane %d\n", plane->index);
- return NULL;
-}
-
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
{
@@ -303,8 +293,8 @@ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
state->pending_config = false;
if (mtk_crtc->pending_planes) {
- for (i = 0; i < mtk_crtc->layer_nr; i++) {
- struct drm_plane *plane = &mtk_crtc->planes[i];
+ for (i = 0; i < mtk_crtc->hwlayer_nr; i++) {
+ struct drm_plane *plane = &mtk_crtc->hwlayers[i].plane;
struct mtk_plane_state *plane_state;
plane_state = to_mtk_plane_state(plane->state);
@@ -315,8 +305,8 @@ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
}
if (mtk_crtc->pending_async_planes) {
- for (i = 0; i < mtk_crtc->layer_nr; i++) {
- struct drm_plane *plane = &mtk_crtc->planes[i];
+ for (i = 0; i < mtk_crtc->hwlayer_nr; i++) {
+ struct drm_plane *plane = &mtk_crtc->hwlayers[i].plane;
struct mtk_plane_state *plane_state;
plane_state = to_mtk_plane_state(plane->state);
@@ -340,6 +330,21 @@ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
}
#endif
+static void mtk_crtc_config_layer(struct mtk_crtc *mtk_crtc,
+ struct mtk_plane_state *plane_state,
+ int layer_num, struct cmdq_pkt *cmdq_pkt)
+{
+ u8 *layer_stages = mtk_crtc->hwlayers[layer_num].layer_stages;
+ u8 i = 0;
+
+ do {
+ mtk_ddp_comp_layer_config(mtk_crtc->ddp_comp[layer_stages[i]],
+ layer_num, plane_state, cmdq_pkt);
+ } while (++i < mtk_crtc->hwlayers[layer_num].layer_stages_nr);
+
+ return;
+}
+
static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
{
struct drm_crtc *crtc = &mtk_crtc->base;
@@ -436,20 +441,16 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
}
/* Initially configure all planes */
- for (i = 0; i < mtk_crtc->layer_nr; i++) {
- struct drm_plane *plane = &mtk_crtc->planes[i];
+ for (i = 0; i < mtk_crtc->hwlayer_nr; i++) {
+ struct drm_plane *plane = &mtk_crtc->hwlayers[i].plane;
struct mtk_plane_state *plane_state;
- struct mtk_ddp_comp *comp;
- unsigned int local_layer;
plane_state = to_mtk_plane_state(plane->state);
/* should not enable layer before crtc enabled */
plane_state->pending.enable = false;
- comp = mtk_ddp_comp_for_plane(crtc, plane, &local_layer);
- if (comp)
- mtk_ddp_comp_layer_config(comp, local_layer,
- plane_state, NULL);
+
+ mtk_crtc_config_layer(mtk_crtc, plane_state, i, NULL);
}
return 0;
@@ -511,7 +512,6 @@ static void mtk_crtc_ddp_config(struct drm_crtc *crtc,
struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
unsigned int i;
- unsigned int local_layer;
/*
* TODO: instead of updating the registers here, we should prepare
@@ -529,8 +529,8 @@ static void mtk_crtc_ddp_config(struct drm_crtc *crtc,
}
if (mtk_crtc->pending_planes) {
- for (i = 0; i < mtk_crtc->layer_nr; i++) {
- struct drm_plane *plane = &mtk_crtc->planes[i];
+ for (i = 0; i < mtk_crtc->hwlayer_nr; i++) {
+ struct drm_plane *plane = &mtk_crtc->hwlayers[i].plane;
struct mtk_plane_state *plane_state;
plane_state = to_mtk_plane_state(plane->state);
@@ -538,12 +538,8 @@ static void mtk_crtc_ddp_config(struct drm_crtc *crtc,
if (!plane_state->pending.config)
continue;
- comp = mtk_ddp_comp_for_plane(crtc, plane, &local_layer);
+ mtk_crtc_config_layer(mtk_crtc, plane_state, i, cmdq_handle);
- if (comp)
- mtk_ddp_comp_layer_config(comp, local_layer,
- plane_state,
- cmdq_handle);
if (!cmdq_handle)
plane_state->pending.config = false;
}
@@ -553,8 +549,8 @@ static void mtk_crtc_ddp_config(struct drm_crtc *crtc,
}
if (mtk_crtc->pending_async_planes) {
- for (i = 0; i < mtk_crtc->layer_nr; i++) {
- struct drm_plane *plane = &mtk_crtc->planes[i];
+ for (i = 0; i < mtk_crtc->hwlayer_nr; i++) {
+ struct drm_plane *plane = &mtk_crtc->hwlayers[i].plane;
struct mtk_plane_state *plane_state;
plane_state = to_mtk_plane_state(plane->state);
@@ -562,12 +558,8 @@ static void mtk_crtc_ddp_config(struct drm_crtc *crtc,
if (!plane_state->pending.async_config)
continue;
- comp = mtk_ddp_comp_for_plane(crtc, plane, &local_layer);
+ mtk_crtc_config_layer(mtk_crtc, plane_state, i, cmdq_handle);
- if (comp)
- mtk_ddp_comp_layer_config(comp, local_layer,
- plane_state,
- cmdq_handle);
if (!cmdq_handle)
plane_state->pending.async_config = false;
}
@@ -597,8 +589,8 @@ static void mtk_crtc_update_config(struct mtk_crtc *mtk_crtc, bool needs_vblank)
if (needs_vblank)
mtk_crtc->pending_needs_vblank = true;
- for (i = 0; i < mtk_crtc->layer_nr; i++) {
- struct drm_plane *plane = &mtk_crtc->planes[i];
+ for (i = 0; i < mtk_crtc->hwlayer_nr; i++) {
+ struct drm_plane *plane = &mtk_crtc->hwlayers[i].plane;
struct mtk_plane_state *plane_state;
plane_state = to_mtk_plane_state(plane->state);
@@ -747,12 +739,19 @@ static void mtk_crtc_update_output(struct drm_crtc *crtc,
int mtk_crtc_plane_check(struct drm_crtc *crtc, struct drm_plane *plane,
struct mtk_plane_state *state)
{
- unsigned int local_layer;
- struct mtk_ddp_comp *comp;
+ struct mtk_crtc_hw_layer *hwlayer = container_of(plane, struct mtk_crtc_hw_layer, plane);
+ struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
+ u8 *layer_stages = hwlayer->layer_stages;
+ int i, ret;
+
+ for (i = 0; i < hwlayer->layer_stages_nr; i++) {
+ struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[layer_stages[i]];
+
+ ret = mtk_ddp_comp_layer_check(comp, 0, state);
+ if (ret)
+ return ret;
+ }
- comp = mtk_ddp_comp_for_plane(crtc, plane, &local_layer);
- if (comp)
- return mtk_ddp_comp_layer_check(comp, local_layer, state);
return 0;
}
@@ -771,8 +770,8 @@ void mtk_crtc_plane_disable(struct drm_crtc *crtc, struct drm_plane *plane)
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];
+ for (i = 0; i < mtk_crtc->hwlayer_nr; i++) {
+ struct drm_plane *mtk_plane = &mtk_crtc->hwlayers[i].plane;
struct mtk_plane_state *mtk_plane_state = to_mtk_plane_state(mtk_plane->state);
if (mtk_plane->index == plane->index) {
@@ -841,8 +840,8 @@ static void mtk_crtc_atomic_disable(struct drm_crtc *crtc,
return;
/* Set all pending plane state to disabled */
- for (i = 0; i < mtk_crtc->layer_nr; i++) {
- struct drm_plane *plane = &mtk_crtc->planes[i];
+ for (i = 0; i < mtk_crtc->hwlayer_nr; i++) {
+ struct drm_plane *plane = &mtk_crtc->hwlayers[i].plane;
struct mtk_plane_state *plane_state;
plane_state = to_mtk_plane_state(plane->state);
@@ -936,11 +935,11 @@ static int mtk_crtc_init(struct drm_device *drm, struct mtk_crtc *mtk_crtc,
struct drm_plane *cursor = NULL;
int i, ret;
- for (i = 0; i < mtk_crtc->layer_nr; i++) {
- if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_PRIMARY)
- primary = &mtk_crtc->planes[i];
- else if (mtk_crtc->planes[i].type == DRM_PLANE_TYPE_CURSOR)
- cursor = &mtk_crtc->planes[i];
+ for (i = 0; i < mtk_crtc->hwlayer_nr; i++) {
+ if (mtk_crtc->hwlayers[i].plane.type == DRM_PLANE_TYPE_PRIMARY)
+ primary = &mtk_crtc->hwlayers[i].plane;
+ else if (mtk_crtc->hwlayers[i].plane.type == DRM_PLANE_TYPE_CURSOR)
+ cursor = &mtk_crtc->hwlayers[i].plane;
}
ret = drm_crtc_init_with_planes(drm, &mtk_crtc->base, primary, cursor,
@@ -957,23 +956,6 @@ static int mtk_crtc_init(struct drm_device *drm, struct mtk_crtc *mtk_crtc,
return ret;
}
-static int mtk_crtc_num_comp_planes(struct mtk_crtc *mtk_crtc, int comp_idx)
-{
- struct mtk_ddp_comp *comp;
-
- if (comp_idx > 1)
- return 0;
-
- comp = mtk_crtc->ddp_comp[comp_idx];
- if (!comp->funcs)
- return 0;
-
- if (comp_idx == 1 && !comp->funcs->bgclr_in_on)
- return 0;
-
- return mtk_ddp_comp_layer_nr(comp);
-}
-
static inline
enum drm_plane_type mtk_crtc_plane_type(unsigned int plane_idx,
unsigned int num_planes)
@@ -991,15 +973,15 @@ static int mtk_crtc_init_comp_planes(struct drm_device *drm_dev,
struct mtk_crtc *mtk_crtc,
int comp_idx, int pipe)
{
- int num_planes = mtk_crtc_num_comp_planes(mtk_crtc, comp_idx);
struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[comp_idx];
+ unsigned int num_planes = mtk_ddp_comp_layer_nr(comp, comp_idx);
int i, ret;
for (i = 0; i < num_planes; i++) {
- ret = mtk_plane_init(drm_dev,
- &mtk_crtc->planes[mtk_crtc->layer_nr],
- BIT(pipe),
- mtk_crtc_plane_type(mtk_crtc->layer_nr, num_planes),
+ struct mtk_crtc_hw_layer *hwlayer = &mtk_crtc->hwlayers[mtk_crtc->hwlayer_nr];
+
+ ret = mtk_plane_init(drm_dev, &hwlayer->plane, BIT(pipe),
+ mtk_crtc_plane_type(mtk_crtc->hwlayer_nr, num_planes),
mtk_ddp_comp_supported_rotations(comp),
mtk_ddp_comp_get_blend_modes(comp),
mtk_ddp_comp_get_formats(comp),
@@ -1008,7 +990,98 @@ static int mtk_crtc_init_comp_planes(struct drm_device *drm_dev,
if (ret)
return ret;
- mtk_crtc->layer_nr++;
+ hwlayer->layer_stages[hwlayer->layer_stages_nr] = comp_idx;
+ hwlayer->layer_stages_nr++;
+
+ mtk_crtc->hwlayer_nr++;
+ }
+ return 0;
+}
+
+static struct mtk_crtc_hw_layer
+*mtk_crtc_find_hwlayer_with_comp(struct mtk_crtc *mtk_crtc, int comp)
+{
+ struct mtk_crtc_hw_layer *hwlayer;
+ int i, j;
+
+ for (i = 0; i < mtk_crtc->hwlayer_nr; i++) {
+ hwlayer = &mtk_crtc->hwlayers[i];
+
+ for (j = 0; j < hwlayer->layer_stages_nr; j++) {
+ if (hwlayer->layer_stages[j] == comp)
+ return hwlayer;
+ }
+ }
+
+ return NULL;
+}
+
+static int mtk_crtc_init_layer_stages(struct mtk_crtc *mtk_crtc)
+{
+ unsigned int prev_master_layer_component = UINT_MAX;
+ unsigned int master_layer_component = 0;
+ unsigned int comp_idx;
+
+ for (comp_idx = 0; comp_idx < mtk_crtc->ddp_comp_nr; comp_idx++) {
+ struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[comp_idx];
+ struct mtk_crtc_hw_layer *hwlayer = NULL;
+
+ /*
+ * A hardware IP represented as a component with layer_nr > 0
+ * is the master (and also the first layer stage), which may
+ * then be composed of other multiple hardware-configurable
+ * layer stages that are directly connected to it.
+ *
+ * Only quirk here is that, in some cases, some layer stages
+ * may be connected together and hence not directly connected
+ * to the master: this corner case is not getting a perfectly
+ * accurate representation in the following code, as it treats
+ * all of the additional layer stages as if they are directly
+ * connected to the master.
+ * That doesn't matter, because any special configuration for
+ * this corner case is handled in the .connect handler of each
+ * specific component driver.
+ *
+ * For example, this is a multi-component layer stage layout:
+ * FRAME_IN -> _____ LAYER_MASTER ______
+ * / | | \ -> BLEND -> NEXT
+ * HW_STG1 HW_STG2 HW_STG3 HW_STGx HW HWIP
+ *
+ * And following, another one that gets handled (to simplify the
+ * code) anyway like the first:
+ * FRAME_IN -> LAYER_MASTER -> HW_STG1 -> HW_STG(x) -> NEXT HWIP
+ *
+ * For the moment, this also supposes that a component cannot be
+ * both primary and secondary (so if it has layer_nr, stage_nr
+ * will not be evaluated for such component).
+ */
+ if (mtk_ddp_comp_layer_nr(comp, comp_idx)) {
+ master_layer_component = comp_idx;
+ continue;
+ }
+
+ /* If this component doesn't provide any stages, keep searching */
+ if (!mtk_ddp_comp_stage_nr(comp))
+ continue;
+
+ /*
+ * If the index of the master layer component changed, find it
+ * in the stack of registered layer components
+ */
+ if (master_layer_component != prev_master_layer_component) {
+ hwlayer = mtk_crtc_find_hwlayer_with_comp(mtk_crtc, master_layer_component);
+ if (!hwlayer) {
+ drm_err(mtk_crtc->base.dev,
+ "Could not find layer master for %d!\n",
+ master_layer_component);
+ continue;
+ }
+ prev_master_layer_component = master_layer_component;
+ }
+
+ /* Add the newly found layer stage to the correct layer master */
+ hwlayer->layer_stages[hwlayer->layer_stages_nr] = comp_idx;
+ hwlayer->layer_stages_nr++;
}
return 0;
}
@@ -1038,6 +1111,7 @@ int mtk_crtc_create(struct drm_device *drm_dev,
struct mtk_ddp_comp *dma_comp;
struct mtk_crtc *mtk_crtc;
unsigned int num_comp_planes = 0;
+ unsigned int max_comp_stages = 0;
int ret;
int i, j;
bool has_ctm = false;
@@ -1123,20 +1197,54 @@ int mtk_crtc_create(struct drm_device *drm_dev,
&mtk_crtc->base);
}
- for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
- num_comp_planes += mtk_crtc_num_comp_planes(mtk_crtc, i);
+ for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
+ struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
+
+ num_comp_planes += mtk_ddp_comp_layer_nr(comp, 0);
+ max_comp_stages = MAX(mtk_ddp_comp_stage_nr(comp), max_comp_stages);
+ }
- mtk_crtc->planes = devm_kcalloc(dev, num_comp_planes,
- sizeof(struct drm_plane), GFP_KERNEL);
- if (!mtk_crtc->planes)
+ /*
+ * On the older and/or simpler display controllers, each layer is single
+ * stage, while newer ones are more complex and may have multiple stages
+ * to form one full layer.
+ *
+ * In both cases, anyway, in order to form a complete layer for plane,
+ * there will always be at least one layer stage, so the maximum number
+ * of stages is always (1 + max_comp_stages): for this reason, just add 1.
+ */
+ max_comp_stages++;
+
+ mtk_crtc->hwlayers = devm_kcalloc(dev, num_comp_planes,
+ sizeof(*mtk_crtc->hwlayers),
+ GFP_KERNEL);
+ if (!mtk_crtc->hwlayers)
return -ENOMEM;
+ for (i = 0; i < num_comp_planes; i++) {
+ struct mtk_crtc_hw_layer *comp_plane = &mtk_crtc->hwlayers[i];
+ comp_plane->layer_stages = devm_kcalloc(dev, max_comp_stages,
+ sizeof(*comp_plane->layer_stages),
+ GFP_KERNEL);
+ if (!comp_plane->layer_stages)
+ return -ENOMEM;
+ }
+
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
ret = mtk_crtc_init_comp_planes(drm_dev, mtk_crtc, i, crtc_i);
if (ret)
return ret;
}
+ /* Initialize multi-stage only if present */
+ if (max_comp_stages > 1) {
+ ret = mtk_crtc_init_layer_stages(mtk_crtc);
+ if (ret)
+ return ret;
+ }
+ dev_dbg(dev, "Found %u layers composed by maximum of %u stage(s) each.\n",
+ mtk_crtc->hwlayer_nr, max_comp_stages);
+
/*
* Default to use the first component as the dma dev.
* In the case of ovl_adaptor sub driver, it needs to use the
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index 5206445b7157..a7ed46a95037 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -50,7 +50,8 @@ struct mtk_ddp_comp_funcs {
void (*enable_vblank)(struct device *dev);
void (*disable_vblank)(struct device *dev);
unsigned int (*supported_rotations)(struct device *dev);
- unsigned int (*layer_nr)(struct device *dev);
+ unsigned int (*layer_nr)(struct device *dev, int pipeline_index);
+ unsigned int (*layerstage_nr)(struct device *dev);
int (*layer_check)(struct device *dev,
unsigned int idx,
struct mtk_plane_state *state);
@@ -196,10 +197,18 @@ unsigned int mtk_ddp_comp_supported_rotations(struct mtk_ddp_comp *comp)
return DRM_MODE_ROTATE_0;
}
-static inline unsigned int mtk_ddp_comp_layer_nr(struct mtk_ddp_comp *comp)
+static inline unsigned int mtk_ddp_comp_layer_nr(struct mtk_ddp_comp *comp, int pipeline_idx)
{
if (comp->funcs && comp->funcs->layer_nr)
- return comp->funcs->layer_nr(comp->dev);
+ return comp->funcs->layer_nr(comp->dev, pipeline_idx);
+
+ return 0;
+}
+
+static inline unsigned int mtk_ddp_comp_stage_nr(struct mtk_ddp_comp *comp)
+{
+ if (comp->funcs && comp->funcs->layerstage_nr)
+ return comp->funcs->layerstage_nr(comp->dev);
return 0;
}
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index e0c30c6c7cc8..7706d95b3be8 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -1,6 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * Copyright (c) 2020 MediaTek Inc.
+ * Copyright (c) 2020-2025 MediaTek Inc.
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
#ifndef _MTK_DISP_DRV_H_
@@ -98,7 +100,7 @@ int mtk_ovl_layer_check(struct device *dev, unsigned int idx,
void mtk_ovl_layer_config(struct device *dev, unsigned int idx,
struct mtk_plane_state *state,
struct cmdq_pkt *cmdq_pkt);
-unsigned int mtk_ovl_layer_nr(struct device *dev);
+unsigned int mtk_ovl_layer_nr(struct device *dev, int pipeline_index);
void mtk_ovl_layer_on(struct device *dev, unsigned int idx,
struct cmdq_pkt *cmdq_pkt);
void mtk_ovl_layer_off(struct device *dev, unsigned int idx,
@@ -141,7 +143,7 @@ void mtk_ovl_adaptor_enable_vblank(struct device *dev);
void mtk_ovl_adaptor_disable_vblank(struct device *dev);
void mtk_ovl_adaptor_start(struct device *dev);
void mtk_ovl_adaptor_stop(struct device *dev);
-unsigned int mtk_ovl_adaptor_layer_nr(struct device *dev);
+unsigned int mtk_ovl_adaptor_layer_nr(struct device *dev, int pipeline_index);
struct device *mtk_ovl_adaptor_dma_dev_get(struct device *dev);
u32 mtk_ovl_adaptor_get_blend_modes(struct device *dev);
const u32 *mtk_ovl_adaptor_get_formats(struct device *dev);
@@ -155,7 +157,7 @@ void mtk_rdma_clk_disable(struct device *dev);
void mtk_rdma_config(struct device *dev, unsigned int width,
unsigned int height, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
-unsigned int mtk_rdma_layer_nr(struct device *dev);
+unsigned int mtk_rdma_layer_nr(struct device *dev, int pipeline_index);
void mtk_rdma_layer_config(struct device *dev, unsigned int idx,
struct mtk_plane_state *state,
struct cmdq_pkt *cmdq_pkt);
@@ -186,7 +188,7 @@ void mtk_wdma_clk_disable(struct device *dev);
void mtk_wdma_config(struct device *dev, unsigned int width,
unsigned int height, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
-unsigned int mtk_wdma_layer_nr(struct device *dev);
+unsigned int mtk_wdma_layer_nr(struct device *dev, int pipeline_index);
void mtk_wdma_layer_config(struct device *dev, unsigned int idx,
struct mtk_plane_state *state,
struct cmdq_pkt *cmdq_pkt);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index fa4607304acb..489a209c4e55 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -348,10 +348,20 @@ void mtk_ovl_config(struct device *dev, unsigned int w,
mtk_ddp_write(cmdq_pkt, 0x0, &ovl->cmdq_reg, ovl->regs, DISP_REG_OVL_RST);
}
-unsigned int mtk_ovl_layer_nr(struct device *dev)
+unsigned int mtk_ovl_layer_nr(struct device *dev, int pipeline_index)
{
struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+ /*
+ * Only the first OVL in a display pipeline can form layers, and it
+ * must be either:
+ * - The first HW component in the pipeline; or
+ * - The second HW component in the pipeline, taking its input from
+ * a ReadDMA (RDMA) output.
+ */
+ if (pipeline_index > 1)
+ return 0;
+
return ovl->data->layer_nr;
}
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
index bbf1d8ccda05..78bc3bee0794 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
@@ -360,7 +360,7 @@ enum drm_mode_status mtk_ovl_adaptor_mode_valid(struct device *dev,
return MODE_OK;
}
-unsigned int mtk_ovl_adaptor_layer_nr(struct device *dev)
+unsigned int mtk_ovl_adaptor_layer_nr(struct device *dev, int pipeline_index)
{
return MTK_OVL_ADAPTOR_LAYER_NUM;
}
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
index 9fd9bb1ee544..dce7a9bc3f11 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
@@ -251,8 +251,15 @@ static unsigned int rdma_fmt_convert(struct mtk_disp_rdma *rdma,
}
}
-unsigned int mtk_rdma_layer_nr(struct device *dev)
+unsigned int mtk_rdma_layer_nr(struct device *dev, int pipeline_index)
{
+ /*
+ * ReadDMA may participate in forming a layer only if it is the first
+ * component in a pipeline, usually passing data to a DispHW Overlay (OVL)
+ */
+ if (pipeline_index > 0)
+ return 0;
+
return 1;
}
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_wdma.c b/drivers/gpu/drm/mediatek/mtk_disp_wdma.c
index 761dbe0148d8..26c80e7e152b 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_wdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_wdma.c
@@ -259,7 +259,7 @@ static u32 wdma_fmt_convert(unsigned int fmt)
}
}
-unsigned int mtk_wdma_layer_nr(struct device *dev)
+unsigned int mtk_wdma_layer_nr(struct device *dev, int pipeline_index)
{
return 1;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 15/42] drm/mediatek: mtk_crtc: Complete documentation for struct mtk_crtc
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (13 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 14/42] drm/mediatek: Add support for hardware multi-stage layers AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 16/42] drm/mediatek: mtk_crtc: Minimize spinlocked time in cmdq callback AngeloGioacchino Del Regno
` (26 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
The mtk_crtc structure was missing many member descriptions, for
which reason, a while ago it was demoted from kerneldoc to code
comment.
Add documentation for all of the missing structure members and
promote it back to kerneldoc.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_crtc.c | 33 +++++++++++++++++++----------
1 file changed, 22 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index 8656b56618a2..e543fae9c580 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -41,18 +41,31 @@ struct mtk_crtc_hw_layer {
u8 layer_stages_nr;
};
-/*
+/**
* struct mtk_crtc - MediaTek specific crtc structure.
- * @base: crtc object.
- * @enabled: records whether crtc_enable succeeded
+ * @base: CRTC object
+ * @enabled: Records whether crtc_enable succeeded
+ * @pending_needs_vblank: Records whether pending config operation needs a VBlank to finish
+ * @event: VBlank event to signal upon completion of state update
* @hwlayers: Array of mtk_crtc_hw_layer structures, one for each overlay plane
* @hwlayer_nr: Number of hwlayers
- * @mmsys_dev: pointer to the mmsys device for configuration registers
- * @mutex: handle to one of the ten disp_mutex streams
- * @ddp_comp_nr: number of components in ddp_comp
- * @ddp_comp: array of pointers the mtk_ddp_comp structures used by this crtc
- *
- * TODO: Needs update: this header is missing a bunch of member descriptions.
+ * @pending_planes: Planes pending atomic configuration operation
+ * @pending_async_planes: Planes pending asynchronous configuration operation
+ * @cmdq_client: CMDQ Mailbox Client structure
+ * @cmdq_handle: Handle to CMDQ Packet structure, used to send a packet
+ * @cmdq_event: Bitmask of GCE Events that CMDQ listens to (to send packets on event)
+ * @cmdq_vblank_cnt: Number of VBlanks after which CMDQ packet sending operation times out
+ * @cb_blocking_queue: Wait queue for sending blocking command packet through CMDQ Mailbox
+ * @mmsys_dev: Pointer to the MMSYS device for configuration registers
+ * @dma_dev: Pointer to the DMA device (usually linked to an IOMMU)
+ * @mutex: Pointer to the MediaTek MuteX device for HW triggers mute/unmuting
+ * @ddp_comp_nr: Number of HW components in ddp_comp structure
+ * @ddp_comp: Array of HW components used in one Display Controller pipeline
+ * @num_conn_routes: Number of alternative connection routes for a pipeline
+ * @conn_routes: Array of HW components usable as alternative connection route
+ * @hw_lock: Display HW access mutex lock
+ * @config_updating: Tracks whether an asynchronous config update operation is in progress
+ * @config_lock: Spinlock to protect config_updating variable
*/
struct mtk_crtc {
struct drm_crtc base;
@@ -82,10 +95,8 @@ struct mtk_crtc {
unsigned int num_conn_routes;
const struct mtk_drm_route *conn_routes;
- /* lock for display hardware access */
struct mutex hw_lock;
bool config_updating;
- /* lock for config_updating to cmd buffer */
spinlock_t config_lock;
};
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 16/42] drm/mediatek: mtk_crtc: Minimize spinlocked time in cmdq callback
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (14 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 15/42] drm/mediatek: mtk_crtc: Complete documentation for struct mtk_crtc AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 17/42] drm/mediatek: mtk_crtc: Dynamically find vblank/cfg component indices AngeloGioacchino Del Regno
` (25 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In ddp_cmdq_cb (the CMDQ mailbox callback), the config_lock spin
lock is being locked to read the config_updating variable in the
mtk_crtc structure, as, if configuration is updating, the callback
function shall not run (or shall run at a later time).
It is therefore unnecessary to keep the spinlock until the end of
the function, in case pending config, planes, or async planes
bools need to be updated.
Though the cmdq callback is not a performance path in this case,
this may be running for each frame that is pushed to the display,
so from 30 (or less) up to 144 times (or more) per second.
Add a temporary "cfg_updating" variable to aid with readability,
and unlock the spinlock as soon as the config_updating variable
read operation is done as a micro-optimization.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_crtc.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index e543fae9c580..35e78ece899a 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -287,6 +287,7 @@ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
struct mtk_crtc_state *state;
unsigned int i;
unsigned long flags;
+ bool cfg_updating;
/* release GCE HW usage and start autosuspend */
pm_runtime_mark_last_busy(cmdq_cl->chan->mbox->dev);
@@ -298,7 +299,10 @@ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
state = to_mtk_crtc_state(mtk_crtc->base.state);
spin_lock_irqsave(&mtk_crtc->config_lock, flags);
- if (mtk_crtc->config_updating)
+ cfg_updating = mtk_crtc->config_updating;
+ spin_unlock_irqrestore(&mtk_crtc->config_lock, flags);
+
+ if (cfg_updating)
goto ddp_cmdq_cb_out;
state->pending_config = false;
@@ -328,14 +332,11 @@ static void ddp_cmdq_cb(struct mbox_client *cl, void *mssg)
}
ddp_cmdq_cb_out:
-
if (mtk_crtc->pending_needs_vblank) {
mtk_crtc_finish_page_flip(mtk_crtc);
mtk_crtc->pending_needs_vblank = false;
}
- spin_unlock_irqrestore(&mtk_crtc->config_lock, flags);
-
mtk_crtc->cmdq_vblank_cnt = 0;
wake_up(&mtk_crtc->cb_blocking_queue);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 17/42] drm/mediatek: mtk_crtc: Dynamically find vblank/cfg component indices
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (15 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 16/42] drm/mediatek: mtk_crtc: Minimize spinlocked time in cmdq callback AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 18/42] soc: mediatek: mtk-mmsys: Migrate to new Multimedia DDP HW indexing AngeloGioacchino Del Regno
` (24 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
As of now mtk_crtc assumes that, on all MediaTek SoCs, both the
vblank and configuration components are the same one, and also
that this would always be the first one in a display pipeline.
This is not true!
Or at least, it's true for the display pipelines supported by the
legacy SoCs like MT8173, and also for the ones that are currently
used in the upstream boards on more recent SoCs like MT8188/95,
but for the latter ones it just happens to be like this because
of how the boards are configured.
This is done both in preparation for adding support for complex
Display Controller pipelines like needed in MT8196 and MT8894, but
also for supporting display pipelines in MT8188/89/95 (and others
from the same generation) that are not starting with a component
that handles both vblank and layer configuration at the same time.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_crtc.c | 56 ++++++++++++++++++++++++++---
1 file changed, 51 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index 35e78ece899a..6a1af60de469 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -61,6 +61,8 @@ struct mtk_crtc_hw_layer {
* @mutex: Pointer to the MediaTek MuteX device for HW triggers mute/unmuting
* @ddp_comp_nr: Number of HW components in ddp_comp structure
* @ddp_comp: Array of HW components used in one Display Controller pipeline
+ * @vblank_comp_idx: Index of HW component where to enable sending VBlanks
+ * @config_comp_idx: Index of main HW component to use for plane configuration
* @num_conn_routes: Number of alternative connection routes for a pipeline
* @conn_routes: Array of HW components usable as alternative connection route
* @hw_lock: Display HW access mutex lock
@@ -92,6 +94,8 @@ struct mtk_crtc {
struct mtk_mutex *mutex;
unsigned int ddp_comp_nr;
struct mtk_ddp_comp **ddp_comp;
+ s8 vblank_comp_idx;
+ s8 config_comp_idx;
unsigned int num_conn_routes;
const struct mtk_drm_route *conn_routes;
@@ -522,7 +526,7 @@ static void mtk_crtc_ddp_config(struct drm_crtc *crtc,
{
struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
struct mtk_crtc_state *state = to_mtk_crtc_state(mtk_crtc->base.state);
- struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
+ struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[mtk_crtc->config_comp_idx];
unsigned int i;
/*
@@ -692,7 +696,7 @@ static void mtk_crtc_ddp_irq(void *data)
static int mtk_crtc_enable_vblank(struct drm_crtc *crtc)
{
struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
- struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
+ struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[mtk_crtc->vblank_comp_idx];
mtk_ddp_comp_enable_vblank(comp);
@@ -702,7 +706,7 @@ static int mtk_crtc_enable_vblank(struct drm_crtc *crtc)
static void mtk_crtc_disable_vblank(struct drm_crtc *crtc)
{
struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
- struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
+ struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[mtk_crtc->vblank_comp_idx];
mtk_ddp_comp_disable_vblank(comp);
}
@@ -815,7 +819,7 @@ static void mtk_crtc_atomic_enable(struct drm_crtc *crtc,
struct drm_atomic_commit *state)
{
struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
- struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
+ struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[mtk_crtc->config_comp_idx];
struct drm_device *dev = mtk_crtc->base.dev;
int ret;
@@ -843,7 +847,7 @@ static void mtk_crtc_atomic_disable(struct drm_crtc *crtc,
struct drm_atomic_commit *state)
{
struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
- struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[0];
+ struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[mtk_crtc->config_comp_idx];
struct drm_device *dev = mtk_crtc->base.dev;
int i;
@@ -1181,6 +1185,10 @@ int mtk_crtc_create(struct drm_device *drm_dev,
return ret;
}
+ /* Component 0 would be valid so initialize vblank and config idx to -EINVAL */
+ mtk_crtc->vblank_comp_idx = -EINVAL;
+ mtk_crtc->config_comp_idx = -EINVAL;
+
for (i = 0, j = 0; i < mtk_crtc->ddp_comp_nr; i++, j++) {
unsigned int comp_id = output_path->comp[i].type;
struct mtk_ddp_comp *comp;
@@ -1203,12 +1211,50 @@ int mtk_crtc_create(struct drm_device *drm_dev,
if (comp->funcs->ctm_set)
has_ctm = true;
+
+ /*
+ * Assumes that there can only be one vblank enabler per CRTC,
+ * and that should there be more than one, the one that should
+ * handle vblanks has to be the bottom-most HW component.
+ */
+ if (mtk_crtc->vblank_comp_idx < 0 && comp->funcs->enable_vblank)
+ mtk_crtc->vblank_comp_idx = j;
+
+ /*
+ * Assumes that there can only be one main configuration
+ * component per CRTC, and that if more than one has to
+ * be configured for at each frame, the main one would
+ * take care of the config chain.
+ *
+ * As a note, such component has specific characteristics:
+ * - It is configurable, and supports per-layer properties;
+ * - It is a main layer component and not a layer stage;
+ * - It is always the first one (the bottom-most) in the
+ * pipeline that has the characteristics explaned above.
+ *
+ * Such hardware is usually an OVL, RDMA or exDMA.
+ *
+ * This may change in the future with more complex pipelines.
+ */
+ if (mtk_crtc->config_comp_idx < 0 && comp->funcs->config &&
+ comp->funcs->layer_config && comp->funcs->layer_nr)
+ mtk_crtc->config_comp_idx = j;
}
mtk_ddp_comp_register_vblank_cb(comp, mtk_crtc_ddp_irq,
&mtk_crtc->base);
}
+ if (mtk_crtc->config_comp_idx < 0) {
+ dev_err(dev, "No HW component for layer configuration. Bailing out.\n");
+ return -EINVAL;
+ }
+
+ if (mtk_crtc->vblank_comp_idx < 0) {
+ dev_info(dev, "No vblank enabler component found! Expect timeouts.\n");
+ mtk_crtc->vblank_comp_idx = 0;
+ }
+
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 18/42] soc: mediatek: mtk-mmsys: Migrate to new Multimedia DDP HW indexing
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (16 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 17/42] drm/mediatek: mtk_crtc: Dynamically find vblank/cfg component indices AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 19/42] drm/mediatek: Fully migrate to new Display Controller " AngeloGioacchino Del Regno
` (23 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
The mediatek-drm driver is ready to switch to the new Multimedia
Subsystem Display Controller HW indexing.
Perform the switch by:
- Adding new "from_comp_inst" and "to_comp_inst" members in the
Multimedia Subsystem HW Routes structure (mtk_mmsys_routes);
- Changing the MMSYS_ROUTE() macro to use those, which performs
the migration of all SoCs in one go (as all of them use this
macro to declare their route entries);
- Adding new mtk_mmsys_hw_connect() and mtk_mmsys_hw_disconnect()
functions, making use of the new HW Component Type-Instance
indexing.
Unfortunately, this change needs to go along with the related one
in the mediatek-drm driver, otherwise functionality of the Display
Controller will regress.
The only way to make this possible in two steps is to duplicate
all of the routes structure arrays for all of the SoCs, which
would result in a total of around ~1200 lines changed twice, and
that ignores the big increase in size for this driver during the
migration process so, in order to avoid useless bloat, I opted
for an inter-dependency between the two changes: mediatek-drm
and mtk-mmsys.
Acked-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/soc/mediatek/mtk-mmsys.c | 99 ++++++++++++++++++++------
drivers/soc/mediatek/mtk-mmsys.h | 14 ++--
include/linux/soc/mediatek/mtk-mmsys.h | 16 ++---
3 files changed, 90 insertions(+), 39 deletions(-)
diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c
index 21f05fac2cb7..24296ebcbae3 100644
--- a/drivers/soc/mediatek/mtk-mmsys.c
+++ b/drivers/soc/mediatek/mtk-mmsys.c
@@ -1,7 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2014 MediaTek Inc.
- * Author: James Liao <jamesjj.liao@mediatek.com>
+ * James Liao <jamesjj.liao@mediatek.com>
+ *
+ * Copyrignt (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
#include <linux/delay.h>
@@ -191,38 +194,90 @@ static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask,
writel_relaxed(tmp, mmsys->regs + offset);
}
-void mtk_mmsys_ddp_connect(struct device *dev,
- enum mtk_ddp_comp_id cur,
- enum mtk_ddp_comp_id next)
+/**
+ * mtk_mmsys_hw_connect - Connect MultiMedia Subsystem (MMSYS) Hardware IPs
+ * @dev: Device pointer
+ * @src_type: Type of the Source IP
+ * @src_hw_inst_id: Hardware instance of the Source IP
+ * @dst_type: Type of the Destination IP
+ * @dst_hw_inst_id: Hardware instance of the Destination IP
+ *
+ * This function connects one MultiMedia Subsystem (MMSYS) related hardware
+ * to another (in the same subsystem), depending on supported connections.
+ * In short, this connects "Source" to "Destination", as in, enables sending
+ * data from a Source IP to a Destination IP.
+ *
+ * As a final note - depending on the SoC and on the specific IPs, it may
+ * also be possible to connect multiple Sources to a single Destination.
+ *
+ * Examples below follow this format to explain hardware components:
+ * [Source Type][Instance ID] -> [Destination Type] [Instance ID]
+ *
+ * Example 1 - Single Source to Destination
+ * GAMMA 0 -> DITHER 0
+ *
+ * Example 2 - Multiple Sources to Single Destination
+ * MDP_RDMA 0 -----\
+ * |
+ * v
+ * MDP_RDMA 1 ---> MERGE 1 \
+ * MDP_RDMA 2 ---> MERGE 2 -\
+ * >> ETHDR_MIXER 0
+ * (other 1) ---> MERGE 3 -/
+ * (other 2) ---> MERGE 4 /
+ *
+ * Note that in Example 2, some components are not chained together, but
+ * connected in parallel to a destination.
+ */
+void mtk_mmsys_hw_connect(struct device *dev,
+ enum mtk_ddp_comp_type src_type, u8 src_hw_inst_id,
+ enum mtk_ddp_comp_type dst_type, u8 dst_hw_inst_id)
{
struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
const struct mtk_mmsys_routes *routes = mmsys->data->routes;
- int i;
- for (i = 0; i < mmsys->data->num_routes; i++)
- if (cur == routes[i].from_comp && next == routes[i].to_comp)
- mtk_mmsys_update_bits(mmsys, routes[i].addr, routes[i].mask,
- routes[i].val, NULL);
+ for (int i = 0; i < mmsys->data->num_routes; i++) {
+ if (src_type != routes[i].from_comp_type ||
+ src_hw_inst_id != routes[i].from_comp_inst ||
+ dst_type != routes[i].to_comp_type ||
+ dst_hw_inst_id != routes[i].to_comp_inst)
+ continue;
- if (mmsys->data->vsync_len)
- mtk_mmsys_update_bits(mmsys, MT8188_VDO1_MIXER_VSYNC_LEN, GENMASK(31, 0),
- mmsys->data->vsync_len, NULL);
+ mtk_mmsys_update_bits(mmsys, routes[i].addr, routes[i].mask, routes[i].val, NULL);
+ dev_dbg(dev, "Connected %u-%u to %u-%u\n",
+ src_type, src_hw_inst_id, dst_type, dst_hw_inst_id);
+ }
}
-EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_connect);
-
-void mtk_mmsys_ddp_disconnect(struct device *dev,
- enum mtk_ddp_comp_id cur,
- enum mtk_ddp_comp_id next)
+EXPORT_SYMBOL_NS_GPL(mtk_mmsys_hw_connect, "MTK_MMSYS");
+
+/**
+ * mtk_mmsys_hw_disconnect - Disconnect MultiMedia Subsystem (MMSYS) Hardware IPs
+ * @dev: Device pointer
+ * @src_type: Type of the Source IP
+ * @src_hw_inst_id: Hardware instance of the Source IP
+ * @dst_type: Type of the Destination IP
+ * @dst_hw_inst_id: Hardware instance of the Destination IP
+ */
+void mtk_mmsys_hw_disconnect(struct device *dev,
+ enum mtk_ddp_comp_type src_type, u8 src_hw_inst_id,
+ enum mtk_ddp_comp_type dst_type, u8 dst_hw_inst_id)
{
struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
const struct mtk_mmsys_routes *routes = mmsys->data->routes;
- int i;
- for (i = 0; i < mmsys->data->num_routes; i++)
- if (cur == routes[i].from_comp && next == routes[i].to_comp)
- mtk_mmsys_update_bits(mmsys, routes[i].addr, routes[i].mask, 0, NULL);
+ for (int i = 0; i < mmsys->data->num_routes; i++) {
+ if (src_type != routes[i].from_comp_type ||
+ src_hw_inst_id != routes[i].from_comp_inst ||
+ dst_type != routes[i].to_comp_type ||
+ dst_hw_inst_id != routes[i].to_comp_inst)
+ continue;
+
+ mtk_mmsys_update_bits(mmsys, routes[i].addr, routes[i].mask, 0, NULL);
+ dev_dbg(dev, "Disconnected %u-%u from %u-%u\n",
+ src_type, src_hw_inst_id, dst_type, dst_hw_inst_id);
+ }
}
-EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_disconnect);
+EXPORT_SYMBOL_NS_GPL(mtk_mmsys_hw_disconnect, "MTK_MMSYS");
void mtk_mmsys_merge_async_config(struct device *dev, int idx, int width, int height,
struct cmdq_pkt *cmdq_pkt)
diff --git a/drivers/soc/mediatek/mtk-mmsys.h b/drivers/soc/mediatek/mtk-mmsys.h
index d534d43aad6f..5c9319f3a2bb 100644
--- a/drivers/soc/mediatek/mtk-mmsys.h
+++ b/drivers/soc/mediatek/mtk-mmsys.h
@@ -80,19 +80,13 @@
#define MMSYS_RST_NR(bank, bit) (((bank) * 32) + (bit))
-/* Temporary compatibility definitions */
-#define DDP_COMPONENT_CCORR0 DDP_COMPONENT_CCORR
-#define DDP_COMPONENT_UFOE0 DDP_COMPONENT_UFOE
-#define DDP_COMPONENT_GAMMA0 DDP_COMPONENT_GAMMA
-#define DDP_COMPONENT_ETHDR_MIXER0 DDP_COMPONENT_ETHDR_MIXER
-
/*
* This macro adds a compile time check to make sure that the in/out
* selection bit(s) fit in the register mask, similar to bitfield
* macros, but this does not transform the value.
*/
#define MMSYS_ROUTE(from, fsid, to, tsid, reg_addr, reg_mask, selection) \
- { DDP_COMPONENT_##from##fsid, DDP_COMPONENT_##to##tsid, reg_addr, reg_mask, \
+ { MTK_DISP_##from, fsid, MTK_DISP_##to, tsid, reg_addr, reg_mask, \
(__BUILD_BUG_ON_ZERO_MSG((reg_mask) == 0, "Invalid mask") + \
__BUILD_BUG_ON_ZERO_MSG(~(reg_mask) & (selection), \
#selection " does not fit in " \
@@ -101,8 +95,10 @@
}
struct mtk_mmsys_routes {
- u32 from_comp;
- u32 to_comp;
+ u8 from_comp_type;
+ u8 from_comp_inst;
+ u8 to_comp_type;
+ u8 to_comp_inst;
u32 addr;
u32 mask;
u32 val;
diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h
index bbdd0b01927d..f67f21d04163 100644
--- a/include/linux/soc/mediatek/mtk-mmsys.h
+++ b/include/linux/soc/mediatek/mtk-mmsys.h
@@ -118,14 +118,6 @@ enum mtk_ddp_comp_type {
MTK_DDP_COMP_TYPE_MAX
};
-void mtk_mmsys_ddp_connect(struct device *dev,
- enum mtk_ddp_comp_id cur,
- enum mtk_ddp_comp_id next);
-
-void mtk_mmsys_ddp_disconnect(struct device *dev,
- enum mtk_ddp_comp_id cur,
- enum mtk_ddp_comp_id next);
-
void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val);
void mtk_mmsys_merge_async_config(struct device *dev, int idx, int width,
@@ -134,6 +126,14 @@ void mtk_mmsys_merge_async_config(struct device *dev, int idx, int width,
void mtk_mmsys_hdr_config(struct device *dev, int be_width, int be_height,
struct cmdq_pkt *cmdq_pkt);
+void mtk_mmsys_hw_connect(struct device *dev,
+ enum mtk_ddp_comp_type src_type, u8 src_hw_inst_id,
+ enum mtk_ddp_comp_type dst_type, u8 dst_hw_inst_id);
+
+void mtk_mmsys_hw_disconnect(struct device *dev,
+ enum mtk_ddp_comp_type src_type, u8 src_hw_inst_id,
+ enum mtk_ddp_comp_type dst_type, u8 dst_hw_inst_id);
+
void mtk_mmsys_mixer_in_config(struct device *dev, int idx, bool alpha_sel, u16 alpha,
u8 mode, u32 biwidth, struct cmdq_pkt *cmdq_pkt);
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 19/42] drm/mediatek: Fully migrate to new Display Controller HW indexing
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (17 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 18/42] soc: mediatek: mtk-mmsys: Migrate to new Multimedia DDP HW indexing AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 20/42] drm/mediatek: mtk_dpi: Pass parameters with new mtk_dpi_sync structure AngeloGioacchino Del Regno
` (22 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Perform a full migration to HW Type -> HW Instance ID indexing
for all of the currently supported Display Controller hardware
sub-components.
This allows to remove the big fixed-size catch-all components
array (that contains as many element as much as the number of
supported hardware and number of instances of that), which is
currently growing bigger and bigger at every sub-ip support
addition in mediatek-drm.
Note that this cleanup became necessary seen the need to add
support for new components found in MT8196, MT8994 and other
variants of it, and of course those SoCs won't be the last
ones to be upstreamed... so the size of that array would get
out of control pretty fast (and again, it's already very big).
As a side effect, while saving memory compared to before this
change, this also allows to have up to 24 (as an extensible fixed
size declared in this driver) instances of the same HW Type with
no further increase in memory footprint.
Similarly, adding support for new hardware will not produce an
increase of memory footprint on all SoCs (if not only temporarily
while the probe process is in place) as there's no more catch-all
array, but only a dynamically allocated list of per display output
components.
Unfortunately, this change needs to go along with the related one
in the mtk-mmsys driver, otherwise functionality of the Display
Controller will regress.
The only way to make this possible in two steps is to duplicate
all of the routes structure arrays for all of the SoCs, which
would result in a total of around ~1200 lines changed twice, and
that ignores the big increase in size for this driver during the
migration process so, in order to avoid useless bloat, I opted
for an inter-dependency between the two changes: mediatek-drm
and mtk-mmsys.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_crtc.c | 126 ++--
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 131 ++--
drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 28 +-
drivers/gpu/drm/mediatek/mtk_disp_drv.h | 9 +-
.../gpu/drm/mediatek/mtk_disp_ovl_adaptor.c | 108 ++--
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 74 +--
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 9 +-
drivers/gpu/drm/mediatek/mtk_drm_legacy.c | 602 +++++++++---------
drivers/gpu/drm/mediatek/mtk_drm_legacy.h | 3 +-
9 files changed, 538 insertions(+), 552 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index 6a1af60de469..ee23a50cf4d1 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -415,28 +415,32 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
}
for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) {
- if (!mtk_ddp_comp_connect(mtk_crtc->ddp_comp[i], mtk_crtc->mmsys_dev,
- mtk_crtc->ddp_comp[i + 1]->id))
- mtk_mmsys_ddp_connect(mtk_crtc->mmsys_dev,
- mtk_crtc->ddp_comp[i]->id,
- mtk_crtc->ddp_comp[i + 1]->id);
- if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
- mtk_mutex_add_comp(mtk_crtc->mutex,
- mtk_crtc->ddp_comp[i]->id);
-
- /* For now, only single DSI is supported */
- if (mtk_crtc->ddp_comp[i]->id >= DDP_COMPONENT_DSI0 &&
- mtk_crtc->ddp_comp[i]->id <= DDP_COMPONENT_DSI3)
- if (!comp_dsi)
- comp_dsi = mtk_crtc->ddp_comp[i];
-
- if (mtk_crtc->ddp_comp[i]->id == DDP_COMPONENT_DSC0 ||
- mtk_crtc->ddp_comp[i]->id == DDP_COMPONENT_DSC1)
- if (!comp_dsc)
- comp_dsc = mtk_crtc->ddp_comp[i];
+ struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
+ struct mtk_ddp_comp *next = mtk_crtc->ddp_comp[i + 1];
+
+ if (!mtk_ddp_comp_connect(comp, mtk_crtc->mmsys_dev, next))
+ mtk_mmsys_hw_connect(mtk_crtc->mmsys_dev,
+ comp->type, comp->inst_id,
+ next->type, next->inst_id);
+
+ if (!mtk_ddp_comp_add(comp, mtk_crtc->mutex))
+ mtk_mutex_add_trigger(mtk_crtc->mutex,
+ comp->type, comp->inst_id,
+ comp->mtx_trig_id);
+
+ /* For DSC only single DSI is supported at the moment */
+ if (comp->type == MTK_DISP_DSI && !comp_dsi)
+ comp_dsi = mtk_crtc->ddp_comp[i];
+
+ if (comp->type == MTK_DISP_DSC && !comp_dsc)
+ comp_dsc = mtk_crtc->ddp_comp[i];
}
if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
- mtk_mutex_add_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id);
+ mtk_mutex_add_trigger(mtk_crtc->mutex,
+ mtk_crtc->ddp_comp[i]->type,
+ mtk_crtc->ddp_comp[i]->inst_id,
+ mtk_crtc->ddp_comp[i]->mtx_trig_id);
+
mtk_mutex_enable(mtk_crtc->mutex);
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
@@ -493,21 +497,31 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_crtc *mtk_crtc)
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
- mtk_mutex_remove_comp(mtk_crtc->mutex,
- mtk_crtc->ddp_comp[i]->id);
+ mtk_mutex_remove_trigger(mtk_crtc->mutex,
+ mtk_crtc->ddp_comp[i]->type,
+ mtk_crtc->ddp_comp[i]->inst_id,
+ mtk_crtc->ddp_comp[i]->mtx_trig_id);
mtk_mutex_disable(mtk_crtc->mutex);
for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) {
- if (!mtk_ddp_comp_disconnect(mtk_crtc->ddp_comp[i], mtk_crtc->mmsys_dev,
- mtk_crtc->ddp_comp[i + 1]->id))
- mtk_mmsys_ddp_disconnect(mtk_crtc->mmsys_dev,
- mtk_crtc->ddp_comp[i]->id,
- mtk_crtc->ddp_comp[i + 1]->id);
+ struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
+ struct mtk_ddp_comp *next = mtk_crtc->ddp_comp[i + 1];
+
+ if (!mtk_ddp_comp_disconnect(comp, mtk_crtc->mmsys_dev, next))
+ mtk_mmsys_hw_disconnect(mtk_crtc->mmsys_dev,
+ comp->type, comp->inst_id,
+ next->type, next->inst_id);
+
if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
- mtk_mutex_remove_comp(mtk_crtc->mutex,
- mtk_crtc->ddp_comp[i]->id);
+ mtk_mutex_remove_trigger(mtk_crtc->mutex,
+ mtk_crtc->ddp_comp[i]->type,
+ mtk_crtc->ddp_comp[i]->inst_id,
+ mtk_crtc->ddp_comp[i]->mtx_trig_id);
}
if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
- mtk_mutex_remove_comp(mtk_crtc->mutex, mtk_crtc->ddp_comp[i]->id);
+ mtk_mutex_remove_trigger(mtk_crtc->mutex,
+ mtk_crtc->ddp_comp[i]->type,
+ mtk_crtc->ddp_comp[i]->inst_id,
+ mtk_crtc->ddp_comp[i]->mtx_trig_id);
mtk_crtc_ddp_clk_disable(mtk_crtc);
mtk_mutex_unprepare(mtk_crtc->mutex);
@@ -738,15 +752,16 @@ static void mtk_crtc_update_output(struct drm_crtc *crtc,
const struct mtk_drm_route *conn_route = &mtk_crtc->conn_routes[i];
struct mtk_ddp_comp *comp;
- comp = mtk_ddp_comp_find_by_id(&priv->hlist, conn_route->route_ddp);
+ comp = mtk_ddp_comp_find_by_id(&priv->hlist, conn_route->route_ddp_type,
+ conn_route->route_ddp_inst_id);
if (!comp)
continue;
if (comp->encoder_index >= 0 &&
(encoder_mask & BIT(comp->encoder_index))) {
mtk_crtc->ddp_comp[mtk_crtc->ddp_comp_nr - 1] = comp;
- dev_dbg(dev, "Add comp_id: %d at path index %d\n",
- comp->id, mtk_crtc->ddp_comp_nr - 1);
+ dev_dbg(dev, "Add comp %u-%u at path index %d\n",
+ comp->type, comp->inst_id, mtk_crtc->ddp_comp_nr - 1);
break;
}
}
@@ -1142,25 +1157,15 @@ int mtk_crtc_create(struct drm_device *drm_dev,
crtc_i++;
for (i = 0; i < output_path[i].len; i++) {
- enum mtk_ddp_comp_id comp_id = output_path->comp[i].type;
- struct device_node *node;
+ enum mtk_ddp_comp_type comp_type = output_path->comp[i].type;
+ u8 comp_inst = output_path->comp[i].inst_id;
struct mtk_ddp_comp *comp;
- node = priv->comp_node[comp_id];
- comp = mtk_ddp_comp_find_by_id(&priv->hlist, comp_id);
-
- /* Not all drm components have a DTS device node, such as ovl_adaptor,
- * which is the drm bring up sub driver
- */
- if (!node && comp_id != DDP_COMPONENT_DRM_OVL_ADAPTOR) {
- dev_info(dev,
- "Not creating crtc %d because component %d is disabled or missing\n",
- crtc_i, comp_id);
- return 0;
- }
-
+ comp = mtk_ddp_comp_find_by_id(&priv->hlist, comp_type, comp_inst);
if (!comp || !comp->dev) {
- dev_err(dev, "Component %pOF not initialized\n", node);
+ dev_err(dev,
+ "CRTC%d: Component type=%u inst=%u not initialized\n",
+ crtc_i, comp_type, comp_inst);
return -ENODEV;
}
}
@@ -1190,13 +1195,14 @@ int mtk_crtc_create(struct drm_device *drm_dev,
mtk_crtc->config_comp_idx = -EINVAL;
for (i = 0, j = 0; i < mtk_crtc->ddp_comp_nr; i++, j++) {
- unsigned int comp_id = output_path->comp[i].type;
+ enum mtk_ddp_comp_type comp_type = output_path->comp[i].type;
+ u8 comp_inst = output_path->comp[i].inst_id;
struct mtk_ddp_comp *comp;
- comp = mtk_ddp_comp_find_by_id(&priv->hlist, comp_id);
+ comp = mtk_ddp_comp_find_by_id(&priv->hlist, comp_type, comp_inst);
if (!comp) {
j--;
- dev_dbg(dev, "Cannot find component %d.\n", comp_id);
+ dev_dbg(dev, "Cannot find component %u-%u.\n", comp_type, comp_inst);
continue;
}
mtk_crtc->ddp_comp[j] = comp;
@@ -1308,7 +1314,9 @@ int mtk_crtc_create(struct drm_device *drm_dev,
* In the case of ovl_adaptor sub driver, it needs to use the
* dma_dev_get function to get representative dma dev.
*/
- dma_comp = mtk_ddp_comp_find_by_id(&priv->hlist, output_path->comp[0].type);
+ dma_comp = mtk_ddp_comp_find_by_id(&priv->hlist,
+ output_path->comp[0].type,
+ output_path->comp[0].inst_id);
if (dma_comp == NULL) {
dev_err(dev, "Could not find appropriate DMA device!\n");
return -EINVAL;
@@ -1370,13 +1378,15 @@ int mtk_crtc_create(struct drm_device *drm_dev,
if (conn_routes) {
for (i = 0; i < num_conn_routes; i++) {
- unsigned int comp_id = conn_routes[i].route_ddp;
- struct device_node *node = priv->comp_node[comp_id];
- struct mtk_ddp_comp *comp = mtk_ddp_comp_find_by_id(&priv->hlist, comp_id);
+ enum mtk_ddp_comp_type comp_type = conn_routes[i].route_ddp_type;
+ u8 comp_inst = conn_routes[i].route_ddp_inst_id;
+ struct mtk_ddp_comp *comp;
+ comp = mtk_ddp_comp_find_by_id(&priv->hlist, comp_type, comp_inst);
if (!comp || !comp->dev) {
- dev_dbg(dev, "comp_id:%d, Component %pOF not initialized\n",
- comp_id, node);
+ dev_dbg(dev, "Cannot find conn_route component %u-%u.\n",
+ comp_type, comp_inst);
+
/* mark encoder_index to -1, if route comp device is not enabled */
if (comp)
comp->encoder_index = -1;
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index f45588ae7342..3be891f740d3 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -4,6 +4,10 @@
* Authors:
* YT Shen <yt.shen@mediatek.com>
* CK Hu <ck.hu@mediatek.com>
+ *
+ * Major refactoring
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
#include <linux/clk.h>
@@ -428,65 +432,36 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_DSI] = "dsi",
};
-struct mtk_ddp_comp_match {
- enum mtk_ddp_comp_type type;
- int alias_id;
- const struct mtk_ddp_comp_funcs *funcs;
-};
-
-static const struct mtk_ddp_comp_match mtk_ddp_matches[DDP_COMPONENT_DRM_ID_MAX] = {
- [DDP_COMPONENT_AAL0] = { MTK_DISP_AAL, 0, &ddp_aal },
- [DDP_COMPONENT_AAL1] = { MTK_DISP_AAL, 1, &ddp_aal },
- [DDP_COMPONENT_BLS] = { MTK_DISP_BLS, 0, NULL },
- [DDP_COMPONENT_CCORR] = { MTK_DISP_CCORR, 0, &ddp_ccorr },
- [DDP_COMPONENT_COLOR0] = { MTK_DISP_COLOR, 0, &ddp_color },
- [DDP_COMPONENT_COLOR1] = { MTK_DISP_COLOR, 1, &ddp_color },
- [DDP_COMPONENT_DITHER0] = { MTK_DISP_DITHER, 0, &ddp_dither },
- [DDP_COMPONENT_DP_INTF0] = { MTK_DISP_DP_INTF, 0, &ddp_dpi },
- [DDP_COMPONENT_DP_INTF1] = { MTK_DISP_DP_INTF, 1, &ddp_dpi },
- [DDP_COMPONENT_DPI0] = { MTK_DISP_DPI, 0, &ddp_dpi },
- [DDP_COMPONENT_DPI1] = { MTK_DISP_DPI, 1, &ddp_dpi },
- [DDP_COMPONENT_DRM_OVL_ADAPTOR] = { MTK_DISP_OVL_ADAPTOR, 0, &ddp_ovl_adaptor },
- [DDP_COMPONENT_DSC0] = { MTK_DISP_DSC, 0, &ddp_dsc },
- [DDP_COMPONENT_DSC1] = { MTK_DISP_DSC, 1, &ddp_dsc },
- [DDP_COMPONENT_DSI0] = { MTK_DISP_DSI, 0, &ddp_dsi },
- [DDP_COMPONENT_DSI1] = { MTK_DISP_DSI, 1, &ddp_dsi },
- [DDP_COMPONENT_DSI2] = { MTK_DISP_DSI, 2, &ddp_dsi },
- [DDP_COMPONENT_DSI3] = { MTK_DISP_DSI, 3, &ddp_dsi },
- [DDP_COMPONENT_GAMMA] = { MTK_DISP_GAMMA, 0, &ddp_gamma },
- [DDP_COMPONENT_MERGE0] = { MTK_DISP_MERGE, 0, &ddp_merge },
- [DDP_COMPONENT_MERGE1] = { MTK_DISP_MERGE, 1, &ddp_merge },
- [DDP_COMPONENT_MERGE2] = { MTK_DISP_MERGE, 2, &ddp_merge },
- [DDP_COMPONENT_MERGE3] = { MTK_DISP_MERGE, 3, &ddp_merge },
- [DDP_COMPONENT_MERGE4] = { MTK_DISP_MERGE, 4, &ddp_merge },
- [DDP_COMPONENT_MERGE5] = { MTK_DISP_MERGE, 5, &ddp_merge },
- [DDP_COMPONENT_OD0] = { MTK_DISP_OD, 0, &ddp_od },
- [DDP_COMPONENT_OD1] = { MTK_DISP_OD, 1, &ddp_od },
- [DDP_COMPONENT_OVL0] = { MTK_DISP_OVL, 0, &ddp_ovl },
- [DDP_COMPONENT_OVL1] = { MTK_DISP_OVL, 1, &ddp_ovl },
- [DDP_COMPONENT_OVL_2L0] = { MTK_DISP_OVL_2L, 0, &ddp_ovl },
- [DDP_COMPONENT_OVL_2L1] = { MTK_DISP_OVL_2L, 1, &ddp_ovl },
- [DDP_COMPONENT_OVL_2L2] = { MTK_DISP_OVL_2L, 2, &ddp_ovl },
- [DDP_COMPONENT_POSTMASK0] = { MTK_DISP_POSTMASK, 0, &ddp_postmask },
- [DDP_COMPONENT_PWM0] = { MTK_DISP_PWM, 0, NULL },
- [DDP_COMPONENT_PWM1] = { MTK_DISP_PWM, 1, NULL },
- [DDP_COMPONENT_PWM2] = { MTK_DISP_PWM, 2, NULL },
- [DDP_COMPONENT_RDMA0] = { MTK_DISP_RDMA, 0, &ddp_rdma },
- [DDP_COMPONENT_RDMA1] = { MTK_DISP_RDMA, 1, &ddp_rdma },
- [DDP_COMPONENT_RDMA2] = { MTK_DISP_RDMA, 2, &ddp_rdma },
- [DDP_COMPONENT_RDMA4] = { MTK_DISP_RDMA, 4, &ddp_rdma },
- [DDP_COMPONENT_UFOE] = { MTK_DISP_UFOE, 0, &ddp_ufoe },
- [DDP_COMPONENT_WDMA0] = { MTK_DISP_WDMA, 0, &ddp_wdma },
- [DDP_COMPONENT_WDMA1] = { MTK_DISP_WDMA, 1, &ddp_wdma },
+static const struct mtk_ddp_comp_funcs *mtk_ddp_funcs[MTK_DDP_COMP_TYPE_MAX] = {
+ [MTK_DISP_AAL] = &ddp_aal,
+ [MTK_DISP_BLS] = NULL,
+ [MTK_DISP_CCORR] = &ddp_ccorr,
+ [MTK_DISP_COLOR] = &ddp_color,
+ [MTK_DISP_DITHER] = &ddp_dither,
+ [MTK_DISP_DSC] = &ddp_dsc,
+ [MTK_DISP_GAMMA] = &ddp_gamma,
+ [MTK_DISP_MERGE] = &ddp_merge,
+ [MTK_DISP_OD] = &ddp_od,
+ [MTK_DISP_OVL] = &ddp_ovl,
+ [MTK_DISP_OVL_2L] = &ddp_ovl,
+ [MTK_DISP_OVL_ADAPTOR] = &ddp_ovl_adaptor,
+ [MTK_DISP_POSTMASK] = &ddp_postmask,
+ [MTK_DISP_PWM] = NULL,
+ [MTK_DISP_RDMA] = &ddp_rdma,
+ [MTK_DISP_UFOE] = &ddp_ufoe,
+ [MTK_DISP_WDMA] = &ddp_wdma,
+ [MTK_DISP_DPI] = &ddp_dpi,
+ [MTK_DISP_DP_INTF] = &ddp_dpi,
+ [MTK_DISP_DSI] = &ddp_dsi,
};
static bool mtk_ddp_find_comp_dev_in_table(const struct mtk_drm_comp_list *hlist,
- const unsigned int comp_id,
+ const unsigned int comp_type,
struct device *dev)
{
struct mtk_ddp_comp *ddp_comp;
- hash_for_each_possible(hlist->ddp_list, ddp_comp, lnode, comp_id) {
+ hash_for_each_possible(hlist->ddp_list, ddp_comp, lnode, comp_type) {
if (ddp_comp->dev == dev)
return true;
}
@@ -518,42 +493,23 @@ static int mtk_ddp_comp_find_in_route(struct device *dev,
return -EINVAL;
for (i = 0; i < num_routes; i++)
- if (mtk_ddp_find_comp_dev_in_table(hlist, routes[i].route_ddp, dev))
+ if (mtk_ddp_find_comp_dev_in_table(hlist, routes[i].route_ddp_type, dev))
return BIT(routes[i].crtc_id);
return -ENODEV;
}
-static bool mtk_ddp_path_available(const struct mtk_drm_path_definition *output_path,
- struct device_node **comp_node)
-{
- unsigned int i;
-
- for (i = 0U; i < output_path->len; i++) {
- /* OVL_ADAPTOR doesn't have a device node */
- if (output_path->comp[i].type == DDP_COMPONENT_DRM_OVL_ADAPTOR)
- continue;
-
- if (!comp_node[output_path->comp[i].type])
- return false;
- }
-
- return true;
-}
-
int mtk_ddp_comp_get_id(struct device_node *node,
enum mtk_ddp_comp_type comp_type)
{
- int id = of_alias_get_id(node, mtk_ddp_comp_stem[comp_type]);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(mtk_ddp_matches); i++) {
- if (comp_type == mtk_ddp_matches[i].type &&
- (id < 0 || id == mtk_ddp_matches[i].alias_id))
- return i;
+ /* If there's an alias, return the ID from that */
+ if (mtk_ddp_comp_stem[comp_type]) {
+ int alias_id = of_alias_get_id(node, mtk_ddp_comp_stem[comp_type]);
+ if (alias_id >= 0)
+ return alias_id;
}
- return -EINVAL;
+ return 0;
}
int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev)
@@ -561,7 +517,7 @@ int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev)
struct mtk_drm_private *private = drm->dev_private;
const struct mtk_mmsys_driver_data *data;
struct mtk_drm_private *priv_n;
- int i = 0, j;
+ int i, j;
int ret;
for (j = 0; j < private->data->mmsys_dev_num; j++) {
@@ -674,24 +630,22 @@ static int mtk_ddp_comp_init_internal_comp(struct device *dev, struct device *co
int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
struct mtk_drm_comp_list *hlist,
- unsigned int comp_id)
+ enum mtk_ddp_comp_type comp_type, int comp_inst_id)
{
struct platform_device *comp_pdev;
struct mtk_ddp_comp *comp;
- enum mtk_ddp_comp_type type;
int ret;
- if (comp_id >= DDP_COMPONENT_DRM_ID_MAX)
+ if (comp_type >= MTK_DDP_COMP_TYPE_MAX)
return -EINVAL;
comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL);
if (!comp)
return -ENOMEM;
- type = mtk_ddp_matches[comp_id].type;
-
- comp->id = comp_id;
- comp->funcs = mtk_ddp_matches[comp_id].funcs;
+ comp->type = comp_type;
+ comp->inst_id = comp_inst_id;
+ comp->funcs = mtk_ddp_funcs[comp_type];
/* Not all drm components have a DTS device node, such as ovl_adaptor,
* which is the drm bring up sub driver
*/
@@ -716,13 +670,14 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
comp->mtx_trig_id = ret;
/* If there's no external driver for this component, allocate and init now */
- if (mtk_ddp_comp_is_internal_comp(type) || mtk_ddp_comp_is_backlight_comp(type)) {
+ if (mtk_ddp_comp_is_internal_comp(comp->type) ||
+ mtk_ddp_comp_is_backlight_comp(comp->type)) {
ret = mtk_ddp_comp_init_internal_comp(dev, comp->dev);
if (ret)
return ret;
}
end:
- hash_add(hlist->ddp_list, &comp->lnode, comp->id);
+ hash_add(hlist->ddp_list, &comp->lnode, comp->type);
return 0;
}
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index a7ed46a95037..ab9d5e4dfb98 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -16,6 +16,7 @@
#include <drm/drm_modes.h>
#define MTK_DISP_CONTROLLER_MAX_COMP_PER_PATH 24
+#define MTK_DISP_CONTROLLER_MAX_HW_COMP_INSTANCE 32
struct device;
struct device_node;
@@ -70,8 +71,10 @@ struct mtk_ddp_comp_funcs {
const u32 *(*get_formats)(struct device *dev);
size_t (*get_num_formats)(struct device *dev);
bool (*is_afbc_supported)(struct device *dev);
- void (*connect)(struct device *dev, struct device *mmsys_dev, unsigned int next);
- void (*disconnect)(struct device *dev, struct device *mmsys_dev, unsigned int next);
+ void (*connect)(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next);
+ void (*disconnect)(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next);
void (*add)(struct device *dev, struct mtk_mutex *mutex);
void (*remove)(struct device *dev, struct mtk_mutex *mutex);
unsigned int (*encoder_index)(struct device *dev);
@@ -81,7 +84,8 @@ struct mtk_ddp_comp_funcs {
struct mtk_ddp_comp {
struct device *dev;
int irq;
- unsigned int id;
+ enum mtk_ddp_comp_type type;
+ u8 inst_id;
u8 mtx_trig_id;
int encoder_index;
const struct mtk_ddp_comp_funcs *funcs;
@@ -326,20 +330,20 @@ static inline bool mtk_ddp_comp_remove(struct mtk_ddp_comp *comp, struct mtk_mut
}
static inline bool mtk_ddp_comp_connect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
- unsigned int next)
+ struct mtk_ddp_comp *next)
{
if (comp->funcs && comp->funcs->connect) {
- comp->funcs->connect(comp->dev, mmsys_dev, next);
+ comp->funcs->connect(comp, mmsys_dev, next);
return true;
}
return false;
}
static inline bool mtk_ddp_comp_disconnect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
- unsigned int next)
+ struct mtk_ddp_comp *next)
{
if (comp->funcs && comp->funcs->disconnect) {
- comp->funcs->disconnect(comp->dev, mmsys_dev, next);
+ comp->funcs->disconnect(comp, mmsys_dev, next);
return true;
}
return false;
@@ -353,12 +357,14 @@ static inline void mtk_ddp_comp_encoder_index_set(struct mtk_ddp_comp *comp)
static inline struct mtk_ddp_comp
*mtk_ddp_comp_find_by_id(struct mtk_drm_comp_list *hlist,
- const unsigned int id)
+ const unsigned int comp_type,
+ const unsigned int comp_inst_id)
{
struct mtk_ddp_comp *ddp_comp;
- hash_for_each_possible(hlist->ddp_list, ddp_comp, lnode, id)
- return ddp_comp;
+ hash_for_each_possible(hlist->ddp_list, ddp_comp, lnode, comp_type)
+ if (ddp_comp->inst_id == comp_inst_id)
+ return ddp_comp;
return NULL;
}
@@ -369,7 +375,7 @@ int mtk_ddp_comp_get_id(struct device_node *node,
int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev);
int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
struct mtk_drm_comp_list *hlist,
- unsigned int comp_id);
+ enum mtk_ddp_comp_type comp_type, int comp_inst_id);
int mtk_ddp_comp_get_mutex_trigger(struct device_node *node, unsigned int index);
enum mtk_ddp_comp_type mtk_ddp_comp_get_type(unsigned int comp_id);
void mtk_ddp_write(struct cmdq_pkt *cmdq_pkt, unsigned int value,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 7706d95b3be8..c4b44b761633 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -11,6 +11,7 @@
#include <linux/soc/mediatek/mtk-cmdq.h>
#include <linux/soc/mediatek/mtk-mmsys.h>
#include <linux/soc/mediatek/mtk-mutex.h>
+#include "mtk_ddp_comp.h"
#include "mtk_mdp_rdma.h"
#include "mtk_plane.h"
@@ -122,10 +123,10 @@ bool mtk_ovl_is_afbc_supported(struct device *dev);
void mtk_ovl_adaptor_add_comp(struct device *dev, struct mtk_mutex *mutex);
void mtk_ovl_adaptor_remove_comp(struct device *dev, struct mtk_mutex *mutex);
bool mtk_ovl_adaptor_is_comp_present(struct device_node *node);
-void mtk_ovl_adaptor_connect(struct device *dev, struct device *mmsys_dev,
- unsigned int next);
-void mtk_ovl_adaptor_disconnect(struct device *dev, struct device *mmsys_dev,
- unsigned int next);
+void mtk_ovl_adaptor_connect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next);
+void mtk_ovl_adaptor_disconnect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next);
int mtk_ovl_adaptor_power_on(struct device *dev);
void mtk_ovl_adaptor_power_off(struct device *dev);
int mtk_ovl_adaptor_clk_enable(struct device *dev);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
index 78bc3bee0794..225ab87bca71 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
@@ -61,7 +61,7 @@ enum mtk_ovl_adaptor_comp_id {
struct ovl_adaptor_comp_match {
enum mtk_ovl_adaptor_comp_type type;
- enum mtk_ddp_comp_id comp_id;
+ enum mtk_ddp_comp_type comp_type;
int alias_id;
const struct mtk_ddp_comp_funcs *funcs;
};
@@ -108,27 +108,27 @@ static const struct mtk_ddp_comp_funcs rdma = {
};
static const struct ovl_adaptor_comp_match comp_matches[OVL_ADAPTOR_ID_MAX] = {
- [OVL_ADAPTOR_ETHDR0] = { OVL_ADAPTOR_TYPE_ETHDR, DDP_COMPONENT_ETHDR_MIXER, 0, ðdr },
- [OVL_ADAPTOR_MDP_RDMA0] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA0, 0, &rdma },
- [OVL_ADAPTOR_MDP_RDMA1] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA1, 1, &rdma },
- [OVL_ADAPTOR_MDP_RDMA2] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA2, 2, &rdma },
- [OVL_ADAPTOR_MDP_RDMA3] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA3, 3, &rdma },
- [OVL_ADAPTOR_MDP_RDMA4] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA4, 4, &rdma },
- [OVL_ADAPTOR_MDP_RDMA5] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA5, 5, &rdma },
- [OVL_ADAPTOR_MDP_RDMA6] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA6, 6, &rdma },
- [OVL_ADAPTOR_MDP_RDMA7] = { OVL_ADAPTOR_TYPE_MDP_RDMA, DDP_COMPONENT_MDP_RDMA7, 7, &rdma },
- [OVL_ADAPTOR_MERGE0] = { OVL_ADAPTOR_TYPE_MERGE, DDP_COMPONENT_MERGE1, 1, &merge },
- [OVL_ADAPTOR_MERGE1] = { OVL_ADAPTOR_TYPE_MERGE, DDP_COMPONENT_MERGE2, 2, &merge },
- [OVL_ADAPTOR_MERGE2] = { OVL_ADAPTOR_TYPE_MERGE, DDP_COMPONENT_MERGE3, 3, &merge },
- [OVL_ADAPTOR_MERGE3] = { OVL_ADAPTOR_TYPE_MERGE, DDP_COMPONENT_MERGE4, 4, &merge },
- [OVL_ADAPTOR_PADDING0] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING0, 0, &padding },
- [OVL_ADAPTOR_PADDING1] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING1, 1, &padding },
- [OVL_ADAPTOR_PADDING2] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING2, 2, &padding },
- [OVL_ADAPTOR_PADDING3] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING3, 3, &padding },
- [OVL_ADAPTOR_PADDING4] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING4, 4, &padding },
- [OVL_ADAPTOR_PADDING5] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING5, 5, &padding },
- [OVL_ADAPTOR_PADDING6] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING6, 6, &padding },
- [OVL_ADAPTOR_PADDING7] = { OVL_ADAPTOR_TYPE_PADDING, DDP_COMPONENT_PADDING7, 7, &padding },
+ [OVL_ADAPTOR_ETHDR0] = { OVL_ADAPTOR_TYPE_ETHDR, MTK_DISP_ETHDR_MIXER, 0, ðdr },
+ [OVL_ADAPTOR_MDP_RDMA0] = { OVL_ADAPTOR_TYPE_MDP_RDMA, MTK_DISP_MDP_RDMA, 0, &rdma },
+ [OVL_ADAPTOR_MDP_RDMA1] = { OVL_ADAPTOR_TYPE_MDP_RDMA, MTK_DISP_MDP_RDMA, 1, &rdma },
+ [OVL_ADAPTOR_MDP_RDMA2] = { OVL_ADAPTOR_TYPE_MDP_RDMA, MTK_DISP_MDP_RDMA, 2, &rdma },
+ [OVL_ADAPTOR_MDP_RDMA3] = { OVL_ADAPTOR_TYPE_MDP_RDMA, MTK_DISP_MDP_RDMA, 3, &rdma },
+ [OVL_ADAPTOR_MDP_RDMA4] = { OVL_ADAPTOR_TYPE_MDP_RDMA, MTK_DISP_MDP_RDMA, 4, &rdma },
+ [OVL_ADAPTOR_MDP_RDMA5] = { OVL_ADAPTOR_TYPE_MDP_RDMA, MTK_DISP_MDP_RDMA, 5, &rdma },
+ [OVL_ADAPTOR_MDP_RDMA6] = { OVL_ADAPTOR_TYPE_MDP_RDMA, MTK_DISP_MDP_RDMA, 6, &rdma },
+ [OVL_ADAPTOR_MDP_RDMA7] = { OVL_ADAPTOR_TYPE_MDP_RDMA, MTK_DISP_MDP_RDMA, 7, &rdma },
+ [OVL_ADAPTOR_MERGE0] = { OVL_ADAPTOR_TYPE_MERGE, MTK_DISP_MERGE, 1, &merge },
+ [OVL_ADAPTOR_MERGE1] = { OVL_ADAPTOR_TYPE_MERGE, MTK_DISP_MERGE, 2, &merge },
+ [OVL_ADAPTOR_MERGE2] = { OVL_ADAPTOR_TYPE_MERGE, MTK_DISP_MERGE, 3, &merge },
+ [OVL_ADAPTOR_MERGE3] = { OVL_ADAPTOR_TYPE_MERGE, MTK_DISP_MERGE, 4, &merge },
+ [OVL_ADAPTOR_PADDING0] = { OVL_ADAPTOR_TYPE_PADDING, MTK_DISP_PADDING, 0, &padding },
+ [OVL_ADAPTOR_PADDING1] = { OVL_ADAPTOR_TYPE_PADDING, MTK_DISP_PADDING, 1, &padding },
+ [OVL_ADAPTOR_PADDING2] = { OVL_ADAPTOR_TYPE_PADDING, MTK_DISP_PADDING, 2, &padding },
+ [OVL_ADAPTOR_PADDING3] = { OVL_ADAPTOR_TYPE_PADDING, MTK_DISP_PADDING, 3, &padding },
+ [OVL_ADAPTOR_PADDING4] = { OVL_ADAPTOR_TYPE_PADDING, MTK_DISP_PADDING, 4, &padding },
+ [OVL_ADAPTOR_PADDING5] = { OVL_ADAPTOR_TYPE_PADDING, MTK_DISP_PADDING, 5, &padding },
+ [OVL_ADAPTOR_PADDING6] = { OVL_ADAPTOR_TYPE_PADDING, MTK_DISP_PADDING, 6, &padding },
+ [OVL_ADAPTOR_PADDING7] = { OVL_ADAPTOR_TYPE_PADDING, MTK_DISP_PADDING, 7, &padding },
};
void mtk_ovl_adaptor_layer_config(struct device *dev, unsigned int idx,
@@ -431,7 +431,11 @@ void mtk_ovl_adaptor_add_comp(struct device *dev, struct mtk_mutex *mutex)
for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
if (!ovl_adaptor->ovl_adaptor_comp[i])
continue;
- mtk_mutex_add_comp(mutex, comp_matches[i].comp_id);
+
+ mtk_mutex_add_trigger(mutex,
+ comp_matches[i].comp_type,
+ comp_matches[i].alias_id,
+ ovl_adaptor->mtx_trig_ids[i]);
}
}
@@ -443,32 +447,38 @@ void mtk_ovl_adaptor_remove_comp(struct device *dev, struct mtk_mutex *mutex)
for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
if (!ovl_adaptor->ovl_adaptor_comp[i])
continue;
- mtk_mutex_remove_comp(mutex, comp_matches[i].comp_id);
+
+ mtk_mutex_remove_trigger(mutex,
+ comp_matches[i].comp_type,
+ comp_matches[i].alias_id,
+ ovl_adaptor->mtx_trig_ids[i]);
}
}
-void mtk_ovl_adaptor_connect(struct device *dev, struct device *mmsys_dev, unsigned int next)
+void mtk_ovl_adaptor_connect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next)
{
- mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_ETHDR_MIXER, next);
- mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MDP_RDMA0, DDP_COMPONENT_MERGE1);
- mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MDP_RDMA1, DDP_COMPONENT_MERGE1);
- mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MDP_RDMA2, DDP_COMPONENT_MERGE2);
- mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MERGE1, DDP_COMPONENT_ETHDR_MIXER);
- mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MERGE2, DDP_COMPONENT_ETHDR_MIXER);
- mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MERGE3, DDP_COMPONENT_ETHDR_MIXER);
- mtk_mmsys_ddp_connect(mmsys_dev, DDP_COMPONENT_MERGE4, DDP_COMPONENT_ETHDR_MIXER);
+ mtk_mmsys_hw_connect(mmsys_dev, MTK_DISP_ETHDR_MIXER, 0, next->type, next->inst_id);
+ mtk_mmsys_hw_connect(mmsys_dev, MTK_DISP_MDP_RDMA, 0, MTK_DISP_MERGE, 1);
+ mtk_mmsys_hw_connect(mmsys_dev, MTK_DISP_MDP_RDMA, 1, MTK_DISP_MERGE, 1);
+ mtk_mmsys_hw_connect(mmsys_dev, MTK_DISP_MDP_RDMA, 2, MTK_DISP_MERGE, 2);
+ mtk_mmsys_hw_connect(mmsys_dev, MTK_DISP_MERGE, 1, MTK_DISP_ETHDR_MIXER, 0);
+ mtk_mmsys_hw_connect(mmsys_dev, MTK_DISP_MERGE, 2, MTK_DISP_ETHDR_MIXER, 0);
+ mtk_mmsys_hw_connect(mmsys_dev, MTK_DISP_MERGE, 3, MTK_DISP_ETHDR_MIXER, 0);
+ mtk_mmsys_hw_connect(mmsys_dev, MTK_DISP_MERGE, 4, MTK_DISP_ETHDR_MIXER, 0);
}
-void mtk_ovl_adaptor_disconnect(struct device *dev, struct device *mmsys_dev, unsigned int next)
+void mtk_ovl_adaptor_disconnect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next)
{
- mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_ETHDR_MIXER, next);
- mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MDP_RDMA0, DDP_COMPONENT_MERGE1);
- mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MDP_RDMA1, DDP_COMPONENT_MERGE1);
- mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MDP_RDMA2, DDP_COMPONENT_MERGE2);
- mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MERGE1, DDP_COMPONENT_ETHDR_MIXER);
- mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MERGE2, DDP_COMPONENT_ETHDR_MIXER);
- mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MERGE3, DDP_COMPONENT_ETHDR_MIXER);
- mtk_mmsys_ddp_disconnect(mmsys_dev, DDP_COMPONENT_MERGE4, DDP_COMPONENT_ETHDR_MIXER);
+ mtk_mmsys_hw_disconnect(mmsys_dev, MTK_DISP_ETHDR_MIXER, 0, next->type, next->inst_id);
+ mtk_mmsys_hw_disconnect(mmsys_dev, MTK_DISP_MDP_RDMA, 0, MTK_DISP_MERGE, 1);
+ mtk_mmsys_hw_disconnect(mmsys_dev, MTK_DISP_MDP_RDMA, 1, MTK_DISP_MERGE, 1);
+ mtk_mmsys_hw_disconnect(mmsys_dev, MTK_DISP_MDP_RDMA, 2, MTK_DISP_MERGE, 2);
+ mtk_mmsys_hw_disconnect(mmsys_dev, MTK_DISP_MERGE, 1, MTK_DISP_ETHDR_MIXER, 0);
+ mtk_mmsys_hw_disconnect(mmsys_dev, MTK_DISP_MERGE, 2, MTK_DISP_ETHDR_MIXER, 0);
+ mtk_mmsys_hw_disconnect(mmsys_dev, MTK_DISP_MERGE, 3, MTK_DISP_ETHDR_MIXER, 0);
+ mtk_mmsys_hw_disconnect(mmsys_dev, MTK_DISP_MERGE, 4, MTK_DISP_ETHDR_MIXER, 0);
}
static int ovl_adaptor_comp_get_id(struct device *dev, struct device_node *node,
@@ -557,12 +567,12 @@ static int ovl_adaptor_comp_init(struct device *dev, struct device_node *mutex_n
parent = dev->parent->parent->of_node->parent;
for_each_child_of_node_scoped(parent, node) {
- enum mtk_ovl_adaptor_comp_type type;
- enum mtk_ddp_comp_id ddp_type;
+ enum mtk_ovl_adaptor_comp_type ovla_type;
+ enum mtk_ddp_comp_type ddp_type;
+ u8 ddp_inst_id, mtx_id;
int id, ret;
- u8 mtx_id;
- ret = ovl_adaptor_of_get_ddp_comp_type(node, &type);
+ ret = ovl_adaptor_of_get_ddp_comp_type(node, &ovla_type);
if (ret)
continue;
@@ -572,15 +582,17 @@ static int ovl_adaptor_comp_init(struct device *dev, struct device_node *mutex_n
continue;
}
- id = ovl_adaptor_comp_get_id(dev, node, type);
+ id = ovl_adaptor_comp_get_id(dev, node, ovla_type);
if (id < 0) {
dev_warn(dev, "Skipping unknown component %pOF\n",
node);
continue;
}
- ddp_type = comp_matches[id].comp_id;
+ ddp_type = comp_matches[id].comp_type;
+ ddp_inst_id = comp_matches[id].alias_id;
mtx_id = mtk_drm_legacy_get_ovl_adaptor_mutex_trig_id(ddp_type,
+ ddp_inst_id,
mutex_node);
comp_pdev = of_find_device_by_node(node);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index cdff5edd09da..f7cbf9b47672 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -102,8 +102,8 @@ static const struct mtk_mmsys_driver_data mt8186_mmsys_driver_data = {
};
static const struct mtk_drm_route mt8188_mtk_ddp_main_routes[] = {
- { 0, DDP_COMPONENT_DP_INTF0 },
- { 0, DDP_COMPONENT_DSI0 },
+ { 0, MTK_DISP_DP_INTF, 0 },
+ { 0, MTK_DISP_DSI, 0 },
};
static const struct mtk_mmsys_driver_data mt8188_vdosys0_driver_data = {
@@ -245,7 +245,8 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
return false;
}
-static bool mtk_drm_find_mmsys_comp(struct mtk_drm_private *private, int comp_id)
+static bool mtk_drm_find_mmsys_comp(struct mtk_drm_private *private,
+ enum mtk_ddp_comp_type type, u8 inst_id)
{
const struct mtk_mmsys_driver_data *data = private->data;
int i, j;
@@ -254,7 +255,8 @@ static bool mtk_drm_find_mmsys_comp(struct mtk_drm_private *private, int comp_id
const struct mtk_drm_path_definition *output_path = &data->output_paths[i];
for (j = 0; j < output_path->len; j++) {
- if (output_path->comp[j].type != comp_id)
+ if (output_path->comp[j].type != type ||
+ output_path->comp[j].inst_id != inst_id)
continue;
return true;
@@ -263,7 +265,8 @@ static bool mtk_drm_find_mmsys_comp(struct mtk_drm_private *private, int comp_id
if (data->num_conn_routes)
for (i = 0; i < data->num_conn_routes; i++)
- if (data->conn_routes[i].route_ddp == comp_id)
+ if (data->conn_routes[i].route_ddp_type == type &&
+ data->conn_routes[i].route_ddp_inst_id == inst_id)
return true;
return false;
@@ -635,7 +638,7 @@ static int mtk_drm_of_get_ddp_comp_type(struct device_node *node, enum mtk_ddp_c
return 0;
}
-static int mtk_drm_of_get_ddp_ep_cid(struct device_node *node,
+static int mtk_drm_of_get_ddp_ep_cid(struct device *dev, struct device_node *node,
int output_port, enum mtk_crtc_path crtc_path,
struct device_node **next,
struct mtk_drm_comp_definition *comp_def)
@@ -666,7 +669,9 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device_node *node,
ret = mtk_drm_of_get_ddp_comp_type(ep_dev_node, &comp_type);
if (ret) {
if (mtk_ovl_adaptor_is_comp_present(ep_dev_node)) {
- comp_def->type = DDP_COMPONENT_DRM_OVL_ADAPTOR;
+ comp_def->type = MTK_DISP_OVL_ADAPTOR;
+ comp_def->inst_id = 0;
+
return 0;
}
return ret;
@@ -677,7 +682,11 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device_node *node,
return ret;
/* All ok! Pass the Component ID to the caller. */
- comp_def->type = ret;
+ comp_def->type = comp_type;
+ comp_def->inst_id = ret;
+
+ dev_vdbg(dev, "Found component %pOF with Type:%u, HW Instance:%u\n",
+ ep_dev_node, comp_def->type, comp_def->inst_id);
return 0;
}
@@ -710,9 +719,9 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, enum mtk_crtc_path
int ret;
/* Get the first entry for the temp_path array */
- ret = mtk_drm_of_get_ddp_ep_cid(vdo, 0, cpath, &next, &temp_path[idx]);
+ ret = mtk_drm_of_get_ddp_ep_cid(dev, vdo, 0, cpath, &next, &temp_path[idx]);
if (ret) {
- if (next && temp_path[idx].type == DDP_COMPONENT_DRM_OVL_ADAPTOR) {
+ if (next && temp_path[idx].type == MTK_DISP_OVL_ADAPTOR) {
dev_dbg(dev, "Adding OVL Adaptor for %pOF\n", next);
ovl_adaptor_comp_added = true;
} else {
@@ -732,9 +741,10 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, enum mtk_crtc_path
*/
do {
prev = next;
- ret = mtk_drm_of_get_ddp_ep_cid(next, 1, cpath, &next, &temp_path[idx]);
+ ret = mtk_drm_of_get_ddp_ep_cid(dev, next, 1, cpath, &next, &temp_path[idx]);
of_node_put(prev);
if (ret) {
+ dev_vdbg(dev, "Invalid comp reached with result %d\n", ret);
of_node_put(next);
break;
}
@@ -746,13 +756,13 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, enum mtk_crtc_path
* to probe that component master driver of which only one instance
* is needed and possible.
*/
- if (temp_path[idx].type == DDP_COMPONENT_DRM_OVL_ADAPTOR) {
+ if (temp_path[idx].type == MTK_DISP_OVL_ADAPTOR) {
if (!ovl_adaptor_comp_added)
ovl_adaptor_comp_added = true;
else
idx--;
}
- } while (++idx < DDP_COMPONENT_DRM_ID_MAX);
+ } while (++idx < MTK_DISP_CONTROLLER_MAX_COMP_PER_PATH);
/*
* The device component might not be enabled: in that case, don't
@@ -763,18 +773,13 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, enum mtk_crtc_path
/* If the last entry is not a final display output, the configuration is wrong */
switch (temp_path[idx - 1].type) {
- case DDP_COMPONENT_DP_INTF0:
- case DDP_COMPONENT_DP_INTF1:
- case DDP_COMPONENT_DPI0:
- case DDP_COMPONENT_DPI1:
- case DDP_COMPONENT_DSI0:
- case DDP_COMPONENT_DSI1:
- case DDP_COMPONENT_DSI2:
- case DDP_COMPONENT_DSI3:
+ case MTK_DISP_DP_INTF:
+ case MTK_DISP_DPI:
+ case MTK_DISP_DSI:
break;
default:
- dev_err(dev, "Invalid display hw pipeline. Last component: %d (ret=%d)\n",
- temp_path[idx - 1].type, ret);
+ dev_err(dev, "Invalid display hw pipeline. Last component: %u-%u (ret=%d)\n",
+ temp_path[idx - 1].type, temp_path[idx - 1].inst_id, ret);
return -EINVAL;
}
@@ -852,7 +857,6 @@ static int mtk_drm_probe(struct platform_device *pdev)
struct device_node *node;
struct component_match *match = NULL;
int ret;
- int i;
private = devm_kzalloc(dev, sizeof(*private), GFP_KERNEL);
if (!private)
@@ -901,7 +905,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
/* Iterate over sibling DISP function blocks */
for_each_child_of_node(phandle->parent, node) {
enum mtk_ddp_comp_type comp_type;
- int comp_id;
+ u8 comp_inst_id;
ret = mtk_drm_of_get_ddp_comp_type(node, &comp_type);
if (ret)
@@ -924,18 +928,16 @@ static int mtk_drm_probe(struct platform_device *pdev)
continue;
}
- comp_id = mtk_ddp_comp_get_id(node, comp_type);
- if (comp_id < 0) {
+ comp_inst_id = mtk_ddp_comp_get_id(node, comp_type);
+ if (comp_inst_id < 0) {
dev_warn(dev, "Skipping unknown component %pOF\n",
node);
continue;
}
- if (!mtk_drm_find_mmsys_comp(private, comp_id))
+ if (!mtk_drm_find_mmsys_comp(private, comp_type, comp_inst_id))
continue;
- private->comp_node[comp_id] = of_node_get(node);
-
/*
* Currently only the AAL, CCORR, COLOR, GAMMA, MERGE, OVL, RDMA, DSI, and DPI
* blocks have separate component platform drivers and initialize their own
@@ -949,7 +951,8 @@ static int mtk_drm_probe(struct platform_device *pdev)
node);
}
- ret = mtk_ddp_comp_init(dev, node, &private->hlist, comp_id);
+ ret = mtk_ddp_comp_init(dev, node, &private->hlist,
+ comp_type, comp_inst_id);
if (ret) {
of_node_put(node);
goto err_node;
@@ -970,7 +973,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
}
/* Bringup ovl_adaptor */
- if (mtk_drm_find_mmsys_comp(private, DDP_COMPONENT_DRM_OVL_ADAPTOR))
+ if (mtk_drm_find_mmsys_comp(private, MTK_DISP_OVL_ADAPTOR, 0))
mtk_drm_legacy_ovl_adaptor_probe(dev, private, &match);
pm_runtime_enable(dev);
@@ -987,21 +990,16 @@ static int mtk_drm_probe(struct platform_device *pdev)
pm_runtime_disable(dev);
err_node:
of_node_put(private->mutex_node);
- for (i = 0; i < DDP_COMPONENT_DRM_ID_MAX; i++)
- of_node_put(private->comp_node[i]);
return ret;
}
static void mtk_drm_remove(struct platform_device *pdev)
{
struct mtk_drm_private *private = platform_get_drvdata(pdev);
- int i;
component_master_del(&pdev->dev, &mtk_drm_ops);
pm_runtime_disable(&pdev->dev);
of_node_put(private->mutex_node);
- for (i = 0; i < DDP_COMPONENT_DRM_ID_MAX; i++)
- of_node_put(private->comp_node[i]);
}
static void mtk_drm_shutdown(struct platform_device *pdev)
@@ -1085,4 +1083,6 @@ module_exit(mtk_drm_exit);
MODULE_AUTHOR("YT SHEN <yt.shen@mediatek.com>");
MODULE_DESCRIPTION("Mediatek SoC DRM driver");
+MODULE_IMPORT_NS("MTK_MMSYS");
+MODULE_IMPORT_NS("MTK_MUTEX");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index 7dc208669c2e..d86175180e11 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -10,8 +10,6 @@
#include "mtk_ddp_comp.h"
#define MAX_CONNECTOR 2
-#define DDP_COMPONENT_DRM_OVL_ADAPTOR (DDP_COMPONENT_ID_MAX + 1)
-#define DDP_COMPONENT_DRM_ID_MAX (DDP_COMPONENT_DRM_OVL_ADAPTOR + 1)
enum mtk_crtc_path {
CRTC_MAIN,
@@ -30,11 +28,13 @@ struct regmap;
struct mtk_drm_route {
const unsigned int crtc_id;
- const unsigned int route_ddp;
+ const enum mtk_ddp_comp_type route_ddp_type;
+ const u8 route_ddp_inst_id;
};
struct mtk_drm_comp_definition {
- enum mtk_ddp_comp_id type;
+ enum mtk_ddp_comp_type type;
+ u8 inst_id;
};
struct mtk_drm_path_definition {
@@ -66,7 +66,6 @@ struct mtk_drm_private {
struct device *mutex_dev;
struct device *mmsys_dev;
struct mtk_drm_comp_list hlist;
- struct device_node *comp_node[DDP_COMPONENT_DRM_ID_MAX];
struct mtk_mmsys_driver_data *data;
struct drm_atomic_commit *suspend_state;
unsigned int mbox_index;
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_legacy.c b/drivers/gpu/drm/mediatek/mtk_drm_legacy.c
index d6e3ab7e08ba..801e0ab43ff5 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_legacy.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_legacy.c
@@ -248,16 +248,16 @@ struct mtk_drm_legacy_mtx_data {
};
static const struct mtk_drm_comp_definition mt2701_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_BLS },
- { DDP_COMPONENT_DSI0 },
+ { MTK_DISP_OVL, 0 },
+ { MTK_DISP_RDMA, 0 },
+ { MTK_DISP_COLOR, 0 },
+ { MTK_DISP_BLS, 0 },
+ { MTK_DISP_DSI, 0 },
};
static const struct mtk_drm_comp_definition mt2701_mtk_ddp_ext[] = {
- { DDP_COMPONENT_RDMA1 },
- { DDP_COMPONENT_DPI0 },
+ { MTK_DISP_RDMA, 1 },
+ { MTK_DISP_DPI, 0 },
};
struct mtk_drm_path_definition mt2701_legacy_paths[MAX_CRTC] = {
@@ -272,29 +272,29 @@ struct mtk_drm_path_definition mt2701_legacy_paths[MAX_CRTC] = {
};
static const struct mtk_drm_comp_definition mt2712_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_OD0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_DPI0 },
- { DDP_COMPONENT_PWM0 },
+ { MTK_DISP_OVL, 0 },
+ { MTK_DISP_COLOR, 0 },
+ { MTK_DISP_AAL, 0 },
+ { MTK_DISP_OD, 0 },
+ { MTK_DISP_RDMA, 0 },
+ { MTK_DISP_DPI, 0 },
+ { MTK_DISP_PWM, 0 },
};
static const struct mtk_drm_comp_definition mt2712_mtk_ddp_ext[] = {
- { DDP_COMPONENT_OVL1 },
- { DDP_COMPONENT_COLOR1 },
- { DDP_COMPONENT_AAL1 },
- { DDP_COMPONENT_OD1 },
- { DDP_COMPONENT_RDMA1 },
- { DDP_COMPONENT_DPI1 },
- { DDP_COMPONENT_PWM1 },
+ { MTK_DISP_OVL, 1 },
+ { MTK_DISP_COLOR, 1 },
+ { MTK_DISP_AAL, 1 },
+ { MTK_DISP_OD, 1 },
+ { MTK_DISP_RDMA, 1 },
+ { MTK_DISP_DPI, 1 },
+ { MTK_DISP_PWM, 1 },
};
static const struct mtk_drm_comp_definition mt2712_mtk_ddp_third[] = {
- { DDP_COMPONENT_RDMA2 },
- { DDP_COMPONENT_DSI3 },
- { DDP_COMPONENT_PWM2 },
+ { MTK_DISP_RDMA, 2 },
+ { MTK_DISP_DSI, 3 },
+ { MTK_DISP_PWM, 2 },
};
struct mtk_drm_path_definition mt2712_legacy_paths[MAX_CRTC] = {
@@ -313,16 +313,16 @@ struct mtk_drm_path_definition mt2712_legacy_paths[MAX_CRTC] = {
};
static const struct mtk_drm_comp_definition mt7623_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_BLS },
- { DDP_COMPONENT_DPI0 },
+ { MTK_DISP_OVL, 0 },
+ { MTK_DISP_RDMA, 0 },
+ { MTK_DISP_COLOR, 0 },
+ { MTK_DISP_BLS, 0 },
+ { MTK_DISP_DPI, 0 },
};
static const struct mtk_drm_comp_definition mt7623_mtk_ddp_ext[] = {
- { DDP_COMPONENT_RDMA1 },
- { DDP_COMPONENT_DSI0 },
+ { MTK_DISP_RDMA, 1 },
+ { MTK_DISP_DSI, 0 },
};
struct mtk_drm_path_definition mt7623_legacy_paths[MAX_CRTC] = {
@@ -337,14 +337,14 @@ struct mtk_drm_path_definition mt7623_legacy_paths[MAX_CRTC] = {
};
static const struct mtk_drm_comp_definition mt8167_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_CCORR },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_GAMMA },
- { DDP_COMPONENT_DITHER0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_DSI0 },
+ { MTK_DISP_OVL, 0 },
+ { MTK_DISP_COLOR, 0 },
+ { MTK_DISP_CCORR, 0 },
+ { MTK_DISP_AAL, 0 },
+ { MTK_DISP_GAMMA, 0 },
+ { MTK_DISP_DITHER, 0 },
+ { MTK_DISP_RDMA, 0 },
+ { MTK_DISP_DSI, 0 },
};
struct mtk_drm_path_definition mt8167_legacy_paths[MAX_CRTC] = {
@@ -355,22 +355,22 @@ struct mtk_drm_path_definition mt8167_legacy_paths[MAX_CRTC] = {
};
static const struct mtk_drm_comp_definition mt8173_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_OD0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_UFOE },
- { DDP_COMPONENT_DSI0 },
- { DDP_COMPONENT_PWM0 },
+ { MTK_DISP_OVL, 0 },
+ { MTK_DISP_COLOR, 0 },
+ { MTK_DISP_AAL, 0 },
+ { MTK_DISP_OD, 0 },
+ { MTK_DISP_RDMA, 0 },
+ { MTK_DISP_UFOE, 0 },
+ { MTK_DISP_DSI, 0 },
+ { MTK_DISP_PWM, 0 },
};
static const struct mtk_drm_comp_definition mt8173_mtk_ddp_ext[] = {
- { DDP_COMPONENT_OVL1 },
- { DDP_COMPONENT_COLOR1 },
- { DDP_COMPONENT_GAMMA },
- { DDP_COMPONENT_RDMA1 },
- { DDP_COMPONENT_DPI0 },
+ { MTK_DISP_OVL, 1 },
+ { MTK_DISP_COLOR, 1 },
+ { MTK_DISP_GAMMA, 0 },
+ { MTK_DISP_RDMA, 1 },
+ { MTK_DISP_DPI, 0 },
};
struct mtk_drm_path_definition mt8173_legacy_paths[MAX_CRTC] = {
@@ -385,21 +385,21 @@ struct mtk_drm_path_definition mt8173_legacy_paths[MAX_CRTC] = {
};
static const struct mtk_drm_comp_definition mt8183_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_OVL_2L0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_CCORR },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_GAMMA },
- { DDP_COMPONENT_DITHER0 },
- { DDP_COMPONENT_DSI0 },
+ { MTK_DISP_OVL, 0 },
+ { MTK_DISP_OVL_2L, 0 },
+ { MTK_DISP_RDMA, 0 },
+ { MTK_DISP_COLOR, 0 },
+ { MTK_DISP_CCORR, 0 },
+ { MTK_DISP_AAL, 0 },
+ { MTK_DISP_GAMMA, 0 },
+ { MTK_DISP_DITHER, 0 },
+ { MTK_DISP_DSI, 0 },
};
static const struct mtk_drm_comp_definition mt8183_mtk_ddp_ext[] = {
- { DDP_COMPONENT_OVL_2L1 },
- { DDP_COMPONENT_RDMA1 },
- { DDP_COMPONENT_DPI0 },
+ { MTK_DISP_OVL_2L, 1 },
+ { MTK_DISP_RDMA, 1 },
+ { MTK_DISP_DPI, 0 },
};
struct mtk_drm_path_definition mt8183_legacy_paths[MAX_CRTC] = {
@@ -414,21 +414,21 @@ struct mtk_drm_path_definition mt8183_legacy_paths[MAX_CRTC] = {
};
static const struct mtk_drm_comp_definition mt8186_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_CCORR },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_GAMMA },
- { DDP_COMPONENT_POSTMASK0 },
- { DDP_COMPONENT_DITHER0 },
- { DDP_COMPONENT_DSI0 },
+ { MTK_DISP_OVL, 0 },
+ { MTK_DISP_RDMA, 0 },
+ { MTK_DISP_COLOR, 0 },
+ { MTK_DISP_CCORR, 0 },
+ { MTK_DISP_AAL, 0 },
+ { MTK_DISP_GAMMA, 0 },
+ { MTK_DISP_POSTMASK, 0 },
+ { MTK_DISP_DITHER, 0 },
+ { MTK_DISP_DSI, 0 },
};
static const struct mtk_drm_comp_definition mt8186_mtk_ddp_ext[] = {
- { DDP_COMPONENT_OVL_2L0 },
- { DDP_COMPONENT_RDMA1 },
- { DDP_COMPONENT_DPI0 },
+ { MTK_DISP_OVL_2L, 0 },
+ { MTK_DISP_RDMA, 1 },
+ { MTK_DISP_DPI, 0 },
};
struct mtk_drm_path_definition mt8186_legacy_paths[MAX_CRTC] = {
@@ -443,14 +443,14 @@ struct mtk_drm_path_definition mt8186_legacy_paths[MAX_CRTC] = {
};
static const struct mtk_drm_comp_definition mt8188_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_CCORR },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_GAMMA },
- { DDP_COMPONENT_POSTMASK0 },
- { DDP_COMPONENT_DITHER0 },
+ { MTK_DISP_OVL, 0 },
+ { MTK_DISP_RDMA, 0 },
+ { MTK_DISP_COLOR, 0 },
+ { MTK_DISP_CCORR, 0 },
+ { MTK_DISP_AAL, 0 },
+ { MTK_DISP_GAMMA, 0 },
+ { MTK_DISP_POSTMASK, 0 },
+ { MTK_DISP_DITHER, 0 },
};
struct mtk_drm_path_definition mt8188_legacy_paths[MAX_CRTC] = {
@@ -461,22 +461,22 @@ struct mtk_drm_path_definition mt8188_legacy_paths[MAX_CRTC] = {
};
static const struct mtk_drm_comp_definition mt8192_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_OVL_2L0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_CCORR },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_GAMMA },
- { DDP_COMPONENT_POSTMASK0 },
- { DDP_COMPONENT_DITHER0 },
- { DDP_COMPONENT_DSI0 },
+ { MTK_DISP_OVL, 0 },
+ { MTK_DISP_OVL_2L, 0 },
+ { MTK_DISP_RDMA, 0 },
+ { MTK_DISP_COLOR, 0 },
+ { MTK_DISP_CCORR, 0 },
+ { MTK_DISP_AAL, 0 },
+ { MTK_DISP_GAMMA, 0 },
+ { MTK_DISP_POSTMASK, 0 },
+ { MTK_DISP_DITHER, 0 },
+ { MTK_DISP_DSI, 0 },
};
static const struct mtk_drm_comp_definition mt8192_mtk_ddp_ext[] = {
- { DDP_COMPONENT_OVL_2L2 },
- { DDP_COMPONENT_RDMA4 },
- { DDP_COMPONENT_DPI0 },
+ { MTK_DISP_OVL_2L, 2 },
+ { MTK_DISP_RDMA, 4 },
+ { MTK_DISP_DPI, 0 },
};
struct mtk_drm_path_definition mt8192_legacy_paths[MAX_CRTC] = {
@@ -491,22 +491,22 @@ struct mtk_drm_path_definition mt8192_legacy_paths[MAX_CRTC] = {
};
static const struct mtk_drm_comp_definition mt8195_mtk_ddp_main[] = {
- { DDP_COMPONENT_OVL0 },
- { DDP_COMPONENT_RDMA0 },
- { DDP_COMPONENT_COLOR0 },
- { DDP_COMPONENT_CCORR },
- { DDP_COMPONENT_AAL0 },
- { DDP_COMPONENT_GAMMA },
- { DDP_COMPONENT_DITHER0 },
- { DDP_COMPONENT_DSC0 },
- { DDP_COMPONENT_MERGE0 },
- { DDP_COMPONENT_DP_INTF0 },
+ { MTK_DISP_OVL, 0 },
+ { MTK_DISP_RDMA, 0 },
+ { MTK_DISP_COLOR, 0 },
+ { MTK_DISP_CCORR, 0 },
+ { MTK_DISP_AAL, 0 },
+ { MTK_DISP_GAMMA, 0 },
+ { MTK_DISP_DITHER, 0 },
+ { MTK_DISP_DSC, 0 },
+ { MTK_DISP_MERGE, 0 },
+ { MTK_DISP_DP_INTF, 0 },
};
static const struct mtk_drm_comp_definition mt8195_mtk_ddp_ext[] = {
- { DDP_COMPONENT_DRM_OVL_ADAPTOR },
- { DDP_COMPONENT_MERGE5 },
- { DDP_COMPONENT_DP_INTF1 },
+ { MTK_DISP_OVL_ADAPTOR, 0 },
+ { MTK_DISP_MERGE, 5 },
+ { MTK_DISP_DP_INTF, 1 },
};
struct mtk_drm_path_definition mt8195_vdo0_legacy_paths[MAX_CRTC] = {
@@ -524,12 +524,12 @@ struct mtk_drm_path_definition mt8195_vdo1_legacy_paths[MAX_CRTC] = {
};
static const struct mtk_drm_legacy_mtx_pairs mt2701_legacy_mtx_trig_ids[] = {
- { { DDP_COMPONENT_BLS }, MT2701_MUTEX_MOD_DISP_BLS },
- { { DDP_COMPONENT_COLOR0 }, MT2701_MUTEX_MOD_DISP_COLOR },
- { { DDP_COMPONENT_OVL0 }, MT2701_MUTEX_MOD_DISP_OVL },
- { { DDP_COMPONENT_RDMA0 }, MT2701_MUTEX_MOD_DISP_RDMA0 },
- { { DDP_COMPONENT_RDMA1 }, MT2701_MUTEX_MOD_DISP_RDMA1 },
- { { DDP_COMPONENT_WDMA0 }, MT2701_MUTEX_MOD_DISP_WDMA },
+ { { MTK_DISP_BLS, 0 }, MT2701_MUTEX_MOD_DISP_BLS },
+ { { MTK_DISP_COLOR, 0 }, MT2701_MUTEX_MOD_DISP_COLOR },
+ { { MTK_DISP_OVL, 0 }, MT2701_MUTEX_MOD_DISP_OVL },
+ { { MTK_DISP_RDMA, 0 }, MT2701_MUTEX_MOD_DISP_RDMA0 },
+ { { MTK_DISP_RDMA, 1 }, MT2701_MUTEX_MOD_DISP_RDMA1 },
+ { { MTK_DISP_WDMA, 0 }, MT2701_MUTEX_MOD_DISP_WDMA },
};
const struct mtk_drm_legacy_mtx_data mt2701_legacy_mtx_data = {
@@ -538,23 +538,23 @@ const struct mtk_drm_legacy_mtx_data mt2701_legacy_mtx_data = {
};
static const struct mtk_drm_legacy_mtx_pairs mt2712_legacy_mtx_trig_ids[] = {
- { { DDP_COMPONENT_AAL0 }, MT2712_MUTEX_MOD_DISP_AAL0 },
- { { DDP_COMPONENT_AAL1 }, MT2712_MUTEX_MOD2_DISP_AAL1 },
- { { DDP_COMPONENT_COLOR0 }, MT2712_MUTEX_MOD_DISP_COLOR0 },
- { { DDP_COMPONENT_COLOR1 }, MT2712_MUTEX_MOD_DISP_COLOR1 },
- { { DDP_COMPONENT_OD0 }, MT2712_MUTEX_MOD_DISP_OD0 },
- { { DDP_COMPONENT_OD1 }, MT2712_MUTEX_MOD2_DISP_OD1 },
- { { DDP_COMPONENT_OVL0 }, MT2712_MUTEX_MOD_DISP_OVL0 },
- { { DDP_COMPONENT_OVL1 }, MT2712_MUTEX_MOD_DISP_OVL1 },
- { { DDP_COMPONENT_PWM0 }, MT2712_MUTEX_MOD_DISP_PWM0 },
- { { DDP_COMPONENT_PWM1 }, MT2712_MUTEX_MOD_DISP_PWM1 },
- { { DDP_COMPONENT_PWM2 }, MT2712_MUTEX_MOD_DISP_PWM2 },
- { { DDP_COMPONENT_RDMA0 }, MT2712_MUTEX_MOD_DISP_RDMA0 },
- { { DDP_COMPONENT_RDMA1 }, MT2712_MUTEX_MOD_DISP_RDMA1 },
- { { DDP_COMPONENT_RDMA2 }, MT2712_MUTEX_MOD_DISP_RDMA2 },
- { { DDP_COMPONENT_UFOE }, MT2712_MUTEX_MOD_DISP_UFOE },
- { { DDP_COMPONENT_WDMA0 }, MT2712_MUTEX_MOD_DISP_WDMA0 },
- { { DDP_COMPONENT_WDMA1 }, MT2712_MUTEX_MOD_DISP_WDMA1 },
+ { { MTK_DISP_AAL, 0 }, MT2712_MUTEX_MOD_DISP_AAL0 },
+ { { MTK_DISP_AAL, 1 }, MT2712_MUTEX_MOD2_DISP_AAL1 },
+ { { MTK_DISP_COLOR, 0 }, MT2712_MUTEX_MOD_DISP_COLOR0 },
+ { { MTK_DISP_COLOR, 1 }, MT2712_MUTEX_MOD_DISP_COLOR1 },
+ { { MTK_DISP_OD, 0 }, MT2712_MUTEX_MOD_DISP_OD0 },
+ { { MTK_DISP_OD, 1 }, MT2712_MUTEX_MOD2_DISP_OD1 },
+ { { MTK_DISP_OVL, 0 }, MT2712_MUTEX_MOD_DISP_OVL0 },
+ { { MTK_DISP_OVL, 1 }, MT2712_MUTEX_MOD_DISP_OVL1 },
+ { { MTK_DISP_PWM, 0 }, MT2712_MUTEX_MOD_DISP_PWM0 },
+ { { MTK_DISP_PWM, 1 }, MT2712_MUTEX_MOD_DISP_PWM1 },
+ { { MTK_DISP_PWM, 2 }, MT2712_MUTEX_MOD_DISP_PWM2 },
+ { { MTK_DISP_RDMA, 0 }, MT2712_MUTEX_MOD_DISP_RDMA0 },
+ { { MTK_DISP_RDMA, 1 }, MT2712_MUTEX_MOD_DISP_RDMA1 },
+ { { MTK_DISP_RDMA, 2 }, MT2712_MUTEX_MOD_DISP_RDMA2 },
+ { { MTK_DISP_UFOE, 0 }, MT2712_MUTEX_MOD_DISP_UFOE },
+ { { MTK_DISP_WDMA, 0 }, MT2712_MUTEX_MOD_DISP_WDMA0 },
+ { { MTK_DISP_WDMA, 1 }, MT2712_MUTEX_MOD_DISP_WDMA1 },
};
const struct mtk_drm_legacy_mtx_data mt2712_legacy_mtx_data = {
@@ -563,31 +563,31 @@ const struct mtk_drm_legacy_mtx_data mt2712_legacy_mtx_data = {
};
static const struct mtk_drm_legacy_mtx_pairs mt6893_legacy_mtx_trig_ids[] = {
- { { DDP_COMPONENT_AAL0 }, MT6893_MUTEX_MOD_DISP_AAL0 },
- { { DDP_COMPONENT_AAL1 }, MT6893_MUTEX_MOD_DISP_AAL1 },
- { { DDP_COMPONENT_CCORR }, MT6893_MUTEX_MOD_DISP_CCORR0 },
- { { DDP_COMPONENT_COLOR0 }, MT6893_MUTEX_MOD_DISP_COLOR0 },
- { { DDP_COMPONENT_COLOR1 }, MT6893_MUTEX_MOD_DISP_COLOR1 },
- { { DDP_COMPONENT_DITHER0 }, MT6893_MUTEX_MOD_DISP_DITHER0 },
- { { DDP_COMPONENT_DITHER1 }, MT6893_MUTEX_MOD_DISP_DITHER1 },
- { { DDP_COMPONENT_DP_INTF0 }, MT6893_MUTEX_MOD_DISP_DP },
- { { DDP_COMPONENT_DSC0 }, MT6893_MUTEX_MOD_DISP_DSC0 },
- { { DDP_COMPONENT_DSI0 }, MT6893_MUTEX_MOD_DISP_DSI0 },
- { { DDP_COMPONENT_DSI1 }, MT6893_MUTEX_MOD_DISP_DSI1 },
- { { DDP_COMPONENT_GAMMA }, MT6893_MUTEX_MOD_DISP_GAMMA0 },
- { { DDP_COMPONENT_MERGE1 }, MT6893_MUTEX_MOD_DISP_MERGE1 },
- { { DDP_COMPONENT_OVL0 }, MT6893_MUTEX_MOD_DISP_OVL0 },
- { { DDP_COMPONENT_OVL1 }, MT6893_MUTEX_MOD_DISP_OVL1 },
- { { DDP_COMPONENT_OVL_2L0 }, MT6893_MUTEX_MOD_DISP_OVL0_2L },
- { { DDP_COMPONENT_OVL_2L1 }, MT6893_MUTEX_MOD_DISP_OVL1_2L },
- { { DDP_COMPONENT_OVL_2L2 }, MT6893_MUTEX_MOD_DISP_OVL2 },
- { { DDP_COMPONENT_POSTMASK0 }, MT6893_MUTEX_MOD_DISP_POSTMASK0 },
- { { DDP_COMPONENT_PWM0 }, MT6893_MUTEX_MOD_DISP_PWM0 },
- { { DDP_COMPONENT_RDMA0 }, MT6893_MUTEX_MOD_DISP_RDMA0 },
- { { DDP_COMPONENT_RDMA1 }, MT6893_MUTEX_MOD_DISP_RDMA1 },
- { { DDP_COMPONENT_RDMA4 }, MT6893_MUTEX_MOD_DISP_RDMA4 },
- { { DDP_COMPONENT_WDMA0 }, MT6893_MUTEX_MOD_DISP_WDMA0 },
- { { DDP_COMPONENT_WDMA1 }, MT6893_MUTEX_MOD_DISP_WDMA1 },
+ { { MTK_DISP_AAL, 0 }, MT6893_MUTEX_MOD_DISP_AAL0 },
+ { { MTK_DISP_AAL, 1 }, MT6893_MUTEX_MOD_DISP_AAL1 },
+ { { MTK_DISP_CCORR, 0 }, MT6893_MUTEX_MOD_DISP_CCORR0 },
+ { { MTK_DISP_COLOR, 0 }, MT6893_MUTEX_MOD_DISP_COLOR0 },
+ { { MTK_DISP_COLOR, 1 }, MT6893_MUTEX_MOD_DISP_COLOR1 },
+ { { MTK_DISP_DITHER, 0 }, MT6893_MUTEX_MOD_DISP_DITHER0 },
+ { { MTK_DISP_DITHER, 1 }, MT6893_MUTEX_MOD_DISP_DITHER1 },
+ { { MTK_DISP_DP_INTF, 0 }, MT6893_MUTEX_MOD_DISP_DP },
+ { { MTK_DISP_DSC, 0 }, MT6893_MUTEX_MOD_DISP_DSC0 },
+ { { MTK_DISP_DSI, 0 }, MT6893_MUTEX_MOD_DISP_DSI0 },
+ { { MTK_DISP_DSI, 1 }, MT6893_MUTEX_MOD_DISP_DSI1 },
+ { { MTK_DISP_GAMMA, 0 }, MT6893_MUTEX_MOD_DISP_GAMMA0 },
+ { { MTK_DISP_MERGE, 1 }, MT6893_MUTEX_MOD_DISP_MERGE1 },
+ { { MTK_DISP_OVL, 0 }, MT6893_MUTEX_MOD_DISP_OVL0 },
+ { { MTK_DISP_OVL, 1 }, MT6893_MUTEX_MOD_DISP_OVL1 },
+ { { MTK_DISP_OVL_2L, 0 }, MT6893_MUTEX_MOD_DISP_OVL0_2L },
+ { { MTK_DISP_OVL_2L, 1 }, MT6893_MUTEX_MOD_DISP_OVL1_2L },
+ { { MTK_DISP_OVL_2L, 2 }, MT6893_MUTEX_MOD_DISP_OVL2 },
+ { { MTK_DISP_POSTMASK, 0 }, MT6893_MUTEX_MOD_DISP_POSTMASK0 },
+ { { MTK_DISP_PWM, 0 }, MT6893_MUTEX_MOD_DISP_PWM0 },
+ { { MTK_DISP_RDMA, 0 }, MT6893_MUTEX_MOD_DISP_RDMA0 },
+ { { MTK_DISP_RDMA, 1 }, MT6893_MUTEX_MOD_DISP_RDMA1 },
+ { { MTK_DISP_RDMA, 4 }, MT6893_MUTEX_MOD_DISP_RDMA4 },
+ { { MTK_DISP_WDMA, 0 }, MT6893_MUTEX_MOD_DISP_WDMA0 },
+ { { MTK_DISP_WDMA, 1 }, MT6893_MUTEX_MOD_DISP_WDMA1 },
};
const struct mtk_drm_legacy_mtx_data mt6893_legacy_mtx_data = {
@@ -596,18 +596,18 @@ const struct mtk_drm_legacy_mtx_data mt6893_legacy_mtx_data = {
};
static const struct mtk_drm_legacy_mtx_pairs mt8167_legacy_mtx_trig_ids[] = {
- { { DDP_COMPONENT_AAL0 }, MT8167_MUTEX_MOD_DISP_AAL },
- { { DDP_COMPONENT_CCORR }, MT8167_MUTEX_MOD_DISP_CCORR },
- { { DDP_COMPONENT_COLOR0 }, MT8167_MUTEX_MOD_DISP_COLOR },
- { { DDP_COMPONENT_DITHER0 }, MT8167_MUTEX_MOD_DISP_DITHER },
- { { DDP_COMPONENT_GAMMA }, MT8167_MUTEX_MOD_DISP_GAMMA },
- { { DDP_COMPONENT_OVL0 }, MT8167_MUTEX_MOD_DISP_OVL0 },
- { { DDP_COMPONENT_OVL1 }, MT8167_MUTEX_MOD_DISP_OVL1 },
- { { DDP_COMPONENT_PWM0 }, MT8167_MUTEX_MOD_DISP_PWM },
- { { DDP_COMPONENT_RDMA0 }, MT8167_MUTEX_MOD_DISP_RDMA0 },
- { { DDP_COMPONENT_RDMA1 }, MT8167_MUTEX_MOD_DISP_RDMA1 },
- { { DDP_COMPONENT_UFOE }, MT8167_MUTEX_MOD_DISP_UFOE },
- { { DDP_COMPONENT_WDMA0 }, MT8167_MUTEX_MOD_DISP_WDMA0 },
+ { { MTK_DISP_AAL, 0 }, MT8167_MUTEX_MOD_DISP_AAL },
+ { { MTK_DISP_CCORR, 0 }, MT8167_MUTEX_MOD_DISP_CCORR },
+ { { MTK_DISP_COLOR, 0 }, MT8167_MUTEX_MOD_DISP_COLOR },
+ { { MTK_DISP_DITHER, 0 }, MT8167_MUTEX_MOD_DISP_DITHER },
+ { { MTK_DISP_GAMMA, 0 }, MT8167_MUTEX_MOD_DISP_GAMMA },
+ { { MTK_DISP_OVL, 0 }, MT8167_MUTEX_MOD_DISP_OVL0 },
+ { { MTK_DISP_OVL, 1 }, MT8167_MUTEX_MOD_DISP_OVL1 },
+ { { MTK_DISP_PWM, 0 }, MT8167_MUTEX_MOD_DISP_PWM },
+ { { MTK_DISP_RDMA, 0 }, MT8167_MUTEX_MOD_DISP_RDMA0 },
+ { { MTK_DISP_RDMA, 1 }, MT8167_MUTEX_MOD_DISP_RDMA1 },
+ { { MTK_DISP_UFOE, 0 }, MT8167_MUTEX_MOD_DISP_UFOE },
+ { { MTK_DISP_WDMA, 0 }, MT8167_MUTEX_MOD_DISP_WDMA0 },
};
const struct mtk_drm_legacy_mtx_data mt8167_legacy_mtx_data = {
@@ -616,21 +616,21 @@ const struct mtk_drm_legacy_mtx_data mt8167_legacy_mtx_data = {
};
static const struct mtk_drm_legacy_mtx_pairs mt8173_legacy_mtx_trig_ids[] = {
- { { DDP_COMPONENT_AAL0 }, MT8173_MUTEX_MOD_DISP_AAL },
- { { DDP_COMPONENT_COLOR0 }, MT8173_MUTEX_MOD_DISP_COLOR0 },
- { { DDP_COMPONENT_COLOR1 }, MT8173_MUTEX_MOD_DISP_COLOR1 },
- { { DDP_COMPONENT_GAMMA }, MT8173_MUTEX_MOD_DISP_GAMMA },
- { { DDP_COMPONENT_OD0 }, MT8173_MUTEX_MOD_DISP_OD },
- { { DDP_COMPONENT_OVL0 }, MT8173_MUTEX_MOD_DISP_OVL0 },
- { { DDP_COMPONENT_OVL1 }, MT8173_MUTEX_MOD_DISP_OVL1 },
- { { DDP_COMPONENT_PWM0 }, MT8173_MUTEX_MOD_DISP_PWM0 },
- { { DDP_COMPONENT_PWM1 }, MT8173_MUTEX_MOD_DISP_PWM1 },
- { { DDP_COMPONENT_RDMA0 }, MT8173_MUTEX_MOD_DISP_RDMA0 },
- { { DDP_COMPONENT_RDMA1 }, MT8173_MUTEX_MOD_DISP_RDMA1 },
- { { DDP_COMPONENT_RDMA2 }, MT8173_MUTEX_MOD_DISP_RDMA2 },
- { { DDP_COMPONENT_UFOE }, MT8173_MUTEX_MOD_DISP_UFOE },
- { { DDP_COMPONENT_WDMA0 }, MT8173_MUTEX_MOD_DISP_WDMA0 },
- { { DDP_COMPONENT_WDMA1 }, MT8173_MUTEX_MOD_DISP_WDMA1 },
+ { { MTK_DISP_AAL, 0 }, MT8173_MUTEX_MOD_DISP_AAL },
+ { { MTK_DISP_COLOR, 0 }, MT8173_MUTEX_MOD_DISP_COLOR0 },
+ { { MTK_DISP_COLOR, 1 }, MT8173_MUTEX_MOD_DISP_COLOR1 },
+ { { MTK_DISP_GAMMA, 0 }, MT8173_MUTEX_MOD_DISP_GAMMA },
+ { { MTK_DISP_OD, 0 }, MT8173_MUTEX_MOD_DISP_OD },
+ { { MTK_DISP_OVL, 0 }, MT8173_MUTEX_MOD_DISP_OVL0 },
+ { { MTK_DISP_OVL, 1 }, MT8173_MUTEX_MOD_DISP_OVL1 },
+ { { MTK_DISP_PWM, 0 }, MT8173_MUTEX_MOD_DISP_PWM0 },
+ { { MTK_DISP_PWM, 1 }, MT8173_MUTEX_MOD_DISP_PWM1 },
+ { { MTK_DISP_RDMA, 0 }, MT8173_MUTEX_MOD_DISP_RDMA0 },
+ { { MTK_DISP_RDMA, 1 }, MT8173_MUTEX_MOD_DISP_RDMA1 },
+ { { MTK_DISP_RDMA, 2 }, MT8173_MUTEX_MOD_DISP_RDMA2 },
+ { { MTK_DISP_UFOE, 0 }, MT8173_MUTEX_MOD_DISP_UFOE },
+ { { MTK_DISP_WDMA, 0 }, MT8173_MUTEX_MOD_DISP_WDMA0 },
+ { { MTK_DISP_WDMA, 1 }, MT8173_MUTEX_MOD_DISP_WDMA1 },
};
const struct mtk_drm_legacy_mtx_data mt8173_legacy_mtx_data = {
@@ -639,17 +639,17 @@ const struct mtk_drm_legacy_mtx_data mt8173_legacy_mtx_data = {
};
static const struct mtk_drm_legacy_mtx_pairs mt8183_legacy_mtx_trig_ids[] = {
- { { DDP_COMPONENT_AAL0 }, MT8183_MUTEX_MOD_DISP_AAL0 },
- { { DDP_COMPONENT_CCORR }, MT8183_MUTEX_MOD_DISP_CCORR0 },
- { { DDP_COMPONENT_COLOR0 }, MT8183_MUTEX_MOD_DISP_COLOR0 },
- { { DDP_COMPONENT_DITHER0 }, MT8183_MUTEX_MOD_DISP_DITHER0 },
- { { DDP_COMPONENT_GAMMA }, MT8183_MUTEX_MOD_DISP_GAMMA0 },
- { { DDP_COMPONENT_OVL0 }, MT8183_MUTEX_MOD_DISP_OVL0 },
- { { DDP_COMPONENT_OVL_2L0 }, MT8183_MUTEX_MOD_DISP_OVL0_2L },
- { { DDP_COMPONENT_OVL_2L1 }, MT8183_MUTEX_MOD_DISP_OVL1_2L },
- { { DDP_COMPONENT_RDMA0 }, MT8183_MUTEX_MOD_DISP_RDMA0 },
- { { DDP_COMPONENT_RDMA1 }, MT8183_MUTEX_MOD_DISP_RDMA1 },
- { { DDP_COMPONENT_WDMA0 }, MT8183_MUTEX_MOD_DISP_WDMA0 },
+ { { MTK_DISP_AAL, 0 }, MT8183_MUTEX_MOD_DISP_AAL0 },
+ { { MTK_DISP_CCORR, 0 }, MT8183_MUTEX_MOD_DISP_CCORR0 },
+ { { MTK_DISP_COLOR, 0 }, MT8183_MUTEX_MOD_DISP_COLOR0 },
+ { { MTK_DISP_DITHER, 0 }, MT8183_MUTEX_MOD_DISP_DITHER0 },
+ { { MTK_DISP_GAMMA, 0 }, MT8183_MUTEX_MOD_DISP_GAMMA0 },
+ { { MTK_DISP_OVL, 0 }, MT8183_MUTEX_MOD_DISP_OVL0 },
+ { { MTK_DISP_OVL_2L, 0 }, MT8183_MUTEX_MOD_DISP_OVL0_2L },
+ { { MTK_DISP_OVL_2L, 1 }, MT8183_MUTEX_MOD_DISP_OVL1_2L },
+ { { MTK_DISP_RDMA, 0 }, MT8183_MUTEX_MOD_DISP_RDMA0 },
+ { { MTK_DISP_RDMA, 1 }, MT8183_MUTEX_MOD_DISP_RDMA1 },
+ { { MTK_DISP_WDMA, 0 }, MT8183_MUTEX_MOD_DISP_WDMA0 },
};
const struct mtk_drm_legacy_mtx_data mt8183_legacy_mtx_data = {
@@ -658,16 +658,16 @@ const struct mtk_drm_legacy_mtx_data mt8183_legacy_mtx_data = {
};
static const struct mtk_drm_legacy_mtx_pairs mt8186_legacy_mtx_trig_ids[] = {
- { { DDP_COMPONENT_AAL0 }, MT8186_MUTEX_MOD_DISP_AAL0 },
- { { DDP_COMPONENT_CCORR }, MT8186_MUTEX_MOD_DISP_CCORR0 },
- { { DDP_COMPONENT_COLOR0 }, MT8186_MUTEX_MOD_DISP_COLOR0 },
- { { DDP_COMPONENT_DITHER0 }, MT8186_MUTEX_MOD_DISP_DITHER0 },
- { { DDP_COMPONENT_GAMMA }, MT8186_MUTEX_MOD_DISP_GAMMA0 },
- { { DDP_COMPONENT_OVL0 }, MT8186_MUTEX_MOD_DISP_OVL0 },
- { { DDP_COMPONENT_OVL_2L0 }, MT8186_MUTEX_MOD_DISP_OVL0_2L },
- { { DDP_COMPONENT_POSTMASK0 }, MT8186_MUTEX_MOD_DISP_POSTMASK0 },
- { { DDP_COMPONENT_RDMA0 }, MT8186_MUTEX_MOD_DISP_RDMA0 },
- { { DDP_COMPONENT_RDMA1 }, MT8186_MUTEX_MOD_DISP_RDMA1 },
+ { { MTK_DISP_AAL, 0 }, MT8186_MUTEX_MOD_DISP_AAL0 },
+ { { MTK_DISP_CCORR, 0 }, MT8186_MUTEX_MOD_DISP_CCORR0 },
+ { { MTK_DISP_COLOR, 0 }, MT8186_MUTEX_MOD_DISP_COLOR0 },
+ { { MTK_DISP_DITHER, 0 }, MT8186_MUTEX_MOD_DISP_DITHER0 },
+ { { MTK_DISP_GAMMA, 0 }, MT8186_MUTEX_MOD_DISP_GAMMA0 },
+ { { MTK_DISP_OVL, 0 }, MT8186_MUTEX_MOD_DISP_OVL0 },
+ { { MTK_DISP_OVL_2L, 0 }, MT8186_MUTEX_MOD_DISP_OVL0_2L },
+ { { MTK_DISP_POSTMASK, 0 }, MT8186_MUTEX_MOD_DISP_POSTMASK0 },
+ { { MTK_DISP_RDMA, 0 }, MT8186_MUTEX_MOD_DISP_RDMA0 },
+ { { MTK_DISP_RDMA, 1 }, MT8186_MUTEX_MOD_DISP_RDMA1 },
};
const struct mtk_drm_legacy_mtx_data mt8186_legacy_mtx_data = {
@@ -676,44 +676,44 @@ const struct mtk_drm_legacy_mtx_data mt8186_legacy_mtx_data = {
};
static const struct mtk_drm_legacy_mtx_pairs mt8188_legacy_mtx_trig_ids[] = {
- { { DDP_COMPONENT_OVL0 }, MT8188_MUTEX_MOD_DISP_OVL0 },
- { { DDP_COMPONENT_WDMA0 }, MT8188_MUTEX_MOD_DISP_WDMA0 },
- { { DDP_COMPONENT_RDMA0 }, MT8188_MUTEX_MOD_DISP_RDMA0 },
- { { DDP_COMPONENT_COLOR0 }, MT8188_MUTEX_MOD_DISP_COLOR0 },
- { { DDP_COMPONENT_CCORR }, MT8188_MUTEX_MOD_DISP_CCORR0 },
- { { DDP_COMPONENT_AAL0 }, MT8188_MUTEX_MOD_DISP_AAL0 },
- { { DDP_COMPONENT_GAMMA }, MT8188_MUTEX_MOD_DISP_GAMMA0 },
- { { DDP_COMPONENT_POSTMASK0 }, MT8188_MUTEX_MOD_DISP_POSTMASK0 },
- { { DDP_COMPONENT_DITHER0 }, MT8188_MUTEX_MOD_DISP_DITHER0 },
- { { DDP_COMPONENT_MERGE0 }, MT8188_MUTEX_MOD_DISP_VPP_MERGE },
- { { DDP_COMPONENT_DSC0 }, MT8188_MUTEX_MOD_DISP_DSC_WRAP0_CORE0 },
- { { DDP_COMPONENT_DSI0 }, MT8188_MUTEX_MOD_DISP_DSI0 },
- { { DDP_COMPONENT_PWM0 }, MT8188_MUTEX_MOD2_DISP_PWM0 },
- { { DDP_COMPONENT_DP_INTF0 }, MT8188_MUTEX_MOD_DISP_DP_INTF0 },
- { { DDP_COMPONENT_DP_INTF1 }, MT8188_MUTEX_MOD_DISP1_DP_INTF1 },
- { { DDP_COMPONENT_DPI1 }, MT8188_MUTEX_MOD_DISP1_DPI1 },
- { { DDP_COMPONENT_ETHDR_MIXER }, MT8188_MUTEX_MOD_DISP1_DISP_MIXER },
- { { DDP_COMPONENT_MDP_RDMA0 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA0 },
- { { DDP_COMPONENT_MDP_RDMA1 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA1 },
- { { DDP_COMPONENT_MDP_RDMA2 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA2 },
- { { DDP_COMPONENT_MDP_RDMA3 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA3 },
- { { DDP_COMPONENT_MDP_RDMA4 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA4 },
- { { DDP_COMPONENT_MDP_RDMA5 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA5 },
- { { DDP_COMPONENT_MDP_RDMA6 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA6 },
- { { DDP_COMPONENT_MDP_RDMA7 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA7 },
- { { DDP_COMPONENT_PADDING0 }, MT8188_MUTEX_MOD_DISP1_PADDING0 },
- { { DDP_COMPONENT_PADDING1 }, MT8188_MUTEX_MOD_DISP1_PADDING1 },
- { { DDP_COMPONENT_PADDING2 }, MT8188_MUTEX_MOD_DISP1_PADDING2 },
- { { DDP_COMPONENT_PADDING3 }, MT8188_MUTEX_MOD_DISP1_PADDING3 },
- { { DDP_COMPONENT_PADDING4 }, MT8188_MUTEX_MOD_DISP1_PADDING4 },
- { { DDP_COMPONENT_PADDING5 }, MT8188_MUTEX_MOD_DISP1_PADDING5 },
- { { DDP_COMPONENT_PADDING6 }, MT8188_MUTEX_MOD_DISP1_PADDING6 },
- { { DDP_COMPONENT_PADDING7 }, MT8188_MUTEX_MOD_DISP1_PADDING7 },
- { { DDP_COMPONENT_MERGE1 }, MT8188_MUTEX_MOD_DISP1_VPP_MERGE0 },
- { { DDP_COMPONENT_MERGE2 }, MT8188_MUTEX_MOD_DISP1_VPP_MERGE1 },
- { { DDP_COMPONENT_MERGE3 }, MT8188_MUTEX_MOD_DISP1_VPP_MERGE2 },
- { { DDP_COMPONENT_MERGE4 }, MT8188_MUTEX_MOD_DISP1_VPP_MERGE3 },
- { { DDP_COMPONENT_MERGE5 }, MT8188_MUTEX_MOD_DISP1_VPP_MERGE4 },
+ { { MTK_DISP_OVL, 0 }, MT8188_MUTEX_MOD_DISP_OVL0 },
+ { { MTK_DISP_WDMA, 0 }, MT8188_MUTEX_MOD_DISP_WDMA0 },
+ { { MTK_DISP_RDMA, 0 }, MT8188_MUTEX_MOD_DISP_RDMA0 },
+ { { MTK_DISP_COLOR, 0 }, MT8188_MUTEX_MOD_DISP_COLOR0 },
+ { { MTK_DISP_CCORR, 0 }, MT8188_MUTEX_MOD_DISP_CCORR0 },
+ { { MTK_DISP_AAL, 0 }, MT8188_MUTEX_MOD_DISP_AAL0 },
+ { { MTK_DISP_GAMMA, 0 }, MT8188_MUTEX_MOD_DISP_GAMMA0 },
+ { { MTK_DISP_POSTMASK, 0 }, MT8188_MUTEX_MOD_DISP_POSTMASK0 },
+ { { MTK_DISP_DITHER, 0 }, MT8188_MUTEX_MOD_DISP_DITHER0 },
+ { { MTK_DISP_MERGE, 0 }, MT8188_MUTEX_MOD_DISP_VPP_MERGE },
+ { { MTK_DISP_DSC, 0 }, MT8188_MUTEX_MOD_DISP_DSC_WRAP0_CORE0 },
+ { { MTK_DISP_DSI, 0 }, MT8188_MUTEX_MOD_DISP_DSI0 },
+ { { MTK_DISP_PWM, 0 }, MT8188_MUTEX_MOD2_DISP_PWM0 },
+ { { MTK_DISP_DP_INTF, 0 }, MT8188_MUTEX_MOD_DISP_DP_INTF0 },
+ { { MTK_DISP_DP_INTF, 1 }, MT8188_MUTEX_MOD_DISP1_DP_INTF1 },
+ { { MTK_DISP_DPI, 1 }, MT8188_MUTEX_MOD_DISP1_DPI1 },
+ { { MTK_DISP_ETHDR_MIXER, 0 }, MT8188_MUTEX_MOD_DISP1_DISP_MIXER },
+ { { MTK_DISP_MDP_RDMA, 0 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA0 },
+ { { MTK_DISP_MDP_RDMA, 1 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA1 },
+ { { MTK_DISP_MDP_RDMA, 2 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA2 },
+ { { MTK_DISP_MDP_RDMA, 3 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA3 },
+ { { MTK_DISP_MDP_RDMA, 4 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA4 },
+ { { MTK_DISP_MDP_RDMA, 5 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA5 },
+ { { MTK_DISP_MDP_RDMA, 6 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA6 },
+ { { MTK_DISP_MDP_RDMA, 7 }, MT8188_MUTEX_MOD_DISP1_MDP_RDMA7 },
+ { { MTK_DISP_PADDING, 0 }, MT8188_MUTEX_MOD_DISP1_PADDING0 },
+ { { MTK_DISP_PADDING, 1 }, MT8188_MUTEX_MOD_DISP1_PADDING1 },
+ { { MTK_DISP_PADDING, 2 }, MT8188_MUTEX_MOD_DISP1_PADDING2 },
+ { { MTK_DISP_PADDING, 3 }, MT8188_MUTEX_MOD_DISP1_PADDING3 },
+ { { MTK_DISP_PADDING, 4 }, MT8188_MUTEX_MOD_DISP1_PADDING4 },
+ { { MTK_DISP_PADDING, 5 }, MT8188_MUTEX_MOD_DISP1_PADDING5 },
+ { { MTK_DISP_PADDING, 6 }, MT8188_MUTEX_MOD_DISP1_PADDING6 },
+ { { MTK_DISP_PADDING, 7 }, MT8188_MUTEX_MOD_DISP1_PADDING7 },
+ { { MTK_DISP_MERGE, 1 }, MT8188_MUTEX_MOD_DISP1_VPP_MERGE0 },
+ { { MTK_DISP_MERGE, 2 }, MT8188_MUTEX_MOD_DISP1_VPP_MERGE1 },
+ { { MTK_DISP_MERGE, 3 }, MT8188_MUTEX_MOD_DISP1_VPP_MERGE2 },
+ { { MTK_DISP_MERGE, 4 }, MT8188_MUTEX_MOD_DISP1_VPP_MERGE3 },
+ { { MTK_DISP_MERGE, 5 }, MT8188_MUTEX_MOD_DISP1_VPP_MERGE4 },
};
const struct mtk_drm_legacy_mtx_data mt8188_legacy_mtx_data = {
@@ -722,17 +722,17 @@ const struct mtk_drm_legacy_mtx_data mt8188_legacy_mtx_data = {
};
static const struct mtk_drm_legacy_mtx_pairs mt8192_legacy_mtx_trig_ids[] = {
- { { DDP_COMPONENT_AAL0 }, MT8192_MUTEX_MOD_DISP_AAL0 },
- { { DDP_COMPONENT_CCORR }, MT8192_MUTEX_MOD_DISP_CCORR0 },
- { { DDP_COMPONENT_COLOR0 }, MT8192_MUTEX_MOD_DISP_COLOR0 },
- { { DDP_COMPONENT_DITHER0 }, MT8192_MUTEX_MOD_DISP_DITHER0 },
- { { DDP_COMPONENT_GAMMA }, MT8192_MUTEX_MOD_DISP_GAMMA0 },
- { { DDP_COMPONENT_POSTMASK0 }, MT8192_MUTEX_MOD_DISP_POSTMASK0 },
- { { DDP_COMPONENT_OVL0 }, MT8192_MUTEX_MOD_DISP_OVL0 },
- { { DDP_COMPONENT_OVL_2L0 }, MT8192_MUTEX_MOD_DISP_OVL0_2L },
- { { DDP_COMPONENT_OVL_2L2 }, MT8192_MUTEX_MOD_DISP_OVL2_2L },
- { { DDP_COMPONENT_RDMA0 }, MT8192_MUTEX_MOD_DISP_RDMA0 },
- { { DDP_COMPONENT_RDMA4 }, MT8192_MUTEX_MOD_DISP_RDMA4 },
+ { { MTK_DISP_AAL, 0 }, MT8192_MUTEX_MOD_DISP_AAL0 },
+ { { MTK_DISP_CCORR, 0 }, MT8192_MUTEX_MOD_DISP_CCORR0 },
+ { { MTK_DISP_COLOR, 0 }, MT8192_MUTEX_MOD_DISP_COLOR0 },
+ { { MTK_DISP_DITHER, 0 }, MT8192_MUTEX_MOD_DISP_DITHER0 },
+ { { MTK_DISP_GAMMA, 0 }, MT8192_MUTEX_MOD_DISP_GAMMA0 },
+ { { MTK_DISP_POSTMASK, 0 }, MT8192_MUTEX_MOD_DISP_POSTMASK0 },
+ { { MTK_DISP_OVL, 0 }, MT8192_MUTEX_MOD_DISP_OVL0 },
+ { { MTK_DISP_OVL_2L, 0 }, MT8192_MUTEX_MOD_DISP_OVL0_2L },
+ { { MTK_DISP_OVL_2L, 2 }, MT8192_MUTEX_MOD_DISP_OVL2_2L },
+ { { MTK_DISP_RDMA, 0 }, MT8192_MUTEX_MOD_DISP_RDMA0 },
+ { { MTK_DISP_RDMA, 4 }, MT8192_MUTEX_MOD_DISP_RDMA4 },
};
const struct mtk_drm_legacy_mtx_data mt8192_legacy_mtx_data = {
@@ -741,34 +741,34 @@ const struct mtk_drm_legacy_mtx_data mt8192_legacy_mtx_data = {
};
static const struct mtk_drm_legacy_mtx_pairs mt8195_legacy_mtx_trig_ids[] = {
- { { DDP_COMPONENT_OVL0 }, MT8195_MUTEX_MOD_DISP_OVL0 },
- { { DDP_COMPONENT_WDMA0 }, MT8195_MUTEX_MOD_DISP_WDMA0 },
- { { DDP_COMPONENT_RDMA0 }, MT8195_MUTEX_MOD_DISP_RDMA0 },
- { { DDP_COMPONENT_COLOR0 }, MT8195_MUTEX_MOD_DISP_COLOR0 },
- { { DDP_COMPONENT_CCORR }, MT8195_MUTEX_MOD_DISP_CCORR0 },
- { { DDP_COMPONENT_AAL0 }, MT8195_MUTEX_MOD_DISP_AAL0 },
- { { DDP_COMPONENT_GAMMA }, MT8195_MUTEX_MOD_DISP_GAMMA0 },
- { { DDP_COMPONENT_DITHER0 }, MT8195_MUTEX_MOD_DISP_DITHER0 },
- { { DDP_COMPONENT_MERGE0 }, MT8195_MUTEX_MOD_DISP_VPP_MERGE },
- { { DDP_COMPONENT_DSC0 }, MT8195_MUTEX_MOD_DISP_DSC_WRAP0_CORE0 },
- { { DDP_COMPONENT_DSI0 }, MT8195_MUTEX_MOD_DISP_DSI0 },
- { { DDP_COMPONENT_PWM0 }, MT8195_MUTEX_MOD_DISP_PWM0 },
- { { DDP_COMPONENT_DP_INTF0 }, MT8195_MUTEX_MOD_DISP_DP_INTF0 },
- { { DDP_COMPONENT_MDP_RDMA0 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA0 },
- { { DDP_COMPONENT_MDP_RDMA1 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA1 },
- { { DDP_COMPONENT_MDP_RDMA2 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA2 },
- { { DDP_COMPONENT_MDP_RDMA3 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA3 },
- { { DDP_COMPONENT_MDP_RDMA4 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA4 },
- { { DDP_COMPONENT_MDP_RDMA5 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA5 },
- { { DDP_COMPONENT_MDP_RDMA6 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA6 },
- { { DDP_COMPONENT_MDP_RDMA7 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA7 },
- { { DDP_COMPONENT_MERGE1 }, MT8195_MUTEX_MOD_DISP1_VPP_MERGE0 },
- { { DDP_COMPONENT_MERGE2 }, MT8195_MUTEX_MOD_DISP1_VPP_MERGE1 },
- { { DDP_COMPONENT_MERGE3 }, MT8195_MUTEX_MOD_DISP1_VPP_MERGE2 },
- { { DDP_COMPONENT_MERGE4 }, MT8195_MUTEX_MOD_DISP1_VPP_MERGE3 },
- { { DDP_COMPONENT_ETHDR_MIXER }, MT8195_MUTEX_MOD_DISP1_DISP_MIXER },
- { { DDP_COMPONENT_MERGE5 }, MT8195_MUTEX_MOD_DISP1_VPP_MERGE4 },
- { { DDP_COMPONENT_DP_INTF1 }, MT8195_MUTEX_MOD_DISP1_DP_INTF0 },
+ { { MTK_DISP_OVL, 0 }, MT8195_MUTEX_MOD_DISP_OVL0 },
+ { { MTK_DISP_WDMA, 0 }, MT8195_MUTEX_MOD_DISP_WDMA0 },
+ { { MTK_DISP_RDMA, 0 }, MT8195_MUTEX_MOD_DISP_RDMA0 },
+ { { MTK_DISP_COLOR, 0 }, MT8195_MUTEX_MOD_DISP_COLOR0 },
+ { { MTK_DISP_CCORR, 0 }, MT8195_MUTEX_MOD_DISP_CCORR0 },
+ { { MTK_DISP_AAL, 0 }, MT8195_MUTEX_MOD_DISP_AAL0 },
+ { { MTK_DISP_GAMMA, 0 }, MT8195_MUTEX_MOD_DISP_GAMMA0 },
+ { { MTK_DISP_DITHER, 0 }, MT8195_MUTEX_MOD_DISP_DITHER0 },
+ { { MTK_DISP_MERGE, 0 }, MT8195_MUTEX_MOD_DISP_VPP_MERGE },
+ { { MTK_DISP_DSC, 0 }, MT8195_MUTEX_MOD_DISP_DSC_WRAP0_CORE0 },
+ { { MTK_DISP_DSI, 0 }, MT8195_MUTEX_MOD_DISP_DSI0 },
+ { { MTK_DISP_PWM, 0 }, MT8195_MUTEX_MOD_DISP_PWM0 },
+ { { MTK_DISP_DP_INTF, 0 }, MT8195_MUTEX_MOD_DISP_DP_INTF0 },
+ { { MTK_DISP_MDP_RDMA, 0 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA0 },
+ { { MTK_DISP_MDP_RDMA, 1 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA1 },
+ { { MTK_DISP_MDP_RDMA, 2 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA2 },
+ { { MTK_DISP_MDP_RDMA, 3 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA3 },
+ { { MTK_DISP_MDP_RDMA, 4 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA4 },
+ { { MTK_DISP_MDP_RDMA, 5 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA5 },
+ { { MTK_DISP_MDP_RDMA, 6 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA6 },
+ { { MTK_DISP_MDP_RDMA, 7 }, MT8195_MUTEX_MOD_DISP1_MDP_RDMA7 },
+ { { MTK_DISP_MERGE, 1 }, MT8195_MUTEX_MOD_DISP1_VPP_MERGE0 },
+ { { MTK_DISP_MERGE, 2 }, MT8195_MUTEX_MOD_DISP1_VPP_MERGE1 },
+ { { MTK_DISP_MERGE, 3 }, MT8195_MUTEX_MOD_DISP1_VPP_MERGE2 },
+ { { MTK_DISP_MERGE, 4 }, MT8195_MUTEX_MOD_DISP1_VPP_MERGE3 },
+ { { MTK_DISP_ETHDR_MIXER, 0 }, MT8195_MUTEX_MOD_DISP1_DISP_MIXER },
+ { { MTK_DISP_MERGE, 5 }, MT8195_MUTEX_MOD_DISP1_VPP_MERGE4 },
+ { { MTK_DISP_DP_INTF, 1 }, MT8195_MUTEX_MOD_DISP1_DP_INTF0 },
};
const struct mtk_drm_legacy_mtx_data mt8195_legacy_mtx_data = {
@@ -777,19 +777,19 @@ const struct mtk_drm_legacy_mtx_data mt8195_legacy_mtx_data = {
};
static const struct mtk_drm_legacy_mtx_pairs mt8365_legacy_mtx_trig_ids[] = {
- { { DDP_COMPONENT_AAL0 }, MT8365_MUTEX_MOD_DISP_AAL },
- { { DDP_COMPONENT_CCORR }, MT8365_MUTEX_MOD_DISP_CCORR },
- { { DDP_COMPONENT_COLOR0 }, MT8365_MUTEX_MOD_DISP_COLOR0 },
- { { DDP_COMPONENT_DITHER0 }, MT8365_MUTEX_MOD_DISP_DITHER },
- { { DDP_COMPONENT_DPI0 }, MT8365_MUTEX_MOD_DISP_DPI0 },
- { { DDP_COMPONENT_DSI0 }, MT8365_MUTEX_MOD_DISP_DSI0 },
- { { DDP_COMPONENT_GAMMA }, MT8365_MUTEX_MOD_DISP_GAMMA },
- { { DDP_COMPONENT_OVL0 }, MT8365_MUTEX_MOD_DISP_OVL0 },
- { { DDP_COMPONENT_OVL_2L0 }, MT8365_MUTEX_MOD_DISP_OVL0_2L },
- { { DDP_COMPONENT_PWM0 }, MT8365_MUTEX_MOD_DISP_PWM0 },
- { { DDP_COMPONENT_RDMA0 }, MT8365_MUTEX_MOD_DISP_RDMA0 },
- { { DDP_COMPONENT_RDMA1 }, MT8365_MUTEX_MOD_DISP_RDMA1 },
- { { DDP_COMPONENT_WDMA0 }, MT8365_MUTEX_MOD_DISP_WDMA0 },
+ { { MTK_DISP_AAL, 0 }, MT8365_MUTEX_MOD_DISP_AAL },
+ { { MTK_DISP_CCORR, 0 }, MT8365_MUTEX_MOD_DISP_CCORR },
+ { { MTK_DISP_COLOR, 0 }, MT8365_MUTEX_MOD_DISP_COLOR0 },
+ { { MTK_DISP_DITHER, 0 }, MT8365_MUTEX_MOD_DISP_DITHER },
+ { { MTK_DISP_DPI, 0 }, MT8365_MUTEX_MOD_DISP_DPI0 },
+ { { MTK_DISP_DSI, 0 }, MT8365_MUTEX_MOD_DISP_DSI0 },
+ { { MTK_DISP_GAMMA, 0 }, MT8365_MUTEX_MOD_DISP_GAMMA },
+ { { MTK_DISP_OVL, 0 }, MT8365_MUTEX_MOD_DISP_OVL0 },
+ { { MTK_DISP_OVL_2L, 0 }, MT8365_MUTEX_MOD_DISP_OVL0_2L },
+ { { MTK_DISP_PWM, 0 }, MT8365_MUTEX_MOD_DISP_PWM0 },
+ { { MTK_DISP_RDMA, 0 }, MT8365_MUTEX_MOD_DISP_RDMA0 },
+ { { MTK_DISP_RDMA, 1 }, MT8365_MUTEX_MOD_DISP_RDMA1 },
+ { { MTK_DISP_WDMA, 0 }, MT8365_MUTEX_MOD_DISP_WDMA0 },
};
const struct mtk_drm_legacy_mtx_data mt8365_legacy_mtx_data = {
@@ -831,13 +831,15 @@ int mtk_drm_legacy_inject_mutex_trig_ids(struct mtk_drm_comp_list *hlist,
const struct mtk_drm_comp_definition *comp = &data->pairs[i].comp;
hash_for_each_possible(hlist->ddp_list, ddp_comp, lnode, comp->type)
- ddp_comp->mtx_trig_id = data->pairs[i].mtx_trig_id;
+ if (ddp_comp->inst_id == comp->inst_id)
+ ddp_comp->mtx_trig_id = data->pairs[i].mtx_trig_id;
}
return 0;
}
-u8 mtk_drm_legacy_get_ovl_adaptor_mutex_trig_id(enum mtk_ddp_comp_id ddp_type,
+u8 mtk_drm_legacy_get_ovl_adaptor_mutex_trig_id(enum mtk_ddp_comp_type ddp_type,
+ u8 ddp_inst_id,
struct device_node *mutex_node)
{
struct mtk_drm_legacy_mtx_data *data;
@@ -853,7 +855,7 @@ u8 mtk_drm_legacy_get_ovl_adaptor_mutex_trig_id(enum mtk_ddp_comp_id ddp_type,
for (i = 0; i < data->num_pairs; i++) {
const struct mtk_drm_comp_definition *comp = &data->pairs[i].comp;
- if (ddp_type != comp->type)
+ if (ddp_type != comp->type || ddp_inst_id != comp->inst_id)
continue;
return data->pairs[i].mtx_trig_id;
@@ -871,6 +873,6 @@ void mtk_drm_legacy_ovl_adaptor_probe(struct device *dev, struct mtk_drm_private
PLATFORM_DEVID_AUTO,
(void *)priv, sizeof(*priv));
- mtk_ddp_comp_init(&ovl_adaptor->dev, NULL, &priv->hlist, DDP_COMPONENT_DRM_OVL_ADAPTOR);
+ mtk_ddp_comp_init(&ovl_adaptor->dev, NULL, &priv->hlist, MTK_DISP_OVL_ADAPTOR, 0);
component_match_add(dev, match, component_compare_dev, &ovl_adaptor->dev);
}
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_legacy.h b/drivers/gpu/drm/mediatek/mtk_drm_legacy.h
index 45bcf2674628..da0395d859d2 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_legacy.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_legacy.h
@@ -27,7 +27,8 @@ extern struct mtk_drm_path_definition mt8195_vdo1_legacy_paths[];
int mtk_drm_legacy_inject_mutex_trig_ids(struct mtk_drm_comp_list *hlist,
struct device_node *mutex_node);
-u8 mtk_drm_legacy_get_ovl_adaptor_mutex_trig_id(enum mtk_ddp_comp_id ddp_type,
+u8 mtk_drm_legacy_get_ovl_adaptor_mutex_trig_id(enum mtk_ddp_comp_type ddp_type,
+ u8 ddp_inst_id,
struct device_node *mutex_node);
void mtk_drm_legacy_ovl_adaptor_probe(struct device *dev, struct mtk_drm_private *priv,
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 20/42] drm/mediatek: mtk_dpi: Pass parameters with new mtk_dpi_sync structure
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (18 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 19/42] drm/mediatek: Fully migrate to new Display Controller " AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 21/42] drm/mediatek: mtk_dpi: Fully separate HW setup from common code AngeloGioacchino Del Regno
` (21 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In preparation for moving common code between DPI and DVO into a
new mtk_dpi_common library, add a new mtk_dpi_sync structure which
contains all of the sync parameters, such as HSYNC and Left/Right
Odd and Even VSYNC.
This is now passed as parameter of mtk_dpi_set_display_mode() and
stack initialized in mtk_dpi_bridge_enable(): future preparation
changes will add abstraction for hardware specific configuration
which purpose will be to interpret the generic parameters to write
those to the hardware specific registers.
This brings no functional change.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 76 +++++++++++++++---------------
1 file changed, 39 insertions(+), 37 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index cc6d74ce8b5e..ecd13ea782c2 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -112,6 +112,14 @@ struct mtk_dpi_sync_param {
bool shift_half_line;
};
+struct mtk_dpi_sync {
+ struct mtk_dpi_sync_param hsync;
+ struct mtk_dpi_sync_param vsync_l_odd;
+ struct mtk_dpi_sync_param vsync_l_even;
+ struct mtk_dpi_sync_param vsync_r_odd;
+ struct mtk_dpi_sync_param vsync_r_even;
+};
+
struct mtk_dpi_yc_limit {
u16 y_top;
u16 y_bottom;
@@ -600,14 +608,10 @@ static void mtk_dpi_set_pixel_clk(struct mtk_dpi *dpi, struct videomode *vm, int
}
static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
+ struct mtk_dpi_sync *sync,
struct drm_display_mode *mode)
{
struct mtk_dpi_polarities dpi_pol;
- struct mtk_dpi_sync_param hsync;
- struct mtk_dpi_sync_param vsync_lodd = { 0 };
- struct mtk_dpi_sync_param vsync_leven = { 0 };
- struct mtk_dpi_sync_param vsync_rodd = { 0 };
- struct mtk_dpi_sync_param vsync_reven = { 0 };
struct videomode vm = { 0 };
drm_display_mode_to_videomode(mode, &vm);
@@ -624,42 +628,39 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
/*
* Depending on the IP version, we may output a different amount of
- * pixels for each iteration: divide the clock by this number and
- * adjust the display porches accordingly.
+ * pixels for each iteration: adjust the display porches accordingly.
*/
- hsync.sync_width = vm.hsync_len / dpi->conf->pixels_per_iter;
- hsync.back_porch = vm.hback_porch / dpi->conf->pixels_per_iter;
- hsync.front_porch = vm.hfront_porch / dpi->conf->pixels_per_iter;
-
- hsync.shift_half_line = false;
- vsync_lodd.sync_width = vm.vsync_len;
- vsync_lodd.back_porch = vm.vback_porch;
- vsync_lodd.front_porch = vm.vfront_porch;
- vsync_lodd.shift_half_line = false;
-
- if (vm.flags & DISPLAY_FLAGS_INTERLACED &&
- mode->flags & DRM_MODE_FLAG_3D_MASK) {
- vsync_leven = vsync_lodd;
- vsync_rodd = vsync_lodd;
- vsync_reven = vsync_lodd;
- vsync_leven.shift_half_line = true;
- vsync_reven.shift_half_line = true;
- } else if (vm.flags & DISPLAY_FLAGS_INTERLACED &&
- !(mode->flags & DRM_MODE_FLAG_3D_MASK)) {
- vsync_leven = vsync_lodd;
- vsync_leven.shift_half_line = true;
- } else if (!(vm.flags & DISPLAY_FLAGS_INTERLACED) &&
- mode->flags & DRM_MODE_FLAG_3D_MASK) {
- vsync_rodd = vsync_lodd;
+ sync->hsync.sync_width = vm.hsync_len / dpi->conf->pixels_per_iter;
+ sync->hsync.back_porch = vm.hback_porch / dpi->conf->pixels_per_iter;
+ sync->hsync.front_porch = vm.hfront_porch / dpi->conf->pixels_per_iter;
+ sync->hsync.shift_half_line = false;
+
+ sync->vsync_l_odd.sync_width = vm.vsync_len;
+ sync->vsync_l_odd.back_porch = vm.vback_porch;
+ sync->vsync_l_odd.front_porch = vm.vfront_porch;
+ sync->vsync_l_odd.shift_half_line = false;
+
+ if (vm.flags & DISPLAY_FLAGS_INTERLACED) {
+ sync->vsync_l_even = sync->vsync_l_odd;
+ sync->vsync_l_even.shift_half_line = true;
+
+ if (mode->flags & DRM_MODE_FLAG_3D_MASK) {
+ sync->vsync_r_odd = sync->vsync_l_odd;
+ sync->vsync_r_even = sync->vsync_l_odd;
+ sync->vsync_r_even.shift_half_line = true;
+ }
+ } else if (mode->flags & DRM_MODE_FLAG_3D_MASK) {
+ sync->vsync_r_odd = sync->vsync_l_odd;
}
+
mtk_dpi_sw_reset(dpi, true);
mtk_dpi_config_pol(dpi, &dpi_pol);
- mtk_dpi_config_hsync(dpi, &hsync);
- mtk_dpi_config_vsync_lodd(dpi, &vsync_lodd);
- mtk_dpi_config_vsync_rodd(dpi, &vsync_rodd);
- mtk_dpi_config_vsync_leven(dpi, &vsync_leven);
- mtk_dpi_config_vsync_reven(dpi, &vsync_reven);
+ mtk_dpi_config_hsync(dpi, &sync->hsync);
+ mtk_dpi_config_vsync_lodd(dpi, &sync->vsync_l_odd);
+ mtk_dpi_config_vsync_rodd(dpi, &sync->vsync_r_odd);
+ mtk_dpi_config_vsync_leven(dpi, &sync->vsync_l_even);
+ mtk_dpi_config_vsync_reven(dpi, &sync->vsync_r_even);
mtk_dpi_config_3d(dpi, !!(mode->flags & DRM_MODE_FLAG_3D_MASK));
mtk_dpi_config_interface(dpi, !!(vm.flags &
@@ -863,12 +864,13 @@ static void mtk_dpi_bridge_disable(struct drm_bridge *bridge)
static void mtk_dpi_bridge_enable(struct drm_bridge *bridge)
{
struct mtk_dpi *dpi = bridge_to_dpi(bridge);
+ struct mtk_dpi_sync sync = { 0 };
if (dpi->pinctrl && dpi->pins_dpi)
pinctrl_select_state(dpi->pinctrl, dpi->pins_dpi);
mtk_dpi_power_on(dpi);
- mtk_dpi_set_display_mode(dpi, &dpi->mode);
+ mtk_dpi_set_display_mode(dpi, &sync, &dpi->mode);
mtk_dpi_enable(dpi);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 21/42] drm/mediatek: mtk_dpi: Fully separate HW setup from common code
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (19 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 20/42] drm/mediatek: mtk_dpi: Pass parameters with new mtk_dpi_sync structure AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 22/42] drm/mediatek: Create new mtk_dpi_common lib and move mtk_dpi code AngeloGioacchino Del Regno
` (20 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
As a preparation step for adding support for DVO and creating a
mtk_dpi_common library, fully separate all of the register writing
mechanisms from commonizable hardware setup functions.
While at it, also perform some spare code style cleanups and also
remove the mtk_dpi_config_vsync_{l,r}{odd,even}() functions and
open-code the single line found in each of those, as now all of
the parameters are clearly labeled and won't have any meaningful
impact on human readability.
This change brings no functional differences.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_dpi.c | 172 ++++++++++++++---------------
1 file changed, 86 insertions(+), 86 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index ecd13ea782c2..077e8a42a044 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -246,33 +246,6 @@ static void mtk_dpi_config_vsync(struct mtk_dpi *dpi,
dpi->conf->dimension_mask << VSYNC_FRONT_PORCH_SHIFT);
}
-static void mtk_dpi_config_vsync_lodd(struct mtk_dpi *dpi,
- struct mtk_dpi_sync_param *sync)
-{
- mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH, DPI_TGEN_VPORCH);
-}
-
-static void mtk_dpi_config_vsync_leven(struct mtk_dpi *dpi,
- struct mtk_dpi_sync_param *sync)
-{
- mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH_LEVEN,
- DPI_TGEN_VPORCH_LEVEN);
-}
-
-static void mtk_dpi_config_vsync_rodd(struct mtk_dpi *dpi,
- struct mtk_dpi_sync_param *sync)
-{
- mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH_RODD,
- DPI_TGEN_VPORCH_RODD);
-}
-
-static void mtk_dpi_config_vsync_reven(struct mtk_dpi *dpi,
- struct mtk_dpi_sync_param *sync)
-{
- mtk_dpi_config_vsync(dpi, sync, DPI_TGEN_VWIDTH_REVEN,
- DPI_TGEN_VPORCH_REVEN);
-}
-
static void mtk_dpi_config_pol(struct mtk_dpi *dpi,
struct mtk_dpi_polarities *dpi_pol)
{
@@ -311,30 +284,15 @@ static void mtk_dpi_config_fb_size(struct mtk_dpi *dpi, u32 width, u32 height)
dpi->conf->hvsize_mask << VSIZE);
}
-static void mtk_dpi_config_channel_limit(struct mtk_dpi *dpi)
+static void mtk_dpi_config_channel_limit(struct mtk_dpi *dpi, struct mtk_dpi_yc_limit *limit)
{
- struct mtk_dpi_yc_limit limit;
-
- if (drm_default_rgb_quant_range(&dpi->mode) ==
- HDMI_QUANTIZATION_RANGE_LIMITED) {
- limit.y_bottom = 0x10;
- limit.y_top = 0xfe0;
- limit.c_bottom = 0x10;
- limit.c_top = 0xfe0;
- } else {
- limit.y_bottom = 0;
- limit.y_top = 0xfff;
- limit.c_bottom = 0;
- limit.c_top = 0xfff;
- }
-
- mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit.y_bottom << Y_LIMINT_BOT,
+ mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit->y_bottom << Y_LIMINT_BOT,
Y_LIMINT_BOT_MASK);
- mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit.y_top << Y_LIMINT_TOP,
+ mtk_dpi_mask(dpi, DPI_Y_LIMIT, limit->y_top << Y_LIMINT_TOP,
Y_LIMINT_TOP_MASK);
- mtk_dpi_mask(dpi, DPI_C_LIMIT, limit.c_bottom << C_LIMIT_BOT,
+ mtk_dpi_mask(dpi, DPI_C_LIMIT, limit->c_bottom << C_LIMIT_BOT,
C_LIMIT_BOT_MASK);
- mtk_dpi_mask(dpi, DPI_C_LIMIT, limit.c_top << C_LIMIT_TOP,
+ mtk_dpi_mask(dpi, DPI_C_LIMIT, limit->c_top << C_LIMIT_TOP,
C_LIMIT_TOP_MASK);
}
@@ -516,7 +474,6 @@ static void mtk_dpi_power_off(struct mtk_dpi *dpi)
if (--dpi->refcount != 0)
return;
- mtk_dpi_disable(dpi);
clk_disable_unprepare(dpi->pixel_clk);
clk_disable_unprepare(dpi->tvd_clk);
clk_disable_unprepare(dpi->engine_clk);
@@ -607,40 +564,40 @@ static void mtk_dpi_set_pixel_clk(struct mtk_dpi *dpi, struct videomode *vm, int
pll_rate, vm->pixelclock);
}
-static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
+static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, struct videomode *vm,
struct mtk_dpi_sync *sync,
- struct drm_display_mode *mode)
+ struct mtk_dpi_polarities *dpi_pol,
+ struct mtk_dpi_yc_limit *limit)
{
- struct mtk_dpi_polarities dpi_pol;
- struct videomode vm = { 0 };
+ struct drm_display_mode *mode = &dpi->mode;
- drm_display_mode_to_videomode(mode, &vm);
+ drm_display_mode_to_videomode(mode, vm);
if (!dpi->conf->clocked_by_hdmi)
- mtk_dpi_set_pixel_clk(dpi, &vm, mode->clock);
+ mtk_dpi_set_pixel_clk(dpi, vm, mode->clock);
- dpi_pol.ck_pol = MTK_DPI_POLARITY_FALLING;
- dpi_pol.de_pol = MTK_DPI_POLARITY_RISING;
- dpi_pol.hsync_pol = vm.flags & DISPLAY_FLAGS_HSYNC_HIGH ?
+ dpi_pol->ck_pol = MTK_DPI_POLARITY_FALLING;
+ dpi_pol->de_pol = MTK_DPI_POLARITY_RISING;
+ dpi_pol->hsync_pol = vm->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING;
- dpi_pol.vsync_pol = vm.flags & DISPLAY_FLAGS_VSYNC_HIGH ?
+ dpi_pol->vsync_pol = vm->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING;
/*
* Depending on the IP version, we may output a different amount of
* pixels for each iteration: adjust the display porches accordingly.
*/
- sync->hsync.sync_width = vm.hsync_len / dpi->conf->pixels_per_iter;
- sync->hsync.back_porch = vm.hback_porch / dpi->conf->pixels_per_iter;
- sync->hsync.front_porch = vm.hfront_porch / dpi->conf->pixels_per_iter;
+ sync->hsync.sync_width = vm->hsync_len / dpi->conf->pixels_per_iter;
+ sync->hsync.back_porch = vm->hback_porch / dpi->conf->pixels_per_iter;
+ sync->hsync.front_porch = vm->hfront_porch / dpi->conf->pixels_per_iter;
sync->hsync.shift_half_line = false;
- sync->vsync_l_odd.sync_width = vm.vsync_len;
- sync->vsync_l_odd.back_porch = vm.vback_porch;
- sync->vsync_l_odd.front_porch = vm.vfront_porch;
+ sync->vsync_l_odd.sync_width = vm->vsync_len;
+ sync->vsync_l_odd.back_porch = vm->vback_porch;
+ sync->vsync_l_odd.front_porch = vm->vfront_porch;
sync->vsync_l_odd.shift_half_line = false;
- if (vm.flags & DISPLAY_FLAGS_INTERLACED) {
+ if (vm->flags & DISPLAY_FLAGS_INTERLACED) {
sync->vsync_l_even = sync->vsync_l_odd;
sync->vsync_l_even.shift_half_line = true;
@@ -653,27 +610,55 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
sync->vsync_r_odd = sync->vsync_l_odd;
}
+ if (drm_default_rgb_quant_range(&dpi->mode) == HDMI_QUANTIZATION_RANGE_LIMITED) {
+ limit->y_bottom = 0x10;
+ limit->y_top = 0xfe0;
+ limit->c_bottom = 0x10;
+ limit->c_top = 0xfe0;
+ } else {
+ limit->y_bottom = 0;
+ limit->y_top = 0xfff;
+ limit->c_bottom = 0;
+ limit->c_top = 0xfff;
+ }
+
+ return 0;
+}
+
+static void mtk_dpi_config_hw(struct mtk_dpi *dpi,
+ struct videomode *vm, struct mtk_dpi_sync *sync,
+ struct mtk_dpi_polarities *dpi_pol,
+ struct mtk_dpi_yc_limit *limit)
+{
+ struct drm_display_mode *mode = &dpi->mode;
+ u32 vactive = vm->vactive;
+
mtk_dpi_sw_reset(dpi, true);
- mtk_dpi_config_pol(dpi, &dpi_pol);
+ mtk_dpi_config_pol(dpi, dpi_pol);
mtk_dpi_config_hsync(dpi, &sync->hsync);
- mtk_dpi_config_vsync_lodd(dpi, &sync->vsync_l_odd);
- mtk_dpi_config_vsync_rodd(dpi, &sync->vsync_r_odd);
- mtk_dpi_config_vsync_leven(dpi, &sync->vsync_l_even);
- mtk_dpi_config_vsync_reven(dpi, &sync->vsync_r_even);
+
+ mtk_dpi_config_vsync(dpi, &sync->vsync_l_odd,
+ DPI_TGEN_VWIDTH, DPI_TGEN_VPORCH);
+ mtk_dpi_config_vsync(dpi, &sync->vsync_r_odd,
+ DPI_TGEN_VWIDTH_RODD, DPI_TGEN_VPORCH_RODD);
+ mtk_dpi_config_vsync(dpi, &sync->vsync_l_even,
+ DPI_TGEN_VWIDTH_LEVEN, DPI_TGEN_VPORCH_LEVEN);
+ mtk_dpi_config_vsync(dpi, &sync->vsync_r_even,
+ DPI_TGEN_VWIDTH_REVEN, DPI_TGEN_VPORCH_REVEN);
mtk_dpi_config_3d(dpi, !!(mode->flags & DRM_MODE_FLAG_3D_MASK));
- mtk_dpi_config_interface(dpi, !!(vm.flags &
- DISPLAY_FLAGS_INTERLACED));
- if (vm.flags & DISPLAY_FLAGS_INTERLACED)
- mtk_dpi_config_fb_size(dpi, vm.hactive, vm.vactive >> 1);
- else
- mtk_dpi_config_fb_size(dpi, vm.hactive, vm.vactive);
+ mtk_dpi_config_interface(dpi, !!(vm->flags & DISPLAY_FLAGS_INTERLACED));
+
+ if (vm->flags & DISPLAY_FLAGS_INTERLACED)
+ vactive >>= 1;
- mtk_dpi_config_channel_limit(dpi);
+ mtk_dpi_config_fb_size(dpi, vm->hactive, vactive);
+ mtk_dpi_config_channel_limit(dpi, limit);
mtk_dpi_config_bit_num(dpi, dpi->bit_num);
mtk_dpi_config_channel_swap(dpi, dpi->channel_swap);
mtk_dpi_config_color_format(dpi, dpi->color_format);
+
if (dpi->conf->support_direct_pin) {
mtk_dpi_config_yc_map(dpi, dpi->yc_map);
mtk_dpi_config_2n_h_fre(dpi);
@@ -686,13 +671,13 @@ static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi,
mtk_dpi_config_disable_edge(dpi);
}
- if (dpi->conf->input_2p_en_bit) {
+
+ if (dpi->conf->input_2p_en_bit)
mtk_dpi_mask(dpi, DPI_CON, dpi->conf->input_2p_en_bit,
dpi->conf->input_2p_en_bit);
- }
- mtk_dpi_sw_reset(dpi, false);
- return 0;
+ mtk_dpi_sw_reset(dpi, false);
+ return;
}
static u32 *mtk_dpi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
@@ -855,6 +840,7 @@ static void mtk_dpi_bridge_disable(struct drm_bridge *bridge)
{
struct mtk_dpi *dpi = bridge_to_dpi(bridge);
+ mtk_dpi_disable(dpi);
mtk_dpi_power_off(dpi);
if (dpi->pinctrl && dpi->pins_gpio)
@@ -864,13 +850,22 @@ static void mtk_dpi_bridge_disable(struct drm_bridge *bridge)
static void mtk_dpi_bridge_enable(struct drm_bridge *bridge)
{
struct mtk_dpi *dpi = bridge_to_dpi(bridge);
+ struct mtk_dpi_polarities dpi_pol;
struct mtk_dpi_sync sync = { 0 };
+ struct mtk_dpi_yc_limit limit;
+ struct videomode vm;
if (dpi->pinctrl && dpi->pins_dpi)
pinctrl_select_state(dpi->pinctrl, dpi->pins_dpi);
mtk_dpi_power_on(dpi);
- mtk_dpi_set_display_mode(dpi, &sync, &dpi->mode);
+
+ /* Set pixel clock and initialize parameters to send to the HW */
+ mtk_dpi_set_display_mode(dpi, &vm, &sync, &dpi_pol, &limit);
+
+ /* Format and send the parameters to the HW */
+ mtk_dpi_config_hw(dpi, &vm, &sync, &dpi_pol, &limit);
+
mtk_dpi_enable(dpi);
}
@@ -999,16 +994,21 @@ void mtk_dpi_start(struct device *dev)
{
struct mtk_dpi *dpi = dev_get_drvdata(dev);
- if (!dpi->conf->clocked_by_hdmi)
- mtk_dpi_power_on(dpi);
+ if (dpi->conf->clocked_by_hdmi)
+ return;
+
+ mtk_dpi_power_on(dpi);
}
void mtk_dpi_stop(struct device *dev)
{
struct mtk_dpi *dpi = dev_get_drvdata(dev);
- if (!dpi->conf->clocked_by_hdmi)
- mtk_dpi_power_off(dpi);
+ if (dpi->conf->clocked_by_hdmi)
+ return;
+
+ mtk_dpi_disable(dpi);
+ mtk_dpi_power_off(dpi);
}
unsigned int mtk_dpi_encoder_index(struct device *dev)
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 22/42] drm/mediatek: Create new mtk_dpi_common lib and move mtk_dpi code
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (20 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 21/42] drm/mediatek: mtk_dpi: Fully separate HW setup from common code AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 23/42] dt-bindings: display: mediatek: Introduce Digital Video Output HW AngeloGioacchino Del Regno
` (19 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
As a final preparation step for adding support for the MediaTek
Digital Video Out (DVO) hardware found in newer SoCs, create a
new mtk_dpi_common library and move common code between the DPI
and the upcoming DVO in there.
This change brings no functional differences, as the new file is
built-in on the mediatek-drm object anyway.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/Makefile | 1 +
drivers/gpu/drm/mediatek/mtk_dpi.c | 654 +---------------------
drivers/gpu/drm/mediatek/mtk_dpi_common.c | 468 ++++++++++++++++
drivers/gpu/drm/mediatek/mtk_dpi_common.h | 276 +++++++++
4 files changed, 762 insertions(+), 637 deletions(-)
create mode 100644 drivers/gpu/drm/mediatek/mtk_dpi_common.c
create mode 100644 drivers/gpu/drm/mediatek/mtk_dpi_common.h
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index f40ad5565716..34a1d4721b70 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -15,6 +15,7 @@ mediatek-drm-y := mtk_crtc.o \
mtk_drm_drv.o \
mtk_drm_legacy.o \
mtk_dsi.o \
+ mtk_dpi_common.o \
mtk_dpi.o \
mtk_ethdr.o \
mtk_mdp_rdma.o \
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 077e8a42a044..ac972c0a9711 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -2,17 +2,16 @@
/*
* Copyright (c) 2014 MediaTek Inc.
* Author: Jie Qiu <jie.qiu@mediatek.com>
+ *
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
*/
#include <linux/bitfield.h>
-#include <linux/clk.h>
#include <linux/component.h>
#include <linux/debugfs.h>
-#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/media-bus-format.h>
-#include <linux/of.h>
-#include <linux/of_graph.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/soc/mediatek/mtk-mmsys.h>
@@ -23,172 +22,12 @@
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
-#include <drm/drm_crtc.h>
-#include <drm/drm_edid.h>
#include <drm/drm_of.h>
-#include <drm/drm_simple_kms_helper.h>
#include "mtk_ddp_comp.h"
#include "mtk_disp_drv.h"
+#include "mtk_dpi_common.h"
#include "mtk_dpi_regs.h"
-#include "mtk_drm_drv.h"
-
-enum mtk_dpi_out_bit_num {
- MTK_DPI_OUT_BIT_NUM_8BITS,
- MTK_DPI_OUT_BIT_NUM_10BITS,
- MTK_DPI_OUT_BIT_NUM_12BITS,
- MTK_DPI_OUT_BIT_NUM_16BITS
-};
-
-enum mtk_dpi_out_yc_map {
- MTK_DPI_OUT_YC_MAP_RGB,
- MTK_DPI_OUT_YC_MAP_CYCY,
- MTK_DPI_OUT_YC_MAP_YCYC,
- MTK_DPI_OUT_YC_MAP_CY,
- MTK_DPI_OUT_YC_MAP_YC
-};
-
-enum mtk_dpi_out_channel_swap {
- MTK_DPI_OUT_CHANNEL_SWAP_RGB,
- MTK_DPI_OUT_CHANNEL_SWAP_GBR,
- MTK_DPI_OUT_CHANNEL_SWAP_BRG,
- MTK_DPI_OUT_CHANNEL_SWAP_RBG,
- MTK_DPI_OUT_CHANNEL_SWAP_GRB,
- MTK_DPI_OUT_CHANNEL_SWAP_BGR
-};
-
-enum mtk_dpi_out_color_format {
- MTK_DPI_COLOR_FORMAT_RGB,
- MTK_DPI_COLOR_FORMAT_YCBCR_422,
- MTK_DPI_COLOR_FORMAT_YCBCR_444
-};
-
-struct mtk_dpi {
- struct drm_encoder encoder;
- struct drm_bridge bridge;
- struct drm_bridge *next_bridge;
- struct drm_connector *connector;
- void __iomem *regs;
- struct device *dev;
- struct device *mmsys_dev;
- struct clk *engine_clk;
- struct clk *pixel_clk;
- struct clk *tvd_clk;
- int irq;
- struct drm_display_mode mode;
- const struct mtk_dpi_conf *conf;
- enum mtk_dpi_out_color_format color_format;
- enum mtk_dpi_out_yc_map yc_map;
- enum mtk_dpi_out_bit_num bit_num;
- enum mtk_dpi_out_channel_swap channel_swap;
- struct pinctrl *pinctrl;
- struct pinctrl_state *pins_gpio;
- struct pinctrl_state *pins_dpi;
- u32 output_fmt;
- int refcount;
-};
-
-static inline struct mtk_dpi *bridge_to_dpi(struct drm_bridge *b)
-{
- return container_of(b, struct mtk_dpi, bridge);
-}
-
-enum mtk_dpi_polarity {
- MTK_DPI_POLARITY_RISING,
- MTK_DPI_POLARITY_FALLING,
-};
-
-struct mtk_dpi_polarities {
- enum mtk_dpi_polarity de_pol;
- enum mtk_dpi_polarity ck_pol;
- enum mtk_dpi_polarity hsync_pol;
- enum mtk_dpi_polarity vsync_pol;
-};
-
-struct mtk_dpi_sync_param {
- u32 sync_width;
- u32 front_porch;
- u32 back_porch;
- bool shift_half_line;
-};
-
-struct mtk_dpi_sync {
- struct mtk_dpi_sync_param hsync;
- struct mtk_dpi_sync_param vsync_l_odd;
- struct mtk_dpi_sync_param vsync_l_even;
- struct mtk_dpi_sync_param vsync_r_odd;
- struct mtk_dpi_sync_param vsync_r_even;
-};
-
-struct mtk_dpi_yc_limit {
- u16 y_top;
- u16 y_bottom;
- u16 c_top;
- u16 c_bottom;
-};
-
-struct mtk_dpi_factor {
- u32 clock;
- u8 factor;
-};
-
-/**
- * struct mtk_dpi_conf - Configuration of mediatek dpi.
- * @dpi_factor: SoC-specific pixel clock PLL factor values.
- * @num_dpi_factor: Number of pixel clock PLL factor values.
- * @reg_h_fre_con: Register address of frequency control.
- * @max_clock_khz: Max clock frequency supported for this SoCs in khz units.
- * @edge_sel_en: Enable of edge selection.
- * @output_fmts: Array of supported output formats.
- * @num_output_fmts: Quantity of supported output formats.
- * @is_ck_de_pol: Support CK/DE polarity.
- * @swap_input_support: Support input swap function.
- * @support_direct_pin: IP supports direct connection to dpi panels.
- * @dimension_mask: Mask used for HWIDTH, HPORCH, VSYNC_WIDTH and VSYNC_PORCH
- * (no shift).
- * @hvsize_mask: Mask of HSIZE and VSIZE mask (no shift).
- * @channel_swap_shift: Shift value of channel swap.
- * @yuv422_en_bit: Enable bit of yuv422.
- * @csc_enable_bit: Enable bit of CSC.
- * @input_2p_en_bit: Enable bit for input two pixel per round feature.
- * If present, implies that the feature must be enabled.
- * @pixels_per_iter: Quantity of transferred pixels per iteration.
- * @edge_cfg_in_mmsys: If the edge configuration for DPI's output needs to be set in MMSYS.
- * @clocked_by_hdmi: HDMI IP outputs clock to dpi_pixel_clk input clock, needed
- * for DPI registers access.
- * @output_1pixel: Enable outputting one pixel per round; if the input is two pixel per
- * round, the DPI hardware will internally transform it to 1T1P.
- */
-struct mtk_dpi_conf {
- const struct mtk_dpi_factor *dpi_factor;
- const u8 num_dpi_factor;
- u32 reg_h_fre_con;
- u32 max_clock_khz;
- bool edge_sel_en;
- const u32 *output_fmts;
- u32 num_output_fmts;
- bool is_ck_de_pol;
- bool swap_input_support;
- bool support_direct_pin;
- u32 dimension_mask;
- u32 hvsize_mask;
- u32 channel_swap_shift;
- u32 yuv422_en_bit;
- u32 csc_enable_bit;
- u32 input_2p_en_bit;
- u32 pixels_per_iter;
- bool edge_cfg_in_mmsys;
- bool clocked_by_hdmi;
- bool output_1pixel;
-};
-
-static void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
-{
- u32 tmp = readl(dpi->regs + offset) & ~mask;
-
- tmp |= (val & mask);
- writel(tmp, dpi->regs + offset);
-}
static void mtk_dpi_test_pattern_en(struct mtk_dpi *dpi, u8 type, bool enable)
{
@@ -466,165 +305,6 @@ static void mtk_dpi_dual_edge(struct mtk_dpi *dpi)
}
}
-static void mtk_dpi_power_off(struct mtk_dpi *dpi)
-{
- if (WARN_ON(dpi->refcount == 0))
- return;
-
- if (--dpi->refcount != 0)
- return;
-
- clk_disable_unprepare(dpi->pixel_clk);
- clk_disable_unprepare(dpi->tvd_clk);
- clk_disable_unprepare(dpi->engine_clk);
-}
-
-static int mtk_dpi_power_on(struct mtk_dpi *dpi)
-{
- int ret;
-
- if (++dpi->refcount != 1)
- return 0;
-
- ret = clk_prepare_enable(dpi->engine_clk);
- if (ret) {
- dev_err(dpi->dev, "Failed to enable engine clock: %d\n", ret);
- goto err_refcount;
- }
-
- ret = clk_prepare_enable(dpi->tvd_clk);
- if (ret) {
- dev_err(dpi->dev, "Failed to enable tvd pll: %d\n", ret);
- goto err_engine;
- }
-
- ret = clk_prepare_enable(dpi->pixel_clk);
- if (ret) {
- dev_err(dpi->dev, "Failed to enable pixel clock: %d\n", ret);
- goto err_pixel;
- }
-
- return 0;
-
-err_pixel:
- clk_disable_unprepare(dpi->tvd_clk);
-err_engine:
- clk_disable_unprepare(dpi->engine_clk);
-err_refcount:
- dpi->refcount--;
- return ret;
-}
-
-static unsigned int mtk_dpi_calculate_factor(struct mtk_dpi *dpi, int mode_clk)
-{
- const struct mtk_dpi_factor *dpi_factor = dpi->conf->dpi_factor;
- int i;
-
- for (i = 0; i < dpi->conf->num_dpi_factor; i++) {
- if (mode_clk <= dpi_factor[i].clock)
- return dpi_factor[i].factor;
- }
-
- /* If no match try the lowest possible factor */
- return dpi_factor[dpi->conf->num_dpi_factor - 1].factor;
-}
-
-static void mtk_dpi_set_pixel_clk(struct mtk_dpi *dpi, struct videomode *vm, int mode_clk)
-{
- unsigned long pll_rate;
- unsigned int factor;
-
- /* let pll_rate can fix the valid range of tvdpll (1G~2GHz) */
- factor = mtk_dpi_calculate_factor(dpi, mode_clk);
- pll_rate = vm->pixelclock * factor;
-
- dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
- pll_rate, vm->pixelclock);
-
- clk_set_rate(dpi->tvd_clk, pll_rate);
- pll_rate = clk_get_rate(dpi->tvd_clk);
-
- /*
- * Depending on the IP version, we may output a different amount of
- * pixels for each iteration: divide the clock by this number and
- * adjust the display porches accordingly.
- */
- vm->pixelclock = pll_rate / factor;
- vm->pixelclock /= dpi->conf->pixels_per_iter;
-
- if ((dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_LE) ||
- (dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_BE))
- clk_set_rate(dpi->pixel_clk, vm->pixelclock * 2);
- else
- clk_set_rate(dpi->pixel_clk, vm->pixelclock);
-
- vm->pixelclock = clk_get_rate(dpi->pixel_clk);
-
- dev_dbg(dpi->dev, "Got PLL %lu Hz, pixel clock %lu Hz\n",
- pll_rate, vm->pixelclock);
-}
-
-static int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, struct videomode *vm,
- struct mtk_dpi_sync *sync,
- struct mtk_dpi_polarities *dpi_pol,
- struct mtk_dpi_yc_limit *limit)
-{
- struct drm_display_mode *mode = &dpi->mode;
-
- drm_display_mode_to_videomode(mode, vm);
-
- if (!dpi->conf->clocked_by_hdmi)
- mtk_dpi_set_pixel_clk(dpi, vm, mode->clock);
-
- dpi_pol->ck_pol = MTK_DPI_POLARITY_FALLING;
- dpi_pol->de_pol = MTK_DPI_POLARITY_RISING;
- dpi_pol->hsync_pol = vm->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
- MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING;
- dpi_pol->vsync_pol = vm->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
- MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING;
-
- /*
- * Depending on the IP version, we may output a different amount of
- * pixels for each iteration: adjust the display porches accordingly.
- */
- sync->hsync.sync_width = vm->hsync_len / dpi->conf->pixels_per_iter;
- sync->hsync.back_porch = vm->hback_porch / dpi->conf->pixels_per_iter;
- sync->hsync.front_porch = vm->hfront_porch / dpi->conf->pixels_per_iter;
- sync->hsync.shift_half_line = false;
-
- sync->vsync_l_odd.sync_width = vm->vsync_len;
- sync->vsync_l_odd.back_porch = vm->vback_porch;
- sync->vsync_l_odd.front_porch = vm->vfront_porch;
- sync->vsync_l_odd.shift_half_line = false;
-
- if (vm->flags & DISPLAY_FLAGS_INTERLACED) {
- sync->vsync_l_even = sync->vsync_l_odd;
- sync->vsync_l_even.shift_half_line = true;
-
- if (mode->flags & DRM_MODE_FLAG_3D_MASK) {
- sync->vsync_r_odd = sync->vsync_l_odd;
- sync->vsync_r_even = sync->vsync_l_odd;
- sync->vsync_r_even.shift_half_line = true;
- }
- } else if (mode->flags & DRM_MODE_FLAG_3D_MASK) {
- sync->vsync_r_odd = sync->vsync_l_odd;
- }
-
- if (drm_default_rgb_quant_range(&dpi->mode) == HDMI_QUANTIZATION_RANGE_LIMITED) {
- limit->y_bottom = 0x10;
- limit->y_top = 0xfe0;
- limit->c_bottom = 0x10;
- limit->c_top = 0xfe0;
- } else {
- limit->y_bottom = 0;
- limit->y_top = 0xfff;
- limit->c_bottom = 0;
- limit->c_top = 0xfff;
- }
-
- return 0;
-}
-
static void mtk_dpi_config_hw(struct mtk_dpi *dpi,
struct videomode *vm, struct mtk_dpi_sync *sync,
struct mtk_dpi_polarities *dpi_pol,
@@ -680,143 +360,6 @@ static void mtk_dpi_config_hw(struct mtk_dpi *dpi,
return;
}
-static u32 *mtk_dpi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
- struct drm_bridge_state *bridge_state,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *conn_state,
- unsigned int *num_output_fmts)
-{
- struct mtk_dpi *dpi = bridge_to_dpi(bridge);
- u32 *output_fmts;
-
- *num_output_fmts = 0;
-
- if (!dpi->conf->output_fmts) {
- dev_err(dpi->dev, "output_fmts should not be null\n");
- return NULL;
- }
-
- output_fmts = kcalloc(dpi->conf->num_output_fmts, sizeof(*output_fmts),
- GFP_KERNEL);
- if (!output_fmts)
- return NULL;
-
- *num_output_fmts = dpi->conf->num_output_fmts;
-
- memcpy(output_fmts, dpi->conf->output_fmts,
- sizeof(*output_fmts) * dpi->conf->num_output_fmts);
-
- return output_fmts;
-}
-
-static u32 *mtk_dpi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
- struct drm_bridge_state *bridge_state,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *conn_state,
- u32 output_fmt,
- unsigned int *num_input_fmts)
-{
- u32 *input_fmts;
-
- *num_input_fmts = 0;
-
- input_fmts = kcalloc(1, sizeof(*input_fmts),
- GFP_KERNEL);
- if (!input_fmts)
- return NULL;
-
- *num_input_fmts = 1;
- input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
-
- return input_fmts;
-}
-
-static unsigned int mtk_dpi_bus_fmt_bit_num(unsigned int out_bus_format)
-{
- switch (out_bus_format) {
- default:
- case MEDIA_BUS_FMT_RGB888_1X24:
- case MEDIA_BUS_FMT_BGR888_1X24:
- case MEDIA_BUS_FMT_RGB888_2X12_LE:
- case MEDIA_BUS_FMT_RGB888_2X12_BE:
- case MEDIA_BUS_FMT_YUYV8_1X16:
- case MEDIA_BUS_FMT_YUV8_1X24:
- return MTK_DPI_OUT_BIT_NUM_8BITS;
- case MEDIA_BUS_FMT_RGB101010_1X30:
- case MEDIA_BUS_FMT_YUYV10_1X20:
- case MEDIA_BUS_FMT_YUV10_1X30:
- return MTK_DPI_OUT_BIT_NUM_10BITS;
- case MEDIA_BUS_FMT_YUYV12_1X24:
- return MTK_DPI_OUT_BIT_NUM_12BITS;
- }
-}
-
-static unsigned int mtk_dpi_bus_fmt_channel_swap(unsigned int out_bus_format)
-{
- switch (out_bus_format) {
- default:
- case MEDIA_BUS_FMT_RGB888_1X24:
- case MEDIA_BUS_FMT_RGB888_2X12_LE:
- case MEDIA_BUS_FMT_RGB888_2X12_BE:
- case MEDIA_BUS_FMT_RGB101010_1X30:
- case MEDIA_BUS_FMT_YUYV8_1X16:
- case MEDIA_BUS_FMT_YUYV10_1X20:
- case MEDIA_BUS_FMT_YUYV12_1X24:
- return MTK_DPI_OUT_CHANNEL_SWAP_RGB;
- case MEDIA_BUS_FMT_BGR888_1X24:
- case MEDIA_BUS_FMT_YUV8_1X24:
- case MEDIA_BUS_FMT_YUV10_1X30:
- return MTK_DPI_OUT_CHANNEL_SWAP_BGR;
- }
-}
-
-static unsigned int mtk_dpi_bus_fmt_color_format(unsigned int out_bus_format)
-{
- switch (out_bus_format) {
- default:
- case MEDIA_BUS_FMT_RGB888_1X24:
- case MEDIA_BUS_FMT_BGR888_1X24:
- case MEDIA_BUS_FMT_RGB888_2X12_LE:
- case MEDIA_BUS_FMT_RGB888_2X12_BE:
- case MEDIA_BUS_FMT_RGB101010_1X30:
- return MTK_DPI_COLOR_FORMAT_RGB;
- case MEDIA_BUS_FMT_YUYV8_1X16:
- case MEDIA_BUS_FMT_YUYV10_1X20:
- case MEDIA_BUS_FMT_YUYV12_1X24:
- return MTK_DPI_COLOR_FORMAT_YCBCR_422;
- case MEDIA_BUS_FMT_YUV8_1X24:
- case MEDIA_BUS_FMT_YUV10_1X30:
- return MTK_DPI_COLOR_FORMAT_YCBCR_444;
- }
-}
-
-static int mtk_dpi_bridge_atomic_check(struct drm_bridge *bridge,
- struct drm_bridge_state *bridge_state,
- struct drm_crtc_state *crtc_state,
- struct drm_connector_state *conn_state)
-{
- struct mtk_dpi *dpi = bridge_to_dpi(bridge);
- unsigned int out_bus_format;
-
- out_bus_format = bridge_state->output_bus_cfg.format;
-
- if (out_bus_format == MEDIA_BUS_FMT_FIXED)
- if (dpi->conf->num_output_fmts)
- out_bus_format = dpi->conf->output_fmts[0];
-
- dev_dbg(dpi->dev, "input format 0x%04x, output format 0x%04x\n",
- bridge_state->input_bus_cfg.format,
- bridge_state->output_bus_cfg.format);
-
- dpi->output_fmt = out_bus_format;
- dpi->bit_num = mtk_dpi_bus_fmt_bit_num(out_bus_format);
- dpi->channel_swap = mtk_dpi_bus_fmt_channel_swap(out_bus_format);
- dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB;
- dpi->color_format = mtk_dpi_bus_fmt_color_format(out_bus_format);
-
- return 0;
-}
-
static int mtk_dpi_bridge_attach(struct drm_bridge *bridge,
struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
@@ -827,15 +370,6 @@ static int mtk_dpi_bridge_attach(struct drm_bridge *bridge,
&dpi->bridge, flags);
}
-static void mtk_dpi_bridge_mode_set(struct drm_bridge *bridge,
- const struct drm_display_mode *mode,
- const struct drm_display_mode *adjusted_mode)
-{
- struct mtk_dpi *dpi = bridge_to_dpi(bridge);
-
- drm_mode_copy(&dpi->mode, adjusted_mode);
-}
-
static void mtk_dpi_bridge_disable(struct drm_bridge *bridge)
{
struct mtk_dpi *dpi = bridge_to_dpi(bridge);
@@ -895,39 +429,7 @@ static int mtk_dpi_debug_tp_show(struct seq_file *m, void *arg)
en = val & DPI_PAT_EN;
val = FIELD_GET(DPI_PAT_SEL, val);
- seq_printf(m, "DPI Test Pattern: %s\n", en ? "Enabled" : "Disabled");
-
- if (en) {
- seq_printf(m, "Internal pattern %d: ", val);
- switch (val) {
- case 0:
- seq_puts(m, "256 Vertical Gray\n");
- break;
- case 1:
- seq_puts(m, "1024 Vertical Gray\n");
- break;
- case 2:
- seq_puts(m, "256 Horizontal Gray\n");
- break;
- case 3:
- seq_puts(m, "1024 Horizontal Gray\n");
- break;
- case 4:
- seq_puts(m, "Vertical Color bars\n");
- break;
- case 6:
- seq_puts(m, "Frame border\n");
- break;
- case 7:
- seq_puts(m, "Dot moire\n");
- break;
- default:
- seq_puts(m, "Invalid selection\n");
- break;
- }
- }
-
- return 0;
+ return mtk_dpi_common_debug_tp_show(m, en, val);
}
static ssize_t mtk_dpi_debug_tp_write(struct file *file, const char __user *ubuf,
@@ -935,23 +437,15 @@ static ssize_t mtk_dpi_debug_tp_write(struct file *file, const char __user *ubuf
{
struct seq_file *m = file->private_data;
u32 en, type;
- char buf[6];
-
- if (!m || !m->private || *offp || len > sizeof(buf) - 1)
- return -EINVAL;
-
- memset(buf, 0, sizeof(buf));
- if (copy_from_user(buf, ubuf, len))
- return -EFAULT;
+ ssize_t ret;
- if (sscanf(buf, "%u %u", &en, &type) != 2)
- return -EINVAL;
-
- if (en < 0 || en > 1 || type < 0 || type > 7)
- return -EINVAL;
+ /* seq_file and dpi pointers are checked by mtk_dpi_common_debug_tp_write() */
+ ret = mtk_dpi_common_debug_tp_write(file, ubuf, len, offp, &en, &type);
+ if (ret < 0)
+ return ret;
mtk_dpi_test_pattern_en((struct mtk_dpi *)m->private, type, en);
- return len;
+ return ret;
}
static int mtk_dpi_debug_tp_open(struct inode *inode, struct file *file)
@@ -1020,56 +514,9 @@ unsigned int mtk_dpi_encoder_index(struct device *dev)
return encoder_index;
}
-static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
-{
- struct mtk_dpi *dpi = dev_get_drvdata(dev);
- struct drm_device *drm_dev = data;
- struct mtk_drm_private *priv = drm_dev->dev_private;
- int ret;
-
- dpi->mmsys_dev = priv->mmsys_dev;
- ret = drm_simple_encoder_init(drm_dev, &dpi->encoder,
- DRM_MODE_ENCODER_TMDS);
- if (ret) {
- dev_err(dev, "Failed to initialize decoder: %d\n", ret);
- return ret;
- }
-
- ret = mtk_find_possible_crtcs(drm_dev, dpi->dev);
- if (ret < 0)
- goto err_cleanup;
- dpi->encoder.possible_crtcs = ret;
-
- ret = drm_bridge_attach(&dpi->encoder, &dpi->bridge, NULL,
- DRM_BRIDGE_ATTACH_NO_CONNECTOR);
- if (ret)
- goto err_cleanup;
-
- dpi->connector = drm_bridge_connector_init(drm_dev, &dpi->encoder);
- if (IS_ERR(dpi->connector)) {
- dev_err(dev, "Unable to create bridge connector\n");
- ret = PTR_ERR(dpi->connector);
- goto err_cleanup;
- }
-
- return 0;
-
-err_cleanup:
- drm_encoder_cleanup(&dpi->encoder);
- return ret;
-}
-
-static void mtk_dpi_unbind(struct device *dev, struct device *master,
- void *data)
-{
- struct mtk_dpi *dpi = dev_get_drvdata(dev);
-
- drm_encoder_cleanup(&dpi->encoder);
-}
-
static const struct component_ops mtk_dpi_component_ops = {
- .bind = mtk_dpi_bind,
- .unbind = mtk_dpi_unbind,
+ .bind = mtk_dpi_common_bind,
+ .unbind = mtk_dpi_common_unbind,
};
static const u32 mt8173_output_fmts[] = {
@@ -1249,84 +696,16 @@ static const struct mtk_dpi_conf mt8195_dpintf_conf = {
static int mtk_dpi_probe(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
struct mtk_dpi *dpi;
int ret;
- dpi = devm_drm_bridge_alloc(dev, struct mtk_dpi, bridge,
- &mtk_dpi_bridge_funcs);
+ dpi = mtk_dpi_common_probe(pdev, &mtk_dpi_bridge_funcs);
if (IS_ERR(dpi))
return PTR_ERR(dpi);
- dpi->dev = dev;
- dpi->conf = (struct mtk_dpi_conf *)of_device_get_match_data(dev);
- dpi->output_fmt = MEDIA_BUS_FMT_RGB888_1X24;
-
- dpi->pinctrl = devm_pinctrl_get(&pdev->dev);
- if (IS_ERR(dpi->pinctrl)) {
- dpi->pinctrl = NULL;
- dev_dbg(&pdev->dev, "Cannot find pinctrl!\n");
- }
- if (dpi->pinctrl) {
- dpi->pins_gpio = pinctrl_lookup_state(dpi->pinctrl, "sleep");
- if (IS_ERR(dpi->pins_gpio)) {
- dpi->pins_gpio = NULL;
- dev_dbg(&pdev->dev, "Cannot find pinctrl idle!\n");
- }
- if (dpi->pins_gpio)
- pinctrl_select_state(dpi->pinctrl, dpi->pins_gpio);
-
- dpi->pins_dpi = pinctrl_lookup_state(dpi->pinctrl, "default");
- if (IS_ERR(dpi->pins_dpi)) {
- dpi->pins_dpi = NULL;
- dev_dbg(&pdev->dev, "Cannot find pinctrl active!\n");
- }
- }
- dpi->regs = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(dpi->regs))
- return dev_err_probe(dev, PTR_ERR(dpi->regs),
- "Failed to ioremap mem resource\n");
-
- dpi->engine_clk = devm_clk_get(dev, "engine");
- if (IS_ERR(dpi->engine_clk))
- return dev_err_probe(dev, PTR_ERR(dpi->engine_clk),
- "Failed to get engine clock\n");
-
- dpi->pixel_clk = devm_clk_get(dev, "pixel");
- if (IS_ERR(dpi->pixel_clk))
- return dev_err_probe(dev, PTR_ERR(dpi->pixel_clk),
- "Failed to get pixel clock\n");
-
- dpi->tvd_clk = devm_clk_get(dev, "pll");
- if (IS_ERR(dpi->tvd_clk))
- return dev_err_probe(dev, PTR_ERR(dpi->tvd_clk),
- "Failed to get tvdpll clock\n");
-
- dpi->irq = platform_get_irq(pdev, 0);
- if (dpi->irq < 0)
- return dpi->irq;
-
- dpi->next_bridge = devm_drm_of_get_bridge(dpi->dev, dpi->dev->of_node, 1, -1);
- if (IS_ERR(dpi->next_bridge) && PTR_ERR(dpi->next_bridge) == -ENODEV) {
- /* Old devicetree has only one endpoint */
- dpi->next_bridge = devm_drm_of_get_bridge(dpi->dev, dpi->dev->of_node, 0, 0);
- }
- if (IS_ERR(dpi->next_bridge))
- return dev_err_probe(dpi->dev, PTR_ERR(dpi->next_bridge),
- "Failed to get bridge\n");
-
- platform_set_drvdata(pdev, dpi);
-
- dpi->bridge.of_node = dev->of_node;
- dpi->bridge.type = DRM_MODE_CONNECTOR_DPI;
-
- ret = devm_drm_bridge_add(dev, &dpi->bridge);
- if (ret)
- return ret;
-
- ret = component_add(dev, &mtk_dpi_component_ops);
+ ret = component_add(&pdev->dev, &mtk_dpi_component_ops);
if (ret)
- return dev_err_probe(dev, ret, "Failed to add component.\n");
+ return dev_err_probe(&pdev->dev, ret, "Failed to add component.\n");
return 0;
}
@@ -1357,3 +736,4 @@ struct platform_driver mtk_dpi_driver = {
.of_match_table = mtk_dpi_of_ids,
},
};
+MODULE_IMPORT_NS("DRM_MTK_DPI");
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_common.c b/drivers/gpu/drm/mediatek/mtk_dpi_common.c
new file mode 100644
index 000000000000..b9e7b053d278
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_dpi_common.c
@@ -0,0 +1,468 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/kernel.h>
+#include <linux/media-bus-format.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_bridge_connector.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#include "mtk_ddp_comp.h"
+#include "mtk_dpi_common.h"
+#include "mtk_drm_drv.h"
+
+void mtk_dpi_power_off(struct mtk_dpi *dpi)
+{
+ if (WARN_ON(dpi->refcount == 0))
+ return;
+
+ if (--dpi->refcount != 0)
+ return;
+
+ clk_disable_unprepare(dpi->pixel_clk);
+ clk_disable_unprepare(dpi->tvd_clk);
+ clk_disable_unprepare(dpi->engine_clk);
+}
+EXPORT_SYMBOL_NS_GPL(mtk_dpi_power_off, "DRM_MTK_DPI");
+
+int mtk_dpi_power_on(struct mtk_dpi *dpi)
+{
+ int ret;
+
+ if (++dpi->refcount != 1)
+ return 0;
+
+ ret = clk_prepare_enable(dpi->engine_clk);
+ if (ret) {
+ dev_err(dpi->dev, "Failed to enable engine clock: %d\n", ret);
+ goto err_refcount;
+ }
+
+ ret = clk_prepare_enable(dpi->tvd_clk);
+ if (ret) {
+ dev_err(dpi->dev, "Failed to enable tvd pll: %d\n", ret);
+ goto err_engine;
+ }
+
+ ret = clk_prepare_enable(dpi->pixel_clk);
+ if (ret) {
+ dev_err(dpi->dev, "Failed to enable pixel clock: %d\n", ret);
+ goto err_pixel;
+ }
+
+ return 0;
+
+err_pixel:
+ clk_disable_unprepare(dpi->tvd_clk);
+err_engine:
+ clk_disable_unprepare(dpi->engine_clk);
+err_refcount:
+ dpi->refcount--;
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(mtk_dpi_power_on, "DRM_MTK_DPI");
+
+static unsigned int mtk_dpi_calculate_factor(struct mtk_dpi *dpi, int mode_clk)
+{
+ const struct mtk_dpi_factor *dpi_factor = dpi->conf->dpi_factor;
+ int i;
+
+ for (i = 0; i < dpi->conf->num_dpi_factor; i++) {
+ if (mode_clk <= dpi_factor[i].clock)
+ return dpi_factor[i].factor;
+ }
+
+ /* If no match try the lowest possible factor */
+ return dpi_factor[dpi->conf->num_dpi_factor - 1].factor;
+}
+
+static void mtk_dpi_set_pixel_clk(struct mtk_dpi *dpi, struct videomode *vm, int mode_clk)
+{
+ unsigned long pll_rate;
+ unsigned int factor;
+
+ /* let pll_rate can fix the valid range of tvdpll (1G~2GHz) */
+ factor = mtk_dpi_calculate_factor(dpi, mode_clk);
+ pll_rate = vm->pixelclock * factor;
+
+ dev_dbg(dpi->dev, "Want PLL %lu Hz, pixel clock %lu Hz\n",
+ pll_rate, vm->pixelclock);
+
+ clk_set_rate(dpi->tvd_clk, pll_rate);
+ pll_rate = clk_get_rate(dpi->tvd_clk);
+
+ /*
+ * Depending on the IP version, we may output a different amount of
+ * pixels for each iteration: divide the clock by this number.
+ */
+ vm->pixelclock = pll_rate / factor;
+ vm->pixelclock /= dpi->conf->pixels_per_iter;
+
+ if ((dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_LE) ||
+ (dpi->output_fmt == MEDIA_BUS_FMT_RGB888_2X12_BE))
+ clk_set_rate(dpi->pixel_clk, vm->pixelclock * 2);
+ else
+ clk_set_rate(dpi->pixel_clk, vm->pixelclock);
+
+ vm->pixelclock = clk_get_rate(dpi->pixel_clk);
+
+ dev_dbg(dpi->dev, "Got PLL %lu Hz, pixel clock %lu Hz\n",
+ pll_rate, vm->pixelclock);
+}
+
+int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, struct videomode *vm,
+ struct mtk_dpi_sync *sync,
+ struct mtk_dpi_polarities *dpi_pol,
+ struct mtk_dpi_yc_limit *limit)
+{
+ struct drm_display_mode *mode = &dpi->mode;
+
+ drm_display_mode_to_videomode(mode, vm);
+
+ if (!dpi->conf->clocked_by_hdmi)
+ mtk_dpi_set_pixel_clk(dpi, vm, mode->clock);
+
+ dpi_pol->ck_pol = MTK_DPI_POLARITY_FALLING;
+ dpi_pol->de_pol = MTK_DPI_POLARITY_RISING;
+ dpi_pol->hsync_pol = vm->flags & DISPLAY_FLAGS_HSYNC_HIGH ?
+ MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING;
+ dpi_pol->vsync_pol = vm->flags & DISPLAY_FLAGS_VSYNC_HIGH ?
+ MTK_DPI_POLARITY_FALLING : MTK_DPI_POLARITY_RISING;
+
+ /*
+ * Depending on the IP version, we may output a different amount of
+ * pixels for each iteration: adjust the display porches accordingly.
+ */
+ sync->hsync.sync_width = vm->hsync_len / dpi->conf->pixels_per_iter;
+ sync->hsync.back_porch = vm->hback_porch / dpi->conf->pixels_per_iter;
+ sync->hsync.front_porch = vm->hfront_porch / dpi->conf->pixels_per_iter;
+ sync->hsync.shift_half_line = false;
+
+ sync->vsync_l_odd.sync_width = vm->vsync_len;
+ sync->vsync_l_odd.back_porch = vm->vback_porch;
+ sync->vsync_l_odd.front_porch = vm->vfront_porch;
+ sync->vsync_l_odd.shift_half_line = false;
+
+ if (vm->flags & DISPLAY_FLAGS_INTERLACED) {
+ sync->vsync_l_even = sync->vsync_l_odd;
+ sync->vsync_l_even.shift_half_line = true;
+
+ if (mode->flags & DRM_MODE_FLAG_3D_MASK) {
+ sync->vsync_r_odd = sync->vsync_l_odd;
+ sync->vsync_r_even = sync->vsync_l_odd;
+ sync->vsync_r_even.shift_half_line = true;
+ }
+ } else if (mode->flags & DRM_MODE_FLAG_3D_MASK) {
+ sync->vsync_r_odd = sync->vsync_l_odd;
+ }
+
+ if (drm_default_rgb_quant_range(&dpi->mode) == HDMI_QUANTIZATION_RANGE_LIMITED) {
+ limit->y_bottom = 0x10;
+ limit->y_top = 0xfe0;
+ limit->c_bottom = 0x10;
+ limit->c_top = 0xfe0;
+ } else {
+ limit->y_bottom = 0;
+ limit->y_top = 0xfff;
+ limit->c_bottom = 0;
+ limit->c_top = 0xfff;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(mtk_dpi_set_display_mode, "DRM_MTK_DPI");
+
+u32 *mtk_dpi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ u32 output_fmt,
+ unsigned int *num_input_fmts)
+{
+ u32 *input_fmts;
+
+ *num_input_fmts = 0;
+
+ input_fmts = kcalloc(1, sizeof(*input_fmts), GFP_KERNEL);
+ if (!input_fmts)
+ return NULL;
+
+ *num_input_fmts = 1;
+ input_fmts[0] = MEDIA_BUS_FMT_RGB888_1X24;
+
+ return input_fmts;
+}
+EXPORT_SYMBOL_NS_GPL(mtk_dpi_bridge_atomic_get_input_bus_fmts, "DRM_MTK_DPI");
+
+u32 *mtk_dpi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ unsigned int *num_output_fmts)
+{
+ struct mtk_dpi *dpi = bridge_to_dpi(bridge);
+ u32 *output_fmts;
+
+ *num_output_fmts = 0;
+
+ if (!dpi->conf->output_fmts) {
+ dev_err(dpi->dev, "output_fmts should not be null\n");
+ return NULL;
+ }
+
+ output_fmts = kcalloc(dpi->conf->num_output_fmts, sizeof(*output_fmts), GFP_KERNEL);
+ if (!output_fmts)
+ return NULL;
+
+ *num_output_fmts = dpi->conf->num_output_fmts;
+
+ memcpy(output_fmts, dpi->conf->output_fmts,
+ sizeof(*output_fmts) * dpi->conf->num_output_fmts);
+
+ return output_fmts;
+}
+EXPORT_SYMBOL_NS_GPL(mtk_dpi_bridge_atomic_get_output_bus_fmts, "DRM_MTK_DPI");
+
+int mtk_dpi_bridge_atomic_check(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ unsigned int out_bus_format = bridge_state->output_bus_cfg.format;
+ struct mtk_dpi *dpi = bridge_to_dpi(bridge);
+
+ if (out_bus_format == MEDIA_BUS_FMT_FIXED && dpi->conf->num_output_fmts)
+ out_bus_format = dpi->conf->output_fmts[0];
+
+ dev_dbg(dpi->dev, "input format 0x%04x, output format 0x%04x\n",
+ bridge_state->input_bus_cfg.format,
+ bridge_state->output_bus_cfg.format);
+
+ dpi->output_fmt = out_bus_format;
+ dpi->bit_num = mtk_dpi_bus_fmt_bit_num(out_bus_format);
+ dpi->channel_swap = mtk_dpi_bus_fmt_channel_swap(out_bus_format);
+ dpi->yc_map = MTK_DPI_OUT_YC_MAP_RGB;
+ dpi->color_format = mtk_dpi_bus_fmt_color_format(out_bus_format);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(mtk_dpi_bridge_atomic_check, "DRM_MTK_DPI");
+
+void mtk_dpi_bridge_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode)
+{
+ struct mtk_dpi *dpi = bridge_to_dpi(bridge);
+
+ drm_mode_copy(&dpi->mode, adjusted_mode);
+}
+EXPORT_SYMBOL_NS_GPL(mtk_dpi_bridge_mode_set, "DRM_MTK_DPI");
+
+int mtk_dpi_common_bind(struct device *dev, struct device *master, void *data)
+{
+ struct mtk_dpi *dpi = dev_get_drvdata(dev);
+ struct drm_device *drm_dev = data;
+ struct mtk_drm_private *priv = drm_dev->dev_private;
+ int ret;
+
+ dpi->mmsys_dev = priv->mmsys_dev;
+ ret = drm_simple_encoder_init(drm_dev, &dpi->encoder,
+ DRM_MODE_ENCODER_TMDS);
+ if (ret) {
+ dev_err(dev, "Failed to initialize decoder: %d\n", ret);
+ return ret;
+ }
+
+ ret = mtk_find_possible_crtcs(drm_dev, dpi->dev);
+ if (ret < 0)
+ goto err_cleanup;
+ dpi->encoder.possible_crtcs = ret;
+
+ ret = drm_bridge_attach(&dpi->encoder, &dpi->bridge, NULL,
+ DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+ if (ret)
+ goto err_cleanup;
+
+ dpi->connector = drm_bridge_connector_init(drm_dev, &dpi->encoder);
+ if (IS_ERR(dpi->connector)) {
+ dev_err(dev, "Unable to create bridge connector\n");
+ ret = PTR_ERR(dpi->connector);
+ goto err_cleanup;
+ }
+
+ return 0;
+
+err_cleanup:
+ drm_encoder_cleanup(&dpi->encoder);
+ return ret;
+}
+EXPORT_SYMBOL_NS_GPL(mtk_dpi_common_bind, "DRM_MTK_DPI");
+
+void mtk_dpi_common_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct mtk_dpi *dpi = dev_get_drvdata(dev);
+
+ drm_encoder_cleanup(&dpi->encoder);
+}
+EXPORT_SYMBOL_NS_GPL(mtk_dpi_common_unbind, "DRM_MTK_DPI");
+
+int mtk_dpi_common_debug_tp_show(struct seq_file *m, bool en, u32 sel)
+{
+ seq_printf(m, "DPI Test Pattern: %s\n", en ? "Enabled" : "Disabled");
+
+ if (en) {
+ seq_printf(m, "Internal pattern %d: ", sel);
+
+ switch (sel) {
+ case 0:
+ seq_puts(m, "256 Vertical Gray\n");
+ break;
+ case 1:
+ seq_puts(m, "1024 Vertical Gray\n");
+ break;
+ case 2:
+ seq_puts(m, "256 Horizontal Gray\n");
+ break;
+ case 3:
+ seq_puts(m, "1024 Horizontal Gray\n");
+ break;
+ case 4:
+ seq_puts(m, "Vertical Color bars\n");
+ break;
+ case 6:
+ seq_puts(m, "Frame border\n");
+ break;
+ case 7:
+ seq_puts(m, "Dot moire\n");
+ break;
+ default:
+ seq_puts(m, "Invalid selection\n");
+ break;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(mtk_dpi_common_debug_tp_show, "DRM_MTK_DPI");
+
+ssize_t mtk_dpi_common_debug_tp_write(struct file *file, const char __user *ubuf,
+ size_t len, loff_t *offp, u32 *en, u32 *type)
+{
+ struct seq_file *m = file->private_data;
+ char buf[6];
+
+ if (!m || !m->private || *offp || len > sizeof(buf) - 1)
+ return -EINVAL;
+
+ memset(buf, 0, sizeof(buf));
+ if (copy_from_user(buf, ubuf, len))
+ return -EFAULT;
+
+ if (sscanf(buf, "%u %u", en, type) != 2)
+ return -EINVAL;
+
+ if (*en < 0 || *en > 1 || *type < 0 || *type > 7)
+ return -EINVAL;
+
+ return len;
+}
+EXPORT_SYMBOL_NS_GPL(mtk_dpi_common_debug_tp_write, "DRM_MTK_DPI");
+
+struct mtk_dpi *mtk_dpi_common_probe(struct platform_device *pdev,
+ const struct drm_bridge_funcs *bridge_funcs)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_dpi *dpi;
+ int ret;
+
+ dpi = devm_drm_bridge_alloc(dev, struct mtk_dpi, bridge, bridge_funcs);
+ if (IS_ERR(dpi))
+ return dpi;
+
+ dpi->dev = dev;
+ dpi->conf = (struct mtk_dpi_conf *)of_device_get_match_data(dev);
+ dpi->output_fmt = MEDIA_BUS_FMT_RGB888_1X24;
+
+ dpi->pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR_OR_NULL(dpi->pinctrl)) {
+ dev_dbg(dev, "Cannot find pinctrl!\n");
+ dpi->pinctrl = NULL;
+ } else {
+ dpi->pins_gpio = pinctrl_lookup_state(dpi->pinctrl, "sleep");
+ if (IS_ERR(dpi->pins_gpio)) {
+ dpi->pins_gpio = NULL;
+ dev_dbg(dev, "Cannot find pinctrl idle!\n");
+ }
+ if (dpi->pins_gpio)
+ pinctrl_select_state(dpi->pinctrl, dpi->pins_gpio);
+
+ dpi->pins_dpi = pinctrl_lookup_state(dpi->pinctrl, "default");
+ if (IS_ERR(dpi->pins_dpi)) {
+ dpi->pins_dpi = NULL;
+ dev_dbg(dev, "Cannot find pinctrl active!\n");
+ }
+ }
+
+ dpi->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(dpi->regs))
+ return dev_err_ptr_probe(dev, PTR_ERR(dpi->regs),
+ "Failed to ioremap mem resource\n");
+
+ dpi->engine_clk = devm_clk_get(dev, "engine");
+ if (IS_ERR(dpi->engine_clk))
+ return dev_err_ptr_probe(dev, PTR_ERR(dpi->engine_clk),
+ "Failed to get engine clock\n");
+
+ dpi->pixel_clk = devm_clk_get(dev, "pixel");
+ if (IS_ERR(dpi->pixel_clk))
+ return dev_err_ptr_probe(dev, PTR_ERR(dpi->pixel_clk),
+ "Failed to get pixel clock\n");
+
+ dpi->tvd_clk = devm_clk_get(dev, "pll");
+ if (IS_ERR(dpi->tvd_clk))
+ return dev_err_ptr_probe(dev, PTR_ERR(dpi->tvd_clk),
+ "Failed to get tvdpll clock\n");
+
+ dpi->irq = platform_get_irq(pdev, 0);
+ if (dpi->irq < 0)
+ return ERR_PTR(dpi->irq);
+
+ dpi->next_bridge = devm_drm_of_get_bridge(dpi->dev, dpi->dev->of_node, 1, -1);
+ if (IS_ERR(dpi->next_bridge) && PTR_ERR(dpi->next_bridge) == -ENODEV) {
+ /* Old devicetree has only one endpoint */
+ dpi->next_bridge = devm_drm_of_get_bridge(dpi->dev, dpi->dev->of_node, 0, 0);
+ }
+ if (IS_ERR(dpi->next_bridge))
+ return dev_err_ptr_probe(dpi->dev, PTR_ERR(dpi->next_bridge),
+ "Failed to get bridge\n");
+
+ platform_set_drvdata(pdev, dpi);
+
+ dpi->bridge.of_node = dev->of_node;
+ dpi->bridge.type = DRM_MODE_CONNECTOR_DPI;
+
+ ret = devm_drm_bridge_add(dev, &dpi->bridge);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return dpi;
+}
+EXPORT_SYMBOL_NS_GPL(mtk_dpi_common_probe, "DRM_MTK_DPI");
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("MediaTek DPI/DVO Common Library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_common.h b/drivers/gpu/drm/mediatek/mtk_dpi_common.h
new file mode 100644
index 000000000000..c5cc26c7900d
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_dpi_common.h
@@ -0,0 +1,276 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021 MediaTek Inc.
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#ifndef _MTK_DPI_COMMON_H
+#define _MTK_DPI_COMMON_H
+
+#include <linux/clk.h>
+#include <linux/pinctrl/consumer.h>
+#include <uapi/linux/media-bus-format.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_modes.h>
+#include <video/videomode.h>
+
+enum mtk_dpi_out_bit_num {
+ MTK_DPI_OUT_BIT_NUM_8BITS,
+ MTK_DPI_OUT_BIT_NUM_10BITS,
+ MTK_DPI_OUT_BIT_NUM_12BITS,
+ MTK_DPI_OUT_BIT_NUM_16BITS
+};
+
+enum mtk_dpi_out_yc_map {
+ MTK_DPI_OUT_YC_MAP_RGB,
+ MTK_DPI_OUT_YC_MAP_CYCY,
+ MTK_DPI_OUT_YC_MAP_YCYC,
+ MTK_DPI_OUT_YC_MAP_CY,
+ MTK_DPI_OUT_YC_MAP_YC
+};
+
+enum mtk_dpi_out_channel_swap {
+ MTK_DPI_OUT_CHANNEL_SWAP_RGB,
+ MTK_DPI_OUT_CHANNEL_SWAP_GBR,
+ MTK_DPI_OUT_CHANNEL_SWAP_BRG,
+ MTK_DPI_OUT_CHANNEL_SWAP_RBG,
+ MTK_DPI_OUT_CHANNEL_SWAP_GRB,
+ MTK_DPI_OUT_CHANNEL_SWAP_BGR
+};
+
+enum mtk_dpi_out_color_format {
+ MTK_DPI_COLOR_FORMAT_RGB,
+ MTK_DPI_COLOR_FORMAT_YCBCR_422,
+ MTK_DPI_COLOR_FORMAT_YCBCR_444
+};
+
+struct mtk_dpi {
+ struct drm_encoder encoder;
+ struct drm_bridge bridge;
+ struct drm_bridge *next_bridge;
+ struct drm_connector *connector;
+ void __iomem *regs;
+ struct device *dev;
+ struct device *mmsys_dev;
+ struct clk *engine_clk;
+ struct clk *pixel_clk;
+ struct clk *tvd_clk;
+ int irq;
+ struct drm_display_mode mode;
+ const struct mtk_dpi_conf *conf;
+ enum mtk_dpi_out_color_format color_format;
+ enum mtk_dpi_out_yc_map yc_map;
+ enum mtk_dpi_out_bit_num bit_num;
+ enum mtk_dpi_out_channel_swap channel_swap;
+ struct pinctrl *pinctrl;
+ struct pinctrl_state *pins_gpio;
+ struct pinctrl_state *pins_dpi;
+ u32 output_fmt;
+ s8 refcount;
+};
+
+enum mtk_dpi_polarity {
+ MTK_DPI_POLARITY_RISING,
+ MTK_DPI_POLARITY_FALLING,
+};
+
+struct mtk_dpi_polarities {
+ enum mtk_dpi_polarity de_pol;
+ enum mtk_dpi_polarity ck_pol;
+ enum mtk_dpi_polarity hsync_pol;
+ enum mtk_dpi_polarity vsync_pol;
+};
+
+struct mtk_dpi_sync_param {
+ u32 sync_width;
+ u32 front_porch;
+ u32 back_porch;
+ bool shift_half_line;
+};
+
+struct mtk_dpi_sync {
+ struct mtk_dpi_sync_param hsync;
+ struct mtk_dpi_sync_param vsync_l_odd;
+ struct mtk_dpi_sync_param vsync_l_even;
+ struct mtk_dpi_sync_param vsync_r_odd;
+ struct mtk_dpi_sync_param vsync_r_even;
+};
+
+struct mtk_dpi_yc_limit {
+ u16 y_top;
+ u16 y_bottom;
+ u16 c_top;
+ u16 c_bottom;
+};
+
+struct mtk_dpi_factor {
+ u32 clock;
+ u8 factor;
+};
+
+/**
+ * struct mtk_dpi_conf - Configuration of MediaTek DPI/DVO
+ * @dpi_factor: SoC-specific pixel clock PLL factor values.
+ * @num_dpi_factor: Number of pixel clock PLL factor values.
+ * @reg_h_fre_con: Register address of frequency control.
+ * @max_clock_khz: Max clock frequency supported for this SoCs in khz units.
+ * @edge_sel_en: Enable of edge selection.
+ * @output_fmts: Array of supported output formats.
+ * @num_output_fmts: Quantity of supported output formats.
+ * @is_ck_de_pol: Support CK/DE polarity.
+ * @swap_input_support: Support input swap function.
+ * @support_direct_pin: IP supports direct connection to dpi panels.
+ * @dimension_mask: Mask used for HWIDTH, HPORCH, VSYNC_WIDTH and VSYNC_PORCH
+ * (no shift).
+ * @hvsize_mask: Mask of HSIZE and VSIZE mask (no shift).
+ * @channel_swap_shift: Shift value of channel swap.
+ * @yuv422_en_bit: Enable bit of yuv422.
+ * @csc_enable_bit: Enable bit of CSC.
+ * @input_2p_en_bit: Enable bit for input two pixel per round feature.
+ * If present, implies that the feature must be enabled.
+ * @pixels_per_iter: Quantity of transferred pixels per iteration.
+ * @edge_cfg_in_mmsys: If the edge configuration for DPI's output needs to be set in MMSYS.
+ * @clocked_by_hdmi: HDMI IP outputs clock to dpi_pixel_clk input clock, needed
+ * for DPI registers access.
+ * @output_1pixel: Enable outputting one pixel per round; if the input is two pixel per
+ * round, the DPI hardware will internally transform it to 1T1P.
+ */
+struct mtk_dpi_conf {
+ const struct mtk_dpi_factor *dpi_factor;
+ const u8 num_dpi_factor;
+ u32 reg_h_fre_con;
+ u32 max_clock_khz;
+ bool edge_sel_en;
+ const u32 *output_fmts;
+ u32 num_output_fmts;
+ bool is_ck_de_pol;
+ bool swap_input_support;
+ bool support_direct_pin;
+ u32 dimension_mask;
+ u32 hvsize_mask;
+ u32 channel_swap_shift;
+ u32 yuv422_en_bit;
+ u32 csc_enable_bit;
+ u32 input_2p_en_bit;
+ u32 pixels_per_iter;
+ bool edge_cfg_in_mmsys;
+ bool clocked_by_hdmi;
+ bool output_1pixel;
+};
+
+static inline struct mtk_dpi *bridge_to_dpi(struct drm_bridge *b)
+{
+ return container_of(b, struct mtk_dpi, bridge);
+}
+
+static inline void mtk_dpi_mask(struct mtk_dpi *dpi, u32 offset, u32 val, u32 mask)
+{
+ u32 tmp = readl(dpi->regs + offset);
+
+ tmp &= ~mask;
+ tmp |= (val & mask);
+ writel(tmp, dpi->regs + offset);
+}
+
+static inline enum mtk_dpi_out_bit_num
+mtk_dpi_bus_fmt_bit_num(unsigned int out_bus_format)
+{
+ switch (out_bus_format) {
+ default:
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_BGR888_1X24:
+ case MEDIA_BUS_FMT_RGB888_2X12_LE:
+ case MEDIA_BUS_FMT_RGB888_2X12_BE:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ return MTK_DPI_OUT_BIT_NUM_8BITS;
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ return MTK_DPI_OUT_BIT_NUM_10BITS;
+ case MEDIA_BUS_FMT_YUYV12_1X24:
+ return MTK_DPI_OUT_BIT_NUM_12BITS;
+ }
+}
+
+static inline enum mtk_dpi_out_channel_swap
+mtk_dpi_bus_fmt_channel_swap(unsigned int out_bus_format)
+{
+ switch (out_bus_format) {
+ default:
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_RGB888_2X12_LE:
+ case MEDIA_BUS_FMT_RGB888_2X12_BE:
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_YUYV12_1X24:
+ return MTK_DPI_OUT_CHANNEL_SWAP_RGB;
+ case MEDIA_BUS_FMT_BGR888_1X24:
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ return MTK_DPI_OUT_CHANNEL_SWAP_BGR;
+ }
+}
+
+static inline enum mtk_dpi_out_color_format
+mtk_dpi_bus_fmt_color_format(unsigned int out_bus_format)
+{
+ switch (out_bus_format) {
+ default:
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ case MEDIA_BUS_FMT_BGR888_1X24:
+ case MEDIA_BUS_FMT_RGB888_2X12_LE:
+ case MEDIA_BUS_FMT_RGB888_2X12_BE:
+ case MEDIA_BUS_FMT_RGB101010_1X30:
+ return MTK_DPI_COLOR_FORMAT_RGB;
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_YUYV12_1X24:
+ return MTK_DPI_COLOR_FORMAT_YCBCR_422;
+ case MEDIA_BUS_FMT_YUV8_1X24:
+ case MEDIA_BUS_FMT_YUV10_1X30:
+ return MTK_DPI_COLOR_FORMAT_YCBCR_444;
+ }
+}
+
+u32 *mtk_dpi_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ u32 output_fmt,
+ unsigned int *num_input_fmts);
+u32 *mtk_dpi_bridge_atomic_get_output_bus_fmts(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state,
+ unsigned int *num_output_fmts);
+int mtk_dpi_bridge_atomic_check(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state);
+void mtk_dpi_bridge_mode_set(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ const struct drm_display_mode *adjusted_mode);
+
+int mtk_dpi_common_bind(struct device *dev, struct device *master, void *data);
+void mtk_dpi_common_unbind(struct device *dev, struct device *master, void *data);
+
+void mtk_dpi_power_off(struct mtk_dpi *dpi);
+int mtk_dpi_power_on(struct mtk_dpi *dpi);
+int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, struct videomode *vm,
+ struct mtk_dpi_sync *sync,
+ struct mtk_dpi_polarities *dpi_pol,
+ struct mtk_dpi_yc_limit *limit);
+
+int mtk_dpi_common_debug_tp_show(struct seq_file *m, bool en, u32 sel);
+ssize_t mtk_dpi_common_debug_tp_write(struct file *file, const char __user *ubuf,
+ size_t len, loff_t *offp, u32 *en, u32 *type);
+
+struct mtk_dpi *mtk_dpi_common_probe(struct platform_device *pdev,
+ const struct drm_bridge_funcs *bridge_funcs);
+
+#endif /* _MTK_DPI_COMMON_H */
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 23/42] dt-bindings: display: mediatek: Introduce Digital Video Output HW
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (21 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 22/42] drm/mediatek: Create new mtk_dpi_common lib and move mtk_dpi code AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 14:23 ` Rob Herring (Arm)
2026-07-01 12:20 ` [PATCH 24/42] drm/mediatek: Add support for MediaTek Digital Video Output (DVO) AngeloGioacchino Del Regno
` (18 subsequent siblings)
41 siblings, 1 reply; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Add documentation for the Digital Video Output (DVO) IP found in
the newer generation SoCs MT8196, MT8189 and their variants.
This is effectively a more capable block replacing the DisplayPort
Interface (DPI/DP_INTF) one found in older SoCs.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
.../display/mediatek/mediatek,mt8196-dvo.yaml | 142 ++++++++++++++++++
1 file changed, 142 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml
new file mode 100644
index 000000000000..8e73586e74b9
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml
@@ -0,0 +1,142 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/mediatek/mediatek,mt8196-dvo.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Digital Video Output (DVO) Controller
+
+maintainers:
+ - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+ The MediaTek Digital Video Output (DVO) hardware provides 120-bits (4P) data,
+ video timing and info data for the Embedded DisplayPort, hardware-abstracting
+ the previous generation Display Port Interface (DPI/DP_INTF) blocks, other
+ than providing new capabilities.
+ This hardware block supports 1/2/4 pixels per iteration in both its input and
+ output and provides 8/10-bit RGB, YUV422 and YUV444 data formats in output,
+ other than supporting input/output video window cropping and padding.
+ Digital Video Output also provides Panel Self Refresh (PSR) and Multi-SST
+ Operation (MSO) features for eDP 1.3/1.4.
+
+properties:
+ compatible:
+ - const: mediatek,mt8189-dp-dvo
+ - const: mediatek,mt8189-edp-dvo
+ - const: mediatek,mt8196-edp-dvo
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ items:
+ - description: Pixel Clock
+ - description: Engine Clock
+ - description: DVO PLL
+
+ clock-names:
+ items:
+ - const: pixel
+ - const: engine
+ - const: pll
+
+ pinctrl-0: true
+ pinctrl-1: true
+
+ pinctrl-names:
+ items:
+ - const: default
+ - const: sleep
+
+ power-domains:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Digital Video Output's input port
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: DVO output to an HDMI, LVDS or DisplayPort encoder input
+
+ required:
+ - port@0
+ - port@1
+
+ resets:
+ maxItems: 1
+
+ reset-names:
+ items:
+ - const: dvo
+
+ trigger-sources:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/mediatek,mt8196-clock.h>
+ #include <dt-bindings/power/mediatek,mt8196-power.h>
+
+ dvo@324c0000 {
+ compatible = "mediatek,mt8196-edp-dvo";
+ reg = <0x324c0000 0x1000>;
+ interrupts = <GIC_SPI 461 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&dispsys1 CLK_MM1_DISP_DVO0>,
+ <&dispsys1 CLK_MM1_MOD6>,
+ <&apmixedsys_gp2 CLK_APMIXED2_TVDPLL3>;
+ clock-names = "pixel", "engine", "pll";
+ power-domains = <&hpm_hwv MT8196_POWER_DOMAIN_DIS0_DORMANT>;
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&dvo_pins_default>;
+ pinctrl-1 = <&dvo_pin_sleep>;
+ trigger-sources = <&disp1_mutex 29>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&directlink_output>;
+ };
+ };
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&displayport_input>;
+ };
+ };
+ };
+ };
+
+...
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 23/42] dt-bindings: display: mediatek: Introduce Digital Video Output HW
2026-07-01 12:20 ` [PATCH 23/42] dt-bindings: display: mediatek: Introduce Digital Video Output HW AngeloGioacchino Del Regno
@ 2026-07-01 14:23 ` Rob Herring (Arm)
2026-07-01 16:53 ` AngeloGioacchino Del Regno
0 siblings, 1 reply; 52+ messages in thread
From: Rob Herring (Arm) @ 2026-07-01 14:23 UTC (permalink / raw)
To: AngeloGioacchino Del Regno
Cc: krzk+dt, dri-devel, linux-kernel, p.zabel, kernel, tzimmermann,
chunkuang.hu, simona, linux-arm-kernel, jason-jh.lin, airlied,
conor+dt, maarten.lankhorst, linux-mediatek, matthias.bgg,
mripard, devicetree, justin.yeh
On Wed, 01 Jul 2026 14:20:38 +0200, AngeloGioacchino Del Regno wrote:
> Add documentation for the Digital Video Output (DVO) IP found in
> the newer generation SoCs MT8196, MT8189 and their variants.
>
> This is effectively a more capable block replacing the DisplayPort
> Interface (DPI/DP_INTF) one found in older SoCs.
>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
> .../display/mediatek/mediatek,mt8196-dvo.yaml | 142 ++++++++++++++++++
> 1 file changed, 142 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: ignoring, error in schema: properties: compatible
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
from schema $id: http://devicetree.org/meta-schemas/keywords.yaml
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
Traceback (most recent call last):
File "/usr/local/bin/dt-doc-validate", line 8, in <module>
sys.exit(main())
~~~~^^
File "/usr/local/lib/python3.13/dist-packages/dtschema/doc_validate.py", line 66, in main
ret |= check_doc(f)
~~~~~~~~~^^^
File "/usr/local/lib/python3.13/dist-packages/dtschema/doc_validate.py", line 37, in check_doc
dtsch.check_schema_refs()
~~~~~~~~~~~~~~~~~~~~~~~^^
File "/usr/local/lib/python3.13/dist-packages/dtschema/schema.py", line 242, in check_schema_refs
self._check_schema_refs(resolver, self)
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.13/dist-packages/dtschema/schema.py", line 212, in _check_schema_refs
self._check_schema_refs(resolver, v, parent=k, is_common=is_common,
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
has_constraint=has_constraint)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.13/dist-packages/dtschema/schema.py", line 212, in _check_schema_refs
self._check_schema_refs(resolver, v, parent=k, is_common=is_common,
~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
has_constraint=has_constraint)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.13/dist-packages/dtschema/schema.py", line 203, in _check_schema_refs
ref_sch = resolver.lookup(schema['$ref']).contents
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 682, in lookup
retrieved = self._registry.get_or_retrieve(uri)
File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 422, in get_or_retrieve
registry = self.crawl()
File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 500, in crawl
id = resource.id()
File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 231, in id
id = self._specification.id_of(self.contents)
File "/usr/local/lib/python3.13/dist-packages/referencing/jsonschema.py", line 50, in _dollar_id
return contents.get("$id")
^^^^^^^^^^^^
AttributeError: 'list' object has no attribute 'get'
Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.example.dtb: /example-0/dvo@324c0000: failed to match any schema with compatible: ['mediatek,mt8196-edp-dvo']
doc reference errors (make refcheckdocs):
See https://patchwork.kernel.org/project/devicetree/patch/20260701122057.19648-24-angelogioacchino.delregno@collabora.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 52+ messages in thread* Re: [PATCH 23/42] dt-bindings: display: mediatek: Introduce Digital Video Output HW
2026-07-01 14:23 ` Rob Herring (Arm)
@ 2026-07-01 16:53 ` AngeloGioacchino Del Regno
0 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 16:53 UTC (permalink / raw)
To: Rob Herring (Arm)
Cc: krzk+dt, dri-devel, linux-kernel, p.zabel, kernel, tzimmermann,
chunkuang.hu, simona, linux-arm-kernel, jason-jh.lin, airlied,
conor+dt, maarten.lankhorst, linux-mediatek, matthias.bgg,
mripard, devicetree, justin.yeh
On 7/1/26 16:23, Rob Herring (Arm) wrote:
>
> On Wed, 01 Jul 2026 14:20:38 +0200, AngeloGioacchino Del Regno wrote:
>> Add documentation for the Digital Video Output (DVO) IP found in
>> the newer generation SoCs MT8196, MT8189 and their variants.
>>
>> This is effectively a more capable block replacing the DisplayPort
>> Interface (DPI/DP_INTF) one found in older SoCs.
>>
>> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
>> ---
>> .../display/mediatek/mediatek,mt8196-dvo.yaml | 142 ++++++++++++++++++
>> 1 file changed, 142 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml
>>
>
> My bot found errors running 'make dt_binding_check' on your patch:
>
Those errors on literally all bindings are quite embarassing. Oops.
Already fixed locally, but since this is a huge series, I will allow some time
for reviews before compulsively pushing a v2.
Cheers,
Angelo
> yamllint warnings/errors:
>
> dtschema/dtc warnings/errors:
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: ignoring, error in schema: properties: compatible
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
> from schema $id: http://devicetree.org/meta-schemas/keywords.yaml
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
> /builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.yaml: properties:compatible: [{'const': 'mediatek,mt8189-dp-dvo'}, {'const': 'mediatek,mt8189-edp-dvo'}, {'const': 'mediatek,mt8196-edp-dvo'}] is not of type 'object', 'boolean'
> Traceback (most recent call last):
> File "/usr/local/bin/dt-doc-validate", line 8, in <module>
> sys.exit(main())
> ~~~~^^
> File "/usr/local/lib/python3.13/dist-packages/dtschema/doc_validate.py", line 66, in main
> ret |= check_doc(f)
> ~~~~~~~~~^^^
> File "/usr/local/lib/python3.13/dist-packages/dtschema/doc_validate.py", line 37, in check_doc
> dtsch.check_schema_refs()
> ~~~~~~~~~~~~~~~~~~~~~~~^^
> File "/usr/local/lib/python3.13/dist-packages/dtschema/schema.py", line 242, in check_schema_refs
> self._check_schema_refs(resolver, self)
> ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
> File "/usr/local/lib/python3.13/dist-packages/dtschema/schema.py", line 212, in _check_schema_refs
> self._check_schema_refs(resolver, v, parent=k, is_common=is_common,
> ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> has_constraint=has_constraint)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "/usr/local/lib/python3.13/dist-packages/dtschema/schema.py", line 212, in _check_schema_refs
> self._check_schema_refs(resolver, v, parent=k, is_common=is_common,
> ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> has_constraint=has_constraint)
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> File "/usr/local/lib/python3.13/dist-packages/dtschema/schema.py", line 203, in _check_schema_refs
> ref_sch = resolver.lookup(schema['$ref']).contents
> ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
> File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 682, in lookup
> retrieved = self._registry.get_or_retrieve(uri)
> File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 422, in get_or_retrieve
> registry = self.crawl()
> File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 500, in crawl
> id = resource.id()
> File "/usr/local/lib/python3.13/dist-packages/referencing/_core.py", line 231, in id
> id = self._specification.id_of(self.contents)
> File "/usr/local/lib/python3.13/dist-packages/referencing/jsonschema.py", line 50, in _dollar_id
> return contents.get("$id")
> ^^^^^^^^^^^^
> AttributeError: 'list' object has no attribute 'get'
> Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-dvo.example.dtb: /example-0/dvo@324c0000: failed to match any schema with compatible: ['mediatek,mt8196-edp-dvo']
>
> doc reference errors (make refcheckdocs):
>
> See https://patchwork.kernel.org/project/devicetree/patch/20260701122057.19648-24-angelogioacchino.delregno@collabora.com
>
> The base for the series is generally the latest rc1. A different dependency
> should be noted in *this* patch.
>
> If you already ran 'make dt_binding_check' and didn't see the above
> error(s), then make sure 'yamllint' is installed and dt-schema is up to
> date:
>
> pip3 install dtschema --upgrade
>
> Please check and re-submit after running the above command yourself. Note
> that DT_SCHEMA_FILES can be set to your schema file to speed up checking
> your schema. However, it must be unset to test all examples with your schema.
>
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 24/42] drm/mediatek: Add support for MediaTek Digital Video Output (DVO)
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (22 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 23/42] dt-bindings: display: mediatek: Introduce Digital Video Output HW AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 25/42] drm/mediatek: Pass mtk_ddp_comp in clk and config callbacks AngeloGioacchino Del Regno
` (17 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Add a new driver for the Digital Video Output (DVO) hardware found
in the MT8189, MT8196 Kompanio SoCs and their Dimensity and Genio
variants.
This version currently supports output to Embedded DisplayPort on
MT8189 and MT8196, and to DisplayPort on MT8189.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/Makefile | 1 +
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 8 +
drivers/gpu/drm/mediatek/mtk_disp_drv.h | 4 +
drivers/gpu/drm/mediatek/mtk_dpi_common.c | 5 +
drivers/gpu/drm/mediatek/mtk_dpi_common.h | 23 +
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 11 +
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 +
drivers/gpu/drm/mediatek/mtk_dvo.c | 682 ++++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_dvo_regs.h | 192 ++++++
include/linux/soc/mediatek/mtk-mmsys.h | 1 +
10 files changed, 928 insertions(+)
create mode 100644 drivers/gpu/drm/mediatek/mtk_dvo.c
create mode 100644 drivers/gpu/drm/mediatek/mtk_dvo_regs.h
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index 34a1d4721b70..c48ac3ab08cc 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -17,6 +17,7 @@ mediatek-drm-y := mtk_crtc.o \
mtk_dsi.o \
mtk_dpi_common.o \
mtk_dpi.o \
+ mtk_dvo.o \
mtk_ethdr.o \
mtk_mdp_rdma.o \
mtk_padding.o \
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index 3be891f740d3..f8687f161953 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -290,6 +290,12 @@ static const struct mtk_ddp_comp_funcs ddp_dsi = {
.encoder_index = mtk_dsi_encoder_index,
};
+static const struct mtk_ddp_comp_funcs ddp_dvo = {
+ .start = mtk_dvo_start,
+ .stop = mtk_dvo_stop,
+ .encoder_index = mtk_dvo_encoder_index,
+};
+
static const struct mtk_ddp_comp_funcs ddp_gamma = {
.clk_enable = mtk_gamma_clk_enable,
.clk_disable = mtk_gamma_clk_disable,
@@ -430,6 +436,7 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_DP_INTF] = "dp-intf",
[MTK_DISP_DPI] = "dpi",
[MTK_DISP_DSI] = "dsi",
+ [MTK_DISP_DVO] = "dvo",
};
static const struct mtk_ddp_comp_funcs *mtk_ddp_funcs[MTK_DDP_COMP_TYPE_MAX] = {
@@ -453,6 +460,7 @@ static const struct mtk_ddp_comp_funcs *mtk_ddp_funcs[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_DPI] = &ddp_dpi,
[MTK_DISP_DP_INTF] = &ddp_dpi,
[MTK_DISP_DSI] = &ddp_dsi,
+ [MTK_DISP_DVO] = &ddp_dvo,
};
static bool mtk_ddp_find_comp_dev_in_table(const struct mtk_drm_comp_list *hlist,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index c4b44b761633..abdce23fab17 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -63,6 +63,10 @@ void mtk_dsi_ddp_stop(struct device *dev);
unsigned int mtk_dsi_encoder_index(struct device *dev);
struct drm_dsc_config *mtk_dsi_get_dsc_config(struct device *dev);
+void mtk_dvo_start(struct device *dev);
+void mtk_dvo_stop(struct device *dev);
+unsigned int mtk_dvo_encoder_index(struct device *dev);
+
int mtk_gamma_clk_enable(struct device *dev);
void mtk_gamma_clk_disable(struct device *dev);
void mtk_gamma_config(struct device *dev, unsigned int w,
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_common.c b/drivers/gpu/drm/mediatek/mtk_dpi_common.c
index b9e7b053d278..01bfbe4b5863 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi_common.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi_common.c
@@ -152,6 +152,11 @@ int mtk_dpi_set_display_mode(struct mtk_dpi *dpi, struct videomode *vm,
sync->hsync.front_porch = vm->hfront_porch / dpi->conf->pixels_per_iter;
sync->hsync.shift_half_line = false;
+ if (dpi->conf->quirk_hfp_bs_fix) {
+ sync->hsync.back_porch += sync->hsync.front_porch;
+ sync->hsync.front_porch = 0;
+ }
+
sync->vsync_l_odd.sync_width = vm->vsync_len;
sync->vsync_l_odd.back_porch = vm->vback_porch;
sync->vsync_l_odd.front_porch = vm->vfront_porch;
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi_common.h b/drivers/gpu/drm/mediatek/mtk_dpi_common.h
index c5cc26c7900d..af51efa4c9ea 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi_common.h
+++ b/drivers/gpu/drm/mediatek/mtk_dpi_common.h
@@ -17,6 +17,25 @@
#include <drm/drm_modes.h>
#include <video/videomode.h>
+enum mtk_dpi_golden_setting_level {
+ MTK_DPI_FHD_60FPS_1920 = 0,
+ MTK_DPI_FHD_60FPS_2180,
+ MTK_DPI_FHD_60FPS_2400,
+ MTK_DPI_FHD_60FPS_2520,
+ MTK_DPI_FHD_90FPS,
+ MTK_DPI_FHD_120FPS,
+ MTK_DPI_WQHD_60FPS,
+ MTK_DPI_WQHD_120FPS,
+ MTK_DPI_8K_30FPS,
+ MTK_DPI_GSL_MAX,
+};
+
+struct mtk_dpi_gs_info {
+ u32 dpi_buf_sodi_high;
+ u32 dpi_buf_sodi_low;
+};
+
+
enum mtk_dpi_out_bit_num {
MTK_DPI_OUT_BIT_NUM_8BITS,
MTK_DPI_OUT_BIT_NUM_10BITS,
@@ -65,6 +84,7 @@ struct mtk_dpi {
enum mtk_dpi_out_yc_map yc_map;
enum mtk_dpi_out_bit_num bit_num;
enum mtk_dpi_out_channel_swap channel_swap;
+ enum mtk_dpi_golden_setting_level gs_level;
struct pinctrl *pinctrl;
struct pinctrl_state *pins_gpio;
struct pinctrl_state *pins_dpi;
@@ -137,6 +157,8 @@ struct mtk_dpi_factor {
* for DPI registers access.
* @output_1pixel: Enable outputting one pixel per round; if the input is two pixel per
* round, the DPI hardware will internally transform it to 1T1P.
+ * @quirk_hfp_bs_fix: Set back porch as back+front and use front porch as an adjustment
+ * setting (usually zero) to fix DisplayPort BS generation.
*/
struct mtk_dpi_conf {
const struct mtk_dpi_factor *dpi_factor;
@@ -159,6 +181,7 @@ struct mtk_dpi_conf {
bool edge_cfg_in_mmsys;
bool clocked_by_hdmi;
bool output_1pixel;
+ bool quirk_hfp_bs_fix;
};
static inline struct mtk_dpi *bridge_to_dpi(struct drm_bridge *b)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index f7cbf9b47672..ee835ebbc18c 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -621,8 +621,17 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_DSI },
{ .compatible = "mediatek,mt8188-dsi",
.data = (void *)MTK_DISP_DSI },
+<<<<<<< HEAD
{ .compatible = "mediatek,mt8196-dsi",
.data = (void *)MTK_DISP_DSI },
+=======
+ { .compatible = "mediatek,mt8189-dp-dvo",
+ .data = (void *)MTK_DISP_DVO },
+ { .compatible = "mediatek,mt8189-edp-dvo",
+ .data = (void *)MTK_DISP_DVO },
+ { .compatible = "mediatek,mt8196-edp-dvo",
+ .data = (void *)MTK_DISP_DVO },
+>>>>>>> 60b3d568ba69 (drm/mediatek: Add support for MediaTek Digital Video Output (DVO))
{ }
};
@@ -776,6 +785,7 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, enum mtk_crtc_path
case MTK_DISP_DP_INTF:
case MTK_DISP_DPI:
case MTK_DISP_DSI:
+ case MTK_DISP_DVO:
break;
default:
dev_err(dev, "Invalid display hw pipeline. Last component: %u-%u (ret=%d)\n",
@@ -1059,6 +1069,7 @@ static struct platform_driver * const mtk_drm_drivers[] = {
&mtk_disp_rdma_driver,
&mtk_disp_wdma_driver,
&mtk_dpi_driver,
+ &mtk_dvo_driver,
&mtk_drm_platform_driver,
&mtk_dsi_driver,
&mtk_ethdr_driver,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index d86175180e11..4028268b3cc8 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -84,6 +84,7 @@ extern struct platform_driver mtk_disp_rdma_driver;
extern struct platform_driver mtk_disp_wdma_driver;
extern struct platform_driver mtk_dpi_driver;
extern struct platform_driver mtk_dsi_driver;
+extern struct platform_driver mtk_dvo_driver;
extern struct platform_driver mtk_ethdr_driver;
extern struct platform_driver mtk_mdp_rdma_driver;
extern struct platform_driver mtk_padding_driver;
diff --git a/drivers/gpu/drm/mediatek/mtk_dvo.c b/drivers/gpu/drm/mediatek/mtk_dvo.c
new file mode 100644
index 000000000000..a373db355234
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_dvo.c
@@ -0,0 +1,682 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MediaTek Digital Video Out
+ *
+ * Copyright (c) 2014 MediaTek Inc.
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/debugfs.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/media-bus-format.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/soc/mediatek/mtk-mmsys.h>
+#include <linux/types.h>
+
+#include <video/videomode.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_bridge_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
+#include <drm/drm_print.h>
+#include <drm/drm_simple_kms_helper.h>
+
+#include "mtk_drm_drv.h"
+#include "mtk_crtc.h"
+#include "mtk_disp_drv.h"
+#include "mtk_dpi_common.h"
+#include "mtk_dvo_regs.h"
+
+#define MTK_DVO_OUT_PIXITER_1T1P 0
+#define MTK_DVO_OUT_PIXITER_1T2P 1
+#define MTK_DVO_OUT_PIXITER_1T4P 2
+
+/* DVO INPUT default value is 1T2P */
+#define MTK_DVO_INPUT_MODE 2
+/* DVO OUTPUT value is 1T4P*/
+#define MTK_DVO_OUTPUT_MODE 4
+/* 1 unit = 2 group data = 2 * 1T4P = 8P */
+#define MTK_DISP_BUF_SRAM_UNIT_SIZE 8
+#define MTK_DISP_LINE_BUF_DVO_US 40
+#define MTK_BLANKING_RATIO 1
+#define MTK_DVO_EDP_MAX_CLK 297
+#define MTK_DVO_MAX_HACTIVE 3840
+#define MTK_DVO_LINE_BUFFER_SIZE (MTK_DVO_MAX_HACTIVE / MTK_DISP_BUF_SRAM_UNIT_SIZE)
+#define MTK_DVO_BITS_PER_CYCLE (8 * 32 * 1000000)
+#define TWAIT_SLEEP 1
+#define TWAKE_UP 5
+#define PREULTRA_HIGH_US 26
+#define PREULTRA_LOW_US 25
+#define ULTRA_HIGH_US 25
+#define ULTRA_LOW_US 23
+#define URGENT_HIGH_US 12
+#define URGENT_LOW_US 11
+
+static struct mtk_dpi_gs_info mtk_dvo_gs[MTK_DPI_GSL_MAX] = {
+ [MTK_DPI_FHD_60FPS_1920] = { 6880, 511 },
+ [MTK_DPI_8K_30FPS] = { 5255, 3899 },
+};
+
+static void mtk_dvo_test_pattern_en(struct mtk_dpi *dpi, u8 type, bool enable)
+{
+ u32 val;
+
+ if (enable)
+ val = FIELD_PREP(PRE_PAT_SEL_MASK, type) | PRE_PAT_EN | PRE_PAT_FORCE_ON;
+ else
+ val = 0;
+
+ mtk_dpi_mask(dpi, DVO_PATTERN_CTRL, val, PRE_PAT_SEL_MASK | PRE_PAT_FORCE_ON | PRE_PAT_EN);
+}
+
+static void mtk_dvo_sw_reset(struct mtk_dpi *dvo, bool reset)
+{
+ mtk_dpi_mask(dvo, DVO_RET, reset ? SWRST : 0, SWRST);
+}
+
+static void mtk_dvo_enable(struct mtk_dpi *dvo)
+{
+ mtk_dpi_mask(dvo, DVO_EN, EN, EN);
+}
+
+static void mtk_dvo_disable(struct mtk_dpi *dvo)
+{
+ mtk_dpi_mask(dvo, DVO_EN, 0, EN);
+}
+
+static void mtk_dvo_irq_enable(struct mtk_dpi *dvo)
+{
+ mtk_dpi_mask(dvo, DVO_INTEN, INT_VDE_END_EN | UNDERFLOW_EN,
+ INT_VDE_END_EN | UNDERFLOW_EN);
+}
+
+static void mtk_dvo_info_queue_start(struct mtk_dpi *dvo)
+{
+ mtk_dpi_mask(dvo, DVO_TGEN_INFOQ_LATENCY, 0,
+ INFOQ_START_LATENCY_MASK | INFOQ_END_LATENCY_MASK);
+}
+
+static void mtk_dpi_buffer_ctrl(struct mtk_dpi *dvo)
+{
+ mtk_dpi_mask(dvo, DVO_BUF_CON0, DISP_BUF_EN, DISP_BUF_EN);
+ mtk_dpi_mask(dvo, DVO_BUF_CON0, FIFO_UNDERFLOW_DONE_BLOCK, FIFO_UNDERFLOW_DONE_BLOCK);
+}
+
+static void mtk_dvo_trailing_blank_setting(struct mtk_dpi *dvo)
+{
+ mtk_dpi_mask(dvo, DVO_TGEN_V_LAST_TRAILING_BLANK, 0x20, V_LAST_TRAILING_BLANK_MASK);
+ mtk_dpi_mask(dvo, DVO_TGEN_OUTPUT_DELAY_LINE, 0x20, EXT_TG_DLY_LINE_MASK);
+}
+
+static void mtk_dvo_get_gs_level(struct mtk_dpi *dvo)
+{
+ struct drm_display_mode *mode = &dvo->mode;
+ enum mtk_dpi_golden_setting_level *gsl = &dvo->gs_level;
+
+ if (mode->hdisplay <= 1920 && mode->vdisplay <= 1080)
+ *gsl = MTK_DPI_FHD_60FPS_1920;
+ else
+ *gsl = MTK_DPI_8K_30FPS;
+}
+
+static void mtk_dvo_sodi_setting(struct mtk_dpi *dvo, struct drm_display_mode *mode)
+{
+ const u64 sodi_total = MTK_DVO_BITS_PER_CYCLE * MTK_DISP_BUF_SRAM_UNIT_SIZE * 32ULL;
+ u64 preultra_high, preultra_low, ultra_high, ultra_low, urgent_high, urgent_low;
+ u64 sodi_high, sodi_low, sodi_high_rem, sodi_low_rem, tmp;
+ u64 dvo_fifo_size, fifo_size, total_bit;
+ u64 consume_rate, consume_rate_rem;
+ u64 fill_rate_rem, fill_rate;
+ u64 data_rate;
+ u32 mmsys_clk;
+
+ mmsys_clk = mode->clock / 1000;
+ if (!mmsys_clk) {
+ dev_err(dvo->dev, "mmclk is zero, use default value\n");
+ mmsys_clk = 273;
+ }
+
+ fill_rate = div64_u64_rem(mmsys_clk * MTK_DVO_INPUT_MODE * 30,
+ 32ULL * MTK_DISP_BUF_SRAM_UNIT_SIZE, &fill_rate_rem);
+ data_rate = (u64)mode->hdisplay * mode->vdisplay *
+ div64_u64((u64)mode->clock * 1000, ((u64)mode->htotal * mode->vtotal));
+ consume_rate = div64_u64_rem(((data_rate * 30 * 5) / 4),
+ MTK_DVO_BITS_PER_CYCLE, &consume_rate_rem);
+ total_bit = (u64)MTK_DVO_EDP_MAX_CLK * MTK_DVO_OUTPUT_MODE * 30 *
+ MTK_DISP_LINE_BUF_DVO_US;
+
+ fifo_size = total_bit / (MTK_DISP_BUF_SRAM_UNIT_SIZE * 30);
+
+ /* DVO supports MSO mode, so calculate with three line buffers */
+ dvo_fifo_size = fifo_size + (3 * MTK_DVO_LINE_BUFFER_SIZE);
+
+ /* 1 is to round up */
+ sodi_high_rem = (u64)fill_rate_rem * MTK_DVO_BITS_PER_CYCLE;
+ tmp = (u64)consume_rate_rem * (32 * MTK_DISP_BUF_SRAM_UNIT_SIZE);
+
+ if (sodi_high_rem < tmp) {
+ fill_rate -= 1;
+ sodi_high_rem += sodi_total;
+ }
+ sodi_high_rem -= tmp;
+ sodi_high_rem *= 32 * 6;
+ sodi_high_rem /= sodi_total;
+
+ sodi_high = ((dvo_fifo_size * 30 * 5) -
+ (32 * 6 * (fill_rate - consume_rate)) -
+ sodi_high_rem + (5 * 32 - 1)) / (5 * 32);
+
+ sodi_low_rem = consume_rate_rem * (ULTRA_LOW_US + TWAKE_UP) + MTK_DVO_BITS_PER_CYCLE - 1;
+ sodi_low_rem /= MTK_DVO_BITS_PER_CYCLE;
+
+ sodi_low = consume_rate * (ULTRA_LOW_US + TWAKE_UP) + sodi_low_rem;
+
+ preultra_high = consume_rate * PREULTRA_HIGH_US;
+ preultra_high += (consume_rate_rem * PREULTRA_HIGH_US + MTK_DVO_BITS_PER_CYCLE - 1)
+ / MTK_DVO_BITS_PER_CYCLE;
+
+ preultra_low = consume_rate * PREULTRA_LOW_US;
+ preultra_low += (consume_rate_rem * PREULTRA_LOW_US + MTK_DVO_BITS_PER_CYCLE - 1)
+ / MTK_DVO_BITS_PER_CYCLE;
+
+ ultra_high = consume_rate * ULTRA_HIGH_US;
+ ultra_high += (consume_rate_rem * ULTRA_HIGH_US + MTK_DVO_BITS_PER_CYCLE - 1)
+ / MTK_DVO_BITS_PER_CYCLE;
+
+ ultra_low = consume_rate * ULTRA_LOW_US;
+ ultra_low += (consume_rate_rem * ULTRA_LOW_US + MTK_DVO_BITS_PER_CYCLE - 1)
+ / MTK_DVO_BITS_PER_CYCLE;
+
+ urgent_high = consume_rate * URGENT_HIGH_US;
+ urgent_high += (consume_rate_rem * URGENT_HIGH_US + MTK_DVO_BITS_PER_CYCLE - 1)
+ / MTK_DVO_BITS_PER_CYCLE;
+
+ urgent_low = consume_rate * URGENT_LOW_US;
+ urgent_low += (consume_rate_rem * URGENT_LOW_US + MTK_DVO_BITS_PER_CYCLE - 1)
+ / MTK_DVO_BITS_PER_CYCLE;
+
+ mtk_dpi_mask(dvo, DVO_BUF_SODI_HIGHT, sodi_high, DVO_DISP_BUF_MASK);
+ mtk_dpi_mask(dvo, DVO_BUF_SODI_LOW, sodi_low, DVO_DISP_BUF_MASK);
+ mtk_dpi_mask(dvo, DVO_BUF_PREULTRA_HIGHT, preultra_high, DVO_DISP_BUF_MASK);
+ mtk_dpi_mask(dvo, DVO_BUF_PREULTRA_LOW, preultra_low, DVO_DISP_BUF_MASK);
+ mtk_dpi_mask(dvo, DVO_BUF_ULTRA_HIGHT, ultra_high, DVO_DISP_BUF_MASK);
+ mtk_dpi_mask(dvo, DVO_BUF_ULTRA_LOW, ultra_low, DVO_DISP_BUF_MASK);
+ mtk_dpi_mask(dvo, DVO_BUF_URGENT_HIGHT, urgent_high, DVO_DISP_BUF_MASK);
+ mtk_dpi_mask(dvo, DVO_BUF_URGENT_LOW, urgent_low, DVO_DISP_BUF_MASK);
+}
+
+static void mtk_dvo_golden_setting(struct mtk_dpi *dvo)
+{
+ struct mtk_dpi_gs_info *gs_info = NULL;
+
+ if (dvo->gs_level >= MTK_DPI_GSL_MAX) {
+ dev_err(dvo->dev, "Invalid Golden Setting level %d\n", dvo->gs_level);
+ return;
+ }
+
+ gs_info = &mtk_dvo_gs[dvo->gs_level];
+
+ mtk_dpi_mask(dvo, DVO_BUF_SODI_HIGHT, gs_info->dpi_buf_sodi_high, GENMASK(31, 0));
+ mtk_dpi_mask(dvo, DVO_BUF_SODI_LOW, gs_info->dpi_buf_sodi_low, GENMASK(31, 0));
+}
+
+static void mtk_dvo_config_hsync(struct mtk_dpi *dvo,
+ struct mtk_dpi_sync_param *sync)
+{
+ mtk_dpi_mask(dvo, DVO_TGEN_H0, sync->sync_width << HSYNC,
+ dvo->conf->dimension_mask << HSYNC);
+ mtk_dpi_mask(dvo, DVO_TGEN_H0, sync->front_porch << HFP,
+ dvo->conf->dimension_mask << HFP);
+ mtk_dpi_mask(dvo, DVO_TGEN_H1, (sync->back_porch + sync->sync_width) << HSYNC2ACT,
+ dvo->conf->dimension_mask << HSYNC2ACT);
+}
+
+static void mtk_dvo_config_vsync(struct mtk_dpi *dvo,
+ struct mtk_dpi_sync_param *sync,
+ u32 width_addr, u32 porch_addr)
+{
+ mtk_dpi_mask(dvo, width_addr,
+ sync->sync_width << VSYNC,
+ dvo->conf->dimension_mask << VSYNC);
+ mtk_dpi_mask(dvo, width_addr,
+ sync->front_porch << VFP,
+ dvo->conf->dimension_mask << VFP);
+ mtk_dpi_mask(dvo, porch_addr,
+ (sync->back_porch + sync->sync_width) << VSYNC2ACT,
+ dvo->conf->dimension_mask << VSYNC2ACT);
+}
+
+static void mtk_dvo_config_interface(struct mtk_dpi *dvo, bool inter)
+{
+ mtk_dpi_mask(dvo, DVO_CON, inter ? INTL_EN : 0, INTL_EN);
+}
+
+static void mtk_dvo_config_fb_size(struct mtk_dpi *dvo, u32 width, u32 height)
+{
+ mtk_dpi_mask(dvo, DVO_SRC_SIZE, width << SRC_HSIZE,
+ dvo->conf->hvsize_mask << SRC_HSIZE);
+ mtk_dpi_mask(dvo, DVO_SRC_SIZE, height << SRC_VSIZE,
+ dvo->conf->hvsize_mask << SRC_VSIZE);
+
+ mtk_dpi_mask(dvo, DVO_PIC_SIZE, width << PIC_HSIZE,
+ dvo->conf->hvsize_mask << PIC_HSIZE);
+ mtk_dpi_mask(dvo, DVO_PIC_SIZE, height << PIC_VSIZE,
+ dvo->conf->hvsize_mask << PIC_VSIZE);
+
+ mtk_dpi_mask(dvo, DVO_TGEN_H1, DIV_ROUND_UP(width, dvo->conf->pixels_per_iter) << HACT,
+ dvo->conf->hvsize_mask << HACT);
+ mtk_dpi_mask(dvo, DVO_TGEN_V1, height << VACT,
+ dvo->conf->hvsize_mask << VACT);
+}
+
+static void mtk_dvo_config_channel_limit(struct mtk_dpi *dpi, struct mtk_dpi_yc_limit *limit)
+{
+ mtk_dpi_mask(dpi, DVO_Y_LIMIT, FIELD_PREP(Y_LMT_BOT, limit->y_bottom), Y_LMT_BOT);
+ mtk_dpi_mask(dpi, DVO_Y_LIMIT, FIELD_PREP(Y_LMT_TOP, limit->y_top), Y_LMT_TOP);
+ mtk_dpi_mask(dpi, DVO_C_LIMIT, FIELD_PREP(C_LMT_BOT, limit->c_bottom), C_LMT_BOT);
+ mtk_dpi_mask(dpi, DVO_C_LIMIT, FIELD_PREP(C_LMT_TOP, limit->c_top), C_LMT_TOP);
+}
+
+static void mtk_dvo_config_channel_swap(struct mtk_dpi *dpi,
+ enum mtk_dpi_out_channel_swap swap)
+{
+ u32 val;
+
+ switch (swap) {
+ case MTK_DPI_OUT_CHANNEL_SWAP_RGB:
+ val = SWAP_RGB;
+ break;
+ case MTK_DPI_OUT_CHANNEL_SWAP_GBR:
+ val = SWAP_GBR;
+ break;
+ case MTK_DPI_OUT_CHANNEL_SWAP_BRG:
+ val = SWAP_BRG;
+ break;
+ case MTK_DPI_OUT_CHANNEL_SWAP_RBG:
+ val = SWAP_RBG;
+ break;
+ case MTK_DPI_OUT_CHANNEL_SWAP_GRB:
+ val = SWAP_GRB;
+ break;
+ case MTK_DPI_OUT_CHANNEL_SWAP_BGR:
+ val = SWAP_BGR;
+ break;
+ default:
+ val = SWAP_RGB;
+ break;
+ }
+
+ mtk_dpi_mask(dpi, DVO_OUTPUT_SET, FIELD_PREP(CH_SWAP_MASK, val), CH_SWAP_MASK);
+ return;
+}
+
+static void mtk_dvo_config_csc_enable(struct mtk_dpi *dvo, bool enable)
+{
+ mtk_dpi_mask(dvo, DVO_MATRIX_SET, enable ? BIT(1) : 0, DVO_INT_MTX_SEL_MASK);
+ mtk_dpi_mask(dvo, DVO_MATRIX_SET, enable ? DVO_CSC_EN : 0, DVO_CSC_EN);
+}
+
+static void mtk_dvo_config_yuv422_enable(struct mtk_dpi *dvo, bool enable)
+{
+ mtk_dpi_mask(dvo, DVO_YUV422_SET, enable ? DVO_YUV422_EN : 0, DVO_YUV422_EN);
+ mtk_dpi_mask(dvo, DVO_YUV422_SET, enable ? DVO_CRYCB_MAP : 0, DVO_CRYCB_MAP);
+}
+
+static void mtk_dvo_set_output_pixiter(struct mtk_dpi *dvo)
+{
+ u32 val;
+
+ switch (dvo->conf->pixels_per_iter) {
+ default:
+ case 0:
+ case 1:
+ val = MTK_DVO_OUT_PIXITER_1T1P;
+ break;
+ case 2:
+ val = MTK_DVO_OUT_PIXITER_1T2P;
+ break;
+ case 3:
+ case 4:
+ val = MTK_DVO_OUT_PIXITER_1T4P;
+ break;
+ }
+
+ /* Enable register shadow only when more than 1 pixel per iteration */
+ if (val > MTK_DVO_OUT_PIXITER_1T1P) {
+ mtk_dpi_mask(dvo, DVO_SHADOW_CTRL, 0, BYPASS_SHADOW);
+ mtk_dpi_mask(dvo, DVO_SHADOW_CTRL, FORCE_COMMIT, FORCE_COMMIT);
+ };
+
+ mtk_dpi_mask(dvo, DVO_OUTPUT_SET, val, OUT_NP_SEL);
+ return;
+}
+
+static void mtk_dvo_config_color_format(struct mtk_dpi *dvo,
+ enum mtk_dpi_out_color_format format)
+{
+ mtk_dvo_config_channel_swap(dvo, dvo->channel_swap);
+
+ dev_err(dvo->dev, "[DPTX] format:%d", format);
+
+ switch (format) {
+ case MTK_DPI_COLOR_FORMAT_YCBCR_444:
+ mtk_dvo_config_yuv422_enable(dvo, false);
+ mtk_dvo_config_csc_enable(dvo, true);
+ break;
+ case MTK_DPI_COLOR_FORMAT_YCBCR_422:
+ mtk_dvo_config_yuv422_enable(dvo, true);
+ mtk_dvo_config_csc_enable(dvo, true);
+ break;
+ case MTK_DPI_COLOR_FORMAT_RGB:
+ default:
+ mtk_dvo_config_yuv422_enable(dvo, false);
+ mtk_dvo_config_csc_enable(dvo, false);
+ break;
+ }
+}
+
+static void mtk_dpi_config_pol(struct mtk_dpi *dpi,
+ struct mtk_dpi_polarities *dpi_pol)
+{
+ u32 pol;
+
+ pol = (dpi_pol->hsync_pol == MTK_DPI_POLARITY_RISING ? 0 : HS_INV) |
+ (dpi_pol->vsync_pol == MTK_DPI_POLARITY_RISING ? 0 : VS_INV);
+
+ mtk_dpi_mask(dpi, DVO_OUTPUT_SET, pol, HS_INV | VS_INV);
+}
+
+static void mtk_dvo_config_hw(struct mtk_dpi *dvo,
+ struct videomode *vm, struct mtk_dpi_sync *sync,
+ struct mtk_dpi_polarities *dpi_pol,
+ struct mtk_dpi_yc_limit *limit)
+{
+ struct drm_display_mode *mode = &dvo->mode;
+ u32 vactive = vm->vactive;
+
+ mtk_dvo_sw_reset(dvo, true);
+
+ mtk_dvo_irq_enable(dvo);
+
+ mtk_dpi_config_pol(dvo, dpi_pol);
+
+ mtk_dvo_config_hsync(dvo, &sync->hsync);
+ mtk_dvo_config_vsync(dvo, &sync->vsync_l_odd, DVO_TGEN_V0, DVO_TGEN_V1);
+ mtk_dvo_config_vsync(dvo, &sync->vsync_l_even, DVO_TGEN_V_EVEN0, DVO_TGEN_V_EVEN1);
+
+ mtk_dvo_config_interface(dvo, !!(vm->flags & DISPLAY_FLAGS_INTERLACED));
+
+ if (vm->flags & DISPLAY_FLAGS_INTERLACED)
+ vactive >>= 1;
+
+ mtk_dvo_config_fb_size(dvo, vm->hactive, vactive);
+
+ mtk_dvo_config_channel_limit(dvo, limit);
+ mtk_dvo_config_channel_swap(dvo, dvo->channel_swap);
+ mtk_dvo_config_color_format(dvo, dvo->color_format);
+
+ mtk_dvo_info_queue_start(dvo);
+ mtk_dpi_buffer_ctrl(dvo);
+
+ mtk_dvo_trailing_blank_setting(dvo);
+ mtk_dvo_get_gs_level(dvo);
+ mtk_dvo_golden_setting(dvo);
+ mtk_dvo_sodi_setting(dvo, mode);
+
+ mtk_dvo_set_output_pixiter(dvo);
+
+ mtk_dvo_sw_reset(dvo, false);
+
+ return;
+}
+
+static int mtk_dvo_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
+ enum drm_bridge_attach_flags flags)
+{
+ struct mtk_dpi *dvo = bridge_to_dpi(bridge);
+ int ret;
+
+ ret = drm_bridge_attach(bridge->encoder, dvo->next_bridge,
+ &dvo->bridge, 1);
+ if (ret)
+ dev_err(dvo->dev, "Failed to attach bridge: %d\n", ret);
+
+ return ret;
+}
+
+static void mtk_dvo_bridge_disable(struct drm_bridge *bridge)
+{
+ struct mtk_dpi *dvo = bridge_to_dpi(bridge);
+
+ mtk_dvo_disable(dvo);
+ mtk_dpi_power_off(dvo);
+}
+
+static void mtk_dvo_bridge_enable(struct drm_bridge *bridge)
+{
+ struct mtk_dpi *dpi = bridge_to_dpi(bridge);
+ struct mtk_dpi_polarities dpi_pol;
+ struct mtk_dpi_sync sync = { 0 };
+ struct mtk_dpi_yc_limit limit;
+ struct videomode vm;
+
+ if (dpi->pinctrl && dpi->pins_dpi)
+ pinctrl_select_state(dpi->pinctrl, dpi->pins_dpi);
+
+ mtk_dpi_power_on(dpi);
+
+ /* Set pixel clock and initialize parameters to send to the HW */
+ mtk_dpi_set_display_mode(dpi, &vm, &sync, &dpi_pol, &limit);
+
+ /* Format and send the parameters to the HW */
+ mtk_dvo_config_hw(dpi, &vm, &sync, &dpi_pol, &limit);
+
+ mtk_dvo_enable(dpi);
+}
+
+static enum drm_mode_status
+mtk_dvo_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ return MODE_OK;
+}
+
+static int mtk_dvo_debug_tp_show(struct seq_file *m, void *arg)
+{
+ struct mtk_dpi *dvo = m->private;
+ bool en;
+ u32 val;
+
+ if (!dvo)
+ return -EINVAL;
+
+ val = readl(dvo->regs + DVO_PATTERN_CTRL);
+ en = (val & (PRE_PAT_EN | PRE_PAT_FORCE_ON)) == (PRE_PAT_EN | PRE_PAT_FORCE_ON);
+ val = FIELD_GET(PRE_PAT_SEL_MASK, val);
+
+ return mtk_dpi_common_debug_tp_show(m, en, val);
+}
+
+static ssize_t mtk_dvo_debug_tp_write(struct file *file, const char __user *ubuf,
+ size_t len, loff_t *offp)
+{
+ struct seq_file *m = file->private_data;
+ u32 en, type;
+ ssize_t ret;
+
+ /* seq_file and dvo pointers are checked by mtk_dpi_common_debug_tp_write() */
+ ret = mtk_dpi_common_debug_tp_write(file, ubuf, len, offp, &en, &type);
+ if (ret < 0)
+ return ret;
+
+ mtk_dvo_test_pattern_en((struct mtk_dpi *)m->private, type, en);
+ return ret;
+}
+
+static int mtk_dvo_debug_tp_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mtk_dvo_debug_tp_show, inode->i_private);
+}
+
+static const struct file_operations mtk_dvo_debug_tp_fops = {
+ .owner = THIS_MODULE,
+ .open = mtk_dvo_debug_tp_open,
+ .read = seq_read,
+ .write = mtk_dvo_debug_tp_write,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void mtk_dvo_debugfs_init(struct drm_bridge *bridge, struct dentry *root)
+{
+ struct mtk_dpi *dpi = bridge_to_dpi(bridge);
+
+ debugfs_create_file("dvo_test_pattern", 0640, root, dpi, &mtk_dvo_debug_tp_fops);
+}
+
+static const struct drm_bridge_funcs mtk_dvo_bridge_funcs = {
+ .attach = mtk_dvo_bridge_attach,
+ .mode_set = mtk_dpi_bridge_mode_set,
+ .mode_valid = mtk_dvo_bridge_mode_valid,
+ .disable = mtk_dvo_bridge_disable,
+ .enable = mtk_dvo_bridge_enable,
+ .atomic_check = mtk_dpi_bridge_atomic_check,
+ .atomic_get_output_bus_fmts = mtk_dpi_bridge_atomic_get_output_bus_fmts,
+ .atomic_get_input_bus_fmts = mtk_dpi_bridge_atomic_get_input_bus_fmts,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .debugfs_init = mtk_dvo_debugfs_init,
+};
+
+void mtk_dvo_start(struct device *dev)
+{
+ struct mtk_dpi *dvo = dev_get_drvdata(dev);
+
+ mtk_dpi_power_on(dvo);
+}
+
+void mtk_dvo_stop(struct device *dev)
+{
+ struct mtk_dpi *dvo = dev_get_drvdata(dev);
+
+ mtk_dvo_disable(dvo);
+ mtk_dpi_power_off(dvo);
+}
+
+unsigned int mtk_dvo_encoder_index(struct device *dev)
+{
+ struct mtk_dpi *dvo = dev_get_drvdata(dev);
+
+ return drm_encoder_index(&dvo->encoder);
+}
+
+static const struct component_ops mtk_dvo_component_ops = {
+ .bind = mtk_dpi_common_bind,
+ .unbind = mtk_dpi_common_unbind,
+};
+
+static const struct mtk_dpi_factor dpi_factor_mt8196_dvo[] = {
+ { 70000 - 1, 4 }, { 200000 - 1, 2 }, { U32_MAX, 1 }
+};
+
+static const u32 mt8196_output_fmts[] = {
+ MEDIA_BUS_FMT_RGB888_1X24,
+ MEDIA_BUS_FMT_RGB888_2X12_LE,
+ MEDIA_BUS_FMT_RGB888_2X12_BE,
+ MEDIA_BUS_FMT_RGB101010_1X30,
+ MEDIA_BUS_FMT_YUYV8_1X16,
+ MEDIA_BUS_FMT_YUYV10_1X20,
+ MEDIA_BUS_FMT_YUYV12_1X24,
+ MEDIA_BUS_FMT_BGR888_1X24,
+ MEDIA_BUS_FMT_YUV8_1X24,
+ MEDIA_BUS_FMT_YUV10_1X30,
+};
+
+static const struct mtk_dpi_conf mt8189_conf = {
+ .dpi_factor = dpi_factor_mt8196_dvo,
+ .num_dpi_factor = ARRAY_SIZE(dpi_factor_mt8196_dvo),
+ .reg_h_fre_con = 0xb0,
+ .max_clock_khz = 640000,
+ .output_fmts = mt8196_output_fmts,
+ .num_output_fmts = ARRAY_SIZE(mt8196_output_fmts),
+ .pixels_per_iter = 4,
+ .dimension_mask = HFP_MASK,
+ .hvsize_mask = PIC_HSIZE_MASK,
+};
+
+static const struct mtk_dpi_conf mt8189_dp_conf = {
+ .dpi_factor = dpi_factor_mt8196_dvo,
+ .num_dpi_factor = ARRAY_SIZE(dpi_factor_mt8196_dvo),
+ .reg_h_fre_con = 0xb0,
+ .max_clock_khz = 640000,
+ .output_fmts = mt8196_output_fmts,
+ .num_output_fmts = ARRAY_SIZE(mt8196_output_fmts),
+ .pixels_per_iter = 4,
+ .dimension_mask = HFP_MASK,
+ .hvsize_mask = PIC_HSIZE_MASK,
+ .quirk_hfp_bs_fix = true,
+};
+
+static const struct mtk_dpi_conf mt8196_conf = {
+ .dpi_factor = dpi_factor_mt8196_dvo,
+ .num_dpi_factor = ARRAY_SIZE(dpi_factor_mt8196_dvo),
+ .reg_h_fre_con = 0xb0,
+ .max_clock_khz = 600000,
+ .output_fmts = mt8196_output_fmts,
+ .num_output_fmts = ARRAY_SIZE(mt8196_output_fmts),
+ .pixels_per_iter = 4,
+ .dimension_mask = HFP_MASK,
+ .hvsize_mask = PIC_HSIZE_MASK,
+};
+
+static int mtk_dvo_probe(struct platform_device *pdev)
+{
+ struct mtk_dpi *dvo;
+ int ret;
+
+ dvo = mtk_dpi_common_probe(pdev, &mtk_dvo_bridge_funcs);
+ if (IS_ERR(dvo))
+ return PTR_ERR(dvo);
+
+ ret = component_add(&pdev->dev, &mtk_dvo_component_ops);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to add component.\n");
+
+ return 0;
+}
+
+static void mtk_dvo_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &mtk_dvo_component_ops);
+}
+
+static const struct of_device_id mtk_dvo_of_ids[] = {
+ { .compatible = "mediatek,mt8189-dp-dvo", .data = &mt8189_dp_conf },
+ { .compatible = "mediatek,mt8189-edp-dvo", .data = &mt8189_conf },
+ { .compatible = "mediatek,mt8196-edp-dvo", .data = &mt8196_conf },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mtk_dvo_of_ids);
+
+struct platform_driver mtk_dvo_driver = {
+ .probe = mtk_dvo_probe,
+ .remove = mtk_dvo_remove,
+ .driver = {
+ .name = "mediatek-dvo",
+ .of_match_table = mtk_dvo_of_ids,
+ },
+};
+MODULE_IMPORT_NS("DRM_MTK_DPI");
diff --git a/drivers/gpu/drm/mediatek/mtk_dvo_regs.h b/drivers/gpu/drm/mediatek/mtk_dvo_regs.h
new file mode 100644
index 000000000000..42a6f318d991
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_dvo_regs.h
@@ -0,0 +1,192 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Jie Qiu <jie.qiu@mediatek.com>
+ */
+#ifndef __MTK_DPI_REGS_H
+#define __MTK_DPI_REGS_H
+
+#define DVO_EN 0x00
+#define EN BIT(0)
+#define DVO_FORCE_ON BIT(4)
+#define LINK_OFF BIT(8)
+#define DVO_RET 0x04
+#define SWRST BIT(0)
+#define SWRST_SEL BIT(4)
+#define DVO_INTEN 0x08
+#define INT_VFP_START_EN BIT(0)
+#define INT_VSYNC_START_EN BIT(1)
+#define INT_VSYNC_END_EN BIT(2)
+#define INT_VDE_START_EN BIT(3)
+#define INT_VDE_END_EN BIT(4)
+#define INT_WR_INFOQ_REG_EN BIT(5)
+#define INT_TARGET_LINE0_EN BIT(6)
+#define INT_TARGET_LINE1_EN BIT(7)
+#define INT_TARGET_LINE2_EN BIT(8)
+#define INT_TARGET_LINE3_EN BIT(9)
+#define INT_WR_INFOQ_START_EN BIT(10)
+#define INT_WR_INFOQ_END_EN BIT(11)
+#define EXT_VSYNC_START_EN BIT(12)
+#define EXT_VSYNC_END_EN BIT(13)
+#define EXT_VDE_START_EN BIT(14)
+#define EXT_VDE_END_EN BIT(15)
+#define EXT_VBLANK_END_EN BIT(16)
+#define UNDERFLOW_EN BIT(17)
+#define INFOQ_ABORT_EN BIT(18)
+
+#define DVO_INTSTA 0x0c
+#define INT_VFP_START_STA BIT(0)
+#define INT_VSYNC_START_STA BIT(1)
+#define INT_VSYNC_END_STA BIT(2)
+#define INT_VDE_START_STA BIT(3)
+#define INT_VDE_END_STA BIT(4)
+#define INT_WR_INFOQ_REG_STA BIT(5)
+#define INT_TARGET_LINE0_STA BIT(6)
+#define INT_TARGET_LINE1_STA BIT(7)
+#define INT_TARGET_LINE2_STA BIT(8)
+#define INT_TARGET_LINE3_STA BIT(9)
+#define INT_WR_INFOQ_START_STA BIT(10)
+#define INT_WR_INFOQ_END_STA BIT(11)
+#define EXT_VSYNC_START_STA BIT(12)
+#define EXT_VSYNC_END_STA BIT(13)
+#define EXT_VDE_START_STA BIT(14)
+#define EXT_VDE_END_STA BIT(15)
+#define EXT_VBLANK_END_STA BIT(16)
+#define INT_UNDERFLOW_STA BIT(17)
+#define INFOQ_ABORT_STA BIT(18)
+
+#define DVO_CON 0x10
+#define INTL_EN BIT(0)
+
+#define DVO_OUTPUT_SET 0x18
+#define OUT_NP_SEL (0x3 << 0)
+#define BIT_SWAP BIT(4)
+#define CH_SWAP_MASK GENMASK(7, 5)
+#define SWAP_RGB 0x00
+#define SWAP_GBR 0x01
+#define SWAP_BRG 0x02
+#define SWAP_RBG 0x03
+#define SWAP_GRB 0x04
+#define SWAP_BGR 0x05
+#define PXL_SWAP BIT(8)
+#define R_MASK BIT(12)
+#define G_MASK BIT(13)
+#define B_MASK BIT(14)
+#define DE_MASK BIT(16)
+#define HS_MASK BIT(17)
+#define VS_MASK BIT(18)
+#define HS_INV BIT(20)
+#define VS_INV BIT(21)
+
+#define DVO_SRC_SIZE 0x20
+#define SRC_HSIZE 0
+#define SRC_HSIZE_MASK (0xffff << 0)
+#define SRC_VSIZE 16
+#define SRC_VSIZE_MASK (0xffff << 16)
+
+#define DVO_PIC_SIZE 0x24
+#define PIC_HSIZE 0
+#define PIC_HSIZE_MASK (0xffff << 0)
+#define PIC_VSIZE 16
+#define PIC_VSIZE_MASK (0xffff << 16)
+
+#define DVO_TGEN_H0 0x50
+#define HFP 0
+#define HFP_MASK (0xffff << 0)
+#define HSYNC 16
+#define HSYNC_MASK (0xffff << 16)
+
+#define DVO_TGEN_H1 0x54
+#define HSYNC2ACT 0
+#define HSYNC2ACT_MASK (0xffff << 0)
+#define HACT 16
+#define HACT_MASK (0xffff << 16)
+
+#define DVO_TGEN_V0 0x58
+#define DVO_TGEN_V_EVEN0 0x64
+#define VFP 0
+#define VFP_MASK (0xffff << 0)
+#define VSYNC 16
+#define VSYNC_MASK (0xffff << 16)
+
+#define DVO_TGEN_V1 0x5c
+#define DVO_TGEN_V_EVEN1 0x68
+#define VSYNC2ACT 0
+#define VSYNC2ACT_MASK (0xffff << 0)
+#define VACT 16
+#define VACT_MASK (0xffff << 16)
+
+#define DVO_TGEN_INFOQ_LATENCY 0x80
+#define INFOQ_START_LATENCY 0
+#define INFOQ_START_LATENCY_MASK (0xffff << 0)
+#define INFOQ_END_LATENCY 16
+#define INFOQ_END_LATENCY_MASK (0xffff << 16)
+
+#define DVO_BUF_CON0 0x220
+#define DISP_BUF_EN BIT(0)
+#define FIFO_UNDERFLOW_DONE_BLOCK BIT(4)
+
+
+#define DVO_TGEN_V_LAST_TRAILING_BLANK 0x6c
+#define V_LAST_TRAILING_BLANK 0
+#define V_LAST_TRAILING_BLANK_MASK (0xffff << 0)
+
+#define DVO_TGEN_OUTPUT_DELAY_LINE 0x7c
+#define EXT_TG_DLY_LINE 0
+#define EXT_TG_DLY_LINE_MASK (0xffff << 0)
+
+#define DVO_MUTEX_VSYNC_SET 0x84
+#define MUTEX_VSYNC_SEL BIT(0)
+#define MUTEX_VFP_MASK GENMASK(19, 4)
+
+#define DVO_PATTERN_CTRL 0x100
+#define PRE_PAT_EN BIT(0)
+#define PRE_PAT_SEL_MASK (0x7 << 4)
+#define COLOR_BAR (0x4<<4)
+#define PRE_PAT_FORCE_ON BIT(8)
+
+#define DVO_PATTERN_COLOR 0x104
+#define PAT_R (0x3ff << 0)
+#define PAT_G (0x3ff << 10)
+#define PAT_B (0x3ff << 20)
+
+#define DVO_Y_LIMIT 0x130
+#define Y_LMT_BOT GENMASK(9, 0)
+#define Y_LMT_TOP GENMASK(21, 12)
+
+#define DVO_C_LIMIT 0x134
+#define C_LMT_BOT GENMASK(9, 0)
+#define C_LMT_TOP GENMASK(21, 12)
+
+#define DVO_SHADOW_CTRL 0x190
+#define FORCE_COMMIT BIT(0)
+#define BYPASS_SHADOW BIT(1)
+#define READ_WRK_REG BIT(2)
+
+#define DVO_SIZE 0x18
+#define DVO_TGEN_VWIDTH 0x28
+#define DVO_TGEN_VPORCH 0x2c
+#define DVO_TGEN_HPORCH 0x24
+#define DVO_TGEN_HWIDTH 0x20
+
+#define DVO_BUF_SODI_HIGHT 0x230
+#define DVO_BUF_SODI_LOW 0x234
+#define DVO_BUF_DVFS_HIGHT 0x238
+#define DVO_BUF_DVFS_LOW 0x23c
+#define DVO_BUF_PREULTRA_HIGHT 0x240
+#define DVO_BUF_PREULTRA_LOW 0x244
+#define DVO_BUF_ULTRA_HIGHT 0x248
+#define DVO_BUF_ULTRA_LOW 0x24c
+#define DVO_BUF_URGENT_HIGHT 0x250
+#define DVO_BUF_URGENT_LOW 0x254
+#define DVO_DISP_BUF_MASK GENMASK(31,0)
+
+#define DVO_MATRIX_SET 0x140
+#define DVO_CSC_EN BIT(0)
+#define DVO_INT_MTX_SEL_MASK GENMASK(8, 4)
+
+#define DVO_YUV422_SET 0x170
+#define DVO_YUV422_EN BIT(0)
+#define DVO_CRYCB_MAP BIT(8)
+
+#endif /* __MTK_DPI_REGS_H */
diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h
index f67f21d04163..0b3bef392ab8 100644
--- a/include/linux/soc/mediatek/mtk-mmsys.h
+++ b/include/linux/soc/mediatek/mtk-mmsys.h
@@ -114,6 +114,7 @@ enum mtk_ddp_comp_type {
MTK_DISP_DPI,
MTK_DISP_DP_INTF,
MTK_DISP_DSI,
+ MTK_DISP_DVO,
MTK_DDP_COMP_TYPE_MAX
};
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 25/42] drm/mediatek: Pass mtk_ddp_comp in clk and config callbacks
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (23 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 24/42] drm/mediatek: Add support for MediaTek Digital Video Output (DVO) AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 26/42] dt-bindings: display: mediatek: Introduce MT8196 Layer Blender AngeloGioacchino Del Regno
` (16 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In preparation for adding support for new Display Controller HW
components found in newer-gen SoCs like MT8196/MT8894, change the
.clk_enable(), .clk_disable(), and .config() callbacks to pass a
struct mtk_ddp_comp pointer instead of a struct device, and update
all of the currently supported components to reflect this change.
This is done because some of the new drivers need to track more in
the status of the actual components, such as indexing for multiple
stages layer strategy and others.
Despite being a rather big change in terms of lines, this brings
no functional differences.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 22 +++---
drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 20 +++---
drivers/gpu/drm/mediatek/mtk_disp_aal.c | 12 ++--
drivers/gpu/drm/mediatek/mtk_disp_ccorr.c | 12 ++--
drivers/gpu/drm/mediatek/mtk_disp_color.c | 12 ++--
drivers/gpu/drm/mediatek/mtk_disp_drv.h | 70 +++++++++----------
drivers/gpu/drm/mediatek/mtk_disp_dsc.c | 8 +--
drivers/gpu/drm/mediatek/mtk_disp_gamma.c | 12 ++--
drivers/gpu/drm/mediatek/mtk_disp_merge.c | 18 ++---
drivers/gpu/drm/mediatek/mtk_disp_ovl.c | 12 ++--
.../gpu/drm/mediatek/mtk_disp_ovl_adaptor.c | 50 +++++++------
drivers/gpu/drm/mediatek/mtk_disp_rdma.c | 12 ++--
drivers/gpu/drm/mediatek/mtk_disp_wdma.c | 12 ++--
drivers/gpu/drm/mediatek/mtk_ethdr.c | 10 +--
drivers/gpu/drm/mediatek/mtk_ethdr.h | 4 +-
drivers/gpu/drm/mediatek/mtk_mdp_rdma.c | 8 +--
drivers/gpu/drm/mediatek/mtk_padding.c | 8 +--
17 files changed, 155 insertions(+), 147 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index f8687f161953..8b9228084828 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -109,16 +109,16 @@ void mtk_ddp_write_mask(struct cmdq_pkt *cmdq_pkt, unsigned int value,
#endif
}
-static int mtk_ddp_clk_enable(struct device *dev)
+static int mtk_ddp_clk_enable(struct mtk_ddp_comp *comp)
{
- struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
+ struct mtk_ddp_comp_dev *priv = dev_get_drvdata(comp->dev);
return clk_prepare_enable(priv->clk);
}
-static void mtk_ddp_clk_disable(struct device *dev)
+static void mtk_ddp_clk_disable(struct mtk_ddp_comp *comp)
{
- struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
+ struct mtk_ddp_comp_dev *priv = dev_get_drvdata(comp->dev);
clk_disable_unprepare(priv->clk);
}
@@ -149,11 +149,11 @@ void mtk_dither_set_common(void __iomem *regs, struct cmdq_client_reg *cmdq_reg,
}
}
-static void mtk_dither_config(struct device *dev, unsigned int w,
+static void mtk_dither_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
- struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
+ struct mtk_ddp_comp_dev *priv = dev_get_drvdata(comp->dev);
mtk_ddp_write(cmdq_pkt, w << 16 | h, &priv->cmdq_reg, priv->regs, DISP_REG_DITHER_SIZE);
mtk_ddp_write(cmdq_pkt, DITHER_RELAY_MODE, &priv->cmdq_reg, priv->regs,
@@ -185,15 +185,15 @@ static void mtk_dither_set(struct device *dev, unsigned int bpc,
DISP_DITHERING, cmdq_pkt);
}
-static void mtk_od_config(struct device *dev, unsigned int w,
+static void mtk_od_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
- struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
+ struct mtk_ddp_comp_dev *priv = dev_get_drvdata(comp->dev);
mtk_ddp_write(cmdq_pkt, w << 16 | h, &priv->cmdq_reg, priv->regs, DISP_REG_OD_SIZE);
mtk_ddp_write(cmdq_pkt, OD_RELAYMODE, &priv->cmdq_reg, priv->regs, DISP_REG_OD_CFG);
- mtk_dither_set(dev, bpc, DISP_REG_OD_CFG, cmdq_pkt);
+ mtk_dither_set(comp->dev, bpc, DISP_REG_OD_CFG, cmdq_pkt);
}
static void mtk_od_start(struct device *dev)
@@ -203,11 +203,11 @@ static void mtk_od_start(struct device *dev)
writel(1, priv->regs + DISP_REG_OD_EN);
}
-static void mtk_postmask_config(struct device *dev, unsigned int w,
+static void mtk_postmask_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
- struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
+ struct mtk_ddp_comp_dev *priv = dev_get_drvdata(comp->dev);
mtk_ddp_write(cmdq_pkt, w << 16 | h, &priv->cmdq_reg, priv->regs,
DISP_REG_POSTMASK_SIZE);
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index ab9d5e4dfb98..1297db252821 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -36,9 +36,9 @@ struct mtk_drm_comp_list {
struct mtk_ddp_comp_funcs {
int (*power_on)(struct device *dev);
void (*power_off)(struct device *dev);
- int (*clk_enable)(struct device *dev);
- void (*clk_disable)(struct device *dev);
- void (*config)(struct device *dev, unsigned int w,
+ int (*clk_enable)(struct mtk_ddp_comp *comp);
+ void (*clk_disable)(struct mtk_ddp_comp *comp);
+ void (*config)(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
void (*dsc_setup)(struct device *dev, struct drm_dsc_config *dsc);
@@ -75,8 +75,8 @@ struct mtk_ddp_comp_funcs {
struct mtk_ddp_comp *next);
void (*disconnect)(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
struct mtk_ddp_comp *next);
- void (*add)(struct device *dev, struct mtk_mutex *mutex);
- void (*remove)(struct device *dev, struct mtk_mutex *mutex);
+ void (*add)(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex);
+ void (*remove)(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex);
unsigned int (*encoder_index)(struct device *dev);
enum drm_mode_status (*mode_valid)(struct device *dev, const struct drm_display_mode *mode);
};
@@ -113,7 +113,7 @@ static inline void mtk_ddp_comp_power_off(struct mtk_ddp_comp *comp)
static inline int mtk_ddp_comp_clk_enable(struct mtk_ddp_comp *comp)
{
if (comp->funcs && comp->funcs->clk_enable)
- return comp->funcs->clk_enable(comp->dev);
+ return comp->funcs->clk_enable(comp);
return 0;
}
@@ -121,7 +121,7 @@ static inline int mtk_ddp_comp_clk_enable(struct mtk_ddp_comp *comp)
static inline void mtk_ddp_comp_clk_disable(struct mtk_ddp_comp *comp)
{
if (comp->funcs && comp->funcs->clk_disable)
- comp->funcs->clk_disable(comp->dev);
+ comp->funcs->clk_disable(comp);
}
static inline
@@ -139,7 +139,7 @@ static inline void mtk_ddp_comp_config(struct mtk_ddp_comp *comp,
struct cmdq_pkt *cmdq_pkt)
{
if (comp->funcs && comp->funcs->config)
- comp->funcs->config(comp->dev, w, h, vrefresh, bpc, cmdq_pkt);
+ comp->funcs->config(comp, w, h, vrefresh, bpc, cmdq_pkt);
}
static inline void mtk_ddp_comp_dsc_setup(struct mtk_ddp_comp *comp,
@@ -314,7 +314,7 @@ static inline bool mtk_ddp_comp_is_afbc_supported(struct mtk_ddp_comp *comp)
static inline bool mtk_ddp_comp_add(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex)
{
if (comp->funcs && comp->funcs->add) {
- comp->funcs->add(comp->dev, mutex);
+ comp->funcs->add(comp, mutex);
return true;
}
return false;
@@ -323,7 +323,7 @@ static inline bool mtk_ddp_comp_add(struct mtk_ddp_comp *comp, struct mtk_mutex
static inline bool mtk_ddp_comp_remove(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex)
{
if (comp->funcs && comp->funcs->remove) {
- comp->funcs->remove(comp->dev, mutex);
+ comp->funcs->remove(comp, mutex);
return true;
}
return false;
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_aal.c b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
index abc9e5525d03..5199354e7b51 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_aal.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_aal.c
@@ -50,25 +50,25 @@ struct mtk_disp_aal {
const struct mtk_disp_aal_data *data;
};
-int mtk_aal_clk_enable(struct device *dev)
+int mtk_aal_clk_enable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_aal *aal = dev_get_drvdata(dev);
+ struct mtk_disp_aal *aal = dev_get_drvdata(comp->dev);
return clk_prepare_enable(aal->clk);
}
-void mtk_aal_clk_disable(struct device *dev)
+void mtk_aal_clk_disable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_aal *aal = dev_get_drvdata(dev);
+ struct mtk_disp_aal *aal = dev_get_drvdata(comp->dev);
clk_disable_unprepare(aal->clk);
}
-void mtk_aal_config(struct device *dev, unsigned int w,
+void mtk_aal_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
- struct mtk_disp_aal *aal = dev_get_drvdata(dev);
+ struct mtk_disp_aal *aal = dev_get_drvdata(comp->dev);
u32 sz;
sz = FIELD_PREP(DISP_AAL_SIZE_HSIZE, w);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
index 6d7bf4afa78d..81ce82ba6a9f 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ccorr.c
@@ -40,25 +40,25 @@ struct mtk_disp_ccorr {
const struct mtk_disp_ccorr_data *data;
};
-int mtk_ccorr_clk_enable(struct device *dev)
+int mtk_ccorr_clk_enable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
+ struct mtk_disp_ccorr *ccorr = dev_get_drvdata(comp->dev);
return clk_prepare_enable(ccorr->clk);
}
-void mtk_ccorr_clk_disable(struct device *dev)
+void mtk_ccorr_clk_disable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
+ struct mtk_disp_ccorr *ccorr = dev_get_drvdata(comp->dev);
clk_disable_unprepare(ccorr->clk);
}
-void mtk_ccorr_config(struct device *dev, unsigned int w,
+void mtk_ccorr_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
- struct mtk_disp_ccorr *ccorr = dev_get_drvdata(dev);
+ struct mtk_disp_ccorr *ccorr = dev_get_drvdata(comp->dev);
mtk_ddp_write(cmdq_pkt, w << 16 | h, &ccorr->cmdq_reg, ccorr->regs,
DISP_CCORR_SIZE);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_color.c b/drivers/gpu/drm/mediatek/mtk_disp_color.c
index 39c7de4cdcc1..04ae5e528c34 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_color.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_color.c
@@ -43,25 +43,25 @@ struct mtk_disp_color {
const struct mtk_disp_color_data *data;
};
-int mtk_color_clk_enable(struct device *dev)
+int mtk_color_clk_enable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_color *color = dev_get_drvdata(dev);
+ struct mtk_disp_color *color = dev_get_drvdata(comp->dev);
return clk_prepare_enable(color->clk);
}
-void mtk_color_clk_disable(struct device *dev)
+void mtk_color_clk_disable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_color *color = dev_get_drvdata(dev);
+ struct mtk_disp_color *color = dev_get_drvdata(comp->dev);
clk_disable_unprepare(color->clk);
}
-void mtk_color_config(struct device *dev, unsigned int w,
+void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
- struct mtk_disp_color *color = dev_get_drvdata(dev);
+ struct mtk_disp_color *color = dev_get_drvdata(comp->dev);
mtk_ddp_write(cmdq_pkt, w, &color->cmdq_reg, color->regs, DISP_COLOR_WIDTH(color));
mtk_ddp_write(cmdq_pkt, h, &color->cmdq_reg, color->regs, DISP_COLOR_HEIGHT(color));
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index abdce23fab17..62daf5ade9d1 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -17,9 +17,9 @@
struct drm_dsc_config;
-int mtk_aal_clk_enable(struct device *dev);
-void mtk_aal_clk_disable(struct device *dev);
-void mtk_aal_config(struct device *dev, unsigned int w,
+int mtk_aal_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_aal_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_aal_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
unsigned int mtk_aal_gamma_get_lut_size(struct device *dev);
@@ -28,18 +28,18 @@ void mtk_aal_start(struct device *dev);
void mtk_aal_stop(struct device *dev);
void mtk_ccorr_ctm_set(struct device *dev, struct drm_crtc_state *state);
-int mtk_ccorr_clk_enable(struct device *dev);
-void mtk_ccorr_clk_disable(struct device *dev);
-void mtk_ccorr_config(struct device *dev, unsigned int w,
+int mtk_ccorr_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_ccorr_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_ccorr_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
void mtk_ccorr_start(struct device *dev);
void mtk_ccorr_stop(struct device *dev);
void mtk_color_bypass_shadow(struct device *dev);
-int mtk_color_clk_enable(struct device *dev);
-void mtk_color_clk_disable(struct device *dev);
-void mtk_color_config(struct device *dev, unsigned int w,
+int mtk_color_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_color_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
void mtk_color_start(struct device *dev);
@@ -52,8 +52,8 @@ void mtk_dpi_start(struct device *dev);
void mtk_dpi_stop(struct device *dev);
unsigned int mtk_dpi_encoder_index(struct device *dev);
-int mtk_dsc_clk_enable(struct device *dev);
-void mtk_dsc_clk_disable(struct device *dev);
+int mtk_dsc_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_dsc_clk_disable(struct mtk_ddp_comp *comp);
void mtk_dsc_setup(struct device *dev, struct drm_dsc_config *dsc_cfg);
void mtk_dsc_start(struct device *dev);
void mtk_dsc_stop(struct device *dev);
@@ -67,9 +67,9 @@ void mtk_dvo_start(struct device *dev);
void mtk_dvo_stop(struct device *dev);
unsigned int mtk_dvo_encoder_index(struct device *dev);
-int mtk_gamma_clk_enable(struct device *dev);
-void mtk_gamma_clk_disable(struct device *dev);
-void mtk_gamma_config(struct device *dev, unsigned int w,
+int mtk_gamma_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_gamma_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_gamma_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
unsigned int mtk_gamma_get_lut_size(struct device *dev);
@@ -77,9 +77,9 @@ void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state);
void mtk_gamma_start(struct device *dev);
void mtk_gamma_stop(struct device *dev);
-int mtk_merge_clk_enable(struct device *dev);
-void mtk_merge_clk_disable(struct device *dev);
-void mtk_merge_config(struct device *dev, unsigned int width,
+int mtk_merge_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_merge_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_merge_config(struct mtk_ddp_comp *comp, unsigned int width,
unsigned int height, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
void mtk_merge_start(struct device *dev);
@@ -95,9 +95,9 @@ enum drm_mode_status mtk_merge_mode_valid(struct device *dev,
void mtk_ovl_bgclr_in_on(struct device *dev);
void mtk_ovl_bgclr_in_off(struct device *dev);
void mtk_ovl_bypass_shadow(struct device *dev);
-int mtk_ovl_clk_enable(struct device *dev);
-void mtk_ovl_clk_disable(struct device *dev);
-void mtk_ovl_config(struct device *dev, unsigned int w,
+int mtk_ovl_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_ovl_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_ovl_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
int mtk_ovl_layer_check(struct device *dev, unsigned int idx,
@@ -124,8 +124,8 @@ const u32 *mtk_ovl_get_formats(struct device *dev);
size_t mtk_ovl_get_num_formats(struct device *dev);
bool mtk_ovl_is_afbc_supported(struct device *dev);
-void mtk_ovl_adaptor_add_comp(struct device *dev, struct mtk_mutex *mutex);
-void mtk_ovl_adaptor_remove_comp(struct device *dev, struct mtk_mutex *mutex);
+void mtk_ovl_adaptor_add_comp(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex);
+void mtk_ovl_adaptor_remove_comp(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex);
bool mtk_ovl_adaptor_is_comp_present(struct device_node *node);
void mtk_ovl_adaptor_connect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
struct mtk_ddp_comp *next);
@@ -133,9 +133,9 @@ void mtk_ovl_adaptor_disconnect(struct mtk_ddp_comp *comp, struct device *mmsys_
struct mtk_ddp_comp *next);
int mtk_ovl_adaptor_power_on(struct device *dev);
void mtk_ovl_adaptor_power_off(struct device *dev);
-int mtk_ovl_adaptor_clk_enable(struct device *dev);
-void mtk_ovl_adaptor_clk_disable(struct device *dev);
-void mtk_ovl_adaptor_config(struct device *dev, unsigned int w,
+int mtk_ovl_adaptor_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_ovl_adaptor_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_ovl_adaptor_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
void mtk_ovl_adaptor_layer_config(struct device *dev, unsigned int idx,
@@ -157,9 +157,9 @@ enum drm_mode_status mtk_ovl_adaptor_mode_valid(struct device *dev,
const struct drm_display_mode *mode);
void mtk_rdma_bypass_shadow(struct device *dev);
-int mtk_rdma_clk_enable(struct device *dev);
-void mtk_rdma_clk_disable(struct device *dev);
-void mtk_rdma_config(struct device *dev, unsigned int width,
+int mtk_rdma_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_rdma_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width,
unsigned int height, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
unsigned int mtk_rdma_layer_nr(struct device *dev, int pipeline_index);
@@ -179,8 +179,8 @@ size_t mtk_rdma_get_num_formats(struct device *dev);
int mtk_mdp_rdma_power_on(struct device *dev);
void mtk_mdp_rdma_power_off(struct device *dev);
-int mtk_mdp_rdma_clk_enable(struct device *dev);
-void mtk_mdp_rdma_clk_disable(struct device *dev);
+int mtk_mdp_rdma_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_mdp_rdma_clk_disable(struct mtk_ddp_comp *comp);
void mtk_mdp_rdma_start(struct device *dev, struct cmdq_pkt *cmdq_pkt);
void mtk_mdp_rdma_stop(struct device *dev, struct cmdq_pkt *cmdq_pkt);
void mtk_mdp_rdma_config(struct device *dev, struct mtk_mdp_rdma_cfg *cfg,
@@ -188,9 +188,9 @@ void mtk_mdp_rdma_config(struct device *dev, struct mtk_mdp_rdma_cfg *cfg,
const u32 *mtk_mdp_rdma_get_formats(struct device *dev);
size_t mtk_mdp_rdma_get_num_formats(struct device *dev);
-int mtk_wdma_clk_enable(struct device *dev);
-void mtk_wdma_clk_disable(struct device *dev);
-void mtk_wdma_config(struct device *dev, unsigned int width,
+int mtk_wdma_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_wdma_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_wdma_config(struct mtk_ddp_comp *comp, unsigned int width,
unsigned int height, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
unsigned int mtk_wdma_layer_nr(struct device *dev, int pipeline_index);
@@ -208,8 +208,8 @@ void mtk_wdma_disable_vblank(struct device *dev);
const u32 *mtk_wdma_get_formats(struct device *dev);
size_t mtk_wdma_get_num_formats(struct device *dev);
-int mtk_padding_clk_enable(struct device *dev);
-void mtk_padding_clk_disable(struct device *dev);
+int mtk_padding_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_padding_clk_disable(struct mtk_ddp_comp *comp);
void mtk_padding_start(struct device *dev);
void mtk_padding_stop(struct device *dev);
#endif
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_dsc.c b/drivers/gpu/drm/mediatek/mtk_disp_dsc.c
index 79b66bd7e5f3..19d2e42861f0 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_dsc.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_dsc.c
@@ -135,16 +135,16 @@ struct mtk_dsc {
bool dsc_config_done;
};
-int mtk_dsc_clk_enable(struct device *dev)
+int mtk_dsc_clk_enable(struct mtk_ddp_comp *comp)
{
- struct mtk_dsc *disp_dsc = dev_get_drvdata(dev);
+ struct mtk_dsc *disp_dsc = dev_get_drvdata(comp->dev);
return clk_prepare_enable(disp_dsc->clk);
}
-void mtk_dsc_clk_disable(struct device *dev)
+void mtk_dsc_clk_disable(struct mtk_ddp_comp *comp)
{
- struct mtk_dsc *disp_dsc = dev_get_drvdata(dev);
+ struct mtk_dsc *disp_dsc = dev_get_drvdata(comp->dev);
clk_disable_unprepare(disp_dsc->clk);
}
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
index 8afd15006df2..a30a032e6c35 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_gamma.c
@@ -64,16 +64,16 @@ struct mtk_disp_gamma {
const struct mtk_disp_gamma_data *data;
};
-int mtk_gamma_clk_enable(struct device *dev)
+int mtk_gamma_clk_enable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
+ struct mtk_disp_gamma *gamma = dev_get_drvdata(comp->dev);
return clk_prepare_enable(gamma->clk);
}
-void mtk_gamma_clk_disable(struct device *dev)
+void mtk_gamma_clk_disable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
+ struct mtk_disp_gamma *gamma = dev_get_drvdata(comp->dev);
clk_disable_unprepare(gamma->clk);
}
@@ -206,11 +206,11 @@ void mtk_gamma_set(struct device *dev, struct drm_crtc_state *state)
writel(cfg_val, gamma->regs + DISP_GAMMA_CFG);
}
-void mtk_gamma_config(struct device *dev, unsigned int w,
+void mtk_gamma_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
- struct mtk_disp_gamma *gamma = dev_get_drvdata(dev);
+ struct mtk_disp_gamma *gamma = dev_get_drvdata(comp->dev);
u32 sz;
sz = FIELD_PREP(DISP_GAMMA_SIZE_HSIZE, w);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_merge.c b/drivers/gpu/drm/mediatek/mtk_disp_merge.c
index b174dda091d3..947e5a95947b 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_merge.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_merge.c
@@ -126,11 +126,11 @@ static void mtk_merge_fifo_setting(struct mtk_disp_merge *priv,
FLD_PREULTRA_TH_LOW | FLD_PREULTRA_TH_HIGH);
}
-void mtk_merge_config(struct device *dev, unsigned int w,
+void mtk_merge_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
- mtk_merge_advance_config(dev, w, 0, h, vrefresh, bpc, cmdq_pkt);
+ mtk_merge_advance_config(comp->dev, w, 0, h, vrefresh, bpc, cmdq_pkt);
}
void mtk_merge_advance_config(struct device *dev, unsigned int l_w, unsigned int r_w,
@@ -191,14 +191,14 @@ void mtk_merge_advance_config(struct device *dev, unsigned int l_w, unsigned int
DISP_REG_MERGE_CFG_12, FLD_CFG_MERGE_MODE);
}
-int mtk_merge_clk_enable(struct device *dev)
+int mtk_merge_clk_enable(struct mtk_ddp_comp *comp)
{
- int ret = 0;
- struct mtk_disp_merge *priv = dev_get_drvdata(dev);
+ struct mtk_disp_merge *priv = dev_get_drvdata(comp->dev);
+ int ret;
ret = clk_prepare_enable(priv->clk);
if (ret) {
- dev_err(dev, "merge clk prepare enable failed\n");
+ dev_err(comp->dev, "merge clk prepare enable failed\n");
return ret;
}
@@ -207,16 +207,16 @@ int mtk_merge_clk_enable(struct device *dev)
/* should clean up the state of priv->clk */
clk_disable_unprepare(priv->clk);
- dev_err(dev, "async clk prepare enable failed\n");
+ dev_err(comp->dev, "async clk prepare enable failed\n");
return ret;
}
return ret;
}
-void mtk_merge_clk_disable(struct device *dev)
+void mtk_merge_clk_disable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_merge *priv = dev_get_drvdata(dev);
+ struct mtk_disp_merge *priv = dev_get_drvdata(comp->dev);
clk_disable_unprepare(priv->async_clk);
clk_disable_unprepare(priv->clk);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
index 489a209c4e55..5ceba04a30b1 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl.c
@@ -260,16 +260,16 @@ bool mtk_ovl_is_afbc_supported(struct device *dev)
return ovl->data->supports_afbc;
}
-int mtk_ovl_clk_enable(struct device *dev)
+int mtk_ovl_clk_enable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+ struct mtk_disp_ovl *ovl = dev_get_drvdata(comp->dev);
return clk_prepare_enable(ovl->clk);
}
-void mtk_ovl_clk_disable(struct device *dev)
+void mtk_ovl_clk_disable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+ struct mtk_disp_ovl *ovl = dev_get_drvdata(comp->dev);
clk_disable_unprepare(ovl->clk);
}
@@ -327,11 +327,11 @@ static void mtk_ovl_set_bit_depth(struct device *dev, int idx, u32 format,
OVL_CON_CLRFMT_BIT_DEPTH_MASK(idx));
}
-void mtk_ovl_config(struct device *dev, unsigned int w,
+void mtk_ovl_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
- struct mtk_disp_ovl *ovl = dev_get_drvdata(dev);
+ struct mtk_disp_ovl *ovl = dev_get_drvdata(comp->dev);
if (w != 0 && h != 0)
mtk_ddp_write_relaxed(cmdq_pkt, h << 16 | w, &ovl->cmdq_reg, ovl->regs,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
index 225ab87bca71..e0e956ec56a7 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_ovl_adaptor.c
@@ -208,11 +208,11 @@ void mtk_ovl_adaptor_layer_config(struct device *dev, unsigned int idx,
mtk_ethdr_layer_config(ethdr, idx, state, cmdq_pkt);
}
-void mtk_ovl_adaptor_config(struct device *dev, unsigned int w,
+void mtk_ovl_adaptor_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
- struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
+ struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(comp->dev);
mtk_ethdr_config(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_ETHDR0], w, h,
vrefresh, bpc, cmdq_pkt);
@@ -306,41 +306,49 @@ void mtk_ovl_adaptor_power_off(struct device *dev)
power_off(dev, OVL_ADAPTOR_ID_MAX);
}
-int mtk_ovl_adaptor_clk_enable(struct device *dev)
+int mtk_ovl_adaptor_clk_enable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
- struct device *comp;
+ struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(comp->dev);
int ret;
int i;
for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
- comp = ovl_adaptor->ovl_adaptor_comp[i];
- if (!comp || !comp_matches[i].funcs->clk_enable)
+ struct mtk_ddp_comp adaptor_comp;
+
+ if (!ovl_adaptor->ovl_adaptor_comp[i] ||
+ !comp_matches[i].funcs->clk_enable)
continue;
- ret = comp_matches[i].funcs->clk_enable(comp);
+
+ adaptor_comp.dev = ovl_adaptor->ovl_adaptor_comp[i];
+
+ ret = comp_matches[i].funcs->clk_enable(&adaptor_comp);
if (ret) {
- dev_err(dev, "Failed to enable clock %d, err %d\n", i, ret);
+ dev_err(comp->dev, "Failed to enable clock %d, err %d\n", i, ret);
while (--i >= 0)
- comp_matches[i].funcs->clk_disable(comp);
+ comp_matches[i].funcs->clk_disable(&adaptor_comp);
return ret;
}
}
return 0;
}
-void mtk_ovl_adaptor_clk_disable(struct device *dev)
+void mtk_ovl_adaptor_clk_disable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
- struct device *comp;
+ struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(comp->dev);
int i;
for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
- comp = ovl_adaptor->ovl_adaptor_comp[i];
- if (!comp || !comp_matches[i].funcs->clk_disable)
+ struct mtk_ddp_comp adaptor_comp;
+
+ if (!ovl_adaptor->ovl_adaptor_comp[i] ||
+ !comp_matches[i].funcs->clk_disable)
continue;
- comp_matches[i].funcs->clk_disable(comp);
+
+ adaptor_comp.dev = ovl_adaptor->ovl_adaptor_comp[i];
+
+ comp_matches[i].funcs->clk_disable(&adaptor_comp);
if (i < OVL_ADAPTOR_MERGE0)
- pm_runtime_put(comp);
+ pm_runtime_put(adaptor_comp.dev);
}
}
@@ -423,10 +431,10 @@ size_t mtk_ovl_adaptor_get_num_formats(struct device *dev)
return mtk_mdp_rdma_get_num_formats(ovl_adaptor->ovl_adaptor_comp[OVL_ADAPTOR_MDP_RDMA0]);
}
-void mtk_ovl_adaptor_add_comp(struct device *dev, struct mtk_mutex *mutex)
+void mtk_ovl_adaptor_add_comp(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex)
{
int i;
- struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
+ struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(comp->dev);
for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
if (!ovl_adaptor->ovl_adaptor_comp[i])
@@ -439,10 +447,10 @@ void mtk_ovl_adaptor_add_comp(struct device *dev, struct mtk_mutex *mutex)
}
}
-void mtk_ovl_adaptor_remove_comp(struct device *dev, struct mtk_mutex *mutex)
+void mtk_ovl_adaptor_remove_comp(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex)
{
int i;
- struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(dev);
+ struct mtk_disp_ovl_adaptor *ovl_adaptor = dev_get_drvdata(comp->dev);
for (i = 0; i < OVL_ADAPTOR_ID_MAX; i++) {
if (!ovl_adaptor->ovl_adaptor_comp[i])
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
index dce7a9bc3f11..4b6ecd9bdd5f 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_rdma.c
@@ -157,16 +157,16 @@ size_t mtk_rdma_get_num_formats(struct device *dev)
return rdma->data->num_formats;
}
-int mtk_rdma_clk_enable(struct device *dev)
+int mtk_rdma_clk_enable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
+ struct mtk_disp_rdma *rdma = dev_get_drvdata(comp->dev);
return clk_prepare_enable(rdma->clk);
}
-void mtk_rdma_clk_disable(struct device *dev)
+void mtk_rdma_clk_disable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
+ struct mtk_disp_rdma *rdma = dev_get_drvdata(comp->dev);
clk_disable_unprepare(rdma->clk);
}
@@ -182,13 +182,13 @@ void mtk_rdma_stop(struct device *dev)
rdma_update_bits(dev, DISP_REG_RDMA_GLOBAL_CON, RDMA_ENGINE_EN, 0);
}
-void mtk_rdma_config(struct device *dev, unsigned int width,
+void mtk_rdma_config(struct mtk_ddp_comp *comp, unsigned int width,
unsigned int height, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
unsigned int threshold;
unsigned int reg;
- struct mtk_disp_rdma *rdma = dev_get_drvdata(dev);
+ struct mtk_disp_rdma *rdma = dev_get_drvdata(comp->dev);
u32 rdma_fifo_size;
mtk_ddp_write_mask(cmdq_pkt, width, &rdma->cmdq_reg, rdma->regs,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_wdma.c b/drivers/gpu/drm/mediatek/mtk_disp_wdma.c
index 26c80e7e152b..d5ebd3e3d80f 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_wdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_disp_wdma.c
@@ -189,16 +189,16 @@ size_t mtk_wdma_get_num_formats(struct device *dev)
return wdma->data->num_formats;
}
-int mtk_wdma_clk_enable(struct device *dev)
+int mtk_wdma_clk_enable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_wdma *wdma = dev_get_drvdata(dev);
+ struct mtk_disp_wdma *wdma = dev_get_drvdata(comp->dev);
return clk_prepare_enable(wdma->clk);
}
-void mtk_wdma_clk_disable(struct device *dev)
+void mtk_wdma_clk_disable(struct mtk_ddp_comp *comp)
{
- struct mtk_disp_wdma *wdma = dev_get_drvdata(dev);
+ struct mtk_disp_wdma *wdma = dev_get_drvdata(comp->dev);
clk_disable_unprepare(wdma->clk);
}
@@ -214,11 +214,11 @@ void mtk_wdma_stop(struct device *dev)
wdma_update_bits(dev, DISP_REG_WDMA_EN, WDMA_ENGINE_EN, 0);
}
-void mtk_wdma_config(struct device *dev, unsigned int width,
+void mtk_wdma_config(struct mtk_ddp_comp *comp, unsigned int width,
unsigned int height, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
{
- struct mtk_disp_wdma *wdma = dev_get_drvdata(dev);
+ struct mtk_disp_wdma *wdma = dev_get_drvdata(comp->dev);
writel(WDMA_FORCE_COMMIT | WDMA_BYPASS_SHADOW,
wdma->regs + DISP_REG_WDMA_SHADOW_CTRL);
diff --git a/drivers/gpu/drm/mediatek/mtk_ethdr.c b/drivers/gpu/drm/mediatek/mtk_ethdr.c
index 96832d0cca37..aa257c3780b6 100644
--- a/drivers/gpu/drm/mediatek/mtk_ethdr.c
+++ b/drivers/gpu/drm/mediatek/mtk_ethdr.c
@@ -281,21 +281,21 @@ void mtk_ethdr_stop(struct device *dev)
writel(0, mixer->regs + MIX_RST);
}
-int mtk_ethdr_clk_enable(struct device *dev)
+int mtk_ethdr_clk_enable(struct mtk_ddp_comp *comp)
{
int ret;
- struct mtk_ethdr *priv = dev_get_drvdata(dev);
+ struct mtk_ethdr *priv = dev_get_drvdata(comp->dev);
ret = clk_bulk_prepare_enable(ETHDR_CLK_NUM, priv->ethdr_clk);
if (ret)
- dev_err(dev,
+ dev_err(comp->dev,
"ethdr_clk prepare enable failed\n");
return ret;
}
-void mtk_ethdr_clk_disable(struct device *dev)
+void mtk_ethdr_clk_disable(struct mtk_ddp_comp *comp)
{
- struct mtk_ethdr *priv = dev_get_drvdata(dev);
+ struct mtk_ethdr *priv = dev_get_drvdata(comp->dev);
clk_bulk_disable_unprepare(ETHDR_CLK_NUM, priv->ethdr_clk);
}
diff --git a/drivers/gpu/drm/mediatek/mtk_ethdr.h b/drivers/gpu/drm/mediatek/mtk_ethdr.h
index a72aeee46829..b81b75a092c1 100644
--- a/drivers/gpu/drm/mediatek/mtk_ethdr.h
+++ b/drivers/gpu/drm/mediatek/mtk_ethdr.h
@@ -8,8 +8,8 @@
void mtk_ethdr_start(struct device *dev);
void mtk_ethdr_stop(struct device *dev);
-int mtk_ethdr_clk_enable(struct device *dev);
-void mtk_ethdr_clk_disable(struct device *dev);
+int mtk_ethdr_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_ethdr_clk_disable(struct mtk_ddp_comp *comp);
void mtk_ethdr_config(struct device *dev, unsigned int w,
unsigned int h, unsigned int vrefresh,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
diff --git a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c
index 7982788ae9df..62cc0abca5f3 100644
--- a/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c
+++ b/drivers/gpu/drm/mediatek/mtk_mdp_rdma.c
@@ -258,16 +258,16 @@ void mtk_mdp_rdma_power_off(struct device *dev)
pm_runtime_put(dev);
}
-int mtk_mdp_rdma_clk_enable(struct device *dev)
+int mtk_mdp_rdma_clk_enable(struct mtk_ddp_comp *comp)
{
- struct mtk_mdp_rdma *rdma = dev_get_drvdata(dev);
+ struct mtk_mdp_rdma *rdma = dev_get_drvdata(comp->dev);
return clk_prepare_enable(rdma->clk);
}
-void mtk_mdp_rdma_clk_disable(struct device *dev)
+void mtk_mdp_rdma_clk_disable(struct mtk_ddp_comp *comp)
{
- struct mtk_mdp_rdma *rdma = dev_get_drvdata(dev);
+ struct mtk_mdp_rdma *rdma = dev_get_drvdata(comp->dev);
clk_disable_unprepare(rdma->clk);
}
diff --git a/drivers/gpu/drm/mediatek/mtk_padding.c b/drivers/gpu/drm/mediatek/mtk_padding.c
index b4e3e5a3428b..95183600d150 100644
--- a/drivers/gpu/drm/mediatek/mtk_padding.c
+++ b/drivers/gpu/drm/mediatek/mtk_padding.c
@@ -38,16 +38,16 @@ struct mtk_padding {
struct cmdq_client_reg cmdq_reg;
};
-int mtk_padding_clk_enable(struct device *dev)
+int mtk_padding_clk_enable(struct mtk_ddp_comp *comp)
{
- struct mtk_padding *padding = dev_get_drvdata(dev);
+ struct mtk_padding *padding = dev_get_drvdata(comp->dev);
return clk_prepare_enable(padding->clk);
}
-void mtk_padding_clk_disable(struct device *dev)
+void mtk_padding_clk_disable(struct mtk_ddp_comp *comp)
{
- struct mtk_padding *padding = dev_get_drvdata(dev);
+ struct mtk_padding *padding = dev_get_drvdata(comp->dev);
clk_disable_unprepare(padding->clk);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 26/42] dt-bindings: display: mediatek: Introduce MT8196 Layer Blender
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (24 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 25/42] drm/mediatek: Pass mtk_ddp_comp in clk and config callbacks AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 14:23 ` Rob Herring (Arm)
2026-07-01 12:20 ` [PATCH 27/42] drm/mediatek: Add support for Display Layer Blender component AngeloGioacchino Del Regno
` (15 subsequent siblings)
41 siblings, 1 reply; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Add documentation for the Overlay Layer Blender IP found in the
newer generation SoCs like MT8196, MT8894, MT6991, and their
variants.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
.../mediatek/mediatek,mt8196-blender.yaml | 97 +++++++++++++++++++
1 file changed, 97 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-blender.yaml
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-blender.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-blender.yaml
new file mode 100644
index 000000000000..d907a51c495e
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-blender.yaml
@@ -0,0 +1,97 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/mediatek/mediatek,mt8196-blender.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Display Overlay Layer Blender
+
+maintainers:
+ - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+ The MediaTek Display Overlay Layer Blender hardware is responsible
+ for performing the alpha blending operation for overlapping layers
+ from various sources.
+
+properties:
+ compatible:
+ - const: mediatek,mt8196-disp-blender
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+
+ required:
+ - port@0
+ - port@1
+
+ trigger-sources:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/mediatek,mt8196-clock.h>
+ #include <dt-bindings/power/mediatek,mt8196-power.h>
+
+ blender@328e0000 {
+ compatible = "mediatek,mt8196-disp-blender";
+ reg = <0x328e0000 0x1000>;
+ clocks = <&ovlsys0 CLK_OVL_BLENDER1>;
+ power-domains = <&hpm_hwv MT8196_POWER_DOMAIN_OVL0_DORMANT>;
+ trigger-sources = <&ovl0_mutex 11>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&exdma0_2_out>;
+ };
+ };
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&exdma0_3_in>;
+ };
+ };
+ };
+ };
+
+...
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 26/42] dt-bindings: display: mediatek: Introduce MT8196 Layer Blender
2026-07-01 12:20 ` [PATCH 26/42] dt-bindings: display: mediatek: Introduce MT8196 Layer Blender AngeloGioacchino Del Regno
@ 2026-07-01 14:23 ` Rob Herring (Arm)
0 siblings, 0 replies; 52+ messages in thread
From: Rob Herring (Arm) @ 2026-07-01 14:23 UTC (permalink / raw)
To: AngeloGioacchino Del Regno
Cc: linux-kernel, kernel, airlied, dri-devel, mripard, conor+dt,
justin.yeh, devicetree, jason-jh.lin, linux-arm-kernel, simona,
chunkuang.hu, tzimmermann, linux-mediatek, matthias.bgg,
maarten.lankhorst, p.zabel, krzk+dt
On Wed, 01 Jul 2026 14:20:41 +0200, AngeloGioacchino Del Regno wrote:
> Add documentation for the Overlay Layer Blender IP found in the
> newer generation SoCs like MT8196, MT8894, MT6991, and their
> variants.
>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
> .../mediatek/mediatek,mt8196-blender.yaml | 97 +++++++++++++++++++
> 1 file changed, 97 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-blender.yaml
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-blender.yaml: ignoring, error in schema: properties: compatible
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-blender.yaml: properties:compatible: [{'const': 'mediatek,mt8196-disp-blender'}] is not of type 'object', 'boolean'
from schema $id: http://devicetree.org/meta-schemas/keywords.yaml
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-blender.yaml: properties:compatible: [{'const': 'mediatek,mt8196-disp-blender'}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-blender.yaml: properties:compatible: [{'const': 'mediatek,mt8196-disp-blender'}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-blender.yaml: properties:compatible: [{'const': 'mediatek,mt8196-disp-blender'}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-blender.yaml: properties:compatible: [{'const': 'mediatek,mt8196-disp-blender'}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-blender.yaml: properties:compatible: [{'const': 'mediatek,mt8196-disp-blender'}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-blender.yaml: properties:compatible: [{'const': 'mediatek,mt8196-disp-blender'}] is not of type 'object', 'boolean'
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-blender.yaml: properties:compatible: [{'const': 'mediatek,mt8196-disp-blender'}] is not of type 'object', 'boolean'
Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-blender.example.dtb: /example-0/blender@328e0000: failed to match any schema with compatible: ['mediatek,mt8196-disp-blender']
doc reference errors (make refcheckdocs):
See https://patchwork.kernel.org/project/devicetree/patch/20260701122057.19648-27-angelogioacchino.delregno@collabora.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 27/42] drm/mediatek: Add support for Display Layer Blender component
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (25 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 26/42] dt-bindings: display: mediatek: Introduce MT8196 Layer Blender AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 28/42] dt-bindings: display: mediatek: Introduce MT8196 extended DMA Engine AngeloGioacchino Del Regno
` (14 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Add support for the Layer Blender hardware component, found in the
MediaTek Kompanio Ultra MT8196, Genio Pro 5100 MT8894, Dimensity
9400 MT6991 and others.
This component is responsible for managing blending of single
layer stages and therefore implements one full layer stage which
gets completed by an exDMA hardware component.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/Makefile | 1 +
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 14 +
drivers/gpu/drm/mediatek/mtk_disp_blender.c | 318 ++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_disp_drv.h | 15 +
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 3 +
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 +
include/linux/soc/mediatek/mtk-mmsys.h | 1 +
7 files changed, 353 insertions(+)
create mode 100644 drivers/gpu/drm/mediatek/mtk_disp_blender.c
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index c48ac3ab08cc..a3c1285e8f33 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -3,6 +3,7 @@
mediatek-drm-y := mtk_crtc.o \
mtk_ddp_comp.o \
mtk_disp_aal.o \
+ mtk_disp_blender.o \
mtk_disp_ccorr.o \
mtk_disp_color.o \
mtk_disp_dsc.o \
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index 8b9228084828..6a312f3ddb09 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -246,6 +246,18 @@ static const struct mtk_ddp_comp_funcs ddp_aal = {
.stop = mtk_aal_stop,
};
+static const struct mtk_ddp_comp_funcs ddp_blender = {
+ .clk_enable = mtk_blender_clk_enable,
+ .clk_disable = mtk_blender_clk_disable,
+ .config = mtk_blender_config,
+ .start = mtk_blender_start,
+ .stop = mtk_blender_stop,
+ .layer_config = mtk_blender_layer_config,
+ .get_blend_modes = mtk_blender_get_blend_modes,
+ .layerstage_nr = mtk_blender_layerstage_nr,
+ .connect = mtk_blender_connect,
+};
+
static const struct mtk_ddp_comp_funcs ddp_ccorr = {
.clk_enable = mtk_ccorr_clk_enable,
.clk_disable = mtk_ccorr_clk_disable,
@@ -416,6 +428,7 @@ static const struct mtk_ddp_comp_funcs ddp_ovl_adaptor = {
static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_AAL] = "aal",
+ [MTK_DISP_BLENDER] = "blender",
[MTK_DISP_BLS] = "bls",
[MTK_DISP_CCORR] = "ccorr",
[MTK_DISP_COLOR] = "color",
@@ -441,6 +454,7 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
static const struct mtk_ddp_comp_funcs *mtk_ddp_funcs[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_AAL] = &ddp_aal,
+ [MTK_DISP_BLENDER] = &ddp_blender,
[MTK_DISP_BLS] = NULL,
[MTK_DISP_CCORR] = &ddp_ccorr,
[MTK_DISP_COLOR] = &ddp_color,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_blender.c b/drivers/gpu/drm/mediatek/mtk_disp_blender.c
new file mode 100644
index 000000000000..74679b15a26c
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_disp_blender.c
@@ -0,0 +1,318 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <drm/drm_blend.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_framebuffer.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/soc/mediatek/mtk-cmdq.h>
+#include <linux/soc/mediatek/mtk-mmsys.h>
+
+#include "mtk_crtc.h"
+#include "mtk_ddp_comp.h"
+#include "mtk_disp_drv.h"
+#include "mtk_disp_ovl.h"
+#include "mtk_drm_drv.h"
+
+#define DISP_REG_OVL_BLD_DATAPATH_CON 0x010
+# define OVL_BLD_BGCLR_IN_SEL BIT(0)
+# define OVL_BLD_BGCLR_OUT_TO_PROC BIT(4)
+# define OVL_BLD_BGCLR_OUT_TO_NEXT_LAYER BIT(5)
+
+#define DISP_REG_OVL_BLD_EN 0x020
+# define OVL_BLD_EN BIT(0)
+# define OVL_BLD_FORCE_RELAY_MODE BIT(4)
+# define OVL_BLD_RELAY_MODE BIT(5)
+
+#define DISP_REG_OVL_BLD_RST 0x024
+# define OVL_BLD_RST BIT(0)
+
+#define DISP_REG_OVL_BLD_SHADOW_CTRL 0x028
+# define OVL_BLD_BYPASS_SHADOW BIT(2)
+
+#define DISP_REG_OVL_BLD_ROI_SIZE 0x030
+#define DISP_REG_OVL_BLD_L_EN 0x040
+# define OVL_BLD_L_EN BIT(0)
+
+#define DISP_REG_OVL_BLD_OFFSET 0x044
+#define DISP_REG_OVL_BLD_SRC_SIZE 0x048
+#define DISP_REG_OVL_BLD_L0_CLRFMT 0x050
+# define OVL_BLD_CON_FLD_CLRFMT GENMASK(3, 0)
+# define OVL_BLD_CON_CLRFMT_MAN BIT(4)
+# define OVL_BLD_CON_FLD_CLRFMT_NB GENMASK(9, 8)
+# define OVL_BLD_CON_CLRFMT_NB_10_BIT BIT(8)
+# define OVL_BLD_CON_BYTE_SWAP BIT(16)
+# define OVL_BLD_CON_RGB_SWAP BIT(17)
+
+#define DISP_REG_OVL_BLD_BGCLR_CLR 0x104
+#define DISP_REG_OVL_BLD_L_CON2 0x200
+# define OVL_BLD_L_ALPHA GENMASK(7, 0)
+# define OVL_BLD_L_ALPHA_EN BIT(12)
+
+#define DISP_REG_OVL_BLD_L0_ALPHA_SEL 0x208
+# define OVL_BLD_L0_CONST BIT(24)
+
+#define DISP_REG_OVL_BLD_L0_CLR 0x20c
+# define OVL_BLD_BGCLR_BLACK 0xff000000
+# define OVL_BLD_BGCLR_RED 0xffff0000
+
+#define BLENDER_MAX_SIZE 8191
+
+struct mtk_disp_blender {
+ void __iomem *regs;
+ struct clk *clk;
+ struct cmdq_client_reg cmdq_reg;
+};
+
+static void mtk_blender_unset_input_bgclr(struct mtk_disp_blender *priv)
+{
+ u32 val;
+
+ val = readl(priv->regs + DISP_REG_OVL_BLD_DATAPATH_CON);
+ val &= ~OVL_BLD_BGCLR_IN_SEL;
+ writel(val, priv->regs + DISP_REG_OVL_BLD_DATAPATH_CON);
+}
+
+void mtk_blender_layer_config(struct device *dev, unsigned int idx,
+ struct mtk_plane_state *state,
+ struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_disp_blender *priv = dev_get_drvdata(dev);
+ struct mtk_plane_pending_state *pending = &state->pending;
+ u32 alpha, blend_mode, clrfmt, ignore_pixel_alpha;
+
+ /*
+ * Deselect IN from OVL Background Color if this is the first Blender
+ * to implicitly select input from exDMA instead.
+ */
+ if (idx == 0)
+ mtk_blender_unset_input_bgclr(priv);
+
+ if (!pending->enable || pending->height == 0 || pending->width == 0 ||
+ pending->x > BLENDER_MAX_SIZE || pending->y > BLENDER_MAX_SIZE) {
+ mtk_ddp_write(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs, DISP_REG_OVL_BLD_L_EN);
+ return;
+ }
+
+ mtk_ddp_write(cmdq_pkt,
+ ((pending->height & GENMASK(15, 0)) << 16) |
+ (pending->width & GENMASK(15, 0)),
+ &priv->cmdq_reg, priv->regs, DISP_REG_OVL_BLD_SRC_SIZE);
+ mtk_ddp_write(cmdq_pkt,
+ ((pending->y & GENMASK(15, 0)) << 16) | (pending->x & GENMASK(15, 0)),
+ &priv->cmdq_reg, priv->regs, DISP_REG_OVL_BLD_OFFSET);
+
+ blend_mode = mtk_ovl_get_blend_mode(state, MTK_OVL_SUPPORT_BLEND_MODES);
+ clrfmt = mtk_ovl_fmt_convert(pending->format, blend_mode, true, false, 0,
+ OVL_BLD_CON_CLRFMT_MAN, OVL_BLD_CON_BYTE_SWAP,
+ OVL_BLD_CON_RGB_SWAP);
+ clrfmt |= mtk_ovl_is_10bit_rgb(pending->format) ? OVL_BLD_CON_CLRFMT_NB_10_BIT : 0;
+ mtk_ddp_write_mask(cmdq_pkt, clrfmt, &priv->cmdq_reg, priv->regs,
+ DISP_REG_OVL_BLD_L0_CLRFMT, OVL_BLD_CON_CLRFMT_MAN |
+ OVL_BLD_CON_RGB_SWAP | OVL_BLD_CON_BYTE_SWAP |
+ OVL_BLD_CON_FLD_CLRFMT | OVL_BLD_CON_FLD_CLRFMT_NB);
+
+ if (mtk_ovl_is_ignore_pixel_alpha(state, blend_mode))
+ ignore_pixel_alpha = OVL_BLD_L0_CONST;
+ else
+ ignore_pixel_alpha = 0;
+
+ mtk_ddp_write_mask(cmdq_pkt, ignore_pixel_alpha, &priv->cmdq_reg, priv->regs,
+ DISP_REG_OVL_BLD_L0_ALPHA_SEL, OVL_BLD_L0_CONST);
+
+ alpha = FIELD_PREP(OVL_BLD_L_ALPHA, (state->base.alpha >> 8));
+ alpha |= OVL_BLD_L_ALPHA_EN;
+ mtk_ddp_write_mask(cmdq_pkt, alpha, &priv->cmdq_reg, priv->regs,
+ DISP_REG_OVL_BLD_L_CON2, OVL_BLD_L_ALPHA_EN | OVL_BLD_L_ALPHA);
+
+ mtk_ddp_write(cmdq_pkt, OVL_BLD_L_EN, &priv->cmdq_reg, priv->regs, DISP_REG_OVL_BLD_L_EN);
+}
+
+unsigned int mtk_blender_layerstage_nr(struct device *dev)
+{
+ return 1;
+}
+
+void mtk_blender_start(struct device *dev)
+{
+ struct mtk_disp_blender *priv = dev_get_drvdata(dev);
+ u32 val;
+
+ /* Bypass shadow registers and enable */
+ val = readl(priv->regs + DISP_REG_OVL_BLD_SHADOW_CTRL);
+ val |= OVL_BLD_BYPASS_SHADOW;
+ writel(val, priv->regs + DISP_REG_OVL_BLD_SHADOW_CTRL);
+
+ val = readl(priv->regs + DISP_REG_OVL_BLD_EN);
+ val |= OVL_BLD_EN;
+ writel(val, priv->regs + DISP_REG_OVL_BLD_EN);
+}
+
+void mtk_blender_stop(struct device *dev)
+{
+ struct mtk_disp_blender *priv = dev_get_drvdata(dev);
+ u32 val;
+
+ /* Disable and reset */
+ val = readl(priv->regs + DISP_REG_OVL_BLD_EN);
+ val = val & ~OVL_BLD_EN;
+ writel(val, priv->regs + DISP_REG_OVL_BLD_EN);
+
+ val = readl(priv->regs + DISP_REG_OVL_BLD_RST);
+ val |= OVL_BLD_RST;
+ writel(val, priv->regs + DISP_REG_OVL_BLD_RST);
+
+ val = readl(priv->regs + DISP_REG_OVL_BLD_RST);
+ val = val & ~OVL_BLD_RST;
+ writel(val, priv->regs + DISP_REG_OVL_BLD_RST);
+}
+
+void mtk_blender_config(struct mtk_ddp_comp *comp, unsigned int w,
+ unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_disp_blender *priv = dev_get_drvdata(comp->dev);
+ u32 val;
+
+ /* Set ROI for this Blender */
+ val = ((h & GENMASK(15, 0)) << 16) | (w & GENMASK(15, 0));
+ writel(val, priv->regs + DISP_REG_OVL_BLD_ROI_SIZE);
+
+ /*
+ * Set both background color and constant layer color to Opaque Black
+ * (ARGB) for eventual Alpha Blending to be effective
+ */
+ writel(OVL_BLD_BGCLR_BLACK, priv->regs + DISP_REG_OVL_BLD_BGCLR_CLR);
+ writel(OVL_BLD_BGCLR_BLACK, priv->regs + DISP_REG_OVL_BLD_L0_CLR);
+}
+
+void mtk_blender_connect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next)
+{
+ struct mtk_disp_blender *priv = dev_get_drvdata(comp->dev);
+ const u32 mask = OVL_BLD_BGCLR_OUT_TO_PROC |
+ OVL_BLD_BGCLR_OUT_TO_NEXT_LAYER |
+ OVL_BLD_BGCLR_IN_SEL;
+ u32 data_path = OVL_BLD_BGCLR_IN_SEL;
+ u32 val;
+
+ /* Usually the next component is either another OUTPROC or an exDMA */
+ if (next->type == MTK_DISP_OUTPROC)
+ data_path |= OVL_BLD_BGCLR_OUT_TO_PROC;
+ else
+ data_path |= OVL_BLD_BGCLR_OUT_TO_NEXT_LAYER;
+
+ val = readl(priv->regs + DISP_REG_OVL_BLD_DATAPATH_CON);
+ val = (val & ~mask) | data_path;
+ writel(val, priv->regs + DISP_REG_OVL_BLD_DATAPATH_CON);
+
+ mtk_mmsys_hw_connect(mmsys_dev,
+ comp->type, comp->inst_id, next->type, next->inst_id);
+}
+
+int mtk_blender_clk_enable(struct mtk_ddp_comp *comp)
+{
+ struct mtk_disp_blender *priv = dev_get_drvdata(comp->dev);
+
+ return clk_prepare_enable(priv->clk);
+}
+
+void mtk_blender_clk_disable(struct mtk_ddp_comp *comp)
+{
+ struct mtk_disp_blender *priv = dev_get_drvdata(comp->dev);
+
+ clk_disable_unprepare(priv->clk);
+}
+
+u32 mtk_blender_get_blend_modes(struct device *dev)
+{
+ return MTK_OVL_SUPPORT_BLEND_MODES;
+}
+
+static int mtk_blender_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ return 0;
+}
+
+static void mtk_blender_unbind(struct device *dev, struct device *master, void *data)
+{
+}
+
+static const struct component_ops mtk_disp_blender_component_ops = {
+ .bind = mtk_blender_bind,
+ .unbind = mtk_blender_unbind,
+};
+
+static int mtk_blender_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_disp_blender *priv;
+ int ret = 0;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->regs))
+ return dev_err_probe(dev, PTR_ERR(priv->regs), "Cannot get reg\n");
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk), "Cannot get clocks\n");
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
+ if (ret)
+ dev_dbg(dev, "No mediatek,gce-client-reg\n");
+#endif
+ platform_set_drvdata(pdev, priv);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ ret = component_add(dev, &mtk_disp_blender_component_ops);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add component\n");
+
+ return 0;
+}
+
+static void mtk_blender_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &mtk_disp_blender_component_ops);
+}
+
+static const struct of_device_id mtk_disp_blender_driver_dt_match[] = {
+ { .compatible = "mediatek,mt8196-disp-blender" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mtk_disp_blender_driver_dt_match);
+
+struct platform_driver mtk_disp_blender_driver = {
+ .probe = mtk_blender_probe,
+ .remove = mtk_blender_remove,
+ .driver = {
+ .name = "mediatek-disp-blender",
+ .owner = THIS_MODULE,
+ .of_match_table = mtk_disp_blender_driver_dt_match,
+ },
+};
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_AUTHOR("Nancy Lin <nancy.lin@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek Display Controller Layer Blender Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 62daf5ade9d1..e834bf17d86c 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -27,6 +27,21 @@ void mtk_aal_gamma_set(struct device *dev, struct drm_crtc_state *state);
void mtk_aal_start(struct device *dev);
void mtk_aal_stop(struct device *dev);
+int mtk_blender_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_blender_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_blender_connect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next);
+void mtk_blender_config(struct mtk_ddp_comp *comp, unsigned int w,
+ unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+u32 mtk_blender_get_blend_modes(struct device *dev);
+void mtk_blender_layer_config(struct device *dev, unsigned int idx,
+ struct mtk_plane_state *state,
+ struct cmdq_pkt *cmdq_pkt);
+unsigned int mtk_blender_layerstage_nr(struct device *dev);
+void mtk_blender_start(struct device *dev);
+void mtk_blender_stop(struct device *dev);
+
void mtk_ccorr_ctm_set(struct device *dev, struct drm_crtc_state *state);
int mtk_ccorr_clk_enable(struct mtk_ddp_comp *comp);
void mtk_ccorr_clk_disable(struct mtk_ddp_comp *comp);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index ee835ebbc18c..a70392c54bb9 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -503,6 +503,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_AAL},
{ .compatible = "mediatek,mt8192-disp-aal",
.data = (void *)MTK_DISP_AAL},
+ { .compatible = "mediatek,mt8196-disp-blender",
+ .data = (void *)MTK_DISP_BLENDER },
{ .compatible = "mediatek,mt8167-disp-ccorr",
.data = (void *)MTK_DISP_CCORR },
{ .compatible = "mediatek,mt8183-disp-ccorr",
@@ -1059,6 +1061,7 @@ static struct platform_driver mtk_drm_platform_driver = {
static struct platform_driver * const mtk_drm_drivers[] = {
&mtk_disp_aal_driver,
+ &mtk_disp_blender_driver,
&mtk_disp_ccorr_driver,
&mtk_disp_color_driver,
&mtk_disp_dsc_driver,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index 4028268b3cc8..f36888fd7244 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -73,6 +73,7 @@ struct mtk_drm_private {
};
extern struct platform_driver mtk_disp_aal_driver;
+extern struct platform_driver mtk_disp_blender_driver;
extern struct platform_driver mtk_disp_ccorr_driver;
extern struct platform_driver mtk_disp_color_driver;
extern struct platform_driver mtk_disp_dsc_driver;
diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h
index 0b3bef392ab8..b32f0c92f040 100644
--- a/include/linux/soc/mediatek/mtk-mmsys.h
+++ b/include/linux/soc/mediatek/mtk-mmsys.h
@@ -88,6 +88,7 @@ enum mtk_ddp_comp_type {
/* DISP Components */
MTK_DISP_AAL,
MTK_DISP_BLS,
+ MTK_DISP_BLENDER,
MTK_DISP_CCORR,
MTK_DISP_COLOR,
MTK_DISP_DITHER,
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 28/42] dt-bindings: display: mediatek: Introduce MT8196 extended DMA Engine
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (26 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 27/42] drm/mediatek: Add support for Display Layer Blender component AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 14:23 ` Rob Herring (Arm)
2026-07-01 12:20 ` [PATCH 29/42] drm/mediatek: Add support for Display Controller exDMA component AngeloGioacchino Del Regno
` (13 subsequent siblings)
41 siblings, 1 reply; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Add documentation for the extended DMA Engine (exDMA) IP found in
the newer generation SoCs like MT8196, MT8894, MT6991, and their
variants.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
.../mediatek/mediatek,mt8196-exdma.yaml | 104 ++++++++++++++++++
1 file changed, 104 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-exdma.yaml
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-exdma.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-exdma.yaml
new file mode 100644
index 000000000000..ca08a74ef7ad
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-exdma.yaml
@@ -0,0 +1,104 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/mediatek/mediatek,mt8196-exdma.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Display Overlay extended DMA (exDMA) Engine
+
+maintainers:
+ - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+ The MediaTek Display Overlay extended DMA (exDMA) Engine hardware is used
+ to configure the Display Controller to read the data from DRAM to perform
+ layer overlaying.
+ This hardware also includes color conversion functions to output pixels
+ processed into a consistent color domain.
+
+properties:
+ compatible:
+ - const: mediatek,mt8196-disp-exdma
+
+ reg:
+ maxItems: 1
+
+ "#dma-cells":
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+
+ required:
+ - port@0
+ - port@1
+
+ trigger-sources:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - "#dma-cells"
+ - clocks
+ - clock-names
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/mediatek,mt8196-clock.h>
+ #include <dt-bindings/power/mediatek,mt8196-power.h>
+
+ dma-controller@32850000 {
+ compatible = "mediatek,mt8196-disp-exdma";
+ reg = <0x32850000 0x1000>;
+ #dma-cells = <1>;
+ clocks = <&ovlsys0 CLK_OVL_EXDMA2>;
+ power-domains = <&hpm_hwv MT8196_POWER_DOMAIN_OVL0_DORMANT>;
+ trigger-sources = <&ovl0_mutex 2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&ovl0_resizer0_out>;
+ };
+ };
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&blender0_1_in>;
+ };
+ };
+ };
+ };
+
+...
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 28/42] dt-bindings: display: mediatek: Introduce MT8196 extended DMA Engine
2026-07-01 12:20 ` [PATCH 28/42] dt-bindings: display: mediatek: Introduce MT8196 extended DMA Engine AngeloGioacchino Del Regno
@ 2026-07-01 14:23 ` Rob Herring (Arm)
0 siblings, 0 replies; 52+ messages in thread
From: Rob Herring (Arm) @ 2026-07-01 14:23 UTC (permalink / raw)
To: AngeloGioacchino Del Regno
Cc: conor+dt, mripard, devicetree, maarten.lankhorst, p.zabel,
krzk+dt, chunkuang.hu, matthias.bgg, tzimmermann, airlied,
linux-mediatek, simona, dri-devel, linux-kernel, kernel,
linux-arm-kernel, jason-jh.lin, justin.yeh
On Wed, 01 Jul 2026 14:20:43 +0200, AngeloGioacchino Del Regno wrote:
> Add documentation for the extended DMA Engine (exDMA) IP found in
> the newer generation SoCs like MT8196, MT8894, MT6991, and their
> variants.
>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
> .../mediatek/mediatek,mt8196-exdma.yaml | 104 ++++++++++++++++++
> 1 file changed, 104 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-exdma.yaml
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-exdma.yaml: ignoring, error in schema: properties: compatible
Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-exdma.example.dtb: /example-0/dma-controller@32850000: failed to match any schema with compatible: ['mediatek,mt8196-disp-exdma']
doc reference errors (make refcheckdocs):
See https://patchwork.kernel.org/project/devicetree/patch/20260701122057.19648-29-angelogioacchino.delregno@collabora.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 29/42] drm/mediatek: Add support for Display Controller exDMA component
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (27 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 28/42] dt-bindings: display: mediatek: Introduce MT8196 extended DMA Engine AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 30/42] dt-bindings: display: mediatek: Introduce MT8196 Output Processor AngeloGioacchino Del Regno
` (12 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Add support for the Display Overlay extended DMA engine (exDMA) as
found in the MediaTek Kompanio Ultra MT8196, Genio Pro 5100 MT8894,
Dimensity 9400 MT6991 and others.
This is a DMA engine and its purpose is to configure the Display
Controller to read data from DRAM and also includes color transfer
functions to process pixels into a consistent color domain.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/Makefile | 1 +
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 14 +
drivers/gpu/drm/mediatek/mtk_disp_drv.h | 14 +
drivers/gpu/drm/mediatek/mtk_disp_exdma.c | 344 ++++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 3 +
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 +
include/linux/soc/mediatek/mtk-mmsys.h | 1 +
7 files changed, 378 insertions(+)
create mode 100644 drivers/gpu/drm/mediatek/mtk_disp_exdma.c
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index a3c1285e8f33..5506f306a7b6 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -7,6 +7,7 @@ mediatek-drm-y := mtk_crtc.o \
mtk_disp_ccorr.o \
mtk_disp_color.o \
mtk_disp_dsc.o \
+ mtk_disp_exdma.o \
mtk_disp_gamma.o \
mtk_disp_merge.o \
mtk_disp_ovl.o \
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index 6a312f3ddb09..9896420f902d 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -308,6 +308,18 @@ static const struct mtk_ddp_comp_funcs ddp_dvo = {
.encoder_index = mtk_dvo_encoder_index,
};
+static const struct mtk_ddp_comp_funcs ddp_exdma = {
+ .clk_enable = mtk_exdma_clk_enable,
+ .clk_disable = mtk_exdma_clk_disable,
+ .config = mtk_exdma_config,
+ .start = mtk_exdma_start,
+ .stop = mtk_exdma_stop,
+ .layer_config = mtk_exdma_layer_config,
+ .layer_nr = mtk_exdma_layer_nr,
+ .get_formats = mtk_exdma_get_formats,
+ .get_num_formats = mtk_exdma_get_num_formats,
+};
+
static const struct mtk_ddp_comp_funcs ddp_gamma = {
.clk_enable = mtk_gamma_clk_enable,
.clk_disable = mtk_gamma_clk_disable,
@@ -434,6 +446,7 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_COLOR] = "color",
[MTK_DISP_DITHER] = "dither",
[MTK_DISP_DSC] = "dsc",
+ [MTK_DISP_EXDMA] = "exdma",
[MTK_DISP_GAMMA] = "gamma",
[MTK_DISP_MERGE] = "merge",
[MTK_DISP_MUTEX] = "mutex",
@@ -460,6 +473,7 @@ static const struct mtk_ddp_comp_funcs *mtk_ddp_funcs[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_COLOR] = &ddp_color,
[MTK_DISP_DITHER] = &ddp_dither,
[MTK_DISP_DSC] = &ddp_dsc,
+ [MTK_DISP_EXDMA] = &ddp_exdma,
[MTK_DISP_GAMMA] = &ddp_gamma,
[MTK_DISP_MERGE] = &ddp_merge,
[MTK_DISP_OD] = &ddp_od,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index e834bf17d86c..df4357b0954b 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -82,6 +82,20 @@ void mtk_dvo_start(struct device *dev);
void mtk_dvo_stop(struct device *dev);
unsigned int mtk_dvo_encoder_index(struct device *dev);
+int mtk_exdma_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_exdma_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_exdma_start(struct device *dev);
+void mtk_exdma_stop(struct device *dev);
+void mtk_exdma_config(struct mtk_ddp_comp *comp, unsigned int w,
+ unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+void mtk_exdma_layer_config(struct device *dev, unsigned int idx,
+ struct mtk_plane_state *state,
+ struct cmdq_pkt *cmdq_pkt);
+unsigned int mtk_exdma_layer_nr(struct device *dev, int pipeline_index);
+const u32 *mtk_exdma_get_formats(struct device *dev);
+size_t mtk_exdma_get_num_formats(struct device *dev);
+
int mtk_gamma_clk_enable(struct mtk_ddp_comp *comp);
void mtk_gamma_clk_disable(struct mtk_ddp_comp *comp);
void mtk_gamma_config(struct mtk_ddp_comp *comp, unsigned int w,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_exdma.c b/drivers/gpu/drm/mediatek/mtk_disp_exdma.c
new file mode 100644
index 000000000000..c06eb85ebc2b
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_disp_exdma.c
@@ -0,0 +1,344 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <drm/drm_blend.h>
+#include <drm/drm_framebuffer.h>
+#include <drm/drm_fourcc.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/soc/mediatek/mtk-cmdq.h>
+
+#include "mtk_disp_drv.h"
+#include "mtk_disp_ovl.h"
+#include "mtk_drm_drv.h"
+
+#define DISP_REG_OVL_EXDMA_EN_CON 0xc
+# define OVL_EXDMA_OP_8BIT_MODE BIT(4)
+# define OVL_EXDMA_HG_FOVL_EXDMA_CK_ON BIT(8)
+# define OVL_EXDMA_HF_FOVL_EXDMA_CK_ON BIT(10)
+#define DISP_REG_OVL_EXDMA_DATAPATH_CON 0x014
+# define OVL_EXDMA_DATAPATH_CON_LAYER_SMI_ID_EN BIT(0)
+# define OVL_EXDMA_DATAPATH_CON_GCLAST_EN BIT(24)
+# define OVL_EXDMA_DATAPATH_CON_HDR_GCLAST_EN BIT(25)
+#define DISP_REG_OVL_EXDMA_EN 0x020
+# define OVL_EXDMA_EN BIT(0)
+# define OVL_EXDMA_FORCE_RELAY_MODE BIT(4)
+#define DISP_REG_OVL_EXDMA_RST 0x024
+# define OVL_EXDMA_RST BIT(0)
+#define DISP_REG_OVL_EXDMA_SRC_CON 0x02c
+# define OVL_EXDMA_FORCE_CONSTANT_LAYER BIT(4)
+#define DISP_REG_OVL_EXDMA_ROI_SIZE 0x030
+#define DISP_REG_OVL_EXDMA_L0_EN 0x040
+# define OVL_EXDMA_L0_EN BIT(0)
+# define OVL_EXDMA_L0_SRC GENMASK(9, 8)
+# define OVL_EXDMA_L0_SRC_BLENDER 0
+# define OVL_EXDMA_L0_SRC_COLOR 1
+# define OVL_EXDMA_L0_SRC_UFOD 2
+# define OVL_EXDMA_L0_SRC_PQ 3
+#define DISP_REG_OVL_EXDMA_L0_OFFSET 0x044
+#define DISP_REG_OVL_EXDMA_SRC_SIZE 0x048
+#define DISP_REG_OVL_EXDMA_L0_CLRFMT 0x050
+# define OVL_EXDMA_CON_FLD_CLRFMT GENMASK(3, 0)
+# define OVL_EXDMA_CON_CLRFMT_MAN BIT(4)
+# define OVL_EXDMA_CON_FLD_CLRFMT_NB GENMASK(9, 8)
+# define OVL_EXDMA_CON_CLRFMT_NB_10_BIT BIT(8)
+# define OVL_EXDMA_CON_BYTE_SWAP BIT(16)
+# define OVL_EXDMA_CON_RGB_SWAP BIT(17)
+#define DISP_REG_OVL_EXDMA_RDMA0_CTRL 0x100
+# define OVL_EXDMA_RDMA0_EN BIT(0)
+#define DISP_REG_OVL_EXDMA_RDMA_BURST_CON1 0x1f4
+# define OVL_EXDMA_RDMA_BURST_CON1_BURST16_EN BIT(28)
+# define OVL_EXDMA_RDMA_BURST_CON1_DDR_EN BIT(30)
+# define OVL_EXDMA_RDMA_BURST_CON1_DDR_ACK_EN BIT(31)
+#define DISP_REG_OVL_EXDMA_DUMMY_REG 0x200
+# define OVL_EXDMA_EXT_DDR_EN_OPT BIT(2)
+# define OVL_EXDMA_FORCE_EXT_DDR_EN BIT(3)
+#define DISP_REG_OVL_EXDMA_GDRDY_PRD 0x208
+#define DISP_REG_OVL_EXDMA_PITCH_MSB 0x2f0
+# define OVL_EXDMA_L0_SRC_PITCH_MSB_MASK GENMASK(3, 0)
+#define DISP_REG_OVL_EXDMA_PITCH 0x2f4
+# define OVL_EXDMA_L0_CONST_BLD BIT(28)
+# define OVL_EXDMA_L0_SRC_PITCH_MASK GENMASK(15, 0)
+#define DISP_REG_OVL_EXDMA_L0_GUSER_EXT 0x2fc
+# define OVL_EXDMA_RDMA0_L0_VCSEL BIT(5)
+# define OVL_EXDMA_RDMA0_HDR_L0_VCSEL BIT(21)
+#define DISP_REG_OVL_EXDMA_CON 0x300
+# define OVL_EXDMA_CON_FLD_INT_MTX_SEL GENMASK(19, 16)
+# define OVL_EXDMA_CON_INT_MTX_BT601_TO_RGB 6
+# define OVL_EXDMA_CON_INT_MTX_BT709_TO_RGB 7
+# define OVL_EXDMA_CON_INT_MTX_EN BIT(27)
+#define DISP_REG_OVL_EXDMA_ADDR 0xf40
+#define DISP_REG_OVL_EXDMA_MOUT 0xff0
+# define OVL_EXDMA_MOUT_OUT_DATA BIT(0)
+# define OVL_EXDMA_MOUT_BGCLR_OUT BIT(1)
+
+#define OVL_EXDMA_MAX_SIZE (8191)
+
+struct mtk_disp_exdma {
+ void __iomem *regs;
+ struct clk *clk;
+ struct cmdq_client_reg cmdq_reg;
+};
+
+static unsigned int mtk_exdma_color_convert(unsigned int color_encoding)
+{
+ switch (color_encoding) {
+ default:
+ case DRM_COLOR_YCBCR_BT709:
+ return FIELD_PREP_CONST(OVL_EXDMA_CON_FLD_INT_MTX_SEL,
+ OVL_EXDMA_CON_INT_MTX_BT709_TO_RGB);
+ case DRM_COLOR_YCBCR_BT601:
+ return FIELD_PREP_CONST(OVL_EXDMA_CON_FLD_INT_MTX_SEL,
+ OVL_EXDMA_CON_INT_MTX_BT601_TO_RGB);
+ }
+}
+
+void mtk_exdma_start(struct device *dev)
+{
+ struct mtk_disp_exdma *priv = dev_get_drvdata(dev);
+ const u32 val = OVL_EXDMA_DATAPATH_CON_LAYER_SMI_ID_EN |
+ OVL_EXDMA_DATAPATH_CON_HDR_GCLAST_EN |
+ OVL_EXDMA_DATAPATH_CON_GCLAST_EN;
+
+ writel(val, priv->regs + DISP_REG_OVL_EXDMA_DATAPATH_CON);
+ writel(OVL_EXDMA_EN, priv->regs + DISP_REG_OVL_EXDMA_EN);
+}
+
+void mtk_exdma_stop(struct device *dev)
+{
+ struct mtk_disp_exdma *priv = dev_get_drvdata(dev);
+
+ writel(0, priv->regs + DISP_REG_OVL_EXDMA_EN);
+ writel(0, priv->regs + DISP_REG_OVL_EXDMA_DATAPATH_CON);
+ writel(OVL_EXDMA_RST, priv->regs + DISP_REG_OVL_EXDMA_RST);
+ writel(0, priv->regs + DISP_REG_OVL_EXDMA_RST);
+}
+
+void mtk_exdma_layer_config(struct device *dev, unsigned int idx,
+ struct mtk_plane_state *state,
+ struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_disp_exdma *priv = dev_get_drvdata(dev);
+ struct mtk_plane_pending_state *pending = &state->pending;
+ const struct drm_format_info *fmt_info = drm_format_info(pending->format);
+ const u32 blend_mode = mtk_ovl_get_blend_mode(state, MTK_OVL_SUPPORT_BLEND_MODES);
+ const bool csc_enable = (fmt_info) ? fmt_info->is_yuv : false;
+ u32 val;
+
+ if (!pending->enable || pending->height == 0 || pending->width == 0 ||
+ pending->x > OVL_EXDMA_MAX_SIZE || pending->y > OVL_EXDMA_MAX_SIZE) {
+ mtk_ddp_write_mask(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs,
+ DISP_REG_OVL_EXDMA_RDMA0_CTRL, OVL_EXDMA_RDMA0_EN);
+ mtk_ddp_write_mask(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs,
+ DISP_REG_OVL_EXDMA_L0_EN, OVL_EXDMA_L0_EN);
+ return;
+ }
+
+ /* Set layer Width and Height */
+ val = ((pending->height & GENMASK(15, 0)) << 16) | (pending->width & GENMASK(15, 0));
+ mtk_ddp_write(cmdq_pkt, val, &priv->cmdq_reg,
+ priv->regs, DISP_REG_OVL_EXDMA_ROI_SIZE);
+
+ mtk_ddp_write(cmdq_pkt, val, &priv->cmdq_reg,
+ priv->regs, DISP_REG_OVL_EXDMA_SRC_SIZE);
+
+ /* The layer X/Y */
+ mtk_ddp_write(cmdq_pkt,
+ ((pending->y & GENMASK(15, 0)) << 16) | (pending->x & GENMASK(15, 0)),
+ &priv->cmdq_reg, priv->regs, DISP_REG_OVL_EXDMA_L0_OFFSET);
+
+ /* The memory address */
+ mtk_ddp_write(cmdq_pkt, pending->addr, &priv->cmdq_reg,
+ priv->regs, DISP_REG_OVL_EXDMA_ADDR);
+
+ /* ...and the pitch. */
+ val = pending->pitch;
+ if (mtk_ovl_is_ignore_pixel_alpha(state, blend_mode))
+ val |= OVL_EXDMA_L0_CONST_BLD;
+
+ mtk_ddp_write_mask(cmdq_pkt, val, &priv->cmdq_reg, priv->regs, DISP_REG_OVL_EXDMA_PITCH,
+ OVL_EXDMA_L0_CONST_BLD | OVL_EXDMA_L0_SRC_PITCH_MASK);
+ mtk_ddp_write_mask(cmdq_pkt, pending->pitch >> 16, &priv->cmdq_reg, priv->regs,
+ DISP_REG_OVL_EXDMA_PITCH_MSB, OVL_EXDMA_L0_SRC_PITCH_MSB_MASK);
+
+ val = mtk_exdma_color_convert(pending->color_encoding);
+ val |= csc_enable ? OVL_EXDMA_CON_INT_MTX_EN : 0;
+ mtk_ddp_write_mask(cmdq_pkt, val, &priv->cmdq_reg, priv->regs, DISP_REG_OVL_EXDMA_CON,
+ OVL_EXDMA_CON_FLD_INT_MTX_SEL | OVL_EXDMA_CON_INT_MTX_EN);
+
+ val = mtk_ovl_fmt_convert(pending->format, blend_mode, true, false, 0,
+ OVL_EXDMA_CON_CLRFMT_MAN, OVL_EXDMA_CON_BYTE_SWAP,
+ OVL_EXDMA_CON_RGB_SWAP);
+ if (mtk_ovl_is_10bit_rgb(pending->format))
+ val |= OVL_EXDMA_CON_CLRFMT_NB_10_BIT;
+ mtk_ddp_write_mask(cmdq_pkt, val, &priv->cmdq_reg, priv->regs,
+ DISP_REG_OVL_EXDMA_L0_CLRFMT,
+ OVL_EXDMA_CON_RGB_SWAP | OVL_EXDMA_CON_BYTE_SWAP |
+ OVL_EXDMA_CON_CLRFMT_MAN | OVL_EXDMA_CON_FLD_CLRFMT |
+ OVL_EXDMA_CON_FLD_CLRFMT_NB);
+
+ /* Virtual Channel selection */
+ val = OVL_EXDMA_RDMA0_L0_VCSEL;
+ mtk_ddp_write_mask(cmdq_pkt, val, &priv->cmdq_reg, priv->regs,
+ DISP_REG_OVL_EXDMA_L0_GUSER_EXT, val);
+
+ mtk_ddp_write_mask(cmdq_pkt, OVL_EXDMA_RDMA0_EN, &priv->cmdq_reg, priv->regs,
+ DISP_REG_OVL_EXDMA_RDMA0_CTRL, OVL_EXDMA_RDMA0_EN);
+ mtk_ddp_write_mask(cmdq_pkt, OVL_EXDMA_L0_EN, &priv->cmdq_reg, priv->regs,
+ DISP_REG_OVL_EXDMA_L0_EN, OVL_EXDMA_L0_EN);
+}
+
+unsigned int mtk_exdma_layer_nr(struct device *dev, int pipeline_index)
+{
+ return 1;
+}
+
+void mtk_exdma_config(struct mtk_ddp_comp *comp, unsigned int w,
+ unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_disp_exdma *priv = dev_get_drvdata(comp->dev);
+ unsigned int tmp, val, mask;
+
+ /*
+ * This configuration enables dynamic power switching mechanism for EXDMA,
+ * also known as "SRT mode".
+ * Such configuration allows the system to achieve better power efficiency.
+ */
+ val = OVL_EXDMA_RDMA_BURST_CON1_BURST16_EN | OVL_EXDMA_RDMA_BURST_CON1_DDR_ACK_EN;
+ mask = OVL_EXDMA_RDMA_BURST_CON1_BURST16_EN | OVL_EXDMA_RDMA_BURST_CON1_DDR_EN |
+ OVL_EXDMA_RDMA_BURST_CON1_DDR_ACK_EN;
+ tmp = readl(priv->regs + DISP_REG_OVL_EXDMA_RDMA_BURST_CON1);
+ tmp = (tmp & ~mask) | val;
+ writel(tmp, priv->regs + DISP_REG_OVL_EXDMA_RDMA_BURST_CON1);
+
+ /*
+ * The dummy register is used in the configuration of the EXDMA engine to
+ * signal ddren_request, and get ddren_ack before accessing the DRAM to
+ * ensure data transfers occur normally.
+ */
+ val = OVL_EXDMA_EXT_DDR_EN_OPT | OVL_EXDMA_FORCE_EXT_DDR_EN;
+ writel(val, priv->regs + DISP_REG_OVL_EXDMA_DUMMY_REG);
+ val = OVL_EXDMA_MOUT_BGCLR_OUT;
+ mask = OVL_EXDMA_MOUT_BGCLR_OUT | OVL_EXDMA_MOUT_OUT_DATA;
+ tmp = readl(priv->regs + DISP_REG_OVL_EXDMA_MOUT);
+ tmp = (tmp & ~mask) | val;
+ writel(tmp, priv->regs + DISP_REG_OVL_EXDMA_MOUT);
+ writel(GENMASK(31, 0), priv->regs + DISP_REG_OVL_EXDMA_GDRDY_PRD);
+ val = OVL_EXDMA_HG_FOVL_EXDMA_CK_ON | OVL_EXDMA_HF_FOVL_EXDMA_CK_ON |
+ OVL_EXDMA_OP_8BIT_MODE;
+ writel(val, priv->regs + DISP_REG_OVL_EXDMA_EN_CON);
+ writel(OVL_EXDMA_RDMA0_L0_VCSEL, priv->regs + DISP_REG_OVL_EXDMA_L0_GUSER_EXT);
+}
+
+const u32 *mtk_exdma_get_formats(struct device *dev)
+{
+ return mt8195_ovl_formats;
+}
+
+size_t mtk_exdma_get_num_formats(struct device *dev)
+{
+ return mt8195_ovl_formats_len;
+}
+
+int mtk_exdma_clk_enable(struct mtk_ddp_comp *comp)
+{
+ struct mtk_disp_exdma *exdma = dev_get_drvdata(comp->dev);
+
+ return clk_prepare_enable(exdma->clk);
+}
+
+void mtk_exdma_clk_disable(struct mtk_ddp_comp *comp)
+{
+ struct mtk_disp_exdma *exdma = dev_get_drvdata(comp->dev);
+
+ clk_disable_unprepare(exdma->clk);
+}
+
+static int mtk_exdma_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ return 0;
+}
+
+static void mtk_exdma_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+}
+
+static const struct component_ops mtk_disp_exdma_component_ops = {
+ .bind = mtk_exdma_bind,
+ .unbind = mtk_exdma_unbind,
+};
+
+static int mtk_disp_exdma_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_disp_exdma *priv;
+ int ret = 0;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->regs))
+ return dev_err_probe(dev, PTR_ERR(priv->regs), "Cannot get reg resource\n");
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk), "Cannot get clocks\n");
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
+ if (ret)
+ dev_dbg(dev, "No mediatek,gce-client-reg\n");
+#endif
+ platform_set_drvdata(pdev, priv);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ ret = component_add(dev, &mtk_disp_exdma_component_ops);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add component\n");
+
+ return 0;
+}
+
+static void mtk_disp_exdma_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &mtk_disp_exdma_component_ops);
+}
+
+static const struct of_device_id mtk_disp_exdma_driver_dt_match[] = {
+ { .compatible = "mediatek,mt8196-disp-exdma", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, mtk_disp_exdma_driver_dt_match);
+
+struct platform_driver mtk_disp_exdma_driver = {
+ .probe = mtk_disp_exdma_probe,
+ .remove = mtk_disp_exdma_remove,
+ .driver = {
+ .name = "mediatek-disp-exdma",
+ .owner = THIS_MODULE,
+ .of_match_table = mtk_disp_exdma_driver_dt_match,
+ },
+};
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_AUTHOR("Nancy Lin <nancy.lin@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek Display Controller extended DMA Engine (exDMA) Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index a70392c54bb9..9f1264bb1d5e 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -523,6 +523,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_DITHER },
{ .compatible = "mediatek,mt8195-disp-dsc",
.data = (void *)MTK_DISP_DSC },
+ { .compatible = "mediatek,mt8196-disp-exdma",
+ .data = (void *)MTK_DISP_EXDMA },
{ .compatible = "mediatek,mt8167-disp-gamma",
.data = (void *)MTK_DISP_GAMMA, },
{ .compatible = "mediatek,mt8173-disp-gamma",
@@ -1065,6 +1067,7 @@ static struct platform_driver * const mtk_drm_drivers[] = {
&mtk_disp_ccorr_driver,
&mtk_disp_color_driver,
&mtk_disp_dsc_driver,
+ &mtk_disp_exdma_driver,
&mtk_disp_gamma_driver,
&mtk_disp_merge_driver,
&mtk_disp_ovl_adaptor_driver,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index f36888fd7244..4ef61c1e33e3 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -77,6 +77,7 @@ extern struct platform_driver mtk_disp_blender_driver;
extern struct platform_driver mtk_disp_ccorr_driver;
extern struct platform_driver mtk_disp_color_driver;
extern struct platform_driver mtk_disp_dsc_driver;
+extern struct platform_driver mtk_disp_exdma_driver;
extern struct platform_driver mtk_disp_gamma_driver;
extern struct platform_driver mtk_disp_merge_driver;
extern struct platform_driver mtk_disp_ovl_adaptor_driver;
diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h
index b32f0c92f040..d5c082d920c4 100644
--- a/include/linux/soc/mediatek/mtk-mmsys.h
+++ b/include/linux/soc/mediatek/mtk-mmsys.h
@@ -94,6 +94,7 @@ enum mtk_ddp_comp_type {
MTK_DISP_DITHER,
MTK_DISP_DSC,
MTK_DISP_ETHDR_MIXER,
+ MTK_DISP_EXDMA,
MTK_DISP_GAMMA,
MTK_DISP_MERGE,
MTK_DISP_MUTEX,
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 30/42] dt-bindings: display: mediatek: Introduce MT8196 Output Processor
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (28 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 29/42] drm/mediatek: Add support for Display Controller exDMA component AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 14:23 ` Rob Herring (Arm)
2026-07-01 12:20 ` [PATCH 31/42] drm/mediatek: Add support for Display Output Processor component AngeloGioacchino Del Regno
` (11 subsequent siblings)
41 siblings, 1 reply; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Add documentation for the Overlay Output Processor IP found in
the newer Generation SoCs like MT8196, MT8894, MT6991, and their
variants.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
.../mediatek/mediatek,mt8196-outproc.yaml | 107 ++++++++++++++++++
1 file changed, 107 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-outproc.yaml
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-outproc.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-outproc.yaml
new file mode 100644
index 000000000000..634107db269c
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-outproc.yaml
@@ -0,0 +1,107 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/mediatek/mediatek,mt8196-outproc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Display Overlay Output Processor
+
+maintainers:
+ - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+ The MediaTek Display Overlay Output Processor hardware handles the
+ post-stage of pixel processing in the layer overlaying process and
+ is also capable of performing gamma correction, ensuring that the
+ per-pixel values are within the expected luma range.
+ If an instance of this hardware is configured as last stage, it is
+ also capable of generating VBlank (Frame Done) events which can be
+ then dispatched either via an interrupt (to the CPU) or through a
+ Global Command Engine (GCE) Event, internally sent to programmable
+ Command Queue (CMDQ) Engine(s) for offloading purposes.
+
+properties:
+ compatible:
+ - const: mediatek,mt8196-disp-outproc
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ interrupts:
+ description: Optional VBlank event interrupt
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+
+ required:
+ - port@0
+ - port@1
+
+ trigger-sources:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/mediatek,mt8196-clock.h>
+ #include <dt-bindings/power/mediatek,mt8196-power.h>
+
+ outproc@32970000 {
+ compatible = "mediatek,mt8196-disp-outproc";
+ reg = <0x32970000 0x1000>;
+ clocks = <&ovlsys0 CLK_OVL_OUTPROC0>;
+ power-domains = <&hpm_hwv MT8196_POWER_DOMAIN_OVL0_DORMANT>;
+ trigger-sources = <&ovl0_mutex 20>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&blender0_8_out>;
+ };
+ };
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&ovl0_directlink_out_relay6>;
+ };
+ };
+ };
+ };
+
+...
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 30/42] dt-bindings: display: mediatek: Introduce MT8196 Output Processor
2026-07-01 12:20 ` [PATCH 30/42] dt-bindings: display: mediatek: Introduce MT8196 Output Processor AngeloGioacchino Del Regno
@ 2026-07-01 14:23 ` Rob Herring (Arm)
0 siblings, 0 replies; 52+ messages in thread
From: Rob Herring (Arm) @ 2026-07-01 14:23 UTC (permalink / raw)
To: AngeloGioacchino Del Regno
Cc: linux-kernel, matthias.bgg, jason-jh.lin, airlied,
maarten.lankhorst, conor+dt, mripard, kernel, tzimmermann,
dri-devel, devicetree, chunkuang.hu, simona, linux-arm-kernel,
p.zabel, justin.yeh, linux-mediatek, krzk+dt
On Wed, 01 Jul 2026 14:20:45 +0200, AngeloGioacchino Del Regno wrote:
> Add documentation for the Overlay Output Processor IP found in
> the newer Generation SoCs like MT8196, MT8894, MT6991, and their
> variants.
>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
> .../mediatek/mediatek,mt8196-outproc.yaml | 107 ++++++++++++++++++
> 1 file changed, 107 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-outproc.yaml
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-outproc.yaml: ignoring, error in schema: properties: compatible
Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-outproc.example.dtb: /example-0/outproc@32970000: failed to match any schema with compatible: ['mediatek,mt8196-disp-outproc']
doc reference errors (make refcheckdocs):
See https://patchwork.kernel.org/project/devicetree/patch/20260701122057.19648-31-angelogioacchino.delregno@collabora.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 31/42] drm/mediatek: Add support for Display Output Processor component
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (29 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 30/42] dt-bindings: display: mediatek: Introduce MT8196 Output Processor AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 32/42] drm/mediatek: mtk_crtc: Dynamically find suitable CRTC DMA device AngeloGioacchino Del Regno
` (10 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Add support for the Display Output Processor hardware component,
found in the MediaTek Kompanio Ultra MT8196, Genio Pro 5100 MT8894,
Dimensity 9400 MT6991 and others.
This hardware handles the post-stage of pixel processing in the
layer overlaying process and is also capable of performing gamma
correction, ensuring that the per-pixel values are within the
expected gamma range.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/Makefile | 1 +
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 14 ++
drivers/gpu/drm/mediatek/mtk_disp_drv.h | 14 ++
drivers/gpu/drm/mediatek/mtk_disp_outproc.c | 247 ++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 3 +
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 +
include/linux/soc/mediatek/mtk-mmsys.h | 1 +
7 files changed, 281 insertions(+)
create mode 100644 drivers/gpu/drm/mediatek/mtk_disp_outproc.c
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index 5506f306a7b6..bec46e981ae1 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -10,6 +10,7 @@ mediatek-drm-y := mtk_crtc.o \
mtk_disp_exdma.o \
mtk_disp_gamma.o \
mtk_disp_merge.o \
+ mtk_disp_outproc.o \
mtk_disp_ovl.o \
mtk_disp_ovl_adaptor.o \
mtk_disp_rdma.o \
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index 9896420f902d..0ecb942d6129 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -345,6 +345,18 @@ static const struct mtk_ddp_comp_funcs ddp_od = {
.start = mtk_od_start,
};
+static const struct mtk_ddp_comp_funcs ddp_outproc = {
+ .clk_enable = mtk_outproc_clk_enable,
+ .clk_disable = mtk_outproc_clk_disable,
+ .start = mtk_outproc_start,
+ .stop = mtk_outproc_stop,
+ .config = mtk_outproc_config,
+ .register_vblank_cb = mtk_outproc_register_vblank_cb,
+ .unregister_vblank_cb = mtk_outproc_unregister_vblank_cb,
+ .enable_vblank = mtk_outproc_enable_vblank,
+ .disable_vblank = mtk_outproc_disable_vblank,
+};
+
static const struct mtk_ddp_comp_funcs ddp_ovl = {
.clk_enable = mtk_ovl_clk_enable,
.clk_disable = mtk_ovl_clk_disable,
@@ -451,6 +463,7 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_MERGE] = "merge",
[MTK_DISP_MUTEX] = "mutex",
[MTK_DISP_OD] = "od",
+ [MTK_DISP_OUTPROC] = "outproc",
[MTK_DISP_OVL] = "ovl",
[MTK_DISP_OVL_2L] = "ovl-2l",
[MTK_DISP_OVL_ADAPTOR] = "ovl_adaptor",
@@ -477,6 +490,7 @@ static const struct mtk_ddp_comp_funcs *mtk_ddp_funcs[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_GAMMA] = &ddp_gamma,
[MTK_DISP_MERGE] = &ddp_merge,
[MTK_DISP_OD] = &ddp_od,
+ [MTK_DISP_OUTPROC] = &ddp_outproc,
[MTK_DISP_OVL] = &ddp_ovl,
[MTK_DISP_OVL_2L] = &ddp_ovl,
[MTK_DISP_OVL_ADAPTOR] = &ddp_ovl_adaptor,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index df4357b0954b..7b16f46ce9e2 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -121,6 +121,20 @@ void mtk_merge_stop_cmdq(struct device *dev, struct cmdq_pkt *cmdq_pkt);
enum drm_mode_status mtk_merge_mode_valid(struct device *dev,
const struct drm_display_mode *mode);
+void mtk_outproc_start(struct device *dev);
+void mtk_outproc_stop(struct device *dev);
+int mtk_outproc_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_outproc_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_outproc_config(struct mtk_ddp_comp *comp, unsigned int w,
+ unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+void mtk_outproc_register_vblank_cb(struct device *dev,
+ void (*vblank_cb)(void *),
+ void *vblank_cb_data);
+void mtk_outproc_unregister_vblank_cb(struct device *dev);
+void mtk_outproc_enable_vblank(struct device *dev);
+void mtk_outproc_disable_vblank(struct device *dev);
+
void mtk_ovl_bgclr_in_on(struct device *dev);
void mtk_ovl_bgclr_in_off(struct device *dev);
void mtk_ovl_bypass_shadow(struct device *dev);
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_outproc.c b/drivers/gpu/drm/mediatek/mtk_disp_outproc.c
new file mode 100644
index 000000000000..b8eeefd69964
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_disp_outproc.c
@@ -0,0 +1,247 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2025 MediaTek Inc.
+ * Nancy Lin <nancy.lin@mediatek.com>
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <drm/drm_fourcc.h>
+#include <drm/drm_framebuffer.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/soc/mediatek/mtk-cmdq.h>
+#include <linux/soc/mediatek/mtk-mmsys.h>
+
+#include "mtk_crtc.h"
+#include "mtk_ddp_comp.h"
+#include "mtk_disp_drv.h"
+#include "mtk_drm_drv.h"
+
+#define DISP_REG_OVL_OUTPROC_INTEN 0x004
+#define DISP_REG_OVL_OUTPROC_INTSTA 0x008
+# define OVL_OUTPROC_FME_CPL_INTEN BIT(1)
+
+#define DISP_REG_OVL_OUTPROC_DATAPATH_CON 0x010
+# define OVL_OUTPROC_DATAPATH_CON_OUTPUT_CLAMP BIT(26)
+
+#define DISP_REG_OVL_OUTPROC_EN 0x020
+# define OVL_OUTPROC_OVL_EN BIT(0)
+
+#define DISP_REG_OVL_OUTPROC_RST 0x024
+# define OVL_OUTPROC_RST BIT(0)
+
+#define DISP_REG_OVL_OUTPROC_SHADOW_CTRL 0x028
+# define OVL_OUTPROC_BYPASS_SHADOW BIT(2)
+
+#define DISP_REG_OVL_OUTPROC_ROI_SIZE 0x030
+
+struct mtk_disp_outproc {
+ void __iomem *regs;
+ struct clk *clk;
+ void (*vblank_cb)(void *data);
+ void *vblank_cb_data;
+ int irq;
+ struct cmdq_client_reg cmdq_reg;
+};
+
+void mtk_outproc_register_vblank_cb(struct device *dev, void (*vblank_cb)(void *),
+ void *vblank_cb_data)
+{
+ struct mtk_disp_outproc *priv = dev_get_drvdata(dev);
+
+ priv->vblank_cb = vblank_cb;
+ priv->vblank_cb_data = vblank_cb_data;
+}
+
+void mtk_outproc_unregister_vblank_cb(struct device *dev)
+{
+ struct mtk_disp_outproc *priv = dev_get_drvdata(dev);
+
+ priv->vblank_cb = NULL;
+ priv->vblank_cb_data = NULL;
+}
+
+void mtk_outproc_enable_vblank(struct device *dev)
+{
+ struct mtk_disp_outproc *priv = dev_get_drvdata(dev);
+
+ writel(0x0, priv->regs + DISP_REG_OVL_OUTPROC_INTSTA);
+ writel(OVL_OUTPROC_FME_CPL_INTEN, priv->regs + DISP_REG_OVL_OUTPROC_INTEN);
+}
+
+void mtk_outproc_disable_vblank(struct device *dev)
+{
+ struct mtk_disp_outproc *priv = dev_get_drvdata(dev);
+
+ writel(0x0, priv->regs + DISP_REG_OVL_OUTPROC_INTEN);
+}
+
+static irqreturn_t mtk_outproc_irq_handler(int irq, void *dev_id)
+{
+ struct mtk_disp_outproc *priv = dev_id;
+ u32 val;
+
+ val = readl(priv->regs + DISP_REG_OVL_OUTPROC_INTSTA);
+ if (val == 0)
+ return IRQ_NONE;
+
+ writel(0, priv->regs + DISP_REG_OVL_OUTPROC_INTSTA);
+
+ if (priv->vblank_cb)
+ priv->vblank_cb(priv->vblank_cb_data);
+
+ return IRQ_HANDLED;
+}
+
+void mtk_outproc_config(struct mtk_ddp_comp *comp, unsigned int w,
+ unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_disp_outproc *priv = dev_get_drvdata(comp->dev);
+
+ writel(((h & GENMASK(15, 0)) << 16) | (w & GENMASK(15, 0)),
+ priv->regs + DISP_REG_OVL_OUTPROC_ROI_SIZE);
+
+ writel(OVL_OUTPROC_DATAPATH_CON_OUTPUT_CLAMP,
+ priv->regs + DISP_REG_OVL_OUTPROC_DATAPATH_CON);
+}
+
+void mtk_outproc_start(struct device *dev)
+{
+ struct mtk_disp_outproc *priv = dev_get_drvdata(dev);
+ u32 val;
+
+ writel(OVL_OUTPROC_RST, priv->regs + DISP_REG_OVL_OUTPROC_RST);
+ writel(0, priv->regs + DISP_REG_OVL_OUTPROC_RST);
+
+ val = readl(priv->regs + DISP_REG_OVL_OUTPROC_SHADOW_CTRL);
+ val |= OVL_OUTPROC_BYPASS_SHADOW;
+ writel(val, priv->regs + DISP_REG_OVL_OUTPROC_SHADOW_CTRL);
+
+ writel(OVL_OUTPROC_OVL_EN, priv->regs + DISP_REG_OVL_OUTPROC_EN);
+}
+
+void mtk_outproc_stop(struct device *dev)
+{
+ struct mtk_disp_outproc *priv = dev_get_drvdata(dev);
+
+ /* Don't reset at stop time to avoid vblank timeouts */
+ writel(0, priv->regs + DISP_REG_OVL_OUTPROC_EN);
+}
+
+int mtk_outproc_clk_enable(struct mtk_ddp_comp *comp)
+{
+ struct mtk_disp_outproc *priv = dev_get_drvdata(comp->dev);
+
+ return clk_prepare_enable(priv->clk);
+}
+
+void mtk_outproc_clk_disable(struct mtk_ddp_comp *comp)
+{
+ struct mtk_disp_outproc *priv = dev_get_drvdata(comp->dev);
+
+ clk_disable_unprepare(priv->clk);
+}
+
+static int mtk_outproc_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct mtk_disp_outproc *priv = dev_get_drvdata(dev);
+
+ if (priv->irq)
+ enable_irq(priv->irq);
+
+ return 0;
+}
+
+static void mtk_outproc_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct mtk_disp_outproc *priv = dev_get_drvdata(dev);
+
+ if (priv->irq)
+ disable_irq(priv->irq);
+}
+
+static const struct component_ops mtk_disp_outproc_component_ops = {
+ .bind = mtk_outproc_bind,
+ .unbind = mtk_outproc_unbind,
+};
+
+static int mtk_disp_outproc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_disp_outproc *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(priv->regs))
+ return dev_err_probe(dev, PTR_ERR(priv->regs), "Cannot get reg resource\n");
+
+ priv->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(priv->clk))
+ return dev_err_probe(dev, PTR_ERR(priv->clk), "Cannot get clocks\n");
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ ret = cmdq_dev_get_client_reg(dev, &priv->cmdq_reg, 0);
+ if (ret)
+ dev_dbg(dev, "No mediatek,gce-client-reg\n");
+#endif
+
+ priv->irq = platform_get_irq_optional(pdev, 0);
+ if (priv->irq > 0) {
+ ret = devm_request_irq(dev, priv->irq, mtk_outproc_irq_handler,
+ IRQF_NO_AUTOEN, dev_name(dev), priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to request irq\n");
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ ret = component_add(dev, &mtk_disp_outproc_component_ops);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add component\n");
+
+ return ret;
+}
+
+static void mtk_disp_outproc_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &mtk_disp_outproc_component_ops);
+}
+
+static const struct of_device_id mtk_disp_outproc_driver_dt_match[] = {
+ { .compatible = "mediatek,mt8196-disp-outproc" },
+ { /* sentinel */},
+};
+
+MODULE_DEVICE_TABLE(of, mtk_disp_outproc_driver_dt_match);
+
+struct platform_driver mtk_disp_outproc_driver = {
+ .probe = mtk_disp_outproc_probe,
+ .remove = mtk_disp_outproc_remove,
+ .driver = {
+ .name = "mediatek-disp-outproc",
+ .owner = THIS_MODULE,
+ .of_match_table = mtk_disp_outproc_driver_dt_match,
+ },
+};
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_AUTHOR("Nancy Lin <nancy.lin@mediatek.com>");
+MODULE_DESCRIPTION("MediaTek Display Controller Output Processing Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 9f1264bb1d5e..3ed0e3f45fe2 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -557,6 +557,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_MUTEX },
{ .compatible = "mediatek,mt8173-disp-od",
.data = (void *)MTK_DISP_OD },
+ { .compatible = "mediatek,mt8196-disp-outproc",
+ .data = (void *)MTK_DISP_OUTPROC },
{ .compatible = "mediatek,mt2701-disp-ovl",
.data = (void *)MTK_DISP_OVL },
{ .compatible = "mediatek,mt8167-disp-ovl",
@@ -1070,6 +1072,7 @@ static struct platform_driver * const mtk_drm_drivers[] = {
&mtk_disp_exdma_driver,
&mtk_disp_gamma_driver,
&mtk_disp_merge_driver,
+ &mtk_disp_outproc_driver,
&mtk_disp_ovl_adaptor_driver,
&mtk_disp_ovl_driver,
&mtk_disp_rdma_driver,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index 4ef61c1e33e3..3f84384f8569 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -80,6 +80,7 @@ extern struct platform_driver mtk_disp_dsc_driver;
extern struct platform_driver mtk_disp_exdma_driver;
extern struct platform_driver mtk_disp_gamma_driver;
extern struct platform_driver mtk_disp_merge_driver;
+extern struct platform_driver mtk_disp_outproc_driver;
extern struct platform_driver mtk_disp_ovl_adaptor_driver;
extern struct platform_driver mtk_disp_ovl_driver;
extern struct platform_driver mtk_disp_rdma_driver;
diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h
index d5c082d920c4..a1c8a436b3dc 100644
--- a/include/linux/soc/mediatek/mtk-mmsys.h
+++ b/include/linux/soc/mediatek/mtk-mmsys.h
@@ -99,6 +99,7 @@ enum mtk_ddp_comp_type {
MTK_DISP_MERGE,
MTK_DISP_MUTEX,
MTK_DISP_OD,
+ MTK_DISP_OUTPROC,
MTK_DISP_OVL,
MTK_DISP_OVL_2L,
MTK_DISP_OVL_ADAPTOR,
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 32/42] drm/mediatek: mtk_crtc: Dynamically find suitable CRTC DMA device
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (30 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 31/42] drm/mediatek: Add support for Display Output Processor component AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 33/42] drm/mediatek: Prepare path builder for multi-controller architecture AngeloGioacchino Del Regno
` (9 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Now that the vblank and config components are being dynamically
selected, the only hardcoded strategy that is left is selecting
a DMA device for a CRTC that is being created.
In order to support pipelines including an embedded multimedia
controller (like MDP3) chained with the display controller and
pipelines chaining multiple display controllers together, stop
assuming that the first component in the pipeline is suited to
do DMA operations and implement support to dynamically find not
only a suitable DMA device, but also the best one.
This finds the first device that provides DMA and the first one
that is also behind an IOMMU.
The criteria for selecting the best device is to prefer a DMA
device behind an IOMMU; if not found, the first DMA capable
one is selected instead.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_crtc.c | 68 ++++++++++++++++++++++++-----
1 file changed, 56 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index ee23a50cf4d1..3f70d11270e9 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -1131,6 +1131,60 @@ struct device *mtk_crtc_dma_dev_get(struct drm_crtc *crtc)
return mtk_crtc->dma_dev;
}
+static int mtk_crtc_find_suitable_dma_dev(struct mtk_drm_private *priv,
+ struct mtk_crtc *mtk_crtc,
+ const struct mtk_drm_path_definition *path)
+{
+ struct mtk_ddp_comp *dma_comp = NULL, *dma_comp_mmu = NULL;
+ int i;
+
+ for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
+ const struct mtk_drm_comp_definition *cdef = path[i].comp;
+ struct mtk_ddp_comp *comp;
+
+ comp = mtk_ddp_comp_find_by_id(&priv->hlist,
+ cdef->type, cdef->inst_id);
+ if (!comp)
+ continue;
+
+ /*
+ * Check if this is a legacy OVL_ADAPTOR component and, if so, this
+ * has to forcefully be the DMA device for this CRTC: assign it to
+ * dma_comp_mmu to force that.
+ */
+ if (comp->type == MTK_DISP_OVL_ADAPTOR) {
+ dma_comp_mmu = comp;
+ break;
+ }
+
+ if (!comp->dev || !comp->dev->of_node)
+ continue;
+
+ /* Find the first device provides DMA... */
+ if (!dma_comp) {
+ if (of_property_present(comp->dev->of_node, "#dma-cells"))
+ dma_comp = comp;
+ }
+
+ /* ...and check if that device is also behind an IOMMU */
+ if (!of_property_present(comp->dev->of_node, "iommus"))
+ continue;
+
+ /* If a device behind IOMMU is found, this is the best outcome */
+ dma_comp_mmu = comp;
+ break;
+ }
+
+ if (dma_comp_mmu)
+ mtk_crtc->dma_dev = mtk_ddp_comp_dma_dev_get(dma_comp_mmu);
+ else if (dma_comp)
+ mtk_crtc->dma_dev = mtk_ddp_comp_dma_dev_get(dma_comp);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
int mtk_crtc_create(struct drm_device *drm_dev,
enum mtk_crtc_path path_sel, int priv_data_index,
const struct mtk_drm_route *conn_routes,
@@ -1139,7 +1193,6 @@ int mtk_crtc_create(struct drm_device *drm_dev,
struct mtk_drm_private *priv = drm_dev->dev_private;
const struct mtk_drm_path_definition *output_path;
struct device *dev = drm_dev->dev;
- struct mtk_ddp_comp *dma_comp;
struct mtk_crtc *mtk_crtc;
unsigned int num_comp_planes = 0;
unsigned int max_comp_stages = 0;
@@ -1309,20 +1362,11 @@ int mtk_crtc_create(struct drm_device *drm_dev,
dev_dbg(dev, "Found %u layers composed by maximum of %u stage(s) each.\n",
mtk_crtc->hwlayer_nr, max_comp_stages);
- /*
- * Default to use the first component as the dma dev.
- * In the case of ovl_adaptor sub driver, it needs to use the
- * dma_dev_get function to get representative dma dev.
- */
- dma_comp = mtk_ddp_comp_find_by_id(&priv->hlist,
- output_path->comp[0].type,
- output_path->comp[0].inst_id);
- if (dma_comp == NULL) {
+ ret = mtk_crtc_find_suitable_dma_dev(priv, mtk_crtc, output_path);
+ if (ret) {
dev_err(dev, "Could not find appropriate DMA device!\n");
return -EINVAL;
}
-
- mtk_crtc->dma_dev = mtk_ddp_comp_dma_dev_get(dma_comp);
dev_dbg(dev, "Using DMA device %pOF\n", mtk_crtc->dma_dev->of_node);
ret = mtk_crtc_init(drm_dev, mtk_crtc, crtc_i);
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 33/42] drm/mediatek: Prepare path builder for multi-controller architecture
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (31 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 32/42] drm/mediatek: mtk_crtc: Dynamically find suitable CRTC DMA device AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 34/42] drm/mediatek: Enable bring-up of multi-controller CRTC paths AngeloGioacchino Del Regno
` (8 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In preparation for adding support for the new display controllers
featuring multi-controller w/DirectLink architecture, expand the
path builder to recognize whether a hardware component in display
controller related output path is getting its input from internal
or from any external (to itself, but still internal to the SoC)
display controller component.
When an output path is found, it is also necessary to understand
the enablement order (in terms of mmsys/mutex other than PM) of
the controllers, as that cannot be done randomly: for this, the
initial path builder will start storing an indication to whether
a component is either in a leader or in a follower controller,
and then a new function mtk_drm_set_path_orders(), called when
binding all components, when initializing KMS, takes care of the
looping through the path and setting up the order between all
of the follower display controllers.
As of this point, no multi-controller SoCs are introduced yet,
so this code will not bring any functional change on any of the
currently supported SoCs / display controllers.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 2 +
drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 2 +
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 351 ++++++++++++++++++++--
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 2 +
drivers/gpu/drm/mediatek/mtk_drm_legacy.c | 3 +-
5 files changed, 332 insertions(+), 28 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index 0ecb942d6129..3f25f1c34633 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -680,6 +680,7 @@ static int mtk_ddp_comp_init_internal_comp(struct device *dev, struct device *co
int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
struct mtk_drm_comp_list *hlist,
+ u8 comp_controller_id,
enum mtk_ddp_comp_type comp_type, int comp_inst_id)
{
struct platform_device *comp_pdev;
@@ -695,6 +696,7 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
comp->type = comp_type;
comp->inst_id = comp_inst_id;
+ comp->controller_id = comp_controller_id;
comp->funcs = mtk_ddp_funcs[comp_type];
/* Not all drm components have a DTS device node, such as ovl_adaptor,
* which is the drm bring up sub driver
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index 1297db252821..e94bcf6922c1 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -87,6 +87,7 @@ struct mtk_ddp_comp {
enum mtk_ddp_comp_type type;
u8 inst_id;
u8 mtx_trig_id;
+ u8 controller_id;
int encoder_index;
const struct mtk_ddp_comp_funcs *funcs;
@@ -375,6 +376,7 @@ int mtk_ddp_comp_get_id(struct device_node *node,
int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev);
int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
struct mtk_drm_comp_list *hlist,
+ u8 comp_controller_id,
enum mtk_ddp_comp_type comp_type, int comp_inst_id);
int mtk_ddp_comp_get_mutex_trigger(struct device_node *node, unsigned int index);
enum mtk_ddp_comp_type mtk_ddp_comp_get_type(unsigned int comp_id);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 3ed0e3f45fe2..3bee730cd34f 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -185,7 +185,7 @@ static int mtk_drm_match(struct device *dev, const void *data)
static bool mtk_drm_get_all_drm_priv(struct device *dev)
{
struct mtk_drm_private *drm_priv = dev_get_drvdata(dev);
- struct mtk_drm_private *all_drm_priv[MAX_CRTC];
+ struct mtk_drm_private *all_drm_priv[drm_priv->data->mmsys_dev_num];
struct mtk_drm_private *temp_drm_priv;
struct device_node *phandle = dev->parent->of_node;
const struct of_device_id *of_id;
@@ -194,8 +194,10 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
unsigned int cnt = 0;
int i, j;
+ dev_vdbg(dev, "Populating private data for all controllers on ID%u\n",
+ drm_priv->data->mmsys_id);
+
for_each_child_of_node(phandle->parent, node) {
- const struct mtk_drm_path_definition *output_path;
struct platform_device *pdev;
of_id = of_match_node(mtk_drm_of_ids, node);
@@ -216,19 +218,12 @@ static bool mtk_drm_get_all_drm_priv(struct device *dev)
if (!temp_drm_priv)
continue;
- for (i = 0; i < MAX_CRTC; i++) {
- output_path = &temp_drm_priv->data->output_paths[i];
-
- if (!output_path->len)
- continue;
-
- all_drm_priv[i] = temp_drm_priv;
- }
+ all_drm_priv[temp_drm_priv->data->mmsys_id] = temp_drm_priv;
if (temp_drm_priv->mtk_drm_bound)
cnt++;
- if (cnt == MAX_CRTC) {
+ if (cnt == drm_priv->data->mmsys_dev_num) {
of_node_put(node);
break;
}
@@ -272,6 +267,98 @@ static bool mtk_drm_find_mmsys_comp(struct mtk_drm_private *private,
return false;
}
+static struct mtk_drm_private *
+mtk_drm_find_matching_controller(struct mtk_drm_private **all_drm_private,
+ struct device_node *target_node)
+{
+ for (int i = 0; i < all_drm_private[0]->data->mmsys_dev_num; i++) {
+ struct mtk_drm_private *priv = all_drm_private[i];
+ struct device_node *cur_mmsys_node = priv->mmsys_dev->of_node;
+
+ if (target_node == cur_mmsys_node)
+ return priv;
+ }
+
+ return NULL;
+}
+
+static void mtk_drm_set_path_orders(struct mtk_drm_private **all_drm_private)
+{
+ struct mtk_drm_private *private = all_drm_private[0];
+ unsigned short i, j;
+
+ /*
+ * If the SoC has multiple display controllers w/DirectLink architecture
+ * at this point all controllers have been registered and it is now safe
+ * to iterate through and setup the outputs order so that the data path
+ * follows the correct controllers sequence.
+ *
+ * At the end of this, the controllers are always ordered 0..N hence the
+ * data, for each different display controller output (as each support
+ * multiple different outputs as well) always travels through consecutive
+ * controller indices, like CTRLRx_OUTPUTy -> ... -> CTRLRx+n_OUTPUTy,
+ * where:
+ *
+ * - The first one (0) is responsible for getting input frames from DRM
+ * and dispatching to image processing HW(s) and/or next controller;
+ * - The last one (N) is responsible for output to a physical display
+ *
+ * Note that one controller may also output to a different out-number of
+ * its consecutive, so a display controller-I/O sequence like
+ *
+ * CTRLR0_OUTPUT0 -> CTRLR1_OUTPUT3 -> CTRLR3_OUTPUT2 (-> DISPLAY)
+ * 0 -> 1 -> 2
+ *
+ * should also considered as being valid since the hardware is capable of
+ * doing so, but this is a corner case that is currently not handled to
+ * simplify the implementation.
+ */
+ for (i = 0; i < MAX_CRTC; i++) {
+ unsigned short max_iterations = private->data->mmsys_dev_num;
+ bool order_found;
+
+ do {
+ order_found = false;
+
+ for (j = 0; j < private->data->mmsys_dev_num; j++) {
+ const struct mtk_drm_path_definition *src_path;
+ struct mtk_drm_private *cur_priv, *src_priv;
+ struct mtk_drm_path_definition *cur_path;
+ unsigned int src_order;
+
+ cur_priv = all_drm_private[j];
+ if (!cur_priv)
+ continue;
+
+ cur_path = &cur_priv->data->output_paths[i];
+
+ if (!cur_path->len || !cur_path->input_controller)
+ continue;
+
+ src_priv = mtk_drm_find_matching_controller(all_drm_private,
+ cur_path->input_controller);
+ if (!src_priv)
+ continue;
+
+ /*
+ * Paths are per-output: set order for the new output
+ * by finding the order of the same output number of
+ * the previous controller and incrementing it by one
+ */
+ src_path = &src_priv->data->output_paths[i];
+ src_order = src_path->len ? src_path->order : 0;
+ if (cur_path->order <= src_order) {
+ cur_path->order = src_order + 1;
+
+ /* Order found: check next CRTC now! */
+ order_found = true;
+ break;
+ }
+ }
+ } while (!order_found && max_iterations--);
+ }
+}
+
static int mtk_drm_kms_init(struct drm_device *drm)
{
struct mtk_drm_private *private = drm->dev_private;
@@ -316,6 +403,9 @@ static int mtk_drm_kms_init(struct drm_device *drm)
*/
drm_helper_move_panel_connectors_to_head(drm);
+ /* Set controllers order for multi-controller architecture */
+ mtk_drm_set_path_orders(private->all_drm_private);
+
/*
* 1. We currently support two fixed data streams, each optional,
* and each statically assigned to a crtc:
@@ -653,18 +743,108 @@ static int mtk_drm_of_get_ddp_comp_type(struct device_node *node, enum mtk_ddp_c
return 0;
}
+/**
+ * mtk_drm_of_get_ep_external_controller() - Get parent controller if external
+ * @dev: Device pointer to leading display controller
+ * @ep_dev_node: OF Node pointer to a display controller sub-component hardware
+ * The caller is responsible for dropping the refcount.
+ *
+ * Return: External Display Controller (mmsys) device_node or NULL if the given
+ * sub-component resides in the same Display Controller as *dev.
+ */
+static struct device_node
+*mtk_drm_of_get_ep_external_controller(struct device *dev,
+ struct device_node *ep_dev_node)
+{
+ struct device_node *leader_controller_node = dev->parent->of_node;
+ struct device_node *ep_parent_node;
+
+ ep_parent_node = of_get_parent(ep_dev_node);
+ if (ep_parent_node == leader_controller_node) {
+ of_node_put(ep_parent_node);
+ return NULL;
+ }
+
+ return ep_parent_node;
+}
+
+static int mtk_drm_of_get_first_input(struct device *dev, struct device_node *node,
+ enum mtk_crtc_path crtc_endpoint,
+ struct mtk_drm_comp_definition *comp_def)
+{
+ struct device_node *ep_dev_node, *ep_in;
+ enum mtk_ddp_comp_type comp_type;
+ int inst_id, ret;
+
+ ep_in = of_graph_get_endpoint_by_regs(node, 0, crtc_endpoint);
+ if (!ep_in)
+ return -ENOENT;
+
+ ep_dev_node = of_graph_get_port_parent(ep_in);
+ of_node_put(ep_in);
+ if (!ep_dev_node)
+ return -EINVAL;
+
+ /*
+ * If the first input has no HW component specific driver go out with
+ * -ENOENT: depending on the SoC (for arch gen2), this may be expected.
+ */
+ ret = mtk_drm_of_get_ddp_comp_type(ep_dev_node, &comp_type);
+ of_node_put(ep_dev_node);
+ if (ret)
+ return -ENOENT;
+
+ inst_id = mtk_ddp_comp_get_id(ep_dev_node, comp_type);
+ if (inst_id < 0)
+ return inst_id;
+
+ /* All ok! Pass the Component ID to the caller. */
+ comp_def->type = comp_type;
+ comp_def->inst_id = inst_id;
+
+ dev_dbg(dev, "Found first input component %pOF with ID=%u SubID=%u\n",
+ ep_dev_node, comp_def->type, comp_def->inst_id);
+
+ return 0;
+}
+
+/**
+ * mtk_drm_of_get_ddp_ep_cid - Parse HW component connection information
+ * @dev: The mediatek-drm device
+ * @node: The device node of the display controller component to parse
+ * @output_port: The number of the port, corresponding to an output, to parse
+ * @crtc_endpoint:The number of the current endpoint corresponding to CRTC
+ * @next: Pointer to a struct device_node, used to pass the next node,
+ * corresponding to the next component's input, to the caller
+ * @comp_def: Pointer to the last, uninitialized, entry of the temporary
+ * structure array holding the Display Controller Path that is
+ * being built.
+ * @controller_arch_v2: Check if DirectLink architecture or legacy VDO/MMSYS
+ *
+ * Return:
+ * * %0 - Component connection parsed fully: the currently parsed Display
+ * Controller hardware component is interconnected with a next one
+ * * %-ENOENT - The component's remote endpoint was not found
+ * * %-EINVAL - Component information is not valid, hence not usable
+ * * %-ENODEV - The identified component is a valid connection, but its DT node
+ * is disabled, hence not usable
+ * * %-EREMOTE - The component is interconnected with a next one residing in a
+ * different Display Controller, remote to the current one, hence
+ * cannot be added to the path of the current controller
+ */
static int mtk_drm_of_get_ddp_ep_cid(struct device *dev, struct device_node *node,
- int output_port, enum mtk_crtc_path crtc_path,
+ int output_port, enum mtk_crtc_path crtc_endpoint,
struct device_node **next,
- struct mtk_drm_comp_definition *comp_def)
+ struct mtk_drm_comp_definition *comp_def,
+ bool controller_arch_v2)
{
struct device_node *ep_dev_node, *ep_out;
enum mtk_ddp_comp_type comp_type;
int ret;
- ep_out = of_graph_get_endpoint_by_regs(node, output_port, crtc_path);
+ ep_out = of_graph_get_endpoint_by_regs(node, output_port, crtc_endpoint);
if (!ep_out)
- return -ENOENT;
+ return -EINVAL;
ep_dev_node = of_graph_get_remote_port_parent(ep_out);
of_node_put(ep_out);
@@ -678,6 +858,21 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device *dev, struct device_node *nod
*/
*next = ep_dev_node;
+ if (controller_arch_v2) {
+ struct device_node *rmt_ctrlr_node;
+
+ rmt_ctrlr_node = mtk_drm_of_get_ep_external_controller(dev, ep_dev_node);
+ if (rmt_ctrlr_node) {
+ /* The device is from a different mmsys (remote from this one) */
+ dev_dbg(dev, "Found connection to external mmsys %pOF\n",
+ rmt_ctrlr_node);
+
+ of_node_put(ep_dev_node);
+ of_node_put(rmt_ctrlr_node);
+ return -EREMOTE;
+ }
+ }
+
if (!of_device_is_available(ep_dev_node))
return -ENODEV;
@@ -708,9 +903,13 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device *dev, struct device_node *nod
/**
* mtk_drm_of_ddp_path_build_one - Build a Display HW Pipeline for a CRTC Path
- * @dev: The mediatek-drm device
- * @cpath: CRTC Path relative to a VDO or MMSYS
+ * @dev: The mediatek-drm device, corresponding to leading controller
+ * instance of the current display HW pipeline
+ * @node: The device node containing the first port/endpoint
+ * @cpath: CRTC Path relative to a VDO or MMSYS, also used as
+ * number of the initial endpoint for this CRTC path
* @out_path: Pointer to the structure that will contain the new pipeline
+ * @controller_arch_v2: Check if DirectLink architecture or legacy VDO/MMSYS
*
* MediaTek SoCs can use different DDP hardware pipelines (or paths) depending
* on the board-specific desired display configuration; this function walks
@@ -723,18 +922,62 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device *dev, struct device_node *nod
* * %-EINVAL - Display pipeline built but validation failed
* * %-ENOMEM - Failure to allocate pipeline array to pass to the caller
*/
-static int mtk_drm_of_ddp_path_build_one(struct device *dev, enum mtk_crtc_path cpath,
- struct mtk_drm_path_definition *out_path)
+static int mtk_drm_of_ddp_path_build_one(struct device *dev, struct device_node *node,
+ enum mtk_crtc_path cpath,
+ struct mtk_drm_path_definition *out_path,
+ bool controller_arch_v2)
{
struct mtk_drm_comp_definition temp_path[MTK_DISP_CONTROLLER_MAX_COMP_PER_PATH];
- struct device_node *next = NULL, *prev, *vdo = dev->parent->of_node;
+ struct device_node *next = NULL, *prev;
bool ovl_adaptor_comp_added = false;
unsigned short int idx = 0;
size_t final_comp_sz;
+ u8 temp_order;
int ret;
- /* Get the first entry for the temp_path array */
- ret = mtk_drm_of_get_ddp_ep_cid(dev, vdo, 0, cpath, &next, &temp_path[idx]);
+ dev_vdbg(dev, "Building DDP Path for CRTC%d\n", cpath);
+
+ if (controller_arch_v2) {
+ /* Check if the starting input is already a usable component */
+ ret = mtk_drm_of_get_first_input(dev, node, cpath, &temp_path[idx]);
+ if (ret == 0) {
+ idx++;
+ } else if (ret != -ENOENT) {
+ dev_err(dev, "Cannot parse first input HW component: %d\n", ret);
+ return ret;
+ }
+ }
+
+ /*
+ * Get the first remote for the temp_path array: for leader controllers
+ * this will be an output, while for follower controllers this will be
+ * an input from a DirectLink connection coming from either a leader or
+ * a follower display controller.
+ *
+ * In case this is an input from any remote (leader/follower) controller
+ * this will return EREMOTE and a different port (expressing a relay of
+ * a crossbar) will be used to continue building the path.
+ */
+ ret = mtk_drm_of_get_ddp_ep_cid(dev, node, 0, cpath, &next,
+ &temp_path[idx], controller_arch_v2);
+ if (ret == -EREMOTE) {
+ out_path->input_controller = mtk_drm_of_get_ep_external_controller(dev, next);
+
+ /*
+ * Any follower controller gets the order set to 1 to avoid
+ * iterating once again later when the actual full ordering
+ * is calculated.
+ */
+ temp_order = 1;
+ dev_dbg(dev, "Got external mmsys %pOF\n", out_path->input_controller);
+
+ ret = mtk_drm_of_get_ddp_ep_cid(dev, node, 2, cpath, &next,
+ &temp_path[idx], controller_arch_v2);
+ } else {
+ /* A leader controller gets, of course, its order set to 0 */
+ temp_order = 0;
+ }
+
if (ret) {
if (next && temp_path[idx].type == MTK_DISP_OVL_ADAPTOR) {
dev_dbg(dev, "Adding OVL Adaptor for %pOF\n", next);
@@ -743,7 +986,9 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, enum mtk_crtc_path
if (next)
dev_err(dev, "Invalid component %pOF\n", next);
else
- dev_err(dev, "Cannot find first endpoint for path %d\n", cpath);
+ dev_err(dev,
+ "Cannot find first endpoint for path %d on %pOF\n",
+ cpath, node);
return ret;
}
@@ -756,7 +1001,11 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, enum mtk_crtc_path
*/
do {
prev = next;
- ret = mtk_drm_of_get_ddp_ep_cid(dev, next, 1, cpath, &next, &temp_path[idx]);
+ ret = mtk_drm_of_get_ddp_ep_cid(dev, next, 1, cpath, &next,
+ &temp_path[idx], controller_arch_v2);
+ if (ret == -EREMOTE)
+ ret = mtk_drm_of_get_ddp_ep_cid(dev, prev, 3, cpath, &next,
+ &temp_path[idx], controller_arch_v2);
of_node_put(prev);
if (ret) {
dev_vdbg(dev, "Invalid comp reached with result %d\n", ret);
@@ -806,11 +1055,27 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, enum mtk_crtc_path
if (!out_path->comp)
return -ENOMEM;
+ /*
+ * Anything that is not the primary controller gets order set to 1:
+ * this is done to avoid iterating once again later when the actual
+ * full controllers ordering is calculated.
+ */
+ out_path->order = temp_order;
+
dev_dbg(dev, "Display HW Pipeline built with %d components.\n", idx);
return 0;
}
+static bool mtk_drm_of_ddp_is_arch_v2(struct device_node *cur_mmsys_node)
+{
+ for_each_child_of_node_scoped(cur_mmsys_node, mmsys_child)
+ if (of_property_present(mmsys_child, "compatible"))
+ return true;
+
+ return false;
+}
+
static int mtk_drm_of_ddp_path_build(struct device *dev, struct device_node *node,
struct mtk_mmsys_driver_data *data)
{
@@ -819,8 +1084,15 @@ static int mtk_drm_of_ddp_path_build(struct device *dev, struct device_node *nod
struct of_endpoint of_ep;
bool output_present[MAX_CRTC] = { false };
u8 num_outputs_present = 0;
+ u8 num_outputs_skipped = 0;
+ bool controller_arch_v2;
int i, ret;
+ controller_arch_v2 = mtk_drm_of_ddp_is_arch_v2(dev->parent->of_node);
+
+ dev_dbg(dev, "Building Display Controller v%d Path starting from %pOF\n",
+ controller_arch_v2 ? 2 : 1, node);
+
for_each_endpoint_of_node(node, ep_node) {
ret = of_graph_parse_endpoint(ep_node, &of_ep);
if (ret) {
@@ -854,10 +1126,34 @@ static int mtk_drm_of_ddp_path_build(struct device *dev, struct device_node *nod
if (!output_present[i])
continue;
- ret = mtk_drm_of_ddp_path_build_one(dev, i, &output_paths[i]);
- if (ret && ret != -ENODEV)
- return ret;
+ ret = mtk_drm_of_ddp_path_build_one(dev, node, i, &output_paths[i],
+ controller_arch_v2);
+ /*
+ * For -ENODEV, this could mean that the device is not yet registered,
+ * but that may be just because of a probe deferral, so it is possible
+ * to continue building the path as such failures are properly handled
+ * later when enabling outputs.
+ * For -ENOENT, it means that the devicetree declares a partial output
+ * which is - of course - not okay, but failing entirely is a bit too
+ * much: do a print to advertise invalid outputs, but fail probing
+ * only if there is no valid output at all.
+ */
+ if (ret && ret != -ENODEV) {
+ if (ret == -ENOENT) {
+ dev_dbg(dev, "Skipping invalid output for CRTC%u\n", i);
+ num_outputs_skipped++;
+ } else {
+ dev_err(dev, "Pipeline build failure on CRTC%u\n", i);
+ return ret;
+ }
+ }
+ }
+
+ if (num_outputs_skipped == num_outputs_present) {
+ dev_err(dev, "No valid display output found!\n");
+ return -ENOENT;
}
+
data->output_paths = output_paths;
return 0;
@@ -968,6 +1264,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
}
ret = mtk_ddp_comp_init(dev, node, &private->hlist,
+ private->data->mmsys_id,
comp_type, comp_inst_id);
if (ret) {
of_node_put(node);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index 3f84384f8569..3c403bc8f4fe 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -39,7 +39,9 @@ struct mtk_drm_comp_definition {
struct mtk_drm_path_definition {
const struct mtk_drm_comp_definition *comp;
+ struct device_node *input_controller;
u8 len;
+ u8 order;
};
struct mtk_mmsys_driver_data {
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_legacy.c b/drivers/gpu/drm/mediatek/mtk_drm_legacy.c
index 801e0ab43ff5..85bc432568f0 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_legacy.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_legacy.c
@@ -873,6 +873,7 @@ void mtk_drm_legacy_ovl_adaptor_probe(struct device *dev, struct mtk_drm_private
PLATFORM_DEVID_AUTO,
(void *)priv, sizeof(*priv));
- mtk_ddp_comp_init(&ovl_adaptor->dev, NULL, &priv->hlist, MTK_DISP_OVL_ADAPTOR, 0);
+ mtk_ddp_comp_init(&ovl_adaptor->dev, NULL, &priv->hlist, priv->data->mmsys_id,
+ MTK_DISP_OVL_ADAPTOR, 0);
component_match_add(dev, match, component_compare_dev, &ovl_adaptor->dev);
}
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 34/42] drm/mediatek: Enable bring-up of multi-controller CRTC paths
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (32 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 33/42] drm/mediatek: Prepare path builder for multi-controller architecture AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 35/42] drm/mediatek: Introduce MediaTek Asynchronous DirectLink Controller AngeloGioacchino Del Regno
` (7 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Introduce support for actaully bringing up a full crtc path that
features multiple display controllers: this enables acquisition
and writing to multiple MMSYS and MuteX instances to connect the
multiple display controllers and enable trigger signals from the
various hardware sub-components at the same time.
This currently only works for rather rare display pipelines that
can make use of multi-controller without DirectLink architecture.
This change is also the final preparation to introduce support
for handling DirectLink Display Controller paths, found in the
MediaTek Kompanio Ultra MT8196, Genio Pro 5100 MT8894 and also
in the Dimensity 9400 MT6991, Dimensity 9500 MT6993 SoCs.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_crtc.c | 519 ++++++++++++++++++------
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 6 +-
drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 4 +
3 files changed, 403 insertions(+), 126 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_crtc.c b/drivers/gpu/drm/mediatek/mtk_crtc.c
index 3f70d11270e9..fb6ced49bb4a 100644
--- a/drivers/gpu/drm/mediatek/mtk_crtc.c
+++ b/drivers/gpu/drm/mediatek/mtk_crtc.c
@@ -45,6 +45,9 @@ struct mtk_crtc_hw_layer {
* struct mtk_crtc - MediaTek specific crtc structure.
* @base: CRTC object
* @enabled: Records whether crtc_enable succeeded
+ * @controller_idmap:Array that maps a controller's MMSYS ID to mtk_crtc per-controller
+ * arrays indices; this array is counted by num_controllers.
+ * @num_controllers: Records number of display controllers used by this pipeline
* @pending_needs_vblank: Records whether pending config operation needs a VBlank to finish
* @event: VBlank event to signal upon completion of state update
* @hwlayers: Array of mtk_crtc_hw_layer structures, one for each overlay plane
@@ -58,7 +61,7 @@ struct mtk_crtc_hw_layer {
* @cb_blocking_queue: Wait queue for sending blocking command packet through CMDQ Mailbox
* @mmsys_dev: Pointer to the MMSYS device for configuration registers
* @dma_dev: Pointer to the DMA device (usually linked to an IOMMU)
- * @mutex: Pointer to the MediaTek MuteX device for HW triggers mute/unmuting
+ * @mutex: Pointer to the MediaTek MuteX devices for HW triggers mute/unmuting
* @ddp_comp_nr: Number of HW components in ddp_comp structure
* @ddp_comp: Array of HW components used in one Display Controller pipeline
* @vblank_comp_idx: Index of HW component where to enable sending VBlanks
@@ -72,6 +75,8 @@ struct mtk_crtc_hw_layer {
struct mtk_crtc {
struct drm_crtc base;
bool enabled;
+ u8 *controller_idmap;
+ u8 num_controllers;
bool pending_needs_vblank;
struct drm_pending_vblank_event *event;
@@ -91,7 +96,7 @@ struct mtk_crtc {
struct device *mmsys_dev;
struct device *dma_dev;
- struct mtk_mutex *mutex;
+ struct mtk_mutex **mutex;
unsigned int ddp_comp_nr;
struct mtk_ddp_comp **ddp_comp;
s8 vblank_comp_idx;
@@ -161,7 +166,8 @@ static void mtk_crtc_destroy(struct drm_crtc *crtc)
struct mtk_crtc *mtk_crtc = to_mtk_crtc(crtc);
int i;
- mtk_mutex_put(mtk_crtc->mutex);
+ for (i = 0; i < mtk_crtc->num_controllers; i++)
+ mtk_mutex_put(mtk_crtc->mutex[i]);
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
if (mtk_crtc->cmdq_client.chan) {
cmdq_pkt_destroy(&mtk_crtc->cmdq_client, &mtk_crtc->cmdq_handle);
@@ -361,6 +367,64 @@ static void mtk_crtc_config_layer(struct mtk_crtc *mtk_crtc,
return;
}
+static struct mtk_drm_private
+*mtk_crtc_get_comp_priv(struct mtk_crtc *mtk_crtc, struct mtk_ddp_comp *comp)
+{
+ struct drm_crtc *crtc = &mtk_crtc->base;
+ struct mtk_drm_private *main_priv = crtc->dev->dev_private;
+
+ for (int i = 0; i < main_priv->data->mmsys_dev_num; i++) {
+ struct mtk_drm_private *priv = main_priv->all_drm_private[i];
+ bool comp_found;
+
+ if (!priv)
+ continue;
+
+ comp_found = mtk_ddp_find_comp_dev_in_table(&priv->hlist,
+ comp->type,
+ comp->dev);
+ if (comp_found)
+ return priv;
+ }
+
+ drm_warn(mtk_crtc->base.dev,
+ "Could not find priv for component %u-%u - trying with main...\n",
+ comp->type, comp->inst_id);
+
+ return main_priv;
+}
+
+static struct mtk_drm_private
+*mtk_crtc_get_controller_priv(struct mtk_crtc *mtk_crtc, unsigned int controller_id)
+{
+ struct drm_crtc *crtc = &mtk_crtc->base;
+ struct mtk_drm_private *main_priv = crtc->dev->dev_private;
+
+ for (int i = 0; i < main_priv->data->mmsys_dev_num; i++) {
+ struct mtk_drm_private *priv = main_priv->all_drm_private[i];
+
+ if (priv->data->mmsys_id == controller_id)
+ return priv;
+ }
+
+ /* This should never happen */
+ drm_warn(mtk_crtc->base.dev,
+ "Could not find priv for Controller %u - trying with main..\n",
+ controller_id);
+
+ return main_priv;
+}
+
+static unsigned int mtk_crtc_get_controller_map_idx(struct mtk_crtc *mtk_crtc,
+ unsigned int controller_id)
+{
+ for (int i = 0; i < mtk_crtc->num_controllers; i++)
+ if (mtk_crtc->controller_idmap[i] == controller_id)
+ return i;
+
+ return 0;
+}
+
static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
{
struct drm_crtc *crtc = &mtk_crtc->base;
@@ -371,6 +435,9 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
struct drm_dsc_config *dsc_cfg;
struct drm_device *dev = mtk_crtc->base.dev;
unsigned int width, height, vrefresh, bpc = MTK_MAX_BPC;
+ struct mtk_drm_private *priv;
+ struct mtk_mutex *mtk_mutex;
+ u8 mutex_idx;
int ret;
int i;
@@ -402,10 +469,12 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
return ret;
}
- ret = mtk_mutex_prepare(mtk_crtc->mutex);
- if (ret < 0) {
- drm_err(dev, "Failed to enable mutex clock: %d\n", ret);
- goto err_pm_runtime_put;
+ for (i = 0; i < mtk_crtc->num_controllers; i++) {
+ ret = mtk_mutex_prepare(mtk_crtc->mutex[i]);
+ if (ret < 0) {
+ drm_err(dev, "Failed to enable mutex clock: %d\n", ret);
+ goto err_pm_runtime_put;
+ }
}
ret = mtk_crtc_ddp_clk_enable(mtk_crtc);
@@ -417,14 +486,21 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) {
struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
struct mtk_ddp_comp *next = mtk_crtc->ddp_comp[i + 1];
+ struct device *mmsys_dev;
+
+ priv = mtk_crtc_get_comp_priv(mtk_crtc, comp);
+ mutex_idx = mtk_crtc_get_controller_map_idx(mtk_crtc,
+ priv->data->mmsys_id);
+ mtk_mutex = mtk_crtc->mutex[mutex_idx];
+ mmsys_dev = priv->mmsys_dev;
- if (!mtk_ddp_comp_connect(comp, mtk_crtc->mmsys_dev, next))
- mtk_mmsys_hw_connect(mtk_crtc->mmsys_dev,
+ if (!mtk_ddp_comp_connect(comp, mmsys_dev, next))
+ mtk_mmsys_hw_connect(mmsys_dev,
comp->type, comp->inst_id,
next->type, next->inst_id);
- if (!mtk_ddp_comp_add(comp, mtk_crtc->mutex))
- mtk_mutex_add_trigger(mtk_crtc->mutex,
+ if (!mtk_ddp_comp_add(comp, mtk_mutex))
+ mtk_mutex_add_trigger(mtk_mutex,
comp->type, comp->inst_id,
comp->mtx_trig_id);
@@ -435,13 +511,19 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
if (comp->type == MTK_DISP_DSC && !comp_dsc)
comp_dsc = mtk_crtc->ddp_comp[i];
}
- if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
- mtk_mutex_add_trigger(mtk_crtc->mutex,
+
+ priv = mtk_crtc_get_comp_priv(mtk_crtc, mtk_crtc->ddp_comp[i]);
+ mutex_idx = mtk_crtc_get_controller_map_idx(mtk_crtc, priv->data->mmsys_id);
+ mtk_mutex = mtk_crtc->mutex[mutex_idx];
+
+ if (!mtk_ddp_comp_add(mtk_crtc->ddp_comp[i], mtk_mutex))
+ mtk_mutex_add_trigger(mtk_mutex,
mtk_crtc->ddp_comp[i]->type,
mtk_crtc->ddp_comp[i]->inst_id,
mtk_crtc->ddp_comp[i]->mtx_trig_id);
- mtk_mutex_enable(mtk_crtc->mutex);
+ for (i = 0; i < mtk_crtc->num_controllers; i++)
+ mtk_mutex_enable(mtk_crtc->mutex[i]);
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
@@ -476,7 +558,8 @@ static int mtk_crtc_ddp_hw_init(struct mtk_crtc *mtk_crtc)
return 0;
err_mutex_unprepare:
- mtk_mutex_unprepare(mtk_crtc->mutex);
+ for (i = 0; i < mtk_crtc->num_controllers; i++)
+ mtk_mutex_unprepare(mtk_crtc->mutex[i]);
err_pm_runtime_put:
pm_runtime_put(crtc->dev->dev);
return ret;
@@ -486,44 +569,72 @@ static void mtk_crtc_ddp_hw_fini(struct mtk_crtc *mtk_crtc)
{
struct drm_device *drm = mtk_crtc->base.dev;
struct drm_crtc *crtc = &mtk_crtc->base;
+ struct mtk_drm_private *priv;
+ struct mtk_mutex *mtk_mutex;
unsigned long flags;
+ u8 mutex_idx;
int i;
+
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
mtk_ddp_comp_stop(mtk_crtc->ddp_comp[i]);
if (i == 1)
mtk_ddp_comp_bgclr_in_off(mtk_crtc->ddp_comp[i]);
}
- for (i = 0; i < mtk_crtc->ddp_comp_nr; i++)
- if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
- mtk_mutex_remove_trigger(mtk_crtc->mutex,
+ for (i = 0; i < mtk_crtc->num_controllers; i++)
+ mtk_mutex_disable(mtk_crtc->mutex[i]);
+
+ for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
+ struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
+
+ priv = mtk_crtc_get_comp_priv(mtk_crtc, comp);
+ mutex_idx = mtk_crtc_get_controller_map_idx(mtk_crtc,
+ priv->data->mmsys_id);
+ mtk_mutex = mtk_crtc->mutex[mutex_idx];
+
+ if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_mutex))
+ mtk_mutex_remove_trigger(mtk_mutex,
mtk_crtc->ddp_comp[i]->type,
mtk_crtc->ddp_comp[i]->inst_id,
mtk_crtc->ddp_comp[i]->mtx_trig_id);
- mtk_mutex_disable(mtk_crtc->mutex);
+ }
+
for (i = 0; i < mtk_crtc->ddp_comp_nr - 1; i++) {
struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
struct mtk_ddp_comp *next = mtk_crtc->ddp_comp[i + 1];
+ struct device *mmsys_dev;
+
+ priv = mtk_crtc_get_comp_priv(mtk_crtc, comp);
+ mutex_idx = mtk_crtc_get_controller_map_idx(mtk_crtc,
+ priv->data->mmsys_id);
+ mtk_mutex = mtk_crtc->mutex[mutex_idx];
+ mmsys_dev = priv->mmsys_dev;
- if (!mtk_ddp_comp_disconnect(comp, mtk_crtc->mmsys_dev, next))
- mtk_mmsys_hw_disconnect(mtk_crtc->mmsys_dev,
+ if (!mtk_ddp_comp_disconnect(comp, mmsys_dev, next))
+ mtk_mmsys_hw_disconnect(mmsys_dev,
comp->type, comp->inst_id,
next->type, next->inst_id);
- if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
- mtk_mutex_remove_trigger(mtk_crtc->mutex,
+ if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_mutex))
+ mtk_mutex_remove_trigger(mtk_mutex,
mtk_crtc->ddp_comp[i]->type,
mtk_crtc->ddp_comp[i]->inst_id,
mtk_crtc->ddp_comp[i]->mtx_trig_id);
}
- if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_crtc->mutex))
- mtk_mutex_remove_trigger(mtk_crtc->mutex,
+ priv = mtk_crtc_get_comp_priv(mtk_crtc, mtk_crtc->ddp_comp[i]);
+ mutex_idx = mtk_crtc_get_controller_map_idx(mtk_crtc, priv->data->mmsys_id);
+ mtk_mutex = mtk_crtc->mutex[mutex_idx];
+ if (!mtk_ddp_comp_remove(mtk_crtc->ddp_comp[i], mtk_mutex))
+ mtk_mutex_remove_trigger(mtk_mutex,
mtk_crtc->ddp_comp[i]->type,
mtk_crtc->ddp_comp[i]->inst_id,
mtk_crtc->ddp_comp[i]->mtx_trig_id);
+
mtk_crtc_ddp_clk_disable(mtk_crtc);
- mtk_mutex_unprepare(mtk_crtc->mutex);
+
+ for (i = 0; i < mtk_crtc->num_controllers; i++)
+ mtk_mutex_unprepare(mtk_crtc->mutex[i]);
pm_runtime_put(drm->dev);
@@ -640,9 +751,13 @@ static void mtk_crtc_update_config(struct mtk_crtc *mtk_crtc, bool needs_vblank)
mtk_crtc->pending_async_planes = true;
if (priv->data->shadow_register) {
- mtk_mutex_acquire(mtk_crtc->mutex);
+ for (i = 0; i < mtk_crtc->num_controllers; i++)
+ mtk_mutex_acquire(mtk_crtc->mutex[i]);
+
mtk_crtc_ddp_config(crtc, NULL);
- mtk_mutex_release(mtk_crtc->mutex);
+
+ for (i = 0; i < mtk_crtc->num_controllers; i++)
+ mtk_mutex_release(mtk_crtc->mutex[i]);
}
#if IS_REACHABLE(CONFIG_MTK_CMDQ)
if (mtk_crtc->cmdq_client.chan) {
@@ -959,8 +1074,8 @@ static const struct drm_crtc_helper_funcs mtk_crtc_helper_funcs = {
.atomic_disable = mtk_crtc_atomic_disable,
};
-static int mtk_crtc_init(struct drm_device *drm, struct mtk_crtc *mtk_crtc,
- unsigned int pipe)
+static int mtk_crtc_init_drm_crtc(struct drm_device *drm, struct mtk_crtc *mtk_crtc,
+ unsigned int pipe)
{
struct drm_plane *primary = NULL;
struct drm_plane *cursor = NULL;
@@ -1131,21 +1246,13 @@ struct device *mtk_crtc_dma_dev_get(struct drm_crtc *crtc)
return mtk_crtc->dma_dev;
}
-static int mtk_crtc_find_suitable_dma_dev(struct mtk_drm_private *priv,
- struct mtk_crtc *mtk_crtc,
- const struct mtk_drm_path_definition *path)
+static int mtk_crtc_find_suitable_dma_dev(struct mtk_crtc *mtk_crtc)
{
struct mtk_ddp_comp *dma_comp = NULL, *dma_comp_mmu = NULL;
int i;
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
- const struct mtk_drm_comp_definition *cdef = path[i].comp;
- struct mtk_ddp_comp *comp;
-
- comp = mtk_ddp_comp_find_by_id(&priv->hlist,
- cdef->type, cdef->inst_id);
- if (!comp)
- continue;
+ struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
/*
* Check if this is a legacy OVL_ADAPTOR component and, if so, this
@@ -1185,120 +1292,263 @@ static int mtk_crtc_find_suitable_dma_dev(struct mtk_drm_private *priv,
return 0;
}
+static int mtk_crtc_init_multi_controller_properties(struct device *dev,
+ struct mtk_crtc *mtk_crtc)
+{
+ struct drm_crtc *crtc = &mtk_crtc->base;
+ unsigned long controllers_mask = 0;
+ struct mtk_drm_private *priv;
+ unsigned int i, j, k, z;
+
+ for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
+ u8 controller_id = mtk_crtc->ddp_comp[i]->controller_id;
+
+ if (controller_id > MTK_DISP_CONTROLLER_MAX_CONTROLLERS_NUM) {
+ dev_err(mtk_crtc->mmsys_dev, "Bad controller ID %u\n",
+ controller_id);
+ return -EINVAL;
+ }
+
+ if (!(controllers_mask & BIT(controller_id)))
+ mtk_crtc->num_controllers++;
+
+ controllers_mask |= BIT(controller_id);
+
+ }
+
+ mtk_crtc->controller_idmap = devm_kmalloc_array(dev, mtk_crtc->num_controllers,
+ sizeof(*mtk_crtc->controller_idmap),
+ GFP_KERNEL | __GFP_ZERO);
+ if (!mtk_crtc->controller_idmap)
+ return -ENOMEM;
+
+ dev_info(dev, "Bringing up %d Display Controllers for CRTC %u\n",
+ mtk_crtc->num_controllers, crtc->base.id);
+
+ /* Shortcut: if this is a single controller pipelines, avoid iterating */
+ if (mtk_crtc->num_controllers == 1) {
+ mtk_crtc->controller_idmap[0] = mtk_crtc->ddp_comp[0]->controller_id;
+ return 0;
+ }
+
+ priv = crtc->dev->dev_private;
+
+ for_each_set_bit(i, &controllers_mask, MTK_DISP_CONTROLLER_MAX_CONTROLLERS_NUM) {
+ for (j = 0; j < mtk_crtc->ddp_comp_nr; j++) {
+ struct mtk_drm_private *controller_priv;
+
+ if (mtk_crtc->ddp_comp[j]->controller_id != i)
+ continue;
+
+ /* Find the matching Controller ID's mmsys device */
+ for (k = 0; k < priv->data->mmsys_dev_num; k++) {
+ controller_priv = priv->all_drm_private[k];
+
+ if (controller_priv->data->mmsys_id ==
+ mtk_crtc->ddp_comp[j]->controller_id)
+ break;
+ }
+ if (k == priv->data->mmsys_dev_num)
+ continue;
+
+ mtk_crtc->controller_idmap[z] = mtk_crtc->ddp_comp[j]->controller_id;
+ z++;
+
+ /*
+ * If this is a multi-controller path, link the follower
+ * with the leader controller to make sure that any call
+ * to Runtime PM acts on both.
+ */
+ if (controller_priv->mmsys_dev != mtk_crtc->mmsys_dev)
+ device_link_add(controller_priv->mmsys_dev,
+ mtk_crtc->mmsys_dev,
+ DL_FLAG_PM_RUNTIME);
+
+ if (controller_priv->mutex_dev != priv->mutex_dev)
+ device_link_add(controller_priv->mutex_dev,
+ priv->mutex_dev,
+ DL_FLAG_PM_RUNTIME);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int mtk_crtc_init_mutex(struct device *dev, struct mtk_crtc *mtk_crtc)
+{
+ unsigned int i;
+ int ret;
+
+ mtk_crtc->mutex = devm_kmalloc_array(dev, mtk_crtc->num_controllers,
+ sizeof(*mtk_crtc->mutex), GFP_KERNEL);
+ if (!mtk_crtc->mutex)
+ return -ENOMEM;
+
+ for (i = 0; i < mtk_crtc->num_controllers; i++) {
+ u8 controller_num = mtk_crtc->controller_idmap[i];
+ struct mtk_drm_private *priv = mtk_crtc_get_controller_priv(mtk_crtc, controller_num);
+
+ if (!priv)
+ return -ENODEV;
+
+ mtk_crtc->mutex[i] = mtk_mutex_get(priv->mutex_dev);
+ if (IS_ERR(mtk_crtc->mutex[i])) {
+ ret = PTR_ERR(mtk_crtc->mutex[i]);
+ dev_err(dev, "Failed to get Controller %u MuteX: %d\n", i, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
int mtk_crtc_create(struct drm_device *drm_dev,
enum mtk_crtc_path path_sel, int priv_data_index,
const struct mtk_drm_route *conn_routes,
unsigned int num_conn_routes)
{
struct mtk_drm_private *priv = drm_dev->dev_private;
- const struct mtk_drm_path_definition *output_path;
struct device *dev = drm_dev->dev;
struct mtk_crtc *mtk_crtc;
unsigned int num_comp_planes = 0;
unsigned int max_comp_stages = 0;
+ unsigned int output_path_len = 0;
int ret;
- int i, j;
+ int i, j, k;
bool has_ctm = false;
uint gamma_lut_size = 0;
struct drm_crtc *tmp;
int crtc_i = 0;
priv = priv->all_drm_private[priv_data_index];
- output_path = &priv->data->output_paths[path_sel];
drm_for_each_crtc(tmp, drm_dev)
crtc_i++;
- for (i = 0; i < output_path[i].len; i++) {
- enum mtk_ddp_comp_type comp_type = output_path->comp[i].type;
- u8 comp_inst = output_path->comp[i].inst_id;
- struct mtk_ddp_comp *comp;
+ for (j = 0; j < priv->data->mmsys_dev_num; j++) {
+ for (k = 0; k < priv->data->mmsys_dev_num; k++) {
+ struct mtk_drm_private *subsys_priv = priv->all_drm_private[k];
+ const struct mtk_drm_path_definition *ctrlr_path;
- comp = mtk_ddp_comp_find_by_id(&priv->hlist, comp_type, comp_inst);
- if (!comp || !comp->dev) {
- dev_err(dev,
- "CRTC%d: Component type=%u inst=%u not initialized\n",
- crtc_i, comp_type, comp_inst);
- return -ENODEV;
+ if (!subsys_priv)
+ continue;
+
+ ctrlr_path = &subsys_priv->data->output_paths[path_sel];
+ if (j != ctrlr_path->order)
+ continue;
+
+ output_path_len += ctrlr_path->len;
}
}
+ if (!output_path_len)
+ return 0;
mtk_crtc = devm_kzalloc(dev, sizeof(*mtk_crtc), GFP_KERNEL);
if (!mtk_crtc)
return -ENOMEM;
mtk_crtc->mmsys_dev = priv->mmsys_dev;
- mtk_crtc->ddp_comp_nr = output_path->len;
+ mtk_crtc->ddp_comp_nr = output_path_len;
mtk_crtc->ddp_comp = devm_kcalloc(dev,
mtk_crtc->ddp_comp_nr + (conn_routes ? 1 : 0),
sizeof(*mtk_crtc->ddp_comp),
GFP_KERNEL);
- if (!mtk_crtc->ddp_comp)
- return -ENOMEM;
+ if (!mtk_crtc->ddp_comp) {
+ ret = -ENOMEM;
+ goto err_free_crtc;
+ }
- mtk_crtc->mutex = mtk_mutex_get(priv->mutex_dev);
- if (IS_ERR(mtk_crtc->mutex)) {
- ret = PTR_ERR(mtk_crtc->mutex);
- dev_err(dev, "Failed to get mutex: %d\n", ret);
- return ret;
+ /*
+ * Reusing path_len to initialize the structure in the next loop to
+ * reduce stack size of this function at least a little.
+ */
+ output_path_len = 0;
+
+ for (j = 0; j < priv->data->mmsys_dev_num; j++) {
+ for (k = 0; k < priv->data->mmsys_dev_num; k++) {
+ struct mtk_drm_private *subsys_priv = priv->all_drm_private[k];
+ const struct mtk_drm_path_definition *ctrlr_path;
+
+ subsys_priv = priv->all_drm_private[k];
+ if (!subsys_priv)
+ continue;
+
+ ctrlr_path = &subsys_priv->data->output_paths[path_sel];
+
+ if (!ctrlr_path->len || ctrlr_path->order != j)
+ continue;
+
+ for (i = 0; i < ctrlr_path->len; i++) {
+ struct mtk_ddp_comp *comp;
+
+ comp = mtk_ddp_comp_find_by_id(&subsys_priv->hlist,
+ ctrlr_path->comp[i].type,
+ ctrlr_path->comp[i].inst_id);
+ if (!comp || !comp->dev) {
+ dev_err(dev,
+ "CRTC%d: Component %u-%u not initialized\n",
+ crtc_i, ctrlr_path->comp[i].type,
+ ctrlr_path->comp[i].inst_id);
+ ret = -ENODEV;
+ goto err_free_ddp_comp;
+ }
+ mtk_crtc->ddp_comp[output_path_len] = comp;
+ output_path_len++;
+ }
+ }
}
/* Component 0 would be valid so initialize vblank and config idx to -EINVAL */
mtk_crtc->vblank_comp_idx = -EINVAL;
mtk_crtc->config_comp_idx = -EINVAL;
- for (i = 0, j = 0; i < mtk_crtc->ddp_comp_nr; i++, j++) {
- enum mtk_ddp_comp_type comp_type = output_path->comp[i].type;
- u8 comp_inst = output_path->comp[i].inst_id;
- struct mtk_ddp_comp *comp;
+ for (j = 0; j < mtk_crtc->ddp_comp_nr; j++) {
+ struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[j];
- comp = mtk_ddp_comp_find_by_id(&priv->hlist, comp_type, comp_inst);
- if (!comp) {
- j--;
- dev_dbg(dev, "Cannot find component %u-%u.\n", comp_type, comp_inst);
+ if (!comp->funcs)
continue;
- }
- mtk_crtc->ddp_comp[j] = comp;
- if (comp->funcs) {
- if (comp->funcs->gamma_set && comp->funcs->gamma_get_lut_size) {
- unsigned int lut_sz = mtk_ddp_gamma_get_lut_size(comp);
+ if (comp->funcs->gamma_set && comp->funcs->gamma_get_lut_size) {
+ unsigned int lut_sz = mtk_ddp_gamma_get_lut_size(comp);
- if (lut_sz)
- gamma_lut_size = lut_sz;
- }
+ if (lut_sz)
+ gamma_lut_size = lut_sz;
+ }
- if (comp->funcs->ctm_set)
- has_ctm = true;
+ if (comp->funcs->ctm_set)
+ has_ctm = true;
- /*
- * Assumes that there can only be one vblank enabler per CRTC,
- * and that should there be more than one, the one that should
- * handle vblanks has to be the bottom-most HW component.
- */
- if (mtk_crtc->vblank_comp_idx < 0 && comp->funcs->enable_vblank)
- mtk_crtc->vblank_comp_idx = j;
+ /*
+ * Assumes that there can only be one vblank enabler per CRTC,
+ * and that should there be more than one, the one that should
+ * handle vblanks has to be the bottom-most HW component.
+ */
+ if (mtk_crtc->vblank_comp_idx < 0 && comp->funcs->enable_vblank)
+ mtk_crtc->vblank_comp_idx = j;
- /*
- * Assumes that there can only be one main configuration
- * component per CRTC, and that if more than one has to
- * be configured for at each frame, the main one would
- * take care of the config chain.
- *
- * As a note, such component has specific characteristics:
- * - It is configurable, and supports per-layer properties;
- * - It is a main layer component and not a layer stage;
- * - It is always the first one (the bottom-most) in the
- * pipeline that has the characteristics explaned above.
- *
- * Such hardware is usually an OVL, RDMA or exDMA.
- *
- * This may change in the future with more complex pipelines.
- */
- if (mtk_crtc->config_comp_idx < 0 && comp->funcs->config &&
- comp->funcs->layer_config && comp->funcs->layer_nr)
- mtk_crtc->config_comp_idx = j;
- }
+ /*
+ * Assumes that there can only be one main configuration
+ * component per CRTC, and that if more than one has to
+ * be configured for at each frame, the main one would
+ * take care of the config chain.
+ *
+ * As a note, such component has specific characteristics:
+ * - It is configurable, and supports per-layer properties;
+ * - It is a main layer component and not a layer stage;
+ * - It is always the first one (the bottom-most) in the
+ * pipeline that has the characteristics explaned above.
+ *
+ * Such hardware is usually an OVL, RDMA or exDMA.
+ *
+ * This may change in the future with more complex pipelines.
+ */
+ if (mtk_crtc->config_comp_idx < 0 && comp->funcs->config &&
+ comp->funcs->layer_config && comp->funcs->layer_nr)
+ mtk_crtc->config_comp_idx = j;
+
+ num_comp_planes += mtk_ddp_comp_layer_nr(comp, 0);
+ max_comp_stages = MAX(mtk_ddp_comp_stage_nr(comp), max_comp_stages);
mtk_ddp_comp_register_vblank_cb(comp, mtk_crtc_ddp_irq,
&mtk_crtc->base);
@@ -1306,7 +1556,8 @@ int mtk_crtc_create(struct drm_device *drm_dev,
if (mtk_crtc->config_comp_idx < 0) {
dev_err(dev, "No HW component for layer configuration. Bailing out.\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_free_ddp_comp;
}
if (mtk_crtc->vblank_comp_idx < 0) {
@@ -1314,13 +1565,6 @@ int mtk_crtc_create(struct drm_device *drm_dev,
mtk_crtc->vblank_comp_idx = 0;
}
- for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
- struct mtk_ddp_comp *comp = mtk_crtc->ddp_comp[i];
-
- num_comp_planes += mtk_ddp_comp_layer_nr(comp, 0);
- max_comp_stages = MAX(mtk_ddp_comp_stage_nr(comp), max_comp_stages);
- }
-
/*
* On the older and/or simpler display controllers, each layer is single
* stage, while newer ones are more complex and may have multiple stages
@@ -1335,43 +1579,55 @@ int mtk_crtc_create(struct drm_device *drm_dev,
mtk_crtc->hwlayers = devm_kcalloc(dev, num_comp_planes,
sizeof(*mtk_crtc->hwlayers),
GFP_KERNEL);
- if (!mtk_crtc->hwlayers)
- return -ENOMEM;
+ if (!mtk_crtc->hwlayers) {
+ ret = -ENOMEM;
+ goto err_free_ddp_comp;
+ }
for (i = 0; i < num_comp_planes; i++) {
struct mtk_crtc_hw_layer *comp_plane = &mtk_crtc->hwlayers[i];
comp_plane->layer_stages = devm_kcalloc(dev, max_comp_stages,
sizeof(*comp_plane->layer_stages),
GFP_KERNEL);
- if (!comp_plane->layer_stages)
- return -ENOMEM;
+ if (!comp_plane->layer_stages) {
+ ret = -ENOMEM;
+ goto err_free_layer_stages;
+ }
}
for (i = 0; i < mtk_crtc->ddp_comp_nr; i++) {
ret = mtk_crtc_init_comp_planes(drm_dev, mtk_crtc, i, crtc_i);
if (ret)
- return ret;
+ goto err_free_layer_stages;
}
/* Initialize multi-stage only if present */
if (max_comp_stages > 1) {
ret = mtk_crtc_init_layer_stages(mtk_crtc);
if (ret)
- return ret;
+ goto err_free_layer_stages;
}
dev_dbg(dev, "Found %u layers composed by maximum of %u stage(s) each.\n",
mtk_crtc->hwlayer_nr, max_comp_stages);
- ret = mtk_crtc_find_suitable_dma_dev(priv, mtk_crtc, output_path);
+ ret = mtk_crtc_find_suitable_dma_dev(mtk_crtc);
if (ret) {
dev_err(dev, "Could not find appropriate DMA device!\n");
return -EINVAL;
}
dev_dbg(dev, "Using DMA device %pOF\n", mtk_crtc->dma_dev->of_node);
- ret = mtk_crtc_init(drm_dev, mtk_crtc, crtc_i);
+ ret = mtk_crtc_init_drm_crtc(drm_dev, mtk_crtc, crtc_i);
if (ret < 0)
- return ret;
+ goto err_free_layer_stages;
+
+ ret = mtk_crtc_init_multi_controller_properties(dev, mtk_crtc);
+ if (ret)
+ goto err_free_layer_stages;
+
+ ret = mtk_crtc_init_mutex(dev, mtk_crtc);
+ if (ret)
+ goto err_free_idmap;
if (gamma_lut_size)
drm_mode_crtc_set_gamma_size(&mtk_crtc->base, gamma_lut_size);
@@ -1448,4 +1704,21 @@ int mtk_crtc_create(struct drm_device *drm_dev,
}
return 0;
+
+err_free_idmap:
+ devm_kfree(dev, mtk_crtc->controller_idmap);
+err_free_layer_stages:
+ for (i = 0; i < num_comp_planes; i++) {
+ struct mtk_crtc_hw_layer *comp_plane = &mtk_crtc->hwlayers[i];
+
+ if (comp_plane->layer_stages)
+ devm_kfree(dev, comp_plane->layer_stages);
+ }
+ devm_kfree(dev, mtk_crtc->hwlayers);
+err_free_ddp_comp:
+ devm_kfree(dev, mtk_crtc->ddp_comp);
+err_free_crtc:
+ devm_kfree(dev, mtk_crtc);
+
+ return ret;
}
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index 3f25f1c34633..a305b5f6a42d 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -505,9 +505,9 @@ static const struct mtk_ddp_comp_funcs *mtk_ddp_funcs[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_DVO] = &ddp_dvo,
};
-static bool mtk_ddp_find_comp_dev_in_table(const struct mtk_drm_comp_list *hlist,
- const unsigned int comp_type,
- struct device *dev)
+bool mtk_ddp_find_comp_dev_in_table(const struct mtk_drm_comp_list *hlist,
+ const unsigned int comp_type,
+ struct device *dev)
{
struct mtk_ddp_comp *ddp_comp;
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index e94bcf6922c1..165bf83ccd10 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -15,6 +15,7 @@
#include <drm/drm_modes.h>
+#define MTK_DISP_CONTROLLER_MAX_CONTROLLERS_NUM 7
#define MTK_DISP_CONTROLLER_MAX_COMP_PER_PATH 24
#define MTK_DISP_CONTROLLER_MAX_HW_COMP_INSTANCE 32
@@ -370,6 +371,9 @@ static inline struct mtk_ddp_comp
return NULL;
}
+bool mtk_ddp_find_comp_dev_in_table(const struct mtk_drm_comp_list *hlist,
+ const unsigned int comp_type,
+ struct device *dev);
bool mtk_ddp_comp_is_internal_comp(enum mtk_ddp_comp_type type);
int mtk_ddp_comp_get_id(struct device_node *node,
enum mtk_ddp_comp_type comp_type);
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 35/42] drm/mediatek: Introduce MediaTek Asynchronous DirectLink Controller
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (33 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 34/42] drm/mediatek: Enable bring-up of multi-controller CRTC paths AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 36/42] drm/mediatek: Support registering disp controller device subnodes AngeloGioacchino Del Regno
` (6 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Add support for the MediaTek Display Controller's Asynchronous
Direct Link Controller.
This is responsible for managing internal I/O connections between
multiple display controllers in a leader to follower(s) topology,
adding the ability to enable data exchange between multimedia
related controllers and the display controller(s), and between
multiple display controllers, effectively changing the hardware
capabilities of multiple display output paths.
For example, this could be used to support multiple outputs with
lower resolution and/or color depth, or to support less outputs
but with high resolution and/or color depth, up to 8k60 in some
MediaTek SoCs like MT8196.
Moreover please note that, on new generation SoCs, (MT8196, MT8894,
MT6991, MT6993, etc), the Asynchronous DirectLink (DL_ASYNC) sub
component is required to be set up in order to achieve any display
output at all as, differently from slightly older ones (MT8195)
where a display controller reset resulted in default valid outputs
being set, the new ones have a "muted" configuration by default.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/Makefile | 1 +
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 42 +-
drivers/gpu/drm/mediatek/mtk_ddp_comp.h | 33 +-
.../gpu/drm/mediatek/mtk_disp_directlink.c | 434 ++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_disp_drv.h | 12 +
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 160 ++++++-
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 +
include/linux/soc/mediatek/mtk-mmsys.h | 4 +
8 files changed, 661 insertions(+), 26 deletions(-)
create mode 100644 drivers/gpu/drm/mediatek/mtk_disp_directlink.c
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index bec46e981ae1..e9478fa1a2ba 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -7,6 +7,7 @@ mediatek-drm-y := mtk_crtc.o \
mtk_disp_ccorr.o \
mtk_disp_color.o \
mtk_disp_dsc.o \
+ mtk_disp_directlink.o \
mtk_disp_exdma.o \
mtk_disp_gamma.o \
mtk_disp_merge.o \
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index a305b5f6a42d..7e12ddffbe77 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -13,6 +13,7 @@
#include <linux/clk.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/of_graph.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/soc/mediatek/mtk-cmdq.h>
@@ -274,6 +275,16 @@ static const struct mtk_ddp_comp_funcs ddp_color = {
.start = mtk_color_start,
};
+static const struct mtk_ddp_comp_funcs ddp_direct_link = {
+ .add = mtk_direct_link_add,
+ .remove = mtk_direct_link_mtx_remove,
+ .connect = mtk_direct_link_connect,
+ .disconnect = mtk_direct_link_disconnect,
+ .clk_enable = mtk_direct_link_clk_enable,
+ .clk_disable = mtk_direct_link_clk_disable,
+ .config = mtk_direct_link_config,
+};
+
static const struct mtk_ddp_comp_funcs ddp_dither = {
.clk_enable = mtk_ddp_clk_enable,
.clk_disable = mtk_ddp_clk_disable,
@@ -503,6 +514,8 @@ static const struct mtk_ddp_comp_funcs *mtk_ddp_funcs[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_DP_INTF] = &ddp_dpi,
[MTK_DISP_DSI] = &ddp_dsi,
[MTK_DISP_DVO] = &ddp_dvo,
+ [MTK_DISP_DIRECT_LINK_OUT] = &ddp_direct_link,
+ [MTK_DISP_DIRECT_LINK_IN] = &ddp_direct_link,
};
bool mtk_ddp_find_comp_dev_in_table(const struct mtk_drm_comp_list *hlist,
@@ -549,7 +562,7 @@ static int mtk_ddp_comp_find_in_route(struct device *dev,
return -ENODEV;
}
-int mtk_ddp_comp_get_id(struct device_node *node,
+int mtk_ddp_comp_get_id(struct device_node *node, struct device_node *ep_node,
enum mtk_ddp_comp_type comp_type)
{
/* If there's an alias, return the ID from that */
@@ -559,6 +572,24 @@ int mtk_ddp_comp_get_id(struct device_node *node,
return alias_id;
}
+ /*
+ * Alias ID -1 means that hardcoded IDs are not supported and
+ * must be taken from the endpoint.
+ */
+ if ((comp_type == MTK_DISP_DIRECT_LINK_IN ||
+ comp_type == MTK_DISP_DIRECT_LINK_OUT) && ep_node) {
+ struct of_endpoint endpoint;
+ int ret;
+
+ ret = of_graph_parse_endpoint(ep_node, &endpoint);
+ if (ret) {
+ pr_err("Cannot parse endpoint for node %pOF\n", ep_node);
+ return ret;
+ }
+
+ return endpoint.id;
+ }
+
return 0;
}
@@ -698,6 +729,15 @@ int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
comp->inst_id = comp_inst_id;
comp->controller_id = comp_controller_id;
comp->funcs = mtk_ddp_funcs[comp_type];
+
+ /*
+ * For DirectLink components, call the DirectLink-specific connection
+ * and disconnection callbacks regardless of whether it is a source or
+ * a destination component during the pipeline setup.
+ */
+ if (comp->type == MTK_DISP_DIRECT_LINK_OUT || comp->type == MTK_DISP_DIRECT_LINK_IN)
+ comp->special_connect = true;
+
/* Not all drm components have a DTS device node, such as ovl_adaptor,
* which is the drm bring up sub driver
*/
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
index 165bf83ccd10..9f483d9cb873 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.h
@@ -91,6 +91,7 @@ struct mtk_ddp_comp {
u8 controller_id;
int encoder_index;
const struct mtk_ddp_comp_funcs *funcs;
+ bool special_connect;
struct hlist_node lnode;
};
@@ -334,9 +335,18 @@ static inline bool mtk_ddp_comp_remove(struct mtk_ddp_comp *comp, struct mtk_mut
static inline bool mtk_ddp_comp_connect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
struct mtk_ddp_comp *next)
{
- if (comp->funcs && comp->funcs->connect) {
- comp->funcs->connect(comp, mmsys_dev, next);
- return true;
+ if (comp->funcs) {
+ const struct mtk_ddp_comp_funcs *funcs;
+
+ if (next->special_connect)
+ funcs = next->funcs;
+ else
+ funcs = comp->funcs;
+
+ if (funcs->connect) {
+ funcs->connect(comp, mmsys_dev, next);
+ return true;
+ }
}
return false;
}
@@ -344,9 +354,18 @@ static inline bool mtk_ddp_comp_connect(struct mtk_ddp_comp *comp, struct device
static inline bool mtk_ddp_comp_disconnect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
struct mtk_ddp_comp *next)
{
- if (comp->funcs && comp->funcs->disconnect) {
- comp->funcs->disconnect(comp, mmsys_dev, next);
- return true;
+ if (comp->funcs) {
+ const struct mtk_ddp_comp_funcs *funcs;
+
+ if (next->special_connect)
+ funcs = next->funcs;
+ else
+ funcs = comp->funcs;
+
+ if (funcs->disconnect) {
+ funcs->disconnect(comp, mmsys_dev, next);
+ return true;
+ }
}
return false;
}
@@ -375,7 +394,7 @@ bool mtk_ddp_find_comp_dev_in_table(const struct mtk_drm_comp_list *hlist,
const unsigned int comp_type,
struct device *dev);
bool mtk_ddp_comp_is_internal_comp(enum mtk_ddp_comp_type type);
-int mtk_ddp_comp_get_id(struct device_node *node,
+int mtk_ddp_comp_get_id(struct device_node *node, struct device_node *ep_node,
enum mtk_ddp_comp_type comp_type);
int mtk_find_possible_crtcs(struct drm_device *drm, struct device *dev);
int mtk_ddp_comp_init(struct device *dev, struct device_node *node,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_directlink.c b/drivers/gpu/drm/mediatek/mtk_disp_directlink.c
new file mode 100644
index 000000000000..a473939dab5c
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_disp_directlink.c
@@ -0,0 +1,434 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MediaTek Asynchronous Direct Link (DL_ASYNC) driver
+ *
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_graph.h>
+#include <linux/platform_device.h>
+#include <linux/soc/mediatek/mtk-cmdq.h>
+#include <linux/soc/mediatek/mtk-mmsys.h>
+
+#include "mtk_crtc.h"
+#include "mtk_ddp_comp.h"
+#include "mtk_disp_drv.h"
+#include "mtk_drm_drv.h"
+
+#define MTK_DISP_REG_DL_IN_ASYNC0_SIZE_MT8196 0
+#define MTK_DISP_REG_DL_OUT_ASYNC0_SIZE_MT8196 0x64
+#define MTK_OVL_REG_DL_IN_RELAY0_SIZE_MT8196 0
+#define MTK_OVL_REG_DL_OUT_RELAY0_SIZE_MT8196 0x28
+
+#define MTK_DL_INOUT_REG_WIDTH 0x4
+
+#define MTK_DISP_DL_RELAY_WIDTH GENMASK(15, 0)
+#define MTK_DISP_DL_RELAY_HEIGHT GENMASK(29, 16)
+#define MTK_DISP_DL_IN_RELAY_PIXITER GENMASK(31, 30)
+# define MTK_DISP_DL_IN_RELAY_1T1P 0
+# define MTK_DISP_DL_IN_RELAY_1T2P 1
+# define MTK_DISP_DL_IN_RELAY_1T4P 2
+
+/**
+ * struct mtk_direct_link_data - SoC-specific data for DL_ASYNC
+ * @dli0_size_reg: Register offset of DL_IN_ASYNC0_SIZE
+ * @dlo0_size_reg: Register offset of DL_OUT_ASYNC0_SIZE
+ * @pixels_per_iter: Number of pixels per iteration
+ */
+struct mtk_direct_link_data {
+ u16 dli0_size_reg;
+ u16 dlo0_size_reg;
+ u8 pixels_per_iter;
+};
+
+/**
+ * struct mtk_disp_dl_port - DirectLink Input/Output/Relay Port structure
+ * @clks: Clocks for all of the DirectLink endpoints in port
+ * @link_ids: Active DirectLink hardware endpoint identifier
+ * @num_links: Number of active DirectLink hardware endpoints
+ * @p0_mtx_trig_id: Mute-X trigger idenrifier for first DirectLink HW Endpoint
+ */
+struct mtk_disp_dl_port {
+ struct clk **clks;
+ u8 *link_ids;
+ u8 num_links;
+ u8 p0_mtx_trig_id;
+};
+
+/**
+ * enum mtk_direct_link_port_type - DirectLink Hardware Port Type
+ * @MTK_DISP_DL_IN: DirectLink input port
+ * @MTK_DISP_DL_OUT: DirectLink output port
+ * @MTK_DISP_DL_PORT_MAX: Number of supported DirectLink port types
+ */
+enum mtk_direct_link_port_type {
+ MTK_DISP_DL_IN,
+ MTK_DISP_DL_OUT,
+ MTK_DISP_DL_PORT_MAX
+};
+
+/**
+ * struct mtk_direct_link - Main Asynchronous DirectLink driver structure
+ * @data: SoC-specific data for DirectLink
+ * @regs: DirectLink registers handle
+ * @clk: Main configuration clock for DirectLink HW
+ * @cmdq_reg: CMDQ Client register
+ * @dl_port: Array of DirectLink Port structure
+ */
+struct mtk_direct_link {
+ const struct mtk_direct_link_data *data;
+ void __iomem *regs;
+ struct clk *clk;
+ struct cmdq_client_reg cmdq_reg;
+ struct mtk_disp_dl_port dl_port[MTK_DISP_DL_PORT_MAX];
+};
+
+static struct mtk_disp_dl_port *mtk_direct_link_get_port(struct mtk_ddp_comp *comp)
+{
+ struct mtk_direct_link *dl_async;
+
+ if (comp->type != MTK_DISP_DIRECT_LINK_IN && comp->type != MTK_DISP_DIRECT_LINK_OUT)
+ return NULL;
+
+ dl_async = dev_get_drvdata(comp->dev);
+
+ if (comp->type == MTK_DISP_DIRECT_LINK_OUT)
+ return &dl_async->dl_port[MTK_DISP_DL_OUT];
+
+ return &dl_async->dl_port[MTK_DISP_DL_IN];
+}
+
+void mtk_direct_link_add(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex)
+{
+ struct mtk_disp_dl_port *dl_port = mtk_direct_link_get_port(comp);
+ u8 port_id = dl_port->link_ids[comp->inst_id];
+
+ mtk_mutex_add_trigger(mutex, comp->type, comp->inst_id,
+ dl_port->p0_mtx_trig_id + port_id);
+
+ return;
+}
+
+void mtk_direct_link_mtx_remove(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex)
+{
+ struct mtk_disp_dl_port *dl_port = mtk_direct_link_get_port(comp);
+ u8 port_id = dl_port->link_ids[comp->inst_id];
+
+ mtk_mutex_remove_trigger(mutex, comp->type, comp->inst_id,
+ dl_port->p0_mtx_trig_id + port_id);
+
+ return;
+}
+
+void mtk_direct_link_connect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next)
+{
+ struct mtk_disp_dl_port *dl_comp_port = mtk_direct_link_get_port(comp);
+ struct mtk_disp_dl_port *dl_next_port = mtk_direct_link_get_port(next);
+ u8 comp_inst_id, next_inst_id;
+
+ comp_inst_id = dl_comp_port ? dl_comp_port->link_ids[comp->inst_id] : comp->inst_id;
+ next_inst_id = dl_next_port ? dl_next_port->link_ids[next->inst_id] : next->inst_id;
+
+ mtk_mmsys_hw_connect(mmsys_dev, comp->type, comp_inst_id, next->type, next_inst_id);
+}
+
+void mtk_direct_link_disconnect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next)
+{
+ struct mtk_disp_dl_port *dl_comp_port = mtk_direct_link_get_port(comp);
+ struct mtk_disp_dl_port *dl_next_port = mtk_direct_link_get_port(next);
+ u8 comp_inst_id, next_inst_id;
+
+ comp_inst_id = dl_comp_port ? dl_comp_port->link_ids[comp->inst_id] : comp->inst_id;
+ next_inst_id = dl_next_port ? dl_next_port->link_ids[next->inst_id] : next->inst_id;
+
+ mtk_mmsys_hw_disconnect(mmsys_dev, comp->type, comp_inst_id, next->type, next_inst_id);
+}
+
+int mtk_direct_link_clk_enable(struct mtk_ddp_comp *comp)
+{
+ struct mtk_disp_dl_port *dl_port = mtk_direct_link_get_port(comp);
+
+ return clk_prepare_enable(dl_port->clks[comp->inst_id]);
+}
+
+void mtk_direct_link_clk_disable(struct mtk_ddp_comp *comp)
+{
+ struct mtk_disp_dl_port *dl_port = mtk_direct_link_get_port(comp);
+
+ clk_disable_unprepare(dl_port->clks[comp->inst_id]);
+}
+
+void mtk_direct_link_config(struct mtk_ddp_comp *comp,
+ unsigned int w, unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_direct_link *dl_async = dev_get_drvdata(comp->dev);
+ struct mtk_disp_dl_port *dl_port;
+ u32 reg_offset;
+ u8 port_id;
+ u32 mask;
+ u32 val;
+
+ dl_port = mtk_direct_link_get_port(comp);
+ if (!dl_port) {
+ dev_err(comp->dev, "Could not get DirectLink port.\n");
+ return;
+ }
+
+ /* DL_IN or DL_OUT */
+ if (comp->type == MTK_DISP_DIRECT_LINK_OUT)
+ reg_offset = dl_async->data->dlo0_size_reg;
+ else
+ reg_offset = dl_async->data->dli0_size_reg;
+
+ port_id = dl_port->link_ids[comp->inst_id];
+ reg_offset += port_id * MTK_DL_INOUT_REG_WIDTH;
+
+ mask = MTK_DISP_DL_RELAY_WIDTH | MTK_DISP_DL_RELAY_HEIGHT;
+ val = FIELD_PREP(MTK_DISP_DL_RELAY_WIDTH, w);
+ val |= FIELD_PREP(MTK_DISP_DL_RELAY_HEIGHT, h);
+
+ if (dl_async->data->pixels_per_iter) {
+ val |= FIELD_PREP(MTK_DISP_DL_IN_RELAY_PIXITER, dl_async->data->pixels_per_iter);
+ mask |= MTK_DISP_DL_IN_RELAY_PIXITER;
+ }
+
+ mtk_ddp_write_mask(NULL, val, &dl_async->cmdq_reg, dl_async->regs,
+ reg_offset, mask);
+
+ return;
+}
+
+static int mtk_direct_link_bind(struct device *dev, struct device *master, void *data)
+{
+ struct mtk_direct_link *dl_async = dev_get_drvdata(dev);
+
+ return clk_prepare_enable(dl_async->clk);
+}
+
+static void mtk_direct_link_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct mtk_direct_link *dl_async = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(dl_async->clk);
+}
+
+static const struct component_ops mtk_direct_link_component_ops = {
+ .bind = mtk_direct_link_bind,
+ .unbind = mtk_direct_link_unbind,
+};
+
+static int mtk_direct_link_port_probe(struct device *dev, struct mtk_disp_dl_port *dl_port, u32 of_port_id)
+{
+ struct device_node *node = dev->of_node;
+ struct device_node *of_port;
+ struct clk **clks;
+ u8 *link_ids;
+ u8 num_links = 0;
+ u8 i;
+
+ /*
+ * HW Port IDs: 0=DL_IN, 1=DL_OUT, 2=DL_IN_RELAY, 3=DL_OUT_RELAY
+ *
+ * Relay ports are currently not handled here because at the time of
+ * writing those share configurations with the DL_IN/DL_OUT ports and
+ * they don't need any special and/or extra configuration.
+ *
+ * Since port 2/3 do actually exist, those are handled gracefully, but
+ * anything greater doesn't exist, so has to return an error.
+ */
+ if (of_port_id > 3)
+ return dev_err_probe(dev, -EINVAL, "Port %d out of range", of_port_id);
+ else if (of_port_id > 1)
+ return 0;
+
+ of_port = of_graph_get_port_by_id(node, of_port_id);
+ if (!of_port)
+ return -ENOENT;
+
+ for_each_of_graph_port_endpoint(of_port, ep)
+ num_links++;
+
+ clks = devm_kcalloc(dev, num_links, sizeof(*clks), GFP_KERNEL);
+ if (!clks)
+ return -ENOMEM;
+
+ link_ids = devm_kcalloc(dev, num_links, sizeof(*link_ids), GFP_KERNEL);
+ if (!link_ids)
+ return -ENOMEM;
+
+ i = 0;
+ for_each_of_graph_port_endpoint(of_port, ep) {
+ struct of_endpoint endpoint;
+ u32 hw_port_id;
+ int ret;
+
+ ret = of_graph_parse_endpoint(ep, &endpoint);
+ if (ret)
+ continue;
+
+ ret = of_property_read_u32(ep, "mediatek,port-id", &hw_port_id);
+ link_ids[i] = ret ? endpoint.id : hw_port_id;
+ clks[i] = devm_get_clk_from_child(dev, ep, NULL);
+ if (IS_ERR(clks[i])) {
+ return dev_err_probe(dev, PTR_ERR(clks[i]),
+ "Could not get clock\n");
+ }
+ i++;
+ }
+ dl_port->clks = clks;
+ dl_port->link_ids = link_ids;
+ dl_port->num_links = num_links;
+
+ return 0;
+}
+
+static int mtk_direct_link_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *main_node = dev->of_node;
+ struct mtk_direct_link *dl_async;
+ int in_mtx_id, out_mtx_id;
+ unsigned int num_ports;
+ int i, ret;
+
+ dl_async = devm_kzalloc(dev, sizeof(*dl_async), GFP_KERNEL);
+ if (!dl_async)
+ return -ENOMEM;
+
+ dl_async->data = device_get_match_data(dev);
+
+ dl_async->regs = of_iomap(dev->of_node, 0);
+ if (IS_ERR(dl_async->regs))
+ return dev_err_probe(&pdev->dev, PTR_ERR(dl_async->regs),
+ "Could not get regs\n");
+
+ num_ports = of_graph_get_port_count(main_node);
+ if (num_ports == 0)
+ return dev_err_probe(dev, -ENOENT, "No Input/Output ports found.\n");
+
+ /*
+ * Get the Trigger ID for DL_IN_0 and for DL_OUT_0, as all of the other
+ * HW ports have linearly increasing IDs.
+ */
+ in_mtx_id = mtk_ddp_comp_get_mutex_trigger(main_node, MTK_DISP_DL_IN);
+ out_mtx_id = mtk_ddp_comp_get_mutex_trigger(main_node, MTK_DISP_DL_OUT);
+ switch (num_ports) {
+ default:
+ /* fallthrough */
+ case 2:
+ if (in_mtx_id && out_mtx_id) {
+ ret = 0;
+ break;
+ }
+
+ ret = in_mtx_id < 0 ? in_mtx_id : out_mtx_id;
+ break;
+ case 1:
+ if (in_mtx_id || out_mtx_id) {
+ if (in_mtx_id < 0)
+ in_mtx_id = 0;
+ if (out_mtx_id < 0)
+ out_mtx_id = 0;
+
+ ret = 0;
+ break;
+ }
+
+ ret = in_mtx_id < 0 ? in_mtx_id : out_mtx_id;
+ break;
+ }
+
+ if (ret)
+ return dev_err_probe(dev, ret, "Could not get %s port 0 trigger ID\n",
+ in_mtx_id < 0 ? "input" : "output");
+
+ if (in_mtx_id > U8_MAX || out_mtx_id > U8_MAX)
+ return dev_err_probe(dev, -EINVAL, "Implausible trigger ID found\n");
+
+ /* IDs are now validated and safe to assign */
+ dl_async->dl_port[MTK_DISP_DL_IN].p0_mtx_trig_id = in_mtx_id;
+ dl_async->dl_port[MTK_DISP_DL_OUT].p0_mtx_trig_id = out_mtx_id;
+
+ i = 0;
+ for_each_of_graph_port(main_node, port_node) {
+ u32 port_id;
+
+ of_property_read_u32(port_node, "reg", &port_id);
+ if (port_id > 1)
+ continue;
+
+ ret = mtk_direct_link_port_probe(dev, &dl_async->dl_port[i], port_id);
+ if (ret)
+ return ret;
+
+ i++;
+ }
+
+ dl_async->clk = devm_clk_get(dev, 0);
+ if (IS_ERR(dl_async->clk))
+ return dev_err_probe(dev, PTR_ERR(dl_async->clk),
+ "Could not get config clock\n");
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ ret = cmdq_dev_get_client_reg(dev, &dl_async->cmdq_reg, 0);
+ if (ret)
+ dev_dbg(dev, "get mediatek,gce-client-reg fail!\n");
+#endif
+
+ platform_set_drvdata(pdev, dl_async);
+
+ ret = component_add(dev, &mtk_direct_link_component_ops);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add component\n");
+
+ dev_info(&pdev->dev, "Found %u HW Inputs and %u HW Outputs\n",
+ dl_async->dl_port[0].num_links, dl_async->dl_port[1].num_links);
+
+ return 0;
+}
+
+static void mtk_direct_link_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &mtk_direct_link_component_ops);
+}
+
+static const struct mtk_direct_link_data mt8196_disp_dl_async_data = {
+ .dli0_size_reg = MTK_DISP_REG_DL_IN_ASYNC0_SIZE_MT8196,
+ .dlo0_size_reg = MTK_DISP_REG_DL_OUT_ASYNC0_SIZE_MT8196,
+ .pixels_per_iter = MTK_DISP_DL_IN_RELAY_1T2P,
+};
+
+static const struct mtk_direct_link_data mt8196_ovl_dl_async_data = {
+ .dli0_size_reg = MTK_OVL_REG_DL_IN_RELAY0_SIZE_MT8196,
+ .dlo0_size_reg = MTK_OVL_REG_DL_OUT_RELAY0_SIZE_MT8196,
+};
+
+static const struct of_device_id mtk_direct_link_driver_dt_match[] = {
+ { .compatible = "mediatek,mt8196-disp-direct-link", .data = &mt8196_disp_dl_async_data },
+ { .compatible = "mediatek,mt8196-ovl-direct-link", .data = &mt8196_ovl_dl_async_data },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mtk_direct_link_driver_dt_match);
+
+struct platform_driver mtk_direct_link_driver = {
+ .probe = mtk_direct_link_probe,
+ .remove = mtk_direct_link_remove,
+ .driver = {
+ .name = "mediatek-disp-direct-link",
+ .of_match_table = mtk_direct_link_driver_dt_match,
+ },
+};
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("MediaTek Display Controller Direct Link Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index 7b16f46ce9e2..f78f12da08a8 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -59,6 +59,18 @@ void mtk_color_config(struct mtk_ddp_comp *comp, unsigned int w,
unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
void mtk_color_start(struct device *dev);
+void mtk_direct_link_connect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next);
+void mtk_direct_link_disconnect(struct mtk_ddp_comp *comp, struct device *mmsys_dev,
+ struct mtk_ddp_comp *next);
+int mtk_direct_link_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_direct_link_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_direct_link_config(struct mtk_ddp_comp *comp,
+ unsigned int w, unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+void mtk_direct_link_mtx_remove(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex);
+void mtk_direct_link_add(struct mtk_ddp_comp *comp, struct mtk_mutex *mutex);
+
void mtk_dither_set_common(void __iomem *regs, struct cmdq_client_reg *cmdq_reg,
unsigned int bpc, unsigned int cfg,
unsigned int dither_en, struct cmdq_pkt *cmdq_pkt);
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 3bee730cd34f..482d05071125 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -251,7 +251,8 @@ static bool mtk_drm_find_mmsys_comp(struct mtk_drm_private *private,
for (j = 0; j < output_path->len; j++) {
if (output_path->comp[j].type != type ||
- output_path->comp[j].inst_id != inst_id)
+ (inst_id != MTK_DISP_CONTROLLER_MAX_HW_COMP_INSTANCE &&
+ output_path->comp[j].inst_id != inst_id))
continue;
return true;
@@ -267,6 +268,19 @@ static bool mtk_drm_find_mmsys_comp(struct mtk_drm_private *private,
return false;
}
+static bool mtk_drm_find_directlink_comp(struct mtk_drm_private *private)
+{
+ if (mtk_drm_find_mmsys_comp(private, MTK_DISP_DIRECT_LINK_IN,
+ MTK_DISP_CONTROLLER_MAX_HW_COMP_INSTANCE))
+ return true;
+
+ if (mtk_drm_find_mmsys_comp(private, MTK_DISP_DIRECT_LINK_OUT,
+ MTK_DISP_CONTROLLER_MAX_HW_COMP_INSTANCE))
+ return true;
+
+ return false;
+}
+
static struct mtk_drm_private *
mtk_drm_find_matching_controller(struct mtk_drm_private **all_drm_private,
struct device_node *target_node)
@@ -607,6 +621,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_COLOR },
{ .compatible = "mediatek,mt8173-disp-color",
.data = (void *)MTK_DISP_COLOR },
+ { .compatible = "mediatek,mt8196-disp-direct-link",
+ .data = (void *)MTK_DISP_DIRECT_LINK },
{ .compatible = "mediatek,mt8167-disp-dither",
.data = (void *)MTK_DISP_DITHER },
{ .compatible = "mediatek,mt8183-disp-dither",
@@ -689,6 +705,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_WDMA },
{ .compatible = "mediatek,mt8173-disp-wdma",
.data = (void *)MTK_DISP_WDMA },
+ { .compatible = "mediatek,mt8196-ovl-direct-link",
+ .data = (void *)MTK_DISP_DIRECT_LINK },
{ .compatible = "mediatek,mt2701-dpi",
.data = (void *)MTK_DISP_DPI },
{ .compatible = "mediatek,mt8167-dsi",
@@ -794,10 +812,27 @@ static int mtk_drm_of_get_first_input(struct device *dev, struct device_node *no
if (ret)
return -ENOENT;
- inst_id = mtk_ddp_comp_get_id(ep_dev_node, comp_type);
+ inst_id = mtk_ddp_comp_get_id(ep_dev_node, ep_in, comp_type);
if (inst_id < 0)
return inst_id;
+ if (comp_type == MTK_DISP_DIRECT_LINK) {
+ struct device_node *remote_port = of_graph_get_remote_port(ep_in);
+
+ /* If there's a remote port this input is active, otherwise it's unused */
+ if (!remote_port)
+ return -ENOENT;
+ of_node_put(remote_port);
+
+ /* All even ports describe inputs, all odd ports describe outputs */
+ comp_type = (crtc_endpoint + 1) % 2 ?
+ MTK_DISP_DIRECT_LINK_IN : MTK_DISP_DIRECT_LINK_OUT;
+
+ dev_dbg(dev, "Found First DirectLink %s with port %pOF and ID %u\n",
+ comp_type == MTK_DISP_DIRECT_LINK_OUT ? "OUT" : "IN",
+ ep_in, crtc_endpoint);
+ }
+
/* All ok! Pass the Component ID to the caller. */
comp_def->type = comp_type;
comp_def->inst_id = inst_id;
@@ -838,7 +873,7 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device *dev, struct device_node *nod
struct mtk_drm_comp_definition *comp_def,
bool controller_arch_v2)
{
- struct device_node *ep_dev_node, *ep_out;
+ struct device_node *ep_dev_node, *ep_out, *remote_ep;
enum mtk_ddp_comp_type comp_type;
int ret;
@@ -846,10 +881,16 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device *dev, struct device_node *nod
if (!ep_out)
return -EINVAL;
- ep_dev_node = of_graph_get_remote_port_parent(ep_out);
+ remote_ep = of_graph_get_remote_endpoint(ep_out);
of_node_put(ep_out);
- if (!ep_dev_node)
+ if (!remote_ep)
+ return -ENOENT;
+
+ ep_dev_node = of_graph_get_port_parent(remote_ep);
+ if (!ep_dev_node) {
+ of_node_put(remote_ep);
return -EINVAL;
+ };
/*
* Pass the next node pointer regardless of failures in the later code
@@ -867,17 +908,20 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device *dev, struct device_node *nod
dev_dbg(dev, "Found connection to external mmsys %pOF\n",
rmt_ctrlr_node);
- of_node_put(ep_dev_node);
of_node_put(rmt_ctrlr_node);
+ of_node_put(remote_ep);
return -EREMOTE;
}
}
- if (!of_device_is_available(ep_dev_node))
+ if (!of_device_is_available(ep_dev_node)) {
+ of_node_put(remote_ep);
return -ENODEV;
+ }
ret = mtk_drm_of_get_ddp_comp_type(ep_dev_node, &comp_type);
if (ret) {
+ of_node_put(remote_ep);
if (mtk_ovl_adaptor_is_comp_present(ep_dev_node)) {
comp_def->type = MTK_DISP_OVL_ADAPTOR;
comp_def->inst_id = 0;
@@ -887,10 +931,26 @@ static int mtk_drm_of_get_ddp_ep_cid(struct device *dev, struct device_node *nod
return ret;
}
- ret = mtk_ddp_comp_get_id(ep_dev_node, comp_type);
+ ret = mtk_ddp_comp_get_id(ep_dev_node, remote_ep, comp_type);
+ of_node_put(remote_ep);
if (ret < 0)
return ret;
+ if (comp_type == MTK_DISP_DIRECT_LINK) {
+ struct device_node *remote_port = of_graph_get_remote_port(ep_out);
+ u32 port_id;
+
+ of_property_read_u32(remote_port, "reg", &port_id);
+ of_node_put(remote_port);
+
+ /* All even ports describe inputs, all odd ports describe outputs */
+ comp_type = (port_id + 1) % 2 ? MTK_DISP_DIRECT_LINK_IN : MTK_DISP_DIRECT_LINK_OUT;
+
+ dev_dbg(dev, "Found DirectLink %s with port %pOF and ID %u\n",
+ comp_type == MTK_DISP_DIRECT_LINK_OUT ? "OUT" : "IN",
+ remote_port, port_id);
+ }
+
/* All ok! Pass the Component ID to the caller. */
comp_def->type = comp_type;
comp_def->inst_id = ret;
@@ -1007,6 +1067,22 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, struct device_node
ret = mtk_drm_of_get_ddp_ep_cid(dev, prev, 3, cpath, &next,
&temp_path[idx], controller_arch_v2);
of_node_put(prev);
+
+ /*
+ * Avoid recursion for special DL_IN/DL_OUT connections:
+ * 1. IN may be directly connected to OUT, expressing a RELAY
+ * internal connection, or
+ * 2. A component's OUT may be directly connected to an
+ * output of DirectLink, expressing a (rare) fixed connection.
+ */
+ for (int i = 1; i <= min(idx, 2); i++) {
+ if (temp_path[idx].type == temp_path[idx - i].type &&
+ temp_path[idx].inst_id == temp_path[idx - i].inst_id) {
+ ret = -ELOOP;
+ break;
+ }
+ }
+
if (ret) {
dev_vdbg(dev, "Invalid comp reached with result %d\n", ret);
of_node_put(next);
@@ -1037,6 +1113,8 @@ static int mtk_drm_of_ddp_path_build_one(struct device *dev, struct device_node
/* If the last entry is not a final display output, the configuration is wrong */
switch (temp_path[idx - 1].type) {
+ case MTK_DISP_DIRECT_LINK_IN:
+ case MTK_DISP_DIRECT_LINK_OUT:
case MTK_DISP_DP_INTF:
case MTK_DISP_DPI:
case MTK_DISP_DSI:
@@ -1190,8 +1268,13 @@ static int mtk_drm_probe(struct platform_device *pdev)
hash_init(private->hlist.ddp_list);
+ if (of_graph_is_present(phandle))
+ node = phandle;
+ else
+ node = of_find_node_by_name(phandle, "direct-link");
+
/* Try to build the display pipeline from devicetree graphs */
- if (of_graph_is_present(phandle)) {
+ if (node) {
dev_dbg(dev, "Building display pipeline for MMSYS %u\n",
mtk_drm_data->mmsys_id);
private->data = devm_kmemdup(dev, mtk_drm_data,
@@ -1199,7 +1282,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
if (!private->data)
return -ENOMEM;
- ret = mtk_drm_of_ddp_path_build(dev, phandle, private->data);
+ ret = mtk_drm_of_ddp_path_build(dev, node, private->data);
if (ret)
return ret;
} else {
@@ -1218,6 +1301,7 @@ static int mtk_drm_probe(struct platform_device *pdev)
for_each_child_of_node(phandle->parent, node) {
enum mtk_ddp_comp_type comp_type;
u8 comp_inst_id;
+ bool comp_found;
ret = mtk_drm_of_get_ddp_comp_type(node, &comp_type);
if (ret)
@@ -1240,14 +1324,20 @@ static int mtk_drm_probe(struct platform_device *pdev)
continue;
}
- comp_inst_id = mtk_ddp_comp_get_id(node, comp_type);
+ comp_inst_id = mtk_ddp_comp_get_id(node, NULL, comp_type);
if (comp_inst_id < 0) {
dev_warn(dev, "Skipping unknown component %pOF\n",
node);
continue;
}
- if (!mtk_drm_find_mmsys_comp(private, comp_type, comp_inst_id))
+ if (comp_type == MTK_DISP_DIRECT_LINK)
+ comp_found = mtk_drm_find_directlink_comp(private);
+ else
+ comp_found = mtk_drm_find_mmsys_comp(private,
+ comp_type, comp_inst_id);
+
+ if (!comp_found)
continue;
/*
@@ -1263,12 +1353,45 @@ static int mtk_drm_probe(struct platform_device *pdev)
node);
}
- ret = mtk_ddp_comp_init(dev, node, &private->hlist,
- private->data->mmsys_id,
- comp_type, comp_inst_id);
- if (ret) {
- of_node_put(node);
- goto err_node;
+ if (comp_type == MTK_DISP_DIRECT_LINK) {
+ for_each_of_graph_port(node, port) {
+ u32 port_id;
+
+ of_property_read_u32(port, "reg", &port_id);
+ if (port_id > 1)
+ continue;
+
+ /* Even ports are inputs, odd ports are outputs */
+ if (port_id % 2)
+ comp_type = MTK_DISP_DIRECT_LINK_OUT;
+
+ for_each_of_graph_port_endpoint(port, ep) {
+ struct of_endpoint of_ep;
+
+ ret = of_graph_parse_endpoint(ep, &of_ep);
+ if (ret)
+ break;
+
+ ret = mtk_ddp_comp_init(dev, node, &private->hlist,
+ private->data->mmsys_id,
+ comp_type, of_ep.id);
+ if (ret)
+ break;
+ }
+
+ if (ret) {
+ of_node_put(node);
+ goto err_node;
+ }
+ }
+ } else {
+ ret = mtk_ddp_comp_init(dev, node, &private->hlist,
+ private->data->mmsys_id,
+ comp_type, comp_inst_id);
+ if (ret) {
+ of_node_put(node);
+ goto err_node;
+ }
}
}
@@ -1361,6 +1484,7 @@ static struct platform_driver mtk_drm_platform_driver = {
};
static struct platform_driver * const mtk_drm_drivers[] = {
+ &mtk_direct_link_driver,
&mtk_disp_aal_driver,
&mtk_disp_blender_driver,
&mtk_disp_ccorr_driver,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index 3c403bc8f4fe..76325d1be5f4 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -74,6 +74,7 @@ struct mtk_drm_private {
struct mtk_drm_private **all_drm_private;
};
+extern struct platform_driver mtk_direct_link_driver;
extern struct platform_driver mtk_disp_aal_driver;
extern struct platform_driver mtk_disp_blender_driver;
extern struct platform_driver mtk_disp_ccorr_driver;
diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h
index a1c8a436b3dc..d6742ca39d86 100644
--- a/include/linux/soc/mediatek/mtk-mmsys.h
+++ b/include/linux/soc/mediatek/mtk-mmsys.h
@@ -91,6 +91,8 @@ enum mtk_ddp_comp_type {
MTK_DISP_BLENDER,
MTK_DISP_CCORR,
MTK_DISP_COLOR,
+ MTK_DISP_DIRECT_LINK_OUT,
+ MTK_DISP_DIRECT_LINK_IN,
MTK_DISP_DITHER,
MTK_DISP_DSC,
MTK_DISP_ETHDR_MIXER,
@@ -122,6 +124,8 @@ enum mtk_ddp_comp_type {
MTK_DDP_COMP_TYPE_MAX
};
+#define MTK_DISP_DIRECT_LINK MTK_DISP_DIRECT_LINK_IN
+
void mtk_mmsys_ddp_dpi_fmt_config(struct device *dev, u32 val);
void mtk_mmsys_merge_async_config(struct device *dev, int idx, int width,
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 36/42] drm/mediatek: Support registering disp controller device subnodes
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (34 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 35/42] drm/mediatek: Introduce MediaTek Asynchronous DirectLink Controller AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 37/42] soc: mediatek: mtk-mmsys: Populate multimedia subsystem subdevices AngeloGioacchino Del Regno
` (5 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
In order to have a correct description of the hardware in the SoC
devicetree, look for Display Controller Subsystem sub-components
declared as subnodes of the display controller itself; to retain
compatibility with the older devicetrees, also keep looking for
sub-components in the main /soc node like before.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 218 ++++++++++++++-----------
1 file changed, 121 insertions(+), 97 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 482d05071125..50b4f79295b3 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -1237,6 +1237,107 @@ static int mtk_drm_of_ddp_path_build(struct device *dev, struct device_node *nod
return 0;
}
+static int mtk_drm_register_sibling(struct device *dev, struct mtk_drm_private *private,
+ struct device_node *node, struct component_match **match)
+{
+ enum mtk_ddp_comp_type comp_type;
+ int comp_inst_id;
+ bool comp_found;
+ int ret;
+
+ ret = mtk_drm_of_get_ddp_comp_type(node, &comp_type);
+ if (ret)
+ return -EAGAIN;
+
+ ret = of_device_is_available(node);
+ if (!ret) {
+ dev_dbg(dev, "Skipping disabled component %pOF\n", node);
+ return -EAGAIN;
+ }
+
+ if (comp_type == MTK_DISP_MUTEX) {
+ int id;
+
+ id = of_alias_get_id(node, "mutex");
+ if (id < 0 || id == private->data->mmsys_id) {
+ private->mutex_node = of_node_get(node);
+ dev_dbg(dev, "get mutex for mmsys %d", private->data->mmsys_id);
+ }
+ return 0;
+ }
+
+ comp_inst_id = mtk_ddp_comp_get_id(node, NULL, comp_type);
+ if (comp_inst_id < 0) {
+ dev_info(dev, "Skipping unknown component %pOF\n", node);
+ return 0;
+ }
+
+ if (comp_type == MTK_DISP_DIRECT_LINK)
+ comp_found = mtk_drm_find_directlink_comp(private);
+ else
+ comp_found = mtk_drm_find_mmsys_comp(private,
+ comp_type, comp_inst_id);
+
+ if (!comp_found)
+ return -EAGAIN;
+
+ /*
+ * Currently only the AAL, CCORR, COLOR, GAMMA, MERGE, OVL, RDMA, DSI, and DPI
+ * blocks have separate component platform drivers and initialize their own
+ * DDP component structure. The others are initialized here.
+ */
+ if (!mtk_ddp_comp_is_internal_comp(comp_type) &&
+ !mtk_ovl_adaptor_is_comp_present(node)) {
+ dev_info(dev, "Adding component match for %pOF\n",
+ node);
+ drm_of_component_match_add(dev, match, component_compare_of,
+ node);
+ }
+
+ if (comp_type == MTK_DISP_DIRECT_LINK) {
+ for_each_of_graph_port(node, port) {
+ u32 port_id;
+
+ of_property_read_u32(port, "reg", &port_id);
+ if (port_id > 1)
+ continue;
+
+ /* Even ports are inputs, odd ports are outputs */
+ if (port_id % 2)
+ comp_type = MTK_DISP_DIRECT_LINK_OUT;
+
+ for_each_of_graph_port_endpoint(port, ep) {
+ struct of_endpoint of_ep;
+
+ ret = of_graph_parse_endpoint(ep, &of_ep);
+ if (ret)
+ break;
+
+ ret = mtk_ddp_comp_init(dev, node, &private->hlist,
+ private->data->mmsys_id,
+ comp_type, of_ep.id);
+ if (ret)
+ break;
+ }
+
+ if (ret) {
+ of_node_put(node);
+ return ret;
+ }
+ }
+ } else {
+ ret = mtk_ddp_comp_init(dev, node, &private->hlist,
+ private->data->mmsys_id,
+ comp_type, comp_inst_id);
+ if (ret) {
+ of_node_put(node);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
static int mtk_drm_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1298,107 +1399,29 @@ static int mtk_drm_probe(struct platform_device *pdev)
return -ENOMEM;
/* Iterate over sibling DISP function blocks */
- for_each_child_of_node(phandle->parent, node) {
- enum mtk_ddp_comp_type comp_type;
- u8 comp_inst_id;
- bool comp_found;
-
- ret = mtk_drm_of_get_ddp_comp_type(node, &comp_type);
- if (ret)
- continue;
-
- if (!of_device_is_available(node)) {
- dev_dbg(dev, "Skipping disabled component %pOF\n",
- node);
- continue;
- }
-
- if (comp_type == MTK_DISP_MUTEX) {
- int id;
-
- id = of_alias_get_id(node, "mutex");
- if (id < 0 || id == private->data->mmsys_id) {
- private->mutex_node = of_node_get(node);
- dev_dbg(dev, "get mutex for mmsys %d", private->data->mmsys_id);
- }
- continue;
- }
-
- comp_inst_id = mtk_ddp_comp_get_id(node, NULL, comp_type);
- if (comp_inst_id < 0) {
- dev_warn(dev, "Skipping unknown component %pOF\n",
- node);
- continue;
- }
-
- if (comp_type == MTK_DISP_DIRECT_LINK)
- comp_found = mtk_drm_find_directlink_comp(private);
- else
- comp_found = mtk_drm_find_mmsys_comp(private,
- comp_type, comp_inst_id);
-
- if (!comp_found)
- continue;
-
- /*
- * Currently only the AAL, CCORR, COLOR, GAMMA, MERGE, OVL, RDMA, DSI, and DPI
- * blocks have separate component platform drivers and initialize their own
- * DDP component structure. The others are initialized here.
- */
- if (!mtk_ddp_comp_is_internal_comp(comp_type) &&
- !mtk_ovl_adaptor_is_comp_present(node)) {
- dev_info(dev, "Adding component match for %pOF\n",
- node);
- drm_of_component_match_add(dev, &match, component_compare_of,
- node);
- }
-
- if (comp_type == MTK_DISP_DIRECT_LINK) {
- for_each_of_graph_port(node, port) {
- u32 port_id;
-
- of_property_read_u32(port, "reg", &port_id);
- if (port_id > 1)
- continue;
-
- /* Even ports are inputs, odd ports are outputs */
- if (port_id % 2)
- comp_type = MTK_DISP_DIRECT_LINK_OUT;
-
- for_each_of_graph_port_endpoint(port, ep) {
- struct of_endpoint of_ep;
-
- ret = of_graph_parse_endpoint(ep, &of_ep);
- if (ret)
- break;
-
- ret = mtk_ddp_comp_init(dev, node, &private->hlist,
- private->data->mmsys_id,
- comp_type, of_ep.id);
- if (ret)
- break;
- }
+ for_each_child_of_node(phandle, node) {
+ ret = mtk_drm_register_sibling(dev, private, node, &match);
+ if (ret && ret != -EAGAIN)
+ goto err_node;
+ }
- if (ret) {
- of_node_put(node);
- goto err_node;
- }
- }
- } else {
- ret = mtk_ddp_comp_init(dev, node, &private->hlist,
- private->data->mmsys_id,
- comp_type, comp_inst_id);
- if (ret) {
- of_node_put(node);
- goto err_node;
- }
- }
+ /*
+ * After the previous loop, it is expected to have all of the display
+ * controller sibling function blocks registered and added to the list.
+ *
+ * If nothing got registered this is a legacy devicetree with DISP
+ * siblings located under the /soc node instead of being children of
+ * the main Display Controller node.
+ */
+ for_each_child_of_node(phandle->parent, node) {
+ ret = mtk_drm_register_sibling(dev, private, node, &match);
+ if (ret && ret != -EAGAIN)
+ goto err_node;
}
if (!private->mutex_node) {
dev_err(dev, "Failed to find disp-mutex node\n");
- ret = -ENODEV;
- goto err_node;
+ return -ENODEV;
}
/* If mtk-mutex is not a trigger source, this is an old devicetree */
@@ -1425,7 +1448,8 @@ static int mtk_drm_probe(struct platform_device *pdev)
err_pm:
pm_runtime_disable(dev);
err_node:
- of_node_put(private->mutex_node);
+ if (private->mutex_node)
+ of_node_put(private->mutex_node);
return ret;
}
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 37/42] soc: mediatek: mtk-mmsys: Populate multimedia subsystem subdevices
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (35 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 36/42] drm/mediatek: Support registering disp controller device subnodes AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 38/42] dt-bindings: display: mediatek: Introduce MT8196 2D Sharpness Processor AngeloGioacchino Del Regno
` (4 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
The multimedia hardware subsystem contains all of the multimedia
related sub-devices, and that really is by hardware design, not
anything software related.
In order to allow specifying a correct description of the hardware
in devicetrees, add support for probing subdevices of multimedia
controllers, specified as subnodes.
Acked-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/soc/mediatek/mtk-mmsys.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c
index 24296ebcbae3..37f7c888e7e2 100644
--- a/drivers/soc/mediatek/mtk-mmsys.c
+++ b/drivers/soc/mediatek/mtk-mmsys.c
@@ -498,6 +498,13 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
return PTR_ERR(clks);
mmsys->clks_pdev = clks;
+ ret = devm_of_platform_populate(dev);
+ if (ret) {
+ dev_err(dev, "Failed to populate child devices: %d\n", ret);
+ platform_device_unregister(clks);
+ return ret;
+ }
+
if (mmsys->data->is_vppsys)
goto out_probe_done;
@@ -543,6 +550,11 @@ static const struct of_device_id of_match_mtk_mmsys[] = {
{ .compatible = "mediatek,mt8195-vdosys1", .data = &mt8195_vdosys1_driver_data },
{ .compatible = "mediatek,mt8195-vppsys0", .data = &mt8195_vppsys0_driver_data },
{ .compatible = "mediatek,mt8195-vppsys1", .data = &mt8195_vppsys1_driver_data },
+ { .compatible = "mediatek,mt8196-dispsys0", .data = &mt8196_dispsys0_driver_data },
+ { .compatible = "mediatek,mt8196-dispsys1", .data = &mt8196_dispsys1_driver_data },
+ { .compatible = "mediatek,mt8196-ovlsys0", .data = &mt8196_ovlsys0_driver_data },
+ { .compatible = "mediatek,mt8196-ovlsys1", .data = &mt8196_ovlsys1_driver_data },
+ { .compatible = "mediatek,mt8196-vdisp-ao", .data = &mt8196_vdisp_ao_driver_data },
{ .compatible = "mediatek,mt8365-mmsys", .data = &mt8365_mmsys_driver_data },
{ /* sentinel */ }
};
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 38/42] dt-bindings: display: mediatek: Introduce MT8196 2D Sharpness Processor
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (36 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 37/42] soc: mediatek: mtk-mmsys: Populate multimedia subsystem subdevices AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 14:23 ` Rob Herring (Arm)
2026-07-01 12:20 ` [PATCH 39/42] drm/mediatek: Add Two-Dimension Sharpness Processor (TDSHP) driver AngeloGioacchino Del Regno
` (3 subsequent siblings)
41 siblings, 1 reply; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Add documentation for the Two-Dimension Sharpness Processor, or
"TDSHP", found in many MediaTek SoCs including MT8196 and its
variants.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
.../mediatek/mediatek,mt8196-tdshp.yaml | 98 +++++++++++++++++++
1 file changed, 98 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-tdshp.yaml
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-tdshp.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-tdshp.yaml
new file mode 100644
index 000000000000..7aa176c788fc
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-tdshp.yaml
@@ -0,0 +1,98 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/mediatek/mediatek,mt8196-tdshp.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Display Two-Dimension Sharpness Processor (TDSHP)
+
+maintainers:
+ - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+ The MediaTek 2D Sharpness Processor (TDSHP) is responsible for performing
+ image sharpness adjustments/enhancements in a display pipeline.
+ This hardware block supports adjusting the luma and contour 2d histograms,
+ frequency weighting, luma-chroma gain and others, with adaptive weights.
+
+properties:
+ compatible:
+ - const: mediatek,mt8196-disp-tdshp
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+
+ required:
+ - port@0
+ - port@1
+
+ trigger-sources:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/mediatek,mt8196-clock.h>
+ #include <dt-bindings/power/mediatek,mt8196-power.h>
+
+ tdshp@321e0000 {
+ compatible = "mediatek,mt8196-disp-tdshp";
+ reg = <0x321e0000 0x1000>;
+ clocks = <&dispsys0 CLK_MM_DISP_TDSHP0>;
+ power-domains = <&hpm_hwv MT8196_POWER_DOMAIN_DIS0_DORMANT>;
+ trigger-sources = <&disp0_mutex 53>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&resizer0_out>;
+ };
+ };
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&ccorr0_in>;
+ };
+ };
+ };
+ };
+
+...
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 38/42] dt-bindings: display: mediatek: Introduce MT8196 2D Sharpness Processor
2026-07-01 12:20 ` [PATCH 38/42] dt-bindings: display: mediatek: Introduce MT8196 2D Sharpness Processor AngeloGioacchino Del Regno
@ 2026-07-01 14:23 ` Rob Herring (Arm)
0 siblings, 0 replies; 52+ messages in thread
From: Rob Herring (Arm) @ 2026-07-01 14:23 UTC (permalink / raw)
To: AngeloGioacchino Del Regno
Cc: linux-kernel, chunkuang.hu, matthias.bgg, mripard, jason-jh.lin,
kernel, devicetree, justin.yeh, simona, p.zabel, tzimmermann,
conor+dt, airlied, maarten.lankhorst, dri-devel, krzk+dt,
linux-mediatek, linux-arm-kernel
On Wed, 01 Jul 2026 14:20:53 +0200, AngeloGioacchino Del Regno wrote:
> Add documentation for the Two-Dimension Sharpness Processor, or
> "TDSHP", found in many MediaTek SoCs including MT8196 and its
> variants.
>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
> .../mediatek/mediatek,mt8196-tdshp.yaml | 98 +++++++++++++++++++
> 1 file changed, 98 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-tdshp.yaml
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-tdshp.yaml: ignoring, error in schema: properties: compatible
Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-tdshp.example.dtb: /example-0/tdshp@321e0000: failed to match any schema with compatible: ['mediatek,mt8196-disp-tdshp']
doc reference errors (make refcheckdocs):
See https://patchwork.kernel.org/project/devicetree/patch/20260701122057.19648-39-angelogioacchino.delregno@collabora.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 39/42] drm/mediatek: Add Two-Dimension Sharpness Processor (TDSHP) driver
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (37 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 38/42] dt-bindings: display: mediatek: Introduce MT8196 2D Sharpness Processor AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 40/42] dt-bindings: display: mediatek: Introduce MT8196 Image Resizer AngeloGioacchino Del Regno
` (2 subsequent siblings)
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
The MediaTek 2D Sharpness Processor (TDSHP) is responsible for
performing image sharpness adjustments/enhancements in a display
pipeline.
Even though this hardware block supports adjusting the luma and
contour 2D histograms, frequency weighting, luma-chroma gain and
others, this only introduces a basic configuration which allows
to bypass TDSHP processing in an effort to forward the data from
this block to others.
That is necessary because some components cannot be connected
directly in specific pipelines; for example, in MT8196/MT6991
pipelines, when Display Resizer (RSZ) and Color Correction (CCORR)
components are required, it is necessary to pass through TDSHP as
direct connection between RSZ and CCORR is not possible due to HW
limitations.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/Makefile | 1 +
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 10 ++
drivers/gpu/drm/mediatek/mtk_disp_drv.h | 8 ++
drivers/gpu/drm/mediatek/mtk_disp_tdshp.c | 167 ++++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 3 +
drivers/gpu/drm/mediatek/mtk_drm_drv.h | 1 +
include/linux/soc/mediatek/mtk-mmsys.h | 2 +
7 files changed, 192 insertions(+)
create mode 100644 drivers/gpu/drm/mediatek/mtk_disp_tdshp.c
diff --git a/drivers/gpu/drm/mediatek/Makefile b/drivers/gpu/drm/mediatek/Makefile
index e9478fa1a2ba..47ba6bc17d9e 100644
--- a/drivers/gpu/drm/mediatek/Makefile
+++ b/drivers/gpu/drm/mediatek/Makefile
@@ -15,6 +15,7 @@ mediatek-drm-y := mtk_crtc.o \
mtk_disp_ovl.o \
mtk_disp_ovl_adaptor.o \
mtk_disp_rdma.o \
+ mtk_disp_tdshp.o \
mtk_disp_wdma.o \
mtk_drm_drv.o \
mtk_drm_legacy.o \
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index 7e12ddffbe77..ea09af8d4705 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -414,6 +414,14 @@ static const struct mtk_ddp_comp_funcs ddp_rdma = {
.get_num_formats = mtk_rdma_get_num_formats,
};
+static const struct mtk_ddp_comp_funcs ddp_tdshp = {
+ .clk_enable = mtk_tdshp_clk_enable,
+ .clk_disable = mtk_tdshp_clk_disable,
+ .config = mtk_tdshp_config,
+ .start = mtk_tdshp_start,
+ .stop = mtk_tdshp_stop,
+};
+
static const struct mtk_ddp_comp_funcs ddp_wdma = {
.clk_enable = mtk_wdma_clk_enable,
.clk_disable = mtk_wdma_clk_disable,
@@ -481,6 +489,7 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_POSTMASK] = "postmask",
[MTK_DISP_PWM] = "pwm",
[MTK_DISP_RDMA] = "rdma",
+ [MTK_DISP_TDSHP] = "tdshp",
[MTK_DISP_UFOE] = "ufoe",
[MTK_DISP_WDMA] = "wdma",
[MTK_DISP_DP_INTF] = "dp-intf",
@@ -508,6 +517,7 @@ static const struct mtk_ddp_comp_funcs *mtk_ddp_funcs[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_POSTMASK] = &ddp_postmask,
[MTK_DISP_PWM] = NULL,
[MTK_DISP_RDMA] = &ddp_rdma,
+ [MTK_DISP_TDSHP] = &ddp_tdshp,
[MTK_DISP_UFOE] = &ddp_ufoe,
[MTK_DISP_WDMA] = &ddp_wdma,
[MTK_DISP_DPI] = &ddp_dpi,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_drv.h b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
index f78f12da08a8..0308094b29cd 100644
--- a/drivers/gpu/drm/mediatek/mtk_disp_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_disp_drv.h
@@ -243,6 +243,14 @@ void mtk_mdp_rdma_config(struct device *dev, struct mtk_mdp_rdma_cfg *cfg,
const u32 *mtk_mdp_rdma_get_formats(struct device *dev);
size_t mtk_mdp_rdma_get_num_formats(struct device *dev);
+int mtk_tdshp_clk_enable(struct mtk_ddp_comp *comp);
+void mtk_tdshp_clk_disable(struct mtk_ddp_comp *comp);
+void mtk_tdshp_config(struct mtk_ddp_comp *comp, unsigned int w,
+ unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt);
+void mtk_tdshp_start(struct device *dev);
+void mtk_tdshp_stop(struct device *dev);
+
int mtk_wdma_clk_enable(struct mtk_ddp_comp *comp);
void mtk_wdma_clk_disable(struct mtk_ddp_comp *comp);
void mtk_wdma_config(struct mtk_ddp_comp *comp, unsigned int width,
diff --git a/drivers/gpu/drm/mediatek/mtk_disp_tdshp.c b/drivers/gpu/drm/mediatek/mtk_disp_tdshp.c
new file mode 100644
index 000000000000..31f57c567137
--- /dev/null
+++ b/drivers/gpu/drm/mediatek/mtk_disp_tdshp.c
@@ -0,0 +1,167 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * MediaTek Two-Dimension Sharpness Processor (TDSHP)
+ *
+ * Copyright (c) 2025 MediaTek Inc.
+ * Copyright (c) 2026 Collabora Ltd.
+ * AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/soc/mediatek/mtk-cmdq.h>
+
+#include "mtk_disp_drv.h"
+#include "mtk_disp_ovl.h"
+#include "mtk_drm_drv.h"
+
+#define DISP_REG_TDSHP_EN 0x0000
+# define DISP_TDSHP_TDS_EN BIT(31)
+#define DISP_REG_TDSHP_CTRL 0x0100
+# define DISP_TDSHP_CTRL_EN BIT(0)
+# define DISP_TDSHP_PWR_SCL_EN BIT(2)
+#define DISP_REG_TDSHP_CFG 0x0110
+# define DISP_TDSHP_RELAY_MODE BIT(0)
+#define DISP_REG_TDSHP_INPUT_SIZE 0x0120
+#define DISP_REG_TDSHP_OUTPUT_OFFSET 0x0124
+#define DISP_REG_TDSHP_OUTPUT_SIZE 0x0128
+
+struct mtk_disp_tdshp {
+ void __iomem *regs;
+ struct clk *clk;
+ struct cmdq_client_reg cmdq_reg;
+};
+
+void mtk_tdshp_config(struct mtk_ddp_comp *comp, unsigned int w,
+ unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_disp_tdshp *tdshp = dev_get_drvdata(comp->dev);
+ u32 val = bpc == 8 ? DISP_TDSHP_PWR_SCL_EN : 0;
+
+ /* Set basic parameters to at least pass the data on */
+ mtk_ddp_write(cmdq_pkt, val | DISP_TDSHP_CTRL_EN, &tdshp->cmdq_reg,
+ tdshp->regs, DISP_REG_TDSHP_CTRL);
+
+ mtk_ddp_write(cmdq_pkt, w << 16 | h, &tdshp->cmdq_reg,
+ tdshp->regs, DISP_REG_TDSHP_INPUT_SIZE);
+ mtk_ddp_write(cmdq_pkt, w << 16 | h, &tdshp->cmdq_reg,
+ tdshp->regs, DISP_REG_TDSHP_OUTPUT_SIZE);
+ mtk_ddp_write(cmdq_pkt, 0x0, &tdshp->cmdq_reg,
+ tdshp->regs, DISP_REG_TDSHP_OUTPUT_OFFSET);
+
+ /* Set RELAY mode to bypass 2D Sharpness processing */
+ mtk_ddp_write(cmdq_pkt, DISP_TDSHP_RELAY_MODE, &tdshp->cmdq_reg,
+ tdshp->regs, DISP_REG_TDSHP_CFG);
+
+ mtk_ddp_write_mask(cmdq_pkt, DISP_TDSHP_TDS_EN, &tdshp->cmdq_reg,
+ tdshp->regs, DISP_REG_TDSHP_EN, DISP_TDSHP_TDS_EN);
+}
+
+void mtk_tdshp_start(struct device *dev)
+{
+ struct mtk_disp_tdshp *tdshp = dev_get_drvdata(dev);
+
+ writel(DISP_TDSHP_CTRL_EN, tdshp->regs + DISP_REG_TDSHP_CTRL);
+}
+
+void mtk_tdshp_stop(struct device *dev)
+{
+ struct mtk_disp_tdshp *tdshp = dev_get_drvdata(dev);
+
+ writel(0, tdshp->regs + DISP_REG_TDSHP_CTRL);
+}
+
+int mtk_tdshp_clk_enable(struct mtk_ddp_comp *comp)
+{
+ struct mtk_disp_tdshp *tdshp = dev_get_drvdata(comp->dev);
+
+ return clk_prepare_enable(tdshp->clk);
+}
+
+void mtk_tdshp_clk_disable(struct mtk_ddp_comp *comp)
+{
+ struct mtk_disp_tdshp *tdshp = dev_get_drvdata(comp->dev);
+
+ clk_disable_unprepare(tdshp->clk);
+}
+
+static int mtk_tdshp_bind(struct device *dev, struct device *master, void *data)
+{
+ return 0;
+}
+
+static void mtk_tdshp_unbind(struct device *dev, struct device *master, void *data)
+{
+}
+
+static const struct component_ops mtk_disp_tdshp_component_ops = {
+ .bind = mtk_tdshp_bind,
+ .unbind = mtk_tdshp_unbind,
+};
+
+static int mtk_disp_tdshp_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct mtk_disp_tdshp *tdshp;
+ int ret = 0;
+
+ tdshp = devm_kzalloc(dev, sizeof(*tdshp), GFP_KERNEL);
+ if (!tdshp)
+ return -ENOMEM;
+
+ tdshp->regs = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(tdshp->regs))
+ return dev_err_probe(dev, PTR_ERR(tdshp->regs), "Cannot get reg resource\n");
+
+ tdshp->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(tdshp->clk))
+ return dev_err_probe(dev, PTR_ERR(tdshp->clk), "Cannot get clocks\n");
+
+#if IS_REACHABLE(CONFIG_MTK_CMDQ)
+ ret = cmdq_dev_get_client_reg(dev, &tdshp->cmdq_reg, 0);
+ if (ret)
+ dev_dbg(dev, "No mediatek,gce-client-reg\n");
+#endif
+ platform_set_drvdata(pdev, tdshp);
+
+ ret = devm_pm_runtime_enable(dev);
+ if (ret)
+ return ret;
+
+ ret = component_add(dev, &mtk_disp_tdshp_component_ops);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add component\n");
+
+ return 0;
+}
+
+static void mtk_disp_tdshp_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &mtk_disp_tdshp_component_ops);
+}
+
+static const struct of_device_id mtk_disp_tdshp_driver_dt_match[] = {
+ { .compatible = "mediatek,mt8196-disp-tdshp", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mtk_disp_tdshp_driver_dt_match);
+
+struct platform_driver mtk_disp_tdshp_driver = {
+ .probe = mtk_disp_tdshp_probe,
+ .remove = mtk_disp_tdshp_remove,
+ .driver = {
+ .name = "mediatek-disp-tdshp",
+ .owner = THIS_MODULE,
+ .of_match_table = mtk_disp_tdshp_driver_dt_match,
+ },
+};
+
+MODULE_AUTHOR("AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>");
+MODULE_DESCRIPTION("MediaTek Display Controller 2D Sharpness Processor Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index 50b4f79295b3..b96cf2f435e5 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -699,6 +699,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_RDMA },
{ .compatible = "mediatek,mt8195-disp-rdma",
.data = (void *)MTK_DISP_RDMA },
+ { .compatible = "mediatek,mt8196-disp-tdshp",
+ .data = (void *)MTK_DISP_TDSHP },
{ .compatible = "mediatek,mt8173-disp-ufoe",
.data = (void *)MTK_DISP_UFOE },
{ .compatible = "mediatek,mt6893-disp-wdma",
@@ -1521,6 +1523,7 @@ static struct platform_driver * const mtk_drm_drivers[] = {
&mtk_disp_ovl_adaptor_driver,
&mtk_disp_ovl_driver,
&mtk_disp_rdma_driver,
+ &mtk_disp_tdshp_driver,
&mtk_disp_wdma_driver,
&mtk_dpi_driver,
&mtk_dvo_driver,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.h b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
index 76325d1be5f4..8bdd7f1017b9 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.h
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.h
@@ -87,6 +87,7 @@ extern struct platform_driver mtk_disp_outproc_driver;
extern struct platform_driver mtk_disp_ovl_adaptor_driver;
extern struct platform_driver mtk_disp_ovl_driver;
extern struct platform_driver mtk_disp_rdma_driver;
+extern struct platform_driver mtk_disp_tdshp_driver;
extern struct platform_driver mtk_disp_wdma_driver;
extern struct platform_driver mtk_dpi_driver;
extern struct platform_driver mtk_dsi_driver;
diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h
index d6742ca39d86..e33cb5b2638c 100644
--- a/include/linux/soc/mediatek/mtk-mmsys.h
+++ b/include/linux/soc/mediatek/mtk-mmsys.h
@@ -109,6 +109,8 @@ enum mtk_ddp_comp_type {
MTK_DISP_POSTMASK,
MTK_DISP_PWM,
MTK_DISP_RDMA,
+ MTK_DISP_RSZ,
+ MTK_DISP_TDSHP,
MTK_DISP_UFOE,
MTK_DISP_WDMA,
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 40/42] dt-bindings: display: mediatek: Introduce MT8196 Image Resizer
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (38 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 39/42] drm/mediatek: Add Two-Dimension Sharpness Processor (TDSHP) driver AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 14:23 ` Rob Herring (Arm)
2026-07-01 12:20 ` [PATCH 41/42] drm/mediatek: Add support for Display Image Resizer (Scaler) AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 42/42] drm/mediatek: mtk_drm_drv: Fail init only if all paths are invalid AngeloGioacchino Del Regno
41 siblings, 1 reply; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Add documentation for the Image Resizer "RSZ" Scaler block found
in the MT8196 SoC and its variants.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
.../display/mediatek/mediatek,mt8196-rsz.yaml | 97 +++++++++++++++++++
1 file changed, 97 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-rsz.yaml
diff --git a/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-rsz.yaml b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-rsz.yaml
new file mode 100644
index 000000000000..cf6b0ed08bfb
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-rsz.yaml
@@ -0,0 +1,97 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/mediatek/mediatek,mt8196-rsz.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Display Image Resizer (RSZ)
+
+maintainers:
+ - AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
+
+description:
+ The MediaTek Display Image Resizer (RSZ) is a high fidelity scaler block,
+ with filters and signal enhancers, responsible for performing downscaling
+ or upscaling of a frame.
+
+properties:
+ compatible:
+ - const: mediatek,mt8196-disp-rsz
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ power-domains:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+
+ required:
+ - port@0
+ - port@1
+
+ trigger-sources:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/clock/mediatek,mt8196-clock.h>
+ #include <dt-bindings/power/mediatek,mt8196-power.h>
+
+ scaler@329d0000 {
+ compatible = "mediatek,mt8196-disp-rsz";
+ reg = <0x329d0000 0x1000>;
+ clocks = <&ovlsys0 CLK_OVL_MDP_RSZ0>;
+ power-domains = <&hpm_hwv MT8196_POWER_DOMAIN_OVL0_DORMANT>;
+ trigger-sources = <&ovl0_mutex 26>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&ep_main_out>;
+ };
+ };
+
+ port@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&exdma0_2_in>;
+ };
+ };
+ };
+ };
+
+...
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* Re: [PATCH 40/42] dt-bindings: display: mediatek: Introduce MT8196 Image Resizer
2026-07-01 12:20 ` [PATCH 40/42] dt-bindings: display: mediatek: Introduce MT8196 Image Resizer AngeloGioacchino Del Regno
@ 2026-07-01 14:23 ` Rob Herring (Arm)
0 siblings, 0 replies; 52+ messages in thread
From: Rob Herring (Arm) @ 2026-07-01 14:23 UTC (permalink / raw)
To: AngeloGioacchino Del Regno
Cc: dri-devel, p.zabel, tzimmermann, justin.yeh, krzk+dt,
linux-kernel, linux-arm-kernel, kernel, mripard, chunkuang.hu,
maarten.lankhorst, conor+dt, matthias.bgg, linux-mediatek,
jason-jh.lin, devicetree, airlied, simona
On Wed, 01 Jul 2026 14:20:55 +0200, AngeloGioacchino Del Regno wrote:
> Add documentation for the Image Resizer "RSZ" Scaler block found
> in the MT8196 SoC and its variants.
>
> Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
> ---
> .../display/mediatek/mediatek,mt8196-rsz.yaml | 97 +++++++++++++++++++
> 1 file changed, 97 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-rsz.yaml
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-rsz.yaml: ignoring, error in schema: properties: compatible
Documentation/devicetree/bindings/display/mediatek/mediatek,mt8196-rsz.example.dtb: /example-0/scaler@329d0000: failed to match any schema with compatible: ['mediatek,mt8196-disp-rsz']
doc reference errors (make refcheckdocs):
See https://patchwork.kernel.org/project/devicetree/patch/20260701122057.19648-41-angelogioacchino.delregno@collabora.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH 41/42] drm/mediatek: Add support for Display Image Resizer (Scaler)
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (39 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 40/42] dt-bindings: display: mediatek: Introduce MT8196 Image Resizer AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
2026-07-01 12:20 ` [PATCH 42/42] drm/mediatek: mtk_drm_drv: Fail init only if all paths are invalid AngeloGioacchino Del Regno
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Add basic support for the Image Resizer hardware found in some
MediaTek Display Controller IPs, like the one found in MT8196.
This is currently set in bypass mode and used to pass the frame
buffer from a RSZ input component to supported RSZ outputs.
Full implementation of hardware-accelerated DRM scaling will be
done later.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_ddp_comp.c | 22 ++++++++++++++++++++++
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 2 ++
2 files changed, 24 insertions(+)
diff --git a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
index ea09af8d4705..453a4a9ad565 100644
--- a/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
+++ b/drivers/gpu/drm/mediatek/mtk_ddp_comp.c
@@ -56,6 +56,10 @@
#define POSTMASK_RELAY_MODE BIT(0)
#define DISP_REG_POSTMASK_SIZE 0x0030
+#define DISP_REG_RSZ_EN 0x0000
+#define DISP_REG_RSZ_INPUT_SIZE 0x0010
+#define DISP_REG_RSZ_OUTPUT_SIZE 0x0014
+
#define DISP_REG_UFO_START 0x0000
#define UFO_BYPASS BIT(2)
@@ -230,6 +234,16 @@ static void mtk_postmask_stop(struct device *dev)
writel_relaxed(0x0, priv->regs + DISP_REG_POSTMASK_EN);
}
+static void mtk_rsz_config(struct mtk_ddp_comp *comp, unsigned int w,
+ unsigned int h, unsigned int vrefresh,
+ unsigned int bpc, struct cmdq_pkt *cmdq_pkt)
+{
+ struct mtk_ddp_comp_dev *priv = dev_get_drvdata(comp->dev);
+
+ mtk_ddp_write(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs, DISP_REG_RSZ_INPUT_SIZE);
+ mtk_ddp_write(cmdq_pkt, 0, &priv->cmdq_reg, priv->regs, DISP_REG_RSZ_OUTPUT_SIZE);
+}
+
static void mtk_ufoe_start(struct device *dev)
{
struct mtk_ddp_comp_dev *priv = dev_get_drvdata(dev);
@@ -414,6 +428,12 @@ static const struct mtk_ddp_comp_funcs ddp_rdma = {
.get_num_formats = mtk_rdma_get_num_formats,
};
+static const struct mtk_ddp_comp_funcs ddp_rsz = {
+ .clk_enable = mtk_ddp_clk_enable,
+ .clk_disable = mtk_ddp_clk_disable,
+ .config = mtk_rsz_config,
+};
+
static const struct mtk_ddp_comp_funcs ddp_tdshp = {
.clk_enable = mtk_tdshp_clk_enable,
.clk_disable = mtk_tdshp_clk_disable,
@@ -489,6 +509,7 @@ static const char * const mtk_ddp_comp_stem[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_POSTMASK] = "postmask",
[MTK_DISP_PWM] = "pwm",
[MTK_DISP_RDMA] = "rdma",
+ [MTK_DISP_RSZ] = "resizer",
[MTK_DISP_TDSHP] = "tdshp",
[MTK_DISP_UFOE] = "ufoe",
[MTK_DISP_WDMA] = "wdma",
@@ -517,6 +538,7 @@ static const struct mtk_ddp_comp_funcs *mtk_ddp_funcs[MTK_DDP_COMP_TYPE_MAX] = {
[MTK_DISP_POSTMASK] = &ddp_postmask,
[MTK_DISP_PWM] = NULL,
[MTK_DISP_RDMA] = &ddp_rdma,
+ [MTK_DISP_RSZ] = &ddp_rsz,
[MTK_DISP_TDSHP] = &ddp_tdshp,
[MTK_DISP_UFOE] = &ddp_ufoe,
[MTK_DISP_WDMA] = &ddp_wdma,
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index b96cf2f435e5..f5c9fe1588d0 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -699,6 +699,8 @@ static const struct of_device_id mtk_ddp_comp_dt_ids[] = {
.data = (void *)MTK_DISP_RDMA },
{ .compatible = "mediatek,mt8195-disp-rdma",
.data = (void *)MTK_DISP_RDMA },
+ { .compatible = "mediatek,mt8196-disp-rsz",
+ .data = (void *)MTK_DISP_RSZ },
{ .compatible = "mediatek,mt8196-disp-tdshp",
.data = (void *)MTK_DISP_TDSHP },
{ .compatible = "mediatek,mt8173-disp-ufoe",
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread* [PATCH 42/42] drm/mediatek: mtk_drm_drv: Fail init only if all paths are invalid
2026-07-01 12:20 [PATCH 00/42] drm/mediatek: The Huge Restructuring and MT8196 support AngeloGioacchino Del Regno
` (40 preceding siblings ...)
2026-07-01 12:20 ` [PATCH 41/42] drm/mediatek: Add support for Display Image Resizer (Scaler) AngeloGioacchino Del Regno
@ 2026-07-01 12:20 ` AngeloGioacchino Del Regno
41 siblings, 0 replies; 52+ messages in thread
From: AngeloGioacchino Del Regno @ 2026-07-01 12:20 UTC (permalink / raw)
To: chunkuang.hu
Cc: p.zabel, airlied, simona, maarten.lankhorst, mripard, tzimmermann,
robh, krzk+dt, conor+dt, matthias.bgg, angelogioacchino.delregno,
dri-devel, linux-mediatek, devicetree, linux-kernel,
linux-arm-kernel, justin.yeh, jason-jh.lin, kernel
Up until now, if not all display controller paths were valid, the
driver would fail probing and refuse to bind components: while
that was a good idea before, now that mediatek-drm gained much
more flexibility, it is finally possible to gracefully handle
this situation and register only the valid paths while leaving
the invalid ones unregistered, without any crash.
Count how many output paths are found, and then count how many
have failed probing: if there is at least one valid path, avoid
erroring out, so that at least some outputs will just work.
Of course, any path failing is not a clean situation and must be
resolved: in this case, function mtk_crtc_create() still prints
error messages so, even though some output works, that will not
go unnoticed, as a quick check in kmsg will show the errors that
made a certain path not to register.
Signed-off-by: AngeloGioacchino Del Regno <angelogioacchino.delregno@collabora.com>
---
drivers/gpu/drm/mediatek/mtk_drm_drv.c | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/mediatek/mtk_drm_drv.c b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
index f5c9fe1588d0..65a891815408 100644
--- a/drivers/gpu/drm/mediatek/mtk_drm_drv.c
+++ b/drivers/gpu/drm/mediatek/mtk_drm_drv.c
@@ -379,6 +379,8 @@ static int mtk_drm_kms_init(struct drm_device *drm)
struct mtk_drm_private *priv_n;
struct device *dma_dev = NULL;
struct drm_crtc *crtc;
+ int num_failed = 0;
+ int num_paths = 0;
int ret, i, j;
if (drm_firmware_drivers_only())
@@ -445,15 +447,29 @@ static int mtk_drm_kms_init(struct drm_device *drm)
if (!priv_n->data->output_paths[i].len)
continue;
+ num_paths++;
+
+ dev_vdbg(drm->dev,
+ "[CTRL%d-CRTC%d] Path Len:%d, Controller Order:%u\n",
+ j, i, priv_n->data->output_paths[i].len,
+ priv_n->data->output_paths[i].order);
+
ret = mtk_crtc_create(drm, i, j,
priv_n->data->conn_routes,
priv_n->data->num_conn_routes);
+ if (ret == 0)
+ break;
- if (ret)
- goto err_component_unbind;
+ num_failed++;
}
}
+ if (num_failed == num_paths) {
+ dev_err(drm->dev, "No valid Display Controller path! Going out.\n");
+ ret = -ENODEV;
+ goto err_component_unbind;
+ }
+
/* IGT will check if the cursor size is configured */
drm->mode_config.cursor_width = 512;
drm->mode_config.cursor_height = 512;
--
2.54.0
^ permalink raw reply related [flat|nested] 52+ messages in thread