[PATCH 29/42] drm/mediatek: Add support for Display Controller exDMA component
AngeloGioacchino Del Regno
angelogioacchino.delregno at collabora.com
Wed Jul 1 05:20:44 PDT 2026
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 at 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 at 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 at collabora.com>");
+MODULE_AUTHOR("Nancy Lin <nancy.lin at 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
More information about the linux-arm-kernel
mailing list