[PATCH v2 06/15] soc: mediatek: add mmsys support for MT8196

paul-pl.chen posted 15 patches 9 months ago
There is a newer version of this series
[PATCH v2 06/15] soc: mediatek: add mmsys support for MT8196
Posted by paul-pl.chen 9 months ago
From: Nancy Lin <nancy.lin@mediatek.com>

1. Defining driver data and adding compatible string
for different subsystems
(DISPSYS0, DISPSYS1, OVLSYS0, OVLSYS1, VDISP_AO)
2. Adding functions to control top clocks and ddp clocks.
3. Updating the probe function to initialize clocks and
enable runtime PM if its node has the power-domains property.
4. Adding functions to configure ddp components and
set default configurations.
5. Adding the routing table for each mmsys in MT8196.

Signed-off-by: Nancy Lin <nancy.lin@mediatek.com>
Signed-off-by: Paul-pl Chen <paul-pl.chen@mediatek.com>
---
 drivers/soc/mediatek/mt8196-mmsys.h    | 451 +++++++++++++++++++++++++
 drivers/soc/mediatek/mtk-mmsys.c       | 203 ++++++++++-
 drivers/soc/mediatek/mtk-mmsys.h       |  18 +
 include/linux/soc/mediatek/mtk-mmsys.h |  60 ++++
 4 files changed, 731 insertions(+), 1 deletion(-)
 create mode 100644 drivers/soc/mediatek/mt8196-mmsys.h

diff --git a/drivers/soc/mediatek/mt8196-mmsys.h b/drivers/soc/mediatek/mt8196-mmsys.h
new file mode 100644
index 000000000000..ff841ae9939a
--- /dev/null
+++ b/drivers/soc/mediatek/mt8196-mmsys.h
@@ -0,0 +1,451 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Nancy Lin <nancy.lin@mediatek.com>
+ */
+
+#ifndef __SOC_MEDIATEK_MT8196_MMSYS_H
+#define __SOC_MEDIATEK_MT8196_MMSYS_H
+
+/* DISPSYS1 */
+#define MT8196_COMP_OUT_CB6_MOUT_EN			0xd30
+#define MT8196_DISP_SPLITTER_OUT_CB_TO_MERGE_OUT_CB0		BIT(0)
+#define MT8196_COMP_OUT_CB7_MOUT_EN			0xd38
+#define MT8196_DISP_SPLITTER_OUT_CB_TO_MERGE_OUT_CB1		BIT(1)
+#define MT8196_COMP_OUT_CB8_MOUT_EN			0xd40
+#define MT8196_DISP_SPLITTER_OUT_CB_TO_MERGE_OUT_CB2		BIT(2)
+#define MT8196_MERGE_OUT_CB0_MOUT_EN			0xdcc
+#define MT8196_DISP_COMP_OUT_CB_TO_DVO0				BIT(9)
+#define MT8196_MERGE_OUT_CB1_MOUT_EN			0xdd4
+#define MT8196_MERGE_OUT_CB2_MOUT_EN			0xddc
+#define MT8196_DISP_COMP_OUT_CB_TO_DSI0				BIT(0)
+#define MT8196_DISP_COMP_OUT_CB_TO_DP_INTF0			BIT(10)
+#define MT8196_DISP_COMP_OUT_CB_TO_DP_INTF1			BIT(11)
+#define MT8196_SPLITTER_IN_CB1_MOUT_EN			0xeac
+#define MT8196_DISP_DLI_RELAY_TO_SPLITTER_OUT_CB9		BIT(5)
+#define MT8196_SPLITTER_IN_CB2_MOUT_EN			0xeb4
+#define MT8196_DISP_DLI_RELAY_TO_SPLITTER_OUT_CB10		BIT(6)
+#define MT8196_SPLITTER_IN_CB3_MOUT_EN			0xebc
+#define MT8196_DISP_DLI_RELAY_TO_SPLITTER_OUT_CB11		BIT(7)
+#define MT8196_SPLITTER_OUT_CB9_MOUT_EN			0xf64
+#define MT8196_DISP_SPLITTER_IN_CB_TO_COMP_OUT_CB6		BIT(10)
+#define MT8196_SPLITTER_OUT_CB10_MOUT_EN		0xf6c
+#define MT8196_DISP_SPLITTER_IN_CB_TO_COMP_OUT_CB7		BIT(11)
+#define MT8196_SPLITTER_OUT_CB11_MOUT_EN		0xf74
+#define MT8196_DISP_SPLITTER_IN_CB_TO_COMP_OUT_CB8		BIT(12)
+#define MT8196_OVL_RSZ_IN_CB2_MOUT_EN			0xf70
+#define MT8196_DISP_OVL_EXDMA2_1_TO_OVL_EXDMA_OUT_CB3		BIT(1)
+
+/* OVLSYS */
+#define MT8196_OVL_BLENDER_OUT_CB4_MOUT_EN		0xe10
+#define MT8196_OVL_BLENDER_OUT_CB8_MOUT_EN		0xe20
+#define MT8196_DISP_OUT_BLENDER_CB_TO_OVL_OUTPROC0		BIT(0)
+#define MT8196_DISP_OUT_BLENDER_CB_TO_OVL_OUTPROC1		BIT(1)
+#define MT8196_DISP_OUT_BLENDER_CB_TO_OVL_OUTPROC2		BIT(2)
+#define MT8196_OVL_EXDMA_OUT_CB2_MOUT_EN		0xe60
+#define MT8196_OVL_EXDMA_OUT_CB3_MOUT_EN		0xe68
+#define MT8196_OVL_EXDMA_OUT_CB4_MOUT_EN		0xe70
+#define MT8196_OVL_EXDMA_OUT_CB5_MOUT_EN		0xe78
+#define MT8196_OVL_EXDMA_OUT_CB6_MOUT_EN		0xe80
+#define MT8196_OVL_EXDMA_OUT_CB7_MOUT_EN		0xe88
+#define MT8196_OVL_EXDMA_OUT_CB8_MOUT_EN		0xe90
+#define MT8196_OVL_EXDMA_OUT_CB9_MOUT_EN		0xe98
+#define MT8196_OVL_EXDMA_OUT_CB10_MOUT_EN		0xea0
+#define MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER1		BIT(2)
+#define MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER2		BIT(3)
+#define MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER3		BIT(4)
+#define MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER4		BIT(5)
+#define MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER5		BIT(6)
+#define MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER6		BIT(7)
+#define MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER7		BIT(8)
+#define MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER8		BIT(9)
+#define MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER9		BIT(10)
+#define MT8196_OVL_OUTPROC_OUT_CB0_MOUT_EN		0xf10
+#define MT8196_OVL_OUTPROC_OUT_CB1_MOUT_EN		0xf14
+#define MT8196_OVL_OUTPROC_OUT_CB2_MOUT_EN		0xf18
+#define MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY5		BIT(0)
+#define MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY6		BIT(1)
+#define MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY7		BIT(2)
+
+/* DISPSYS0 */
+#define MT8196_PANEL_COMP_OUT_CB1_MOUT_EN		0xd84
+#define MT8196_DISP_TO_DLO_RELAY1				BIT(1)
+#define MT8196_PANEL_COMP_OUT_CB2_MOUT_EN		0xd88
+#define MT8196_DISP_TO_DLO_RELAY2				BIT(2)
+#define MT8196_PANEL_COMP_OUT_CB3_MOUT_EN		0xd8c
+#define MT8196_DISP_TO_DLO_RELAY3				BIT(3)
+#define MT8196_PQ_IN_CB0_MOUT_EN			0xdd0
+#define MT8196_PQ_IN_CB0_TO_PQ_OUT_CB_6				BIT(2)
+
+#define MT8196_PQ_IN_CB1_MOUT_EN			0xdd4
+#define MT8196_PQ_IN_CB1_TO_PQ_OUT_CB_7				BIT(3)
+#define MT8196_PQ_IN_CB8_MOUT_EN			0xdf0
+#define MT8196_PQ_IN_CB8_TO_PQ_OUT_CB_8				BIT(4)
+#define MT8196_PQ_OUT_CB6_MOUT_EN			0xe54
+#define MT8196_PQ_OUT_CB6_TO_PANEL0_COMP_OUT_CB1		BIT(1)
+#define MT8196_PQ_OUT_CB7_MOUT_EN			0xe58
+#define MT8196_PQ_OUT_CB7_TO_PANEL0_COMP_OUT_CB2		BIT(2)
+#define MT8196_PQ_OUT_CB8_MOUT_EN			0xe5c
+#define MT8196_PQ_OUT_CB8_TO_PANEL0_COMP_OUT_CB3		BIT(3)
+
+/* OVLSYS config */
+#define MT8196_OVL_INT_MERGE				0x008
+#define MT8196_OVL_DL_OUT_RELAY5_SIZE			0x29c
+#define MT8196_OVL_DL_OUT_RELAY6_SIZE			0x2a0
+#define MT8196_OVLSYS_GCE_EVENT_SEL			0x408
+#define MT8196_OVLSYS_BYPASS_MUX_SHADOW			0xca0
+#define MT8196_OVLSYS_CB_CON				0xcac
+#define MT8196_CB_BYPASS_MUX_SHADOW				(0xff << 16)
+#define MT8196_EVENT_GCE_EN					(BIT(0) | BIT(1))
+
+/* DISPSYS config */
+#define MT8196_DISP0_DLI_RELAY0				0x200
+#define MT8196_DISP0_DLI_RELAY1				0x204
+#define MT8196_DISP0_DLI_RELAY8				0x220
+#define MT8196_DISP0_DLO_RELAY1				0x268
+#define MT8196_DISP0_DLO_RELAY2				0x26c
+#define MT8196_DISP0_DLO_RELAY3				0x270
+#define MT8196_DLI_RELAY_1T2P					BIT(30)
+#define MT8196_DISP0_BYPASS_MUX_SHADOW			0xc30
+#define MT8196_BYPASS_MUX_SHADOW				BIT(0)
+#define MT8196_OVLSYS_CB_BYPASS_MUX_SHADOW			(0xff << 16)
+
+/* DISPSYS1 config */
+#define MT8196_DISP1_INT_MERGE				0x008
+#define MT8196_DISP1_DLI_RELAY21			0x204
+#define MT8196_DISP1_DLI_RELAY22			0x208
+#define MT8196_DISP1_DLI_RELAY23			0x20c
+#define MT8196_DISP1_GCE_FRAME_DONE_SEL0		0xa10
+#define MT8196_DISP1_GCE_FRAME_DONE_SEL1		0xa14
+#define MT8196_FRAME_DONE_DVO					25
+#define MT8196_FRAME_DONE_DP_INTF0				41
+#define MT8196_DISP1_BYPASS_MUX_SHADOW			0xcf8
+
+/* VDISP_AO config */
+#define MT8196_VDISP_AO_REG_INTEN			0x000
+#define MT8196_CPU_INTEN					BIT(0)
+#define MT8196_CPU_INT_MERGE					BIT(4)
+#define MT8196_VDISP_AO_REG_INT_SEL_G0			0x020
+#define MT8196_VDISP_AO_REG_INT_SEL_G1			0x024
+#define MT8196_VDISP_AO_REG_INT_SEL_G2			0x028
+#define MT8196_VDISP_AO_REG_INT_SEL_G3			0x02c
+#define MT8196_VDISP_AO_REG_INT_SEL_G4			0x030
+#define MT8196_VDISP_AO_REG_INT_SEL_G5			0x034
+#define MT8196_VDISP_AO_REG_INT_SEL_G6			0x038
+#define MT8196_IRQ_TABLE_OVL0_OUTPROC0				(0xa6) /* GIC 450 */
+#define MT8196_IRQ_TABLE_OVL0_OUTPROC1				(0xa7) /* GIC 451 */
+#define MT8196_IRQ_TABLE_OVL1_OUTPROC0				(0xd6) /* GIC 452 */
+#define MT8196_IRQ_TABLE_DSI0					(0x35) /* GIC 453 */
+
+static const struct mtk_mmsys_async_info mmsys_mt8196_ovl0_async_comp_table[] = {
+	{DDP_COMPONENT_OVL0_DLO_ASYNC5, 0, MT8196_OVL_DL_OUT_RELAY5_SIZE, GENMASK(29, 0)},
+	{DDP_COMPONENT_OVL0_DLO_ASYNC6, 1, MT8196_OVL_DL_OUT_RELAY6_SIZE, GENMASK(29, 0)},
+};
+
+static const struct mtk_mmsys_async_info mmsys_mt8196_ovl1_async_comp_table[] = {
+	{DDP_COMPONENT_OVL1_DLO_ASYNC5, 0, MT8196_OVL_DL_OUT_RELAY5_SIZE, GENMASK(29, 0)},
+	{DDP_COMPONENT_OVL1_DLO_ASYNC6, 1, MT8196_OVL_DL_OUT_RELAY6_SIZE, GENMASK(29, 0)},
+};
+
+static const struct mtk_mmsys_async_info mmsys_mt8196_disp0_async_comp_table[] = {
+	{DDP_COMPONENT_DLI_ASYNC0, 0, MT8196_DISP0_DLI_RELAY0, GENMASK(29, 0)},
+	{DDP_COMPONENT_DLI_ASYNC1, 1, MT8196_DISP0_DLI_RELAY1, GENMASK(29, 0)},
+	{DDP_COMPONENT_DLI_ASYNC8, 2, MT8196_DISP0_DLI_RELAY8, GENMASK(29, 0)},
+	{DDP_COMPONENT_DLO_ASYNC1, 3, MT8196_DISP0_DLO_RELAY1, GENMASK(29, 0)},
+	{DDP_COMPONENT_DLO_ASYNC2, 4, MT8196_DISP0_DLO_RELAY2, GENMASK(29, 0)},
+	{DDP_COMPONENT_DLO_ASYNC3, 5, MT8196_DISP0_DLO_RELAY3, GENMASK(29, 0)},
+};
+
+static const struct mtk_mmsys_async_info mmsys_mt8196_disp1_async_comp_table[] = {
+	{DDP_COMPONENT_DLI_ASYNC21, 0, MT8196_DISP1_DLI_RELAY21, GENMASK(29, 0)},
+	{DDP_COMPONENT_DLI_ASYNC22, 1, MT8196_DISP1_DLI_RELAY22, GENMASK(29, 0)},
+	{DDP_COMPONENT_DLI_ASYNC23, 2, MT8196_DISP1_DLI_RELAY23, GENMASK(29, 0)},
+};
+
+static const struct mtk_mmsys_default mmsys_mt8196_vdisp_ao_default_table[] = {
+	{MT8196_VDISP_AO_REG_INTEN, MT8196_CPU_INTEN, MT8196_CPU_INT_MERGE | MT8196_CPU_INTEN},
+	{MT8196_VDISP_AO_REG_INT_SEL_G0, MT8196_IRQ_TABLE_OVL0_OUTPROC0, GENMASK(7, 0)},
+	{MT8196_VDISP_AO_REG_INT_SEL_G0, MT8196_IRQ_TABLE_OVL0_OUTPROC1 << 8, GENMASK(15, 8)},
+	{MT8196_VDISP_AO_REG_INT_SEL_G0, MT8196_IRQ_TABLE_OVL1_OUTPROC0 << 16, GENMASK(23, 16)},
+	{MT8196_VDISP_AO_REG_INT_SEL_G0, MT8196_IRQ_TABLE_DSI0 << 24, GENMASK(31, 24)}
+};
+
+static const struct mtk_mmsys_default mmsys_mt8196_ovl0_default_table[] = {
+	{MT8196_OVLSYS_GCE_EVENT_SEL, MT8196_EVENT_GCE_EN, GENMASK(1, 0)},
+	{MT8196_OVL_INT_MERGE, 0, BIT(0)},
+	{MT8196_OVLSYS_BYPASS_MUX_SHADOW,
+	 MT8196_BYPASS_MUX_SHADOW, MT8196_BYPASS_MUX_SHADOW},
+	{MT8196_OVLSYS_CB_CON, MT8196_OVLSYS_CB_BYPASS_MUX_SHADOW,
+	 MT8196_OVLSYS_CB_BYPASS_MUX_SHADOW},
+};
+
+static const struct mtk_mmsys_default mmsys_mt8196_disp0_default_table[] = {
+	{MT8196_OVLSYS_GCE_EVENT_SEL, MT8196_EVENT_GCE_EN, GENMASK(1, 0)},
+	{MT8196_DISP0_BYPASS_MUX_SHADOW,
+	 MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW,
+	 MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW},
+	{MT8196_DISP0_DLI_RELAY0, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
+	{MT8196_DISP0_DLI_RELAY1, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
+	{MT8196_DISP0_DLI_RELAY8, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
+	{MT8196_DISP0_DLO_RELAY1, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
+	{MT8196_DISP0_DLO_RELAY2, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
+	{MT8196_DISP0_DLO_RELAY3, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
+};
+
+static const struct mtk_mmsys_default mmsys_mt8196_disp1_default_table[] = {
+	{MT8196_OVLSYS_GCE_EVENT_SEL, MT8196_EVENT_GCE_EN, GENMASK(1, 0)},
+	{MT8196_DISP1_INT_MERGE, 0, BIT(0)},
+	{MT8196_DISP1_BYPASS_MUX_SHADOW,
+	 MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW,
+	 MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW},
+	{MT8196_DISP1_DLI_RELAY21, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
+	{MT8196_DISP1_DLI_RELAY22, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
+	{MT8196_DISP1_DLI_RELAY23, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
+	{MT8196_DISP1_GCE_FRAME_DONE_SEL0, MT8196_FRAME_DONE_DVO, GENMASK(5, 0)},
+	{MT8196_DISP1_GCE_FRAME_DONE_SEL1, MT8196_FRAME_DONE_DP_INTF0, GENMASK(5, 0)},
+};
+
+static const struct mtk_mmsys_routes mmsys_mt8196_ovl0_routing_table[] = {
+	{
+		DDP_COMPONENT_OVL0_EXDMA2, DDP_COMPONENT_OVL0_BLENDER1,
+		MT8196_OVL_RSZ_IN_CB2_MOUT_EN, MT8196_DISP_OVL_EXDMA2_1_TO_OVL_EXDMA_OUT_CB3,
+		MT8196_DISP_OVL_EXDMA2_1_TO_OVL_EXDMA_OUT_CB3
+	}, {
+		DDP_COMPONENT_OVL0_EXDMA2, DDP_COMPONENT_OVL0_BLENDER1,
+		MT8196_OVL_EXDMA_OUT_CB3_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER1,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER1
+	}, {
+		DDP_COMPONENT_OVL0_EXDMA3, DDP_COMPONENT_OVL0_BLENDER2,
+		MT8196_OVL_EXDMA_OUT_CB4_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER2,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER2
+	}, {
+		DDP_COMPONENT_OVL0_EXDMA4, DDP_COMPONENT_OVL0_BLENDER3,
+		MT8196_OVL_EXDMA_OUT_CB5_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER3,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER3
+	}, {
+		DDP_COMPONENT_OVL0_EXDMA5, DDP_COMPONENT_OVL0_BLENDER4,
+		MT8196_OVL_EXDMA_OUT_CB6_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER4,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER4
+	}, {
+		DDP_COMPONENT_OVL0_EXDMA6, DDP_COMPONENT_OVL0_BLENDER5,
+		MT8196_OVL_EXDMA_OUT_CB7_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER5,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER5
+	}, {
+		DDP_COMPONENT_OVL0_EXDMA7, DDP_COMPONENT_OVL0_BLENDER6,
+		MT8196_OVL_EXDMA_OUT_CB8_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER6,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER6
+	}, {
+		DDP_COMPONENT_OVL0_EXDMA8, DDP_COMPONENT_OVL0_BLENDER7,
+		MT8196_OVL_EXDMA_OUT_CB9_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER7,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER7
+	}, {
+		DDP_COMPONENT_OVL0_EXDMA9, DDP_COMPONENT_OVL0_BLENDER8,
+		MT8196_OVL_EXDMA_OUT_CB10_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER8,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER8
+	}, {
+		DDP_COMPONENT_OVL0_BLENDER4, DDP_COMPONENT_OVL0_OUTPROC0,
+		MT8196_OVL_BLENDER_OUT_CB4_MOUT_EN, MT8196_DISP_OUT_BLENDER_CB_TO_OVL_OUTPROC0,
+		MT8196_DISP_OUT_BLENDER_CB_TO_OVL_OUTPROC0
+	}, {
+		DDP_COMPONENT_OVL0_BLENDER8, DDP_COMPONENT_OVL0_OUTPROC1,
+		MT8196_OVL_BLENDER_OUT_CB8_MOUT_EN, MT8196_DISP_OUT_BLENDER_CB_TO_OVL_OUTPROC1,
+		MT8196_DISP_OUT_BLENDER_CB_TO_OVL_OUTPROC1
+	}, {
+		DDP_COMPONENT_OVL0_OUTPROC0, DDP_COMPONENT_OVL0_DLO_ASYNC5,
+		MT8196_OVL_OUTPROC_OUT_CB0_MOUT_EN, MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY5,
+		MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY5
+	}, {
+		DDP_COMPONENT_OVL0_OUTPROC1, DDP_COMPONENT_OVL0_DLO_ASYNC6,
+		MT8196_OVL_OUTPROC_OUT_CB1_MOUT_EN, MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY6,
+		MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY6
+	}
+};
+
+static const struct mtk_mmsys_routes mmsys_mt8196_ovl1_routing_table[] = {
+	{
+		DDP_COMPONENT_OVL1_EXDMA2, DDP_COMPONENT_OVL1_BLENDER1,
+		MT8196_OVL_RSZ_IN_CB2_MOUT_EN, MT8196_DISP_OVL_EXDMA2_1_TO_OVL_EXDMA_OUT_CB3,
+		MT8196_DISP_OVL_EXDMA2_1_TO_OVL_EXDMA_OUT_CB3
+	}, {
+		DDP_COMPONENT_OVL1_EXDMA2, DDP_COMPONENT_OVL1_BLENDER1,
+		MT8196_OVL_EXDMA_OUT_CB3_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER1,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER1
+	}, {
+		DDP_COMPONENT_OVL1_EXDMA3, DDP_COMPONENT_OVL1_BLENDER2,
+		MT8196_OVL_EXDMA_OUT_CB4_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER2,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER2
+	}, {
+		DDP_COMPONENT_OVL1_EXDMA4, DDP_COMPONENT_OVL1_BLENDER3,
+		MT8196_OVL_EXDMA_OUT_CB5_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER3,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER3
+	}, {
+		DDP_COMPONENT_OVL1_EXDMA5, DDP_COMPONENT_OVL1_BLENDER4,
+		MT8196_OVL_EXDMA_OUT_CB6_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER4,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER4
+	}, {
+		DDP_COMPONENT_OVL1_EXDMA6, DDP_COMPONENT_OVL1_BLENDER5,
+		MT8196_OVL_EXDMA_OUT_CB7_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER5,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER5
+	}, {
+		DDP_COMPONENT_OVL1_EXDMA7, DDP_COMPONENT_OVL1_BLENDER6,
+		MT8196_OVL_EXDMA_OUT_CB8_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER6,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER6
+	}, {
+		DDP_COMPONENT_OVL1_EXDMA8, DDP_COMPONENT_OVL1_BLENDER7,
+		MT8196_OVL_EXDMA_OUT_CB9_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER7,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER7
+	}, {
+		DDP_COMPONENT_OVL1_EXDMA9, DDP_COMPONENT_OVL1_BLENDER8,
+		MT8196_OVL_EXDMA_OUT_CB10_MOUT_EN, MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER8,
+		MT8196_DISP_OVL_EXDMA_OUT_CB_TO_OVL_BLENDER8
+	}, {
+		DDP_COMPONENT_OVL1_BLENDER4, DDP_COMPONENT_OVL1_OUTPROC0,
+		MT8196_OVL_BLENDER_OUT_CB4_MOUT_EN, MT8196_DISP_OUT_BLENDER_CB_TO_OVL_OUTPROC0,
+		MT8196_DISP_OUT_BLENDER_CB_TO_OVL_OUTPROC0
+	}, {
+		DDP_COMPONENT_OVL1_BLENDER8, DDP_COMPONENT_OVL1_OUTPROC1,
+		MT8196_OVL_BLENDER_OUT_CB8_MOUT_EN, MT8196_DISP_OUT_BLENDER_CB_TO_OVL_OUTPROC1,
+		MT8196_DISP_OUT_BLENDER_CB_TO_OVL_OUTPROC1
+	}, {
+		DDP_COMPONENT_OVL1_OUTPROC0, DDP_COMPONENT_OVL1_DLO_ASYNC5,
+		MT8196_OVL_OUTPROC_OUT_CB0_MOUT_EN, MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY5,
+		MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY5
+	}, {
+		DDP_COMPONENT_OVL1_OUTPROC1, DDP_COMPONENT_OVL1_DLO_ASYNC6,
+		MT8196_OVL_OUTPROC_OUT_CB1_MOUT_EN, MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY6,
+		MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY6
+	}
+};
+
+/*
+ * main: DLI_ASYNC0-> PQ_IN_CB0 -> PQ_OUT_CB6 -> PANEL_COMP_OUT_CB1 -> DLO_ASYNC1
+ * ext:  DLI_ASYNC1-> PQ_IN_CB1 -> PQ_OUT_CB7 -> PANEL_COMP_OUT_CB2 -> DLO_ASYNC2
+ */
+static const struct mtk_mmsys_routes mmsys_mt8196_disp0_routing_table[] = {
+	{
+		DDP_COMPONENT_DLI_ASYNC0, DDP_COMPONENT_DLO_ASYNC1,
+		MT8196_PQ_IN_CB0_MOUT_EN, MT8196_PQ_IN_CB0_TO_PQ_OUT_CB_6,
+		MT8196_PQ_IN_CB0_TO_PQ_OUT_CB_6
+	}, {
+		DDP_COMPONENT_DLI_ASYNC0, DDP_COMPONENT_DLO_ASYNC1,
+		MT8196_PQ_OUT_CB6_MOUT_EN, MT8196_PQ_OUT_CB6_TO_PANEL0_COMP_OUT_CB1,
+		MT8196_PQ_OUT_CB6_TO_PANEL0_COMP_OUT_CB1
+	}, {
+		DDP_COMPONENT_DLI_ASYNC0, DDP_COMPONENT_DLO_ASYNC1,
+		MT8196_PANEL_COMP_OUT_CB1_MOUT_EN, MT8196_DISP_TO_DLO_RELAY1,
+		MT8196_DISP_TO_DLO_RELAY1
+	}, {
+		DDP_COMPONENT_DLI_ASYNC1, DDP_COMPONENT_DLO_ASYNC2,
+		MT8196_PQ_IN_CB1_MOUT_EN, MT8196_PQ_IN_CB1_TO_PQ_OUT_CB_7,
+		MT8196_PQ_IN_CB1_TO_PQ_OUT_CB_7
+	}, {
+		DDP_COMPONENT_DLI_ASYNC1, DDP_COMPONENT_DLO_ASYNC2,
+		MT8196_PQ_OUT_CB7_MOUT_EN, MT8196_PQ_OUT_CB7_TO_PANEL0_COMP_OUT_CB2,
+		MT8196_PQ_OUT_CB7_TO_PANEL0_COMP_OUT_CB2
+	}, {
+		DDP_COMPONENT_DLI_ASYNC1, DDP_COMPONENT_DLO_ASYNC2,
+		MT8196_PANEL_COMP_OUT_CB2_MOUT_EN, MT8196_DISP_TO_DLO_RELAY2,
+		MT8196_DISP_TO_DLO_RELAY2
+	}, {
+		DDP_COMPONENT_DLI_ASYNC8, DDP_COMPONENT_DLO_ASYNC3,
+		MT8196_PQ_IN_CB8_MOUT_EN, MT8196_PQ_IN_CB8_TO_PQ_OUT_CB_8,
+		MT8196_PQ_IN_CB8_TO_PQ_OUT_CB_8
+	}, {
+		DDP_COMPONENT_DLI_ASYNC8, DDP_COMPONENT_DLO_ASYNC3,
+		MT8196_PQ_OUT_CB8_MOUT_EN, MT8196_PQ_OUT_CB8_TO_PANEL0_COMP_OUT_CB3,
+		MT8196_PQ_OUT_CB8_TO_PANEL0_COMP_OUT_CB3
+	}, {
+		DDP_COMPONENT_DLI_ASYNC8, DDP_COMPONENT_DLO_ASYNC3,
+		MT8196_PANEL_COMP_OUT_CB3_MOUT_EN, MT8196_DISP_TO_DLO_RELAY3,
+		MT8196_DISP_TO_DLO_RELAY3
+	}
+};
+
+/*
+ * main: DLI_ASYNC21-> SPLITTER_IN_CB1-> SPLITTER_OUT_CB9-> COMP_OUT_CB6-> MERGE_OUT_CB0 -> DVO
+ * ext: DLI_ASYNC22-> SPLITTER_IN_CB2-> SPLITTER_OUT_CB10-> COMP_OUT_CB7-> MERGE_OUT_CB1 -> DP_INTF0
+ */
+static const struct mtk_mmsys_routes mmsys_mt8196_disp1_routing_table[] = {
+	{
+		DDP_COMPONENT_DLI_ASYNC21, DDP_COMPONENT_DVO0,
+		MT8196_SPLITTER_IN_CB1_MOUT_EN, MT8196_DISP_DLI_RELAY_TO_SPLITTER_OUT_CB9,
+		MT8196_DISP_DLI_RELAY_TO_SPLITTER_OUT_CB9
+	}, {
+		DDP_COMPONENT_DLI_ASYNC21, DDP_COMPONENT_DVO0,
+		MT8196_SPLITTER_OUT_CB9_MOUT_EN, MT8196_DISP_SPLITTER_IN_CB_TO_COMP_OUT_CB6,
+		MT8196_DISP_SPLITTER_IN_CB_TO_COMP_OUT_CB6
+	}, {
+		DDP_COMPONENT_DLI_ASYNC21, DDP_COMPONENT_DVO0,
+		MT8196_COMP_OUT_CB6_MOUT_EN, MT8196_DISP_SPLITTER_OUT_CB_TO_MERGE_OUT_CB0,
+		MT8196_DISP_SPLITTER_OUT_CB_TO_MERGE_OUT_CB0
+	}, {
+		DDP_COMPONENT_DLI_ASYNC21, DDP_COMPONENT_DVO0,
+		MT8196_MERGE_OUT_CB0_MOUT_EN, MT8196_DISP_COMP_OUT_CB_TO_DVO0,
+		MT8196_DISP_COMP_OUT_CB_TO_DVO0
+	}, {
+		DDP_COMPONENT_DLI_ASYNC22, DDP_COMPONENT_DP_INTF0,
+		MT8196_SPLITTER_IN_CB2_MOUT_EN, MT8196_DISP_DLI_RELAY_TO_SPLITTER_OUT_CB10,
+		MT8196_DISP_DLI_RELAY_TO_SPLITTER_OUT_CB10
+	}, {
+		DDP_COMPONENT_DLI_ASYNC22, DDP_COMPONENT_DP_INTF0,
+		MT8196_SPLITTER_OUT_CB10_MOUT_EN, MT8196_DISP_SPLITTER_IN_CB_TO_COMP_OUT_CB7,
+		MT8196_DISP_SPLITTER_IN_CB_TO_COMP_OUT_CB7
+	}, {
+		DDP_COMPONENT_DLI_ASYNC22, DDP_COMPONENT_DP_INTF0,
+		MT8196_COMP_OUT_CB7_MOUT_EN, MT8196_DISP_SPLITTER_OUT_CB_TO_MERGE_OUT_CB1,
+		MT8196_DISP_SPLITTER_OUT_CB_TO_MERGE_OUT_CB1
+	}, {
+		DDP_COMPONENT_DLI_ASYNC22, DDP_COMPONENT_DP_INTF0,
+		MT8196_MERGE_OUT_CB1_MOUT_EN, MT8196_DISP_COMP_OUT_CB_TO_DP_INTF0,
+		MT8196_DISP_COMP_OUT_CB_TO_DP_INTF0
+	}, {
+		DDP_COMPONENT_DLI_ASYNC23, DDP_COMPONENT_DVO0,
+		MT8196_SPLITTER_IN_CB3_MOUT_EN, MT8196_DISP_DLI_RELAY_TO_SPLITTER_OUT_CB11,
+		MT8196_DISP_DLI_RELAY_TO_SPLITTER_OUT_CB11
+	}, {
+		DDP_COMPONENT_DLI_ASYNC23, DDP_COMPONENT_DVO0,
+		MT8196_SPLITTER_OUT_CB11_MOUT_EN, MT8196_DISP_SPLITTER_IN_CB_TO_COMP_OUT_CB8,
+		MT8196_DISP_SPLITTER_IN_CB_TO_COMP_OUT_CB8
+	}, {
+		DDP_COMPONENT_DLI_ASYNC23, DDP_COMPONENT_DVO0,
+		MT8196_COMP_OUT_CB8_MOUT_EN, MT8196_DISP_SPLITTER_OUT_CB_TO_MERGE_OUT_CB2,
+		MT8196_DISP_SPLITTER_OUT_CB_TO_MERGE_OUT_CB2
+	}, {
+		DDP_COMPONENT_DLI_ASYNC23, DDP_COMPONENT_DVO0,
+		MT8196_MERGE_OUT_CB2_MOUT_EN, MT8196_DISP_COMP_OUT_CB_TO_DVO0,
+		MT8196_DISP_COMP_OUT_CB_TO_DVO0
+	}, {
+		DDP_COMPONENT_DLI_ASYNC23, DDP_COMPONENT_DP_INTF1,
+		MT8196_SPLITTER_IN_CB3_MOUT_EN, MT8196_DISP_DLI_RELAY_TO_SPLITTER_OUT_CB11,
+		MT8196_DISP_DLI_RELAY_TO_SPLITTER_OUT_CB11
+	}, {
+		DDP_COMPONENT_DLI_ASYNC23, DDP_COMPONENT_DP_INTF1,
+		MT8196_SPLITTER_OUT_CB11_MOUT_EN, MT8196_DISP_SPLITTER_IN_CB_TO_COMP_OUT_CB8,
+		MT8196_DISP_SPLITTER_IN_CB_TO_COMP_OUT_CB8
+	}, {
+		DDP_COMPONENT_DLI_ASYNC23, DDP_COMPONENT_DP_INTF1,
+		MT8196_COMP_OUT_CB8_MOUT_EN, MT8196_DISP_SPLITTER_OUT_CB_TO_MERGE_OUT_CB2,
+		MT8196_DISP_SPLITTER_OUT_CB_TO_MERGE_OUT_CB2
+	}, {
+		DDP_COMPONENT_DLI_ASYNC23, DDP_COMPONENT_DP_INTF1,
+		MT8196_MERGE_OUT_CB2_MOUT_EN, MT8196_DISP_COMP_OUT_CB_TO_DP_INTF1,
+		MT8196_DISP_COMP_OUT_CB_TO_DP_INTF1
+	}, {
+		DDP_COMPONENT_DLI_ASYNC23, DDP_COMPONENT_DSI0,
+		MT8196_SPLITTER_IN_CB3_MOUT_EN, MT8196_DISP_DLI_RELAY_TO_SPLITTER_OUT_CB11,
+		MT8196_DISP_DLI_RELAY_TO_SPLITTER_OUT_CB11
+	}, {
+		DDP_COMPONENT_DLI_ASYNC23, DDP_COMPONENT_DSI0,
+		MT8196_SPLITTER_OUT_CB11_MOUT_EN, MT8196_DISP_SPLITTER_IN_CB_TO_COMP_OUT_CB8,
+		MT8196_DISP_SPLITTER_IN_CB_TO_COMP_OUT_CB8
+	}, {
+		DDP_COMPONENT_DLI_ASYNC23, DDP_COMPONENT_DSI0,
+		MT8196_COMP_OUT_CB8_MOUT_EN, MT8196_DISP_SPLITTER_OUT_CB_TO_MERGE_OUT_CB2,
+		MT8196_DISP_SPLITTER_OUT_CB_TO_MERGE_OUT_CB2
+	}, {
+		DDP_COMPONENT_DLI_ASYNC23, DDP_COMPONENT_DSI0,
+		MT8196_MERGE_OUT_CB2_MOUT_EN, MT8196_DISP_COMP_OUT_CB_TO_DSI0,
+		MT8196_DISP_COMP_OUT_CB_TO_DSI0
+	}
+};
+#endif /* __SOC_MEDIATEK_MT8196_MMSYS_H */
diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c
index bb4639ca0b8c..1d3ca4f9f237 100644
--- a/drivers/soc/mediatek/mtk-mmsys.c
+++ b/drivers/soc/mediatek/mtk-mmsys.c
@@ -4,12 +4,14 @@
  * Author: James Liao <jamesjj.liao@mediatek.com>
  */
 
+#include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/device.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
 #include <linux/reset-controller.h>
 #include <linux/soc/mediatek/mtk-mmsys.h>
 
@@ -21,6 +23,7 @@
 #include "mt8188-mmsys.h"
 #include "mt8192-mmsys.h"
 #include "mt8195-mmsys.h"
+#include "mt8196-mmsys.h"
 #include "mt8365-mmsys.h"
 
 #define MMSYS_SW_RESET_PER_REG 32
@@ -144,6 +147,54 @@ static const struct mtk_mmsys_driver_data mt8195_vppsys1_driver_data = {
 	.is_vppsys = true,
 };
 
+static const struct mtk_mmsys_driver_data mt8196_dispsys0_driver_data = {
+	.clk_driver = "clk-mt8196-disp0",
+	.routes = mmsys_mt8196_disp0_routing_table,
+	.num_routes = ARRAY_SIZE(mmsys_mt8196_disp0_routing_table),
+	.async_info = mmsys_mt8196_disp0_async_comp_table,
+	.num_async_info = ARRAY_SIZE(mmsys_mt8196_disp0_async_comp_table),
+	.def_config = mmsys_mt8196_disp0_default_table,
+	.num_def_config = ARRAY_SIZE(mmsys_mt8196_disp0_default_table),
+	.num_top_clk = 1,
+};
+
+static const struct mtk_mmsys_driver_data mt8196_dispsys1_driver_data = {
+	.clk_driver = "clk-mt8196-disp1",
+	.routes = mmsys_mt8196_disp1_routing_table,
+	.num_routes = ARRAY_SIZE(mmsys_mt8196_disp1_routing_table),
+	.async_info = mmsys_mt8196_disp1_async_comp_table,
+	.num_async_info = ARRAY_SIZE(mmsys_mt8196_disp1_async_comp_table),
+	.def_config = mmsys_mt8196_disp1_default_table,
+	.num_def_config = ARRAY_SIZE(mmsys_mt8196_disp1_default_table),
+	.num_top_clk = 1,
+};
+
+static const struct mtk_mmsys_driver_data mt8196_ovlsys0_driver_data = {
+	.clk_driver = "clk-mt8196-ovl0",
+	.routes = mmsys_mt8196_ovl0_routing_table,
+	.num_routes = ARRAY_SIZE(mmsys_mt8196_ovl0_routing_table),
+	.async_info = mmsys_mt8196_ovl0_async_comp_table,
+	.num_async_info = ARRAY_SIZE(mmsys_mt8196_ovl0_async_comp_table),
+	.def_config = mmsys_mt8196_ovl0_default_table,
+	.num_def_config = ARRAY_SIZE(mmsys_mt8196_ovl0_default_table),
+};
+
+static const struct mtk_mmsys_driver_data mt8196_ovlsys1_driver_data = {
+	.clk_driver = "clk-mt8196-ovl1",
+	.routes = mmsys_mt8196_ovl1_routing_table,
+	.num_routes = ARRAY_SIZE(mmsys_mt8196_ovl1_routing_table),
+	.async_info = mmsys_mt8196_ovl1_async_comp_table,
+	.num_async_info = ARRAY_SIZE(mmsys_mt8196_ovl1_async_comp_table),
+	.def_config = mmsys_mt8196_ovl0_default_table,
+	.num_def_config = ARRAY_SIZE(mmsys_mt8196_ovl0_default_table),
+};
+
+static const struct mtk_mmsys_driver_data mt8196_vdisp_ao_driver_data = {
+	.clk_driver = "clk-mt8196-vdisp_ao",
+	.def_config = mmsys_mt8196_vdisp_ao_default_table,
+	.num_def_config = ARRAY_SIZE(mmsys_mt8196_vdisp_ao_default_table),
+};
+
 static const struct mtk_mmsys_driver_data mt8365_mmsys_driver_data = {
 	.clk_driver = "clk-mt8365-mm",
 	.routes = mt8365_mmsys_routing_table,
@@ -158,6 +209,9 @@ struct mtk_mmsys {
 	spinlock_t lock; /* protects mmsys_sw_rst_b reg */
 	struct reset_controller_dev rcdev;
 	struct cmdq_client_reg cmdq_base;
+	struct clk **async_clk;
+	int num_async_clk;
+	struct clk **top_clk;
 };
 
 static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask, u32 val,
@@ -180,6 +234,99 @@ static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask,
 	writel_relaxed(tmp, mmsys->regs + offset);
 }
 
+int mtk_mmsys_top_clk_enable(struct device *dev)
+{
+	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
+	int ret, i;
+
+	if (!mmsys->data->num_top_clk)
+		return 0;
+
+	for (i = 0; i < mmsys->data->num_top_clk; i++)
+		ret = clk_prepare_enable(mmsys->top_clk[i]);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_top_clk_enable);
+
+void mtk_mmsys_top_clk_disable(struct device *dev)
+{
+	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < mmsys->data->num_top_clk; i++)
+		clk_disable_unprepare(mmsys->top_clk[i]);
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_top_clk_disable);
+
+int mtk_mmsys_ddp_clk_enable(struct device *dev, enum mtk_ddp_comp_id comp_id)
+{
+	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
+	const struct mtk_mmsys_async_info *async = mmsys->data->async_info;
+
+	int i;
+
+	if (!mmsys->data->num_async_info)
+		return 0;
+
+	for (i = 0; i < mmsys->data->num_async_info; i++)
+		if (comp_id == async[i].comp_id)
+			return clk_prepare_enable(mmsys->async_clk[async[i].index]);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_clk_enable);
+
+void mtk_mmsys_ddp_clk_disable(struct device *dev, enum mtk_ddp_comp_id comp_id)
+{
+	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
+	const struct mtk_mmsys_async_info *async = mmsys->data->async_info;
+	int i;
+
+	if (!mmsys->data->num_async_info)
+		return;
+
+	for (i = 0; i < mmsys->data->num_async_info; i++)
+		if (comp_id == async[i].comp_id)
+			clk_disable_unprepare(mmsys->async_clk[async[i].index]);
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_clk_disable);
+
+void mtk_mmsys_ddp_config(struct device *dev, enum mtk_ddp_comp_id comp_id,
+			  int width, int height, struct cmdq_pkt *cmdq_pkt)
+{
+	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
+	const struct mtk_mmsys_async_info *async = mmsys->data->async_info;
+	int i;
+
+	if (!mmsys->data->num_async_info)
+		return;
+
+	for (i = 0; i < mmsys->data->num_async_info; i++)
+		if (comp_id == async[i].comp_id)
+			break;
+
+	if (i == mmsys->data->num_async_info)
+		return;
+
+	mtk_mmsys_update_bits(mmsys, async[i].offset, async[i].mask,
+			      height << 16 | width, cmdq_pkt);
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_config);
+
+void mtk_mmsys_default_config(struct device *dev)
+{
+	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
+	const struct mtk_mmsys_default *def_config = mmsys->data->def_config;
+	int i;
+
+	if (!mmsys->data->num_def_config)
+		return;
+
+	for (i = 0; i < mmsys->data->num_def_config; i++)
+		mtk_mmsys_update_bits(mmsys, def_config[i].offset, def_config[i].mask,
+				      def_config[i].val, NULL);
+}
+EXPORT_SYMBOL_GPL(mtk_mmsys_default_config);
+
 void mtk_mmsys_ddp_connect(struct device *dev,
 			   enum mtk_ddp_comp_id cur,
 			   enum mtk_ddp_comp_id next)
@@ -390,7 +537,7 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
 	struct platform_device *clks;
 	struct platform_device *drm;
 	struct mtk_mmsys *mmsys;
-	int ret;
+	int ret, i;
 
 	mmsys = devm_kzalloc(dev, sizeof(*mmsys), GFP_KERNEL);
 	if (!mmsys)
@@ -432,6 +579,49 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
 		return PTR_ERR(clks);
 	mmsys->clks_pdev = clks;
 
+	if (mmsys->data->num_top_clk) {
+		struct device_node *node;
+
+		node = of_get_child_by_name(dev->of_node, "top");
+		if (!node) {
+			dev_err(&pdev->dev, "Couldn't find top node\n");
+			return -EINVAL;
+		}
+
+		mmsys->top_clk = devm_kmalloc_array(dev, mmsys->data->num_top_clk,
+						    sizeof(*mmsys->top_clk), GFP_KERNEL);
+		if (!mmsys->top_clk)
+			return -ENOMEM;
+
+		for (i = 0; i < mmsys->data->num_top_clk; i++) {
+			mmsys->top_clk[i] = of_clk_get(node, i);
+			if (IS_ERR(mmsys->top_clk[i]))
+				return PTR_ERR(mmsys->top_clk[i]);
+		}
+	}
+
+	if (mmsys->data->num_async_info) {
+		struct device_node *node;
+
+		node = of_get_child_by_name(dev->of_node, "async");
+		if (!node) {
+			dev_err(&pdev->dev, "Couldn't find async node\n");
+			return -EINVAL;
+		}
+
+		mmsys->async_clk = devm_kmalloc_array(dev, mmsys->data->num_async_info,
+						      sizeof(*mmsys->async_clk), GFP_KERNEL);
+		if (!mmsys->async_clk)
+			return -ENOMEM;
+		mmsys->num_async_clk = mmsys->data->num_async_info;
+
+		for (i = 0; i < mmsys->num_async_clk; i++) {
+			mmsys->async_clk[i] = of_clk_get(node, i);
+			if (IS_ERR(mmsys->async_clk[i]))
+				return PTR_ERR(mmsys->async_clk[i]);
+		}
+	}
+
 	if (mmsys->data->is_vppsys)
 		goto out_probe_done;
 
@@ -443,6 +633,9 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
 	}
 	mmsys->drm_pdev = drm;
 
+	if (of_property_present(dev->of_node, "power-domains"))
+		pm_runtime_enable(dev);
+
 out_probe_done:
 	return 0;
 }
@@ -453,6 +646,9 @@ static void mtk_mmsys_remove(struct platform_device *pdev)
 
 	platform_device_unregister(mmsys->drm_pdev);
 	platform_device_unregister(mmsys->clks_pdev);
+
+	if (of_property_present(pdev->dev.of_node, "power-domains"))
+		pm_runtime_disable(&pdev->dev);
 }
 
 static const struct of_device_id of_match_mtk_mmsys[] = {
@@ -476,6 +672,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 */ }
 };
diff --git a/drivers/soc/mediatek/mtk-mmsys.h b/drivers/soc/mediatek/mtk-mmsys.h
index fe628d5f5198..bbc03ef5b025 100644
--- a/drivers/soc/mediatek/mtk-mmsys.h
+++ b/drivers/soc/mediatek/mtk-mmsys.h
@@ -102,6 +102,19 @@ struct mtk_mmsys_routes {
 	u32 val;
 };
 
+struct mtk_mmsys_async_info {
+	u32 comp_id;
+	u32 index;
+	u32 offset;
+	u32 mask;
+};
+
+struct mtk_mmsys_default {
+	u32 offset;
+	u32 val;
+	u32 mask;
+};
+
 /**
  * struct mtk_mmsys_driver_data - Settings of the mmsys
  * @clk_driver: Clock driver name that the mmsys is using
@@ -139,6 +152,11 @@ struct mtk_mmsys_driver_data {
 	const u32 num_resets;
 	const bool is_vppsys;
 	const u8 vsync_len;
+	const struct mtk_mmsys_async_info *async_info;
+	const unsigned int num_async_info;
+	const struct mtk_mmsys_default *def_config;
+	const unsigned int num_def_config;
+	const unsigned int num_top_clk;
 };
 
 /*
diff --git a/include/linux/soc/mediatek/mtk-mmsys.h b/include/linux/soc/mediatek/mtk-mmsys.h
index 4885b065b849..4a0b10567581 100644
--- a/include/linux/soc/mediatek/mtk-mmsys.h
+++ b/include/linux/soc/mediatek/mtk-mmsys.h
@@ -29,6 +29,15 @@ enum mtk_ddp_comp_id {
 	DDP_COMPONENT_COLOR1,
 	DDP_COMPONENT_DITHER0,
 	DDP_COMPONENT_DITHER1,
+	DDP_COMPONENT_DLI_ASYNC0,
+	DDP_COMPONENT_DLI_ASYNC1,
+	DDP_COMPONENT_DLI_ASYNC8,
+	DDP_COMPONENT_DLI_ASYNC21,
+	DDP_COMPONENT_DLI_ASYNC22,
+	DDP_COMPONENT_DLI_ASYNC23,
+	DDP_COMPONENT_DLO_ASYNC1,
+	DDP_COMPONENT_DLO_ASYNC2,
+	DDP_COMPONENT_DLO_ASYNC3,
 	DDP_COMPONENT_DP_INTF0,
 	DDP_COMPONENT_DP_INTF1,
 	DDP_COMPONENT_DPI0,
@@ -39,6 +48,7 @@ enum mtk_ddp_comp_id {
 	DDP_COMPONENT_DSI1,
 	DDP_COMPONENT_DSI2,
 	DDP_COMPONENT_DSI3,
+	DDP_COMPONENT_DVO0,
 	DDP_COMPONENT_ETHDR_MIXER,
 	DDP_COMPONENT_GAMMA,
 	DDP_COMPONENT_MDP_RDMA0,
@@ -58,10 +68,52 @@ enum mtk_ddp_comp_id {
 	DDP_COMPONENT_OD0,
 	DDP_COMPONENT_OD1,
 	DDP_COMPONENT_OVL0,
+	DDP_COMPONENT_OVL0_BLENDER1,
+	DDP_COMPONENT_OVL0_BLENDER2,
+	DDP_COMPONENT_OVL0_BLENDER3,
+	DDP_COMPONENT_OVL0_BLENDER4,
+	DDP_COMPONENT_OVL0_BLENDER5,
+	DDP_COMPONENT_OVL0_BLENDER6,
+	DDP_COMPONENT_OVL0_BLENDER7,
+	DDP_COMPONENT_OVL0_BLENDER8,
+	DDP_COMPONENT_OVL0_BLENDER9,
+	DDP_COMPONENT_OVL0_DLO_ASYNC5,
+	DDP_COMPONENT_OVL0_DLO_ASYNC6,
+	DDP_COMPONENT_OVL0_EXDMA2,
+	DDP_COMPONENT_OVL0_EXDMA3,
+	DDP_COMPONENT_OVL0_EXDMA4,
+	DDP_COMPONENT_OVL0_EXDMA5,
+	DDP_COMPONENT_OVL0_EXDMA6,
+	DDP_COMPONENT_OVL0_EXDMA7,
+	DDP_COMPONENT_OVL0_EXDMA8,
+	DDP_COMPONENT_OVL0_EXDMA9,
+	DDP_COMPONENT_OVL0_OUTPROC0,
+	DDP_COMPONENT_OVL0_OUTPROC1,
 	DDP_COMPONENT_OVL_2L0,
 	DDP_COMPONENT_OVL_2L1,
 	DDP_COMPONENT_OVL_2L2,
 	DDP_COMPONENT_OVL1,
+	DDP_COMPONENT_OVL1_BLENDER1,
+	DDP_COMPONENT_OVL1_BLENDER2,
+	DDP_COMPONENT_OVL1_BLENDER3,
+	DDP_COMPONENT_OVL1_BLENDER4,
+	DDP_COMPONENT_OVL1_BLENDER5,
+	DDP_COMPONENT_OVL1_BLENDER6,
+	DDP_COMPONENT_OVL1_BLENDER7,
+	DDP_COMPONENT_OVL1_BLENDER8,
+	DDP_COMPONENT_OVL1_BLENDER9,
+	DDP_COMPONENT_OVL1_DLO_ASYNC5,
+	DDP_COMPONENT_OVL1_DLO_ASYNC6,
+	DDP_COMPONENT_OVL1_EXDMA2,
+	DDP_COMPONENT_OVL1_EXDMA3,
+	DDP_COMPONENT_OVL1_EXDMA4,
+	DDP_COMPONENT_OVL1_EXDMA5,
+	DDP_COMPONENT_OVL1_EXDMA6,
+	DDP_COMPONENT_OVL1_EXDMA7,
+	DDP_COMPONENT_OVL1_EXDMA8,
+	DDP_COMPONENT_OVL1_EXDMA9,
+	DDP_COMPONENT_OVL1_OUTPROC0,
+	DDP_COMPONENT_OVL1_OUTPROC1,
 	DDP_COMPONENT_PADDING0,
 	DDP_COMPONENT_PADDING1,
 	DDP_COMPONENT_PADDING2,
@@ -84,6 +136,14 @@ enum mtk_ddp_comp_id {
 	DDP_COMPONENT_ID_MAX,
 };
 
+int mtk_mmsys_top_clk_enable(struct device *dev);
+void mtk_mmsys_top_clk_disable(struct device *dev);
+int mtk_mmsys_ddp_clk_enable(struct device *dev, enum mtk_ddp_comp_id comp_id);
+void mtk_mmsys_ddp_clk_disable(struct device *dev, enum mtk_ddp_comp_id comp_id);
+void mtk_mmsys_ddp_config(struct device *dev, enum mtk_ddp_comp_id comp_id,
+			  int width, int height, struct cmdq_pkt *cmdq_pkt);
+void mtk_mmsys_default_config(struct device *dev);
+
 void mtk_mmsys_ddp_connect(struct device *dev,
 			   enum mtk_ddp_comp_id cur,
 			   enum mtk_ddp_comp_id next);
-- 
2.45.2
Re: [PATCH v2 06/15] soc: mediatek: add mmsys support for MT8196
Posted by AngeloGioacchino Del Regno 8 months, 3 weeks ago
Il 21/03/25 10:33, paul-pl.chen ha scritto:
> From: Nancy Lin <nancy.lin@mediatek.com>
> 
> 1. Defining driver data and adding compatible string
> for different subsystems
> (DISPSYS0, DISPSYS1, OVLSYS0, OVLSYS1, VDISP_AO)
> 2. Adding functions to control top clocks and ddp clocks.
> 3. Updating the probe function to initialize clocks and
> enable runtime PM if its node has the power-domains property.
> 4. Adding functions to configure ddp components and
> set default configurations.
> 5. Adding the routing table for each mmsys in MT8196.

You need at least two commits for all that you're doing here... and adding MT8196
tables should be the last one.

> 
> Signed-off-by: Nancy Lin <nancy.lin@mediatek.com>
> Signed-off-by: Paul-pl Chen <paul-pl.chen@mediatek.com>
> ---
>   drivers/soc/mediatek/mt8196-mmsys.h    | 451 +++++++++++++++++++++++++
>   drivers/soc/mediatek/mtk-mmsys.c       | 203 ++++++++++-
>   drivers/soc/mediatek/mtk-mmsys.h       |  18 +
>   include/linux/soc/mediatek/mtk-mmsys.h |  60 ++++
>   4 files changed, 731 insertions(+), 1 deletion(-)
>   create mode 100644 drivers/soc/mediatek/mt8196-mmsys.h
> 
> diff --git a/drivers/soc/mediatek/mt8196-mmsys.h b/drivers/soc/mediatek/mt8196-mmsys.h
> new file mode 100644
> index 000000000000..ff841ae9939a
> --- /dev/null
> +++ b/drivers/soc/mediatek/mt8196-mmsys.h
> @@ -0,0 +1,451 @@

..snip..

> +static const struct mtk_mmsys_default mmsys_mt8196_disp0_default_table[] = {
> +	{MT8196_OVLSYS_GCE_EVENT_SEL, MT8196_EVENT_GCE_EN, GENMASK(1, 0)},
> +	{MT8196_DISP0_BYPASS_MUX_SHADOW,
> +	 MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW,
> +	 MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW},
> +	{MT8196_DISP0_DLI_RELAY0, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
> +	{MT8196_DISP0_DLI_RELAY1, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
> +	{MT8196_DISP0_DLI_RELAY8, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
> +	{MT8196_DISP0_DLO_RELAY1, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
> +	{MT8196_DISP0_DLO_RELAY2, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
> +	{MT8196_DISP0_DLO_RELAY3, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
> +};
> +
> +static const struct mtk_mmsys_default mmsys_mt8196_disp1_default_table[] = {
> +	{MT8196_OVLSYS_GCE_EVENT_SEL, MT8196_EVENT_GCE_EN, GENMASK(1, 0)},
> +	{MT8196_DISP1_INT_MERGE, 0, BIT(0)},
> +	{MT8196_DISP1_BYPASS_MUX_SHADOW,
> +	 MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW,
> +	 MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW},
> +	{MT8196_DISP1_DLI_RELAY21, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
> +	{MT8196_DISP1_DLI_RELAY22, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
> +	{MT8196_DISP1_DLI_RELAY23, MT8196_DLI_RELAY_1T2P, GENMASK(31, 30)},
> +	{MT8196_DISP1_GCE_FRAME_DONE_SEL0, MT8196_FRAME_DONE_DVO, GENMASK(5, 0)},
> +	{MT8196_DISP1_GCE_FRAME_DONE_SEL1, MT8196_FRAME_DONE_DP_INTF0, GENMASK(5, 0)},
> +};
> +
> +static const struct mtk_mmsys_routes mmsys_mt8196_ovl0_routing_table[] = {
> +	{
> +		DDP_COMPONENT_OVL0_EXDMA2, DDP_COMPONENT_OVL0_BLENDER1,

There's a new MMSYS_ROUTE macro that was introduced because tables contained
wrong values in multiple instances and in multiple SoCs: please use it here and
for all routing tables.

> +		MT8196_OVL_RSZ_IN_CB2_MOUT_EN, MT8196_DISP_OVL_EXDMA2_1_TO_OVL_EXDMA_OUT_CB3,
> +		MT8196_DISP_OVL_EXDMA2_1_TO_OVL_EXDMA_OUT_CB3

..snip..

> +};
> +#endif /* __SOC_MEDIATEK_MT8196_MMSYS_H */
> diff --git a/drivers/soc/mediatek/mtk-mmsys.c b/drivers/soc/mediatek/mtk-mmsys.c
> index bb4639ca0b8c..1d3ca4f9f237 100644
> --- a/drivers/soc/mediatek/mtk-mmsys.c
> +++ b/drivers/soc/mediatek/mtk-mmsys.c
> @@ -4,12 +4,14 @@
>    * Author: James Liao <jamesjj.liao@mediatek.com>
>    */
>   
> +#include <linux/clk.h>
>   #include <linux/delay.h>
>   #include <linux/device.h>
>   #include <linux/io.h>
>   #include <linux/module.h>
>   #include <linux/of.h>
>   #include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
>   #include <linux/reset-controller.h>
>   #include <linux/soc/mediatek/mtk-mmsys.h>
>   
> @@ -21,6 +23,7 @@
>   #include "mt8188-mmsys.h"
>   #include "mt8192-mmsys.h"
>   #include "mt8195-mmsys.h"
> +#include "mt8196-mmsys.h"
>   #include "mt8365-mmsys.h"
>   
>   #define MMSYS_SW_RESET_PER_REG 32
> @@ -144,6 +147,54 @@ static const struct mtk_mmsys_driver_data mt8195_vppsys1_driver_data = {
>   	.is_vppsys = true,
>   };
>   
> +static const struct mtk_mmsys_driver_data mt8196_dispsys0_driver_data = {
> +	.clk_driver = "clk-mt8196-disp0",
> +	.routes = mmsys_mt8196_disp0_routing_table,
> +	.num_routes = ARRAY_SIZE(mmsys_mt8196_disp0_routing_table),
> +	.async_info = mmsys_mt8196_disp0_async_comp_table,
> +	.num_async_info = ARRAY_SIZE(mmsys_mt8196_disp0_async_comp_table),
> +	.def_config = mmsys_mt8196_disp0_default_table,
> +	.num_def_config = ARRAY_SIZE(mmsys_mt8196_disp0_default_table),
> +	.num_top_clk = 1,
> +};
> +
> +static const struct mtk_mmsys_driver_data mt8196_dispsys1_driver_data = {
> +	.clk_driver = "clk-mt8196-disp1",
> +	.routes = mmsys_mt8196_disp1_routing_table,
> +	.num_routes = ARRAY_SIZE(mmsys_mt8196_disp1_routing_table),
> +	.async_info = mmsys_mt8196_disp1_async_comp_table,
> +	.num_async_info = ARRAY_SIZE(mmsys_mt8196_disp1_async_comp_table),
> +	.def_config = mmsys_mt8196_disp1_default_table,
> +	.num_def_config = ARRAY_SIZE(mmsys_mt8196_disp1_default_table),
> +	.num_top_clk = 1,
> +};
> +
> +static const struct mtk_mmsys_driver_data mt8196_ovlsys0_driver_data = {
> +	.clk_driver = "clk-mt8196-ovl0",
> +	.routes = mmsys_mt8196_ovl0_routing_table,
> +	.num_routes = ARRAY_SIZE(mmsys_mt8196_ovl0_routing_table),
> +	.async_info = mmsys_mt8196_ovl0_async_comp_table,
> +	.num_async_info = ARRAY_SIZE(mmsys_mt8196_ovl0_async_comp_table),
> +	.def_config = mmsys_mt8196_ovl0_default_table,
> +	.num_def_config = ARRAY_SIZE(mmsys_mt8196_ovl0_default_table),
> +};
> +
> +static const struct mtk_mmsys_driver_data mt8196_ovlsys1_driver_data = {
> +	.clk_driver = "clk-mt8196-ovl1",
> +	.routes = mmsys_mt8196_ovl1_routing_table,
> +	.num_routes = ARRAY_SIZE(mmsys_mt8196_ovl1_routing_table),
> +	.async_info = mmsys_mt8196_ovl1_async_comp_table,
> +	.num_async_info = ARRAY_SIZE(mmsys_mt8196_ovl1_async_comp_table),
> +	.def_config = mmsys_mt8196_ovl0_default_table,
> +	.num_def_config = ARRAY_SIZE(mmsys_mt8196_ovl0_default_table),
> +};
> +
> +static const struct mtk_mmsys_driver_data mt8196_vdisp_ao_driver_data = {
> +	.clk_driver = "clk-mt8196-vdisp_ao",
> +	.def_config = mmsys_mt8196_vdisp_ao_default_table,
> +	.num_def_config = ARRAY_SIZE(mmsys_mt8196_vdisp_ao_default_table),
> +};
> +
>   static const struct mtk_mmsys_driver_data mt8365_mmsys_driver_data = {
>   	.clk_driver = "clk-mt8365-mm",
>   	.routes = mt8365_mmsys_routing_table,
> @@ -158,6 +209,9 @@ struct mtk_mmsys {
>   	spinlock_t lock; /* protects mmsys_sw_rst_b reg */
>   	struct reset_controller_dev rcdev;
>   	struct cmdq_client_reg cmdq_base;
> +	struct clk **async_clk;
> +	int num_async_clk;
> +	struct clk **top_clk;
>   };
>   
>   static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask, u32 val,
> @@ -180,6 +234,99 @@ static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32 offset, u32 mask,
>   	writel_relaxed(tmp, mmsys->regs + offset);
>   }
>   
> +int mtk_mmsys_top_clk_enable(struct device *dev)
> +{
> +	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> +	int ret, i;
> +
> +	if (!mmsys->data->num_top_clk)
> +		return 0;
> +
> +	for (i = 0; i < mmsys->data->num_top_clk; i++)
> +		ret = clk_prepare_enable(mmsys->top_clk[i]);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(mtk_mmsys_top_clk_enable);
> +
> +void mtk_mmsys_top_clk_disable(struct device *dev)
> +{
> +	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> +	int i;
> +
> +	for (i = 0; i < mmsys->data->num_top_clk; i++)
> +		clk_disable_unprepare(mmsys->top_clk[i]);
> +}
> +EXPORT_SYMBOL_GPL(mtk_mmsys_top_clk_disable);
> +
> +int mtk_mmsys_ddp_clk_enable(struct device *dev, enum mtk_ddp_comp_id comp_id)
> +{
> +	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> +	const struct mtk_mmsys_async_info *async = mmsys->data->async_info;
> +
> +	int i;
> +
> +	if (!mmsys->data->num_async_info)
> +		return 0;
> +
> +	for (i = 0; i < mmsys->data->num_async_info; i++)
> +		if (comp_id == async[i].comp_id)
> +			return clk_prepare_enable(mmsys->async_clk[async[i].index]);

Why can't you add the clocks in the mediatek-drm nodes and handle enablement in the
drm driver?!

> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_clk_enable);
> +
> +void mtk_mmsys_ddp_clk_disable(struct device *dev, enum mtk_ddp_comp_id comp_id)
> +{
> +	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> +	const struct mtk_mmsys_async_info *async = mmsys->data->async_info;
> +	int i;
> +
> +	if (!mmsys->data->num_async_info)
> +		return;
> +
> +	for (i = 0; i < mmsys->data->num_async_info; i++)
> +		if (comp_id == async[i].comp_id)
> +			clk_disable_unprepare(mmsys->async_clk[async[i].index]);
> +}
> +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_clk_disable);
> +
> +void mtk_mmsys_ddp_config(struct device *dev, enum mtk_ddp_comp_id comp_id,
> +			  int width, int height, struct cmdq_pkt *cmdq_pkt)
> +{
> +	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> +	const struct mtk_mmsys_async_info *async = mmsys->data->async_info;
> +	int i;
> +
> +	if (!mmsys->data->num_async_info)
> +		return;
> +
> +	for (i = 0; i < mmsys->data->num_async_info; i++)
> +		if (comp_id == async[i].comp_id)
> +			break;
> +
> +	if (i == mmsys->data->num_async_info)
> +		return;
> +
> +	mtk_mmsys_update_bits(mmsys, async[i].offset, async[i].mask,
> +			      height << 16 | width, cmdq_pkt);

linux/bitfield.h provides macros that you should use for those register fields.

> +}
> +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_config);
> +
> +void mtk_mmsys_default_config(struct device *dev)
> +{
> +	struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> +	const struct mtk_mmsys_default *def_config = mmsys->data->def_config;
> +	int i;
> +
> +	if (!mmsys->data->num_def_config)
> +		return;
> +
> +	for (i = 0; i < mmsys->data->num_def_config; i++)
> +		mtk_mmsys_update_bits(mmsys, def_config[i].offset, def_config[i].mask,
> +				      def_config[i].val, NULL);
> +}
> +EXPORT_SYMBOL_GPL(mtk_mmsys_default_config);
> +
>   void mtk_mmsys_ddp_connect(struct device *dev,
>   			   enum mtk_ddp_comp_id cur,
>   			   enum mtk_ddp_comp_id next)
> @@ -390,7 +537,7 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
>   	struct platform_device *clks;
>   	struct platform_device *drm;
>   	struct mtk_mmsys *mmsys;
> -	int ret;
> +	int ret, i;
>   
>   	mmsys = devm_kzalloc(dev, sizeof(*mmsys), GFP_KERNEL);
>   	if (!mmsys)
> @@ -432,6 +579,49 @@ static int mtk_mmsys_probe(struct platform_device *pdev)
>   		return PTR_ERR(clks);
>   	mmsys->clks_pdev = clks;
>   
> +	if (mmsys->data->num_top_clk) {
> +		struct device_node *node;
> +
> +		node = of_get_child_by_name(dev->of_node, "top");

No, you can't do that if there's no binding to support that.

> +		if (!node) {
> +			dev_err(&pdev->dev, "Couldn't find top node\n");
> +			return -EINVAL;
> +		}
> +
> +		mmsys->top_clk = devm_kmalloc_array(dev, mmsys->data->num_top_clk,
> +						    sizeof(*mmsys->top_clk), GFP_KERNEL);
> +		if (!mmsys->top_clk)
> +			return -ENOMEM;
> +
> +		for (i = 0; i < mmsys->data->num_top_clk; i++) {
> +			mmsys->top_clk[i] = of_clk_get(node, i);
> +			if (IS_ERR(mmsys->top_clk[i]))
> +				return PTR_ERR(mmsys->top_clk[i]);
> +		}
> +	}
> +
> +	if (mmsys->data->num_async_info) {
> +		struct device_node *node;
> +
> +		node = of_get_child_by_name(dev->of_node, "async");
> +		if (!node) {
> +			dev_err(&pdev->dev, "Couldn't find async node\n");
> +			return -EINVAL;
> +		}
> +

Also this looks like you have children providing only clocks?!
I really need to look at the bindings to decide, but this looks wrong.

Regards,
Angelo
Re: [PATCH v2 06/15] soc: mediatek: add mmsys support for MT8196
Posted by Paul-pl Chen (陳柏霖) 8 months, 2 weeks ago
On Mon, 2025-03-24 at 18:09 +0100, AngeloGioacchino Del Regno wrote:
> 
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
> 
> 
> Il 21/03/25 10:33, paul-pl.chen ha scritto:
> > From: Nancy Lin <nancy.lin@mediatek.com>
> > 
> > 1. Defining driver data and adding compatible string
> > for different subsystems
> > (DISPSYS0, DISPSYS1, OVLSYS0, OVLSYS1, VDISP_AO)
> > 2. Adding functions to control top clocks and ddp clocks.
> > 3. Updating the probe function to initialize clocks and
> > enable runtime PM if its node has the power-domains property.
> > 4. Adding functions to configure ddp components and
> > set default configurations.
> > 5. Adding the routing table for each mmsys in MT8196.
> 
> You need at least two commits for all that you're doing here... and
> adding MT8196
> tables should be the last one.
> 
Hi AngeloGioacchino,

Thank you for your feedback. I appreciate your suggestion to split the
changes into at least two commits. Based on your advice, I'm
considering dividing the changes as follows:

Commit 1: Add mmsys support
This commit would include:
(1) Defining driver data and adding compatible strings for different
subsystems (DISPSYS0, DISPSYS1, OVLSYS0, OVLSYS1, VDISP_AO)
(2) Adding functions to control top clocks and ddp clocks
(3) Updating the probe function to initialize clocks and enable runtime
PM if its node has the power-domains property
(4) Adding functions to configure ddp components and set default
configurations

Commit 2: Add mmsys tables support for MT8196
This commit would focus on:
(5) Adding the routing table for each mmsys in MT8196

Does this division align with your expectations?
> > 
> > Signed-off-by: Nancy Lin <nancy.lin@mediatek.com>
> > Signed-off-by: Paul-pl Chen <paul-pl.chen@mediatek.com>
> > ---
> >   drivers/soc/mediatek/mt8196-mmsys.h    | 451
> > +++++++++++++++++++++++++
> >   drivers/soc/mediatek/mtk-mmsys.c       | 203 ++++++++++-
> >   drivers/soc/mediatek/mtk-mmsys.h       |  18 +
> >   include/linux/soc/mediatek/mtk-mmsys.h |  60 ++++
> >   4 files changed, 731 insertions(+), 1 deletion(-)
> >   create mode 100644 drivers/soc/mediatek/mt8196-mmsys.h
> > 
> > diff --git a/drivers/soc/mediatek/mt8196-mmsys.h
> > b/drivers/soc/mediatek/mt8196-mmsys.h
> > new file mode 100644
> > index 000000000000..ff841ae9939a
> > --- /dev/null
> > +++ b/drivers/soc/mediatek/mt8196-mmsys.h
> > @@ -0,0 +1,451 @@
> 
> ..snip..
> 
> > +static const struct mtk_mmsys_default
> > mmsys_mt8196_disp0_default_table[] = {
> > +     {MT8196_OVLSYS_GCE_EVENT_SEL, MT8196_EVENT_GCE_EN, GENMASK(1,
> > 0)},
> > +     {MT8196_DISP0_BYPASS_MUX_SHADOW,
> > +      MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW,
> > +      MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW},
> > +     {MT8196_DISP0_DLI_RELAY0, MT8196_DLI_RELAY_1T2P, GENMASK(31,
> > 30)},
> > +     {MT8196_DISP0_DLI_RELAY1, MT8196_DLI_RELAY_1T2P, GENMASK(31,
> > 30)},
> > +     {MT8196_DISP0_DLI_RELAY8, MT8196_DLI_RELAY_1T2P, GENMASK(31,
> > 30)},
> > +     {MT8196_DISP0_DLO_RELAY1, MT8196_DLI_RELAY_1T2P, GENMASK(31,
> > 30)},
> > +     {MT8196_DISP0_DLO_RELAY2, MT8196_DLI_RELAY_1T2P, GENMASK(31,
> > 30)},
> > +     {MT8196_DISP0_DLO_RELAY3, MT8196_DLI_RELAY_1T2P, GENMASK(31,
> > 30)},
> > +};
> > +
> > +static const struct mtk_mmsys_default
> > mmsys_mt8196_disp1_default_table[] = {
> > +     {MT8196_OVLSYS_GCE_EVENT_SEL, MT8196_EVENT_GCE_EN, GENMASK(1,
> > 0)},
> > +     {MT8196_DISP1_INT_MERGE, 0, BIT(0)},
> > +     {MT8196_DISP1_BYPASS_MUX_SHADOW,
> > +      MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW,
> > +      MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW},
> > +     {MT8196_DISP1_DLI_RELAY21, MT8196_DLI_RELAY_1T2P, GENMASK(31,
> > 30)},
> > +     {MT8196_DISP1_DLI_RELAY22, MT8196_DLI_RELAY_1T2P, GENMASK(31,
> > 30)},
> > +     {MT8196_DISP1_DLI_RELAY23, MT8196_DLI_RELAY_1T2P, GENMASK(31,
> > 30)},
> > +     {MT8196_DISP1_GCE_FRAME_DONE_SEL0, MT8196_FRAME_DONE_DVO,
> > GENMASK(5, 0)},
> > +     {MT8196_DISP1_GCE_FRAME_DONE_SEL1,
> > MT8196_FRAME_DONE_DP_INTF0, GENMASK(5, 0)},
> > +};
> > +
> > +static const struct mtk_mmsys_routes
> > mmsys_mt8196_ovl0_routing_table[] = {
> > +     {
> > +             DDP_COMPONENT_OVL0_EXDMA2,
> > DDP_COMPONENT_OVL0_BLENDER1,
> 
> There's a new MMSYS_ROUTE macro that was introduced because tables
> contained
> wrong values in multiple instances and in multiple SoCs: please use
> it here and
> for all routing tables.
> 
Sure, I will use the new MMSYS_ROUTE macro " MMSYS_ROUTE " to replace
the old routing table.
> > +             MT8196_OVL_RSZ_IN_CB2_MOUT_EN,
> > MT8196_DISP_OVL_EXDMA2_1_TO_OVL_EXDMA_OUT_CB3,
> > +             MT8196_DISP_OVL_EXDMA2_1_TO_OVL_EXDMA_OUT_CB3
> 
> ..snip..
> 
> > +};
> > +#endif /* __SOC_MEDIATEK_MT8196_MMSYS_H */
> > diff --git a/drivers/soc/mediatek/mtk-mmsys.c
> > b/drivers/soc/mediatek/mtk-mmsys.c
> > index bb4639ca0b8c..1d3ca4f9f237 100644
> > --- a/drivers/soc/mediatek/mtk-mmsys.c
> > +++ b/drivers/soc/mediatek/mtk-mmsys.c
> > @@ -4,12 +4,14 @@
> >    * Author: James Liao <jamesjj.liao@mediatek.com>
> >    */
> > 
> > +#include <linux/clk.h>
> >   #include <linux/delay.h>
> >   #include <linux/device.h>
> >   #include <linux/io.h>
> >   #include <linux/module.h>
> >   #include <linux/of.h>
> >   #include <linux/platform_device.h>
> > +#include <linux/pm_runtime.h>
> >   #include <linux/reset-controller.h>
> >   #include <linux/soc/mediatek/mtk-mmsys.h>
> > 
> > @@ -21,6 +23,7 @@
> >   #include "mt8188-mmsys.h"
> >   #include "mt8192-mmsys.h"
> >   #include "mt8195-mmsys.h"
> > +#include "mt8196-mmsys.h"
> >   #include "mt8365-mmsys.h"
> > 
> >   #define MMSYS_SW_RESET_PER_REG 32
> > @@ -144,6 +147,54 @@ static const struct mtk_mmsys_driver_data
> > mt8195_vppsys1_driver_data = {
> >       .is_vppsys = true,
> >   };
> > 
> > +static const struct mtk_mmsys_driver_data
> > mt8196_dispsys0_driver_data = {
> > +     .clk_driver = "clk-mt8196-disp0",
> > +     .routes = mmsys_mt8196_disp0_routing_table,
> > +     .num_routes = ARRAY_SIZE(mmsys_mt8196_disp0_routing_table),
> > +     .async_info = mmsys_mt8196_disp0_async_comp_table,
> > +     .num_async_info =
> > ARRAY_SIZE(mmsys_mt8196_disp0_async_comp_table),
> > +     .def_config = mmsys_mt8196_disp0_default_table,
> > +     .num_def_config =
> > ARRAY_SIZE(mmsys_mt8196_disp0_default_table),
> > +     .num_top_clk = 1,
> > +};
> > +
> > +static const struct mtk_mmsys_driver_data
> > mt8196_dispsys1_driver_data = {
> > +     .clk_driver = "clk-mt8196-disp1",
> > +     .routes = mmsys_mt8196_disp1_routing_table,
> > +     .num_routes = ARRAY_SIZE(mmsys_mt8196_disp1_routing_table),
> > +     .async_info = mmsys_mt8196_disp1_async_comp_table,
> > +     .num_async_info =
> > ARRAY_SIZE(mmsys_mt8196_disp1_async_comp_table),
> > +     .def_config = mmsys_mt8196_disp1_default_table,
> > +     .num_def_config =
> > ARRAY_SIZE(mmsys_mt8196_disp1_default_table),
> > +     .num_top_clk = 1,
> > +};
> > +
> > +static const struct mtk_mmsys_driver_data
> > mt8196_ovlsys0_driver_data = {
> > +     .clk_driver = "clk-mt8196-ovl0",
> > +     .routes = mmsys_mt8196_ovl0_routing_table,
> > +     .num_routes = ARRAY_SIZE(mmsys_mt8196_ovl0_routing_table),
> > +     .async_info = mmsys_mt8196_ovl0_async_comp_table,
> > +     .num_async_info =
> > ARRAY_SIZE(mmsys_mt8196_ovl0_async_comp_table),
> > +     .def_config = mmsys_mt8196_ovl0_default_table,
> > +     .num_def_config =
> > ARRAY_SIZE(mmsys_mt8196_ovl0_default_table),
> > +};
> > +
> > +static const struct mtk_mmsys_driver_data
> > mt8196_ovlsys1_driver_data = {
> > +     .clk_driver = "clk-mt8196-ovl1",
> > +     .routes = mmsys_mt8196_ovl1_routing_table,
> > +     .num_routes = ARRAY_SIZE(mmsys_mt8196_ovl1_routing_table),
> > +     .async_info = mmsys_mt8196_ovl1_async_comp_table,
> > +     .num_async_info =
> > ARRAY_SIZE(mmsys_mt8196_ovl1_async_comp_table),
> > +     .def_config = mmsys_mt8196_ovl0_default_table,
> > +     .num_def_config =
> > ARRAY_SIZE(mmsys_mt8196_ovl0_default_table),
> > +};
> > +
> > +static const struct mtk_mmsys_driver_data
> > mt8196_vdisp_ao_driver_data = {
> > +     .clk_driver = "clk-mt8196-vdisp_ao",
> > +     .def_config = mmsys_mt8196_vdisp_ao_default_table,
> > +     .num_def_config =
> > ARRAY_SIZE(mmsys_mt8196_vdisp_ao_default_table),
> > +};
> > +
> >   static const struct mtk_mmsys_driver_data
> > mt8365_mmsys_driver_data = {
> >       .clk_driver = "clk-mt8365-mm",
> >       .routes = mt8365_mmsys_routing_table,
> > @@ -158,6 +209,9 @@ struct mtk_mmsys {
> >       spinlock_t lock; /* protects mmsys_sw_rst_b reg */
> >       struct reset_controller_dev rcdev;
> >       struct cmdq_client_reg cmdq_base;
> > +     struct clk **async_clk;
> > +     int num_async_clk;
> > +     struct clk **top_clk;
> >   };
> > 
> >   static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32
> > offset, u32 mask, u32 val,
> > @@ -180,6 +234,99 @@ static void mtk_mmsys_update_bits(struct
> > mtk_mmsys *mmsys, u32 offset, u32 mask,
> >       writel_relaxed(tmp, mmsys->regs + offset);
> >   }
> > 
> > +int mtk_mmsys_top_clk_enable(struct device *dev)
> > +{
> > +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > +     int ret, i;
> > +
> > +     if (!mmsys->data->num_top_clk)
> > +             return 0;
> > +
> > +     for (i = 0; i < mmsys->data->num_top_clk; i++)
> > +             ret = clk_prepare_enable(mmsys->top_clk[i]);
> > +     return ret;
> > +}
> > +EXPORT_SYMBOL_GPL(mtk_mmsys_top_clk_enable);
> > +
> > +void mtk_mmsys_top_clk_disable(struct device *dev)
> > +{
> > +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > +     int i;
> > +
> > +     for (i = 0; i < mmsys->data->num_top_clk; i++)
> > +             clk_disable_unprepare(mmsys->top_clk[i]);
> > +}
> > +EXPORT_SYMBOL_GPL(mtk_mmsys_top_clk_disable);
> > +
> > +int mtk_mmsys_ddp_clk_enable(struct device *dev, enum
> > mtk_ddp_comp_id comp_id)
> > +{
> > +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > +     const struct mtk_mmsys_async_info *async = mmsys->data-
> > >async_info;
> > +
> > +     int i;
> > +
> > +     if (!mmsys->data->num_async_info)
> > +             return 0;
> > +
> > +     for (i = 0; i < mmsys->data->num_async_info; i++)
> > +             if (comp_id == async[i].comp_id)
> > +                     return clk_prepare_enable(mmsys-
> > >async_clk[async[i].index]);
> 
> Why can't you add the clocks in the mediatek-drm nodes and handle
> enablement in the
> drm driver?!
> 
The "async" is not like other components under mediate-drm that have
independent functions.It only controls which clocks need to be enabled
when the path MUX goes through certain routes.

That's why it's placed in mtk-mmsys. It's only activated when it needs
to be connected to the necessary path MUX.

Currently, the path order is represented through component IDs.
Therefore, to indicate its relative position on the DDP path, we
defined a component ID for it to use.

> > +     return 0;
> > +}
> > +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_clk_enable);
> > +
> > +void mtk_mmsys_ddp_clk_disable(struct device *dev, enum
> > mtk_ddp_comp_id comp_id)
> > +{
> > +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > +     const struct mtk_mmsys_async_info *async = mmsys->data-
> > >async_info;
> > +     int i;
> > +
> > +     if (!mmsys->data->num_async_info)
> > +             return;
> > +
> > +     for (i = 0; i < mmsys->data->num_async_info; i++)
> > +             if (comp_id == async[i].comp_id)
> > +                     clk_disable_unprepare(mmsys-
> > >async_clk[async[i].index]);
> > +}
> > +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_clk_disable);
> > +
> > +void mtk_mmsys_ddp_config(struct device *dev, enum mtk_ddp_comp_id
> > comp_id,
> > +                       int width, int height, struct cmdq_pkt
> > *cmdq_pkt)
> > +{
> > +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > +     const struct mtk_mmsys_async_info *async = mmsys->data-
> > >async_info;
> > +     int i;
> > +
> > +     if (!mmsys->data->num_async_info)
> > +             return;
> > +
> > +     for (i = 0; i < mmsys->data->num_async_info; i++)
> > +             if (comp_id == async[i].comp_id)
> > +                     break;
> > +
> > +     if (i == mmsys->data->num_async_info)
> > +             return;
> > +
> > +     mtk_mmsys_update_bits(mmsys, async[i].offset, async[i].mask,
> > +                           height << 16 | width, cmdq_pkt);
> 
> linux/bitfield.h provides macros that you should use for those
> register fields.
> 

We use "mtk_mmsys_update_bits" to check if a cmdq packet exists.
If the cmdq packet exists, the function will make settings through
cmdq.
If cmdq is NULL, it will directly make settings through the CPU.

Regarding your comment
"linux/bitfield.h provides macros that you should use for those
register fields", are they suggesting that:

[1] We should use the macros provided by linux/bitfield.h to replace
expressions like "height << 16" 

or [2] We should rewrite mtk_mmsys_update_bits using kernel APIs
> > +}
> > +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_config);
> > +
> > +void mtk_mmsys_default_config(struct device *dev)
> > +{
> > +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > +     const struct mtk_mmsys_default *def_config = mmsys->data-
> > >def_config;
> > +     int i;
> > +
> > +     if (!mmsys->data->num_def_config)
> > +             return;
> > +
> > +     for (i = 0; i < mmsys->data->num_def_config; i++)
> > +             mtk_mmsys_update_bits(mmsys, def_config[i].offset,
> > def_config[i].mask,
> > +                                   def_config[i].val, NULL);
> > +}
> > +EXPORT_SYMBOL_GPL(mtk_mmsys_default_config);
> > +
> >   void mtk_mmsys_ddp_connect(struct device *dev,
> >                          enum mtk_ddp_comp_id cur,
> >                          enum mtk_ddp_comp_id next)
> > @@ -390,7 +537,7 @@ static int mtk_mmsys_probe(struct
> > platform_device *pdev)
> >       struct platform_device *clks;
> >       struct platform_device *drm;
> >       struct mtk_mmsys *mmsys;
> > -     int ret;
> > +     int ret, i;
> > 
> >       mmsys = devm_kzalloc(dev, sizeof(*mmsys), GFP_KERNEL);
> >       if (!mmsys)
> > @@ -432,6 +579,49 @@ static int mtk_mmsys_probe(struct
> > platform_device *pdev)
> >               return PTR_ERR(clks);
> >       mmsys->clks_pdev = clks;
> > 
> > +     if (mmsys->data->num_top_clk) {
> > +             struct device_node *node;
> > +
> > +             node = of_get_child_by_name(dev->of_node, "top");
> 
> No, you can't do that if there's no binding to support that.
> 
We will add the "async" component in the MMSYS YAML file.
"async" is a nessceary clock in the specific routing display 
path MUX configuration
> 
> > +             if (!node) {
> > +                     dev_err(&pdev->dev, "Couldn't find top
> > node\n");
> > +                     return -EINVAL;
> > +             }
> > +
> > +             mmsys->top_clk = devm_kmalloc_array(dev, mmsys->data-
> > >num_top_clk,
> > +                                                 sizeof(*mmsys-
> > >top_clk), GFP_KERNEL);
> > +             if (!mmsys->top_clk)
> > +                     return -ENOMEM;
> > +
> > +             for (i = 0; i < mmsys->data->num_top_clk; i++) {
> > +                     mmsys->top_clk[i] = of_clk_get(node, i);
> > +                     if (IS_ERR(mmsys->top_clk[i]))
> > +                             return PTR_ERR(mmsys->top_clk[i]);
> > +             }
> > +     }
> > +
> > +     if (mmsys->data->num_async_info) {
> > +             struct device_node *node;
> > +
> > +             node = of_get_child_by_name(dev->of_node, "async");
> > +             if (!node) {
> > +                     dev_err(&pdev->dev, "Couldn't find async
> > node\n");
> > +                     return -EINVAL;
> > +             }
> > +
> 
> Also this looks like you have children providing only clocks?!
> I really need to look at the bindings to decide, but this looks
> wrong.
> 
We will add the "async" component in the MMSYS YAML file.
"async" is a nessceary clock in the specific routing display 
path MUX configuration
> Regards,
> Angelo
> 
> 
> Best Regards, 
Paul
Re: [PATCH v2 06/15] soc: mediatek: add mmsys support for MT8196
Posted by AngeloGioacchino Del Regno 8 months, 2 weeks ago
Il 02/04/25 06:06, Paul-pl Chen (陳柏霖) ha scritto:
> On Mon, 2025-03-24 at 18:09 +0100, AngeloGioacchino Del Regno wrote:
>>
>> External email : Please do not click links or open attachments until
>> you have verified the sender or the content.
>>
>>
>> Il 21/03/25 10:33, paul-pl.chen ha scritto:
>>> From: Nancy Lin <nancy.lin@mediatek.com>
>>>
>>> 1. Defining driver data and adding compatible string
>>> for different subsystems
>>> (DISPSYS0, DISPSYS1, OVLSYS0, OVLSYS1, VDISP_AO)
>>> 2. Adding functions to control top clocks and ddp clocks.
>>> 3. Updating the probe function to initialize clocks and
>>> enable runtime PM if its node has the power-domains property.
>>> 4. Adding functions to configure ddp components and
>>> set default configurations.
>>> 5. Adding the routing table for each mmsys in MT8196.
>>
>> You need at least two commits for all that you're doing here... and
>> adding MT8196
>> tables should be the last one.
>>
> Hi AngeloGioacchino,
> 
> Thank you for your feedback. I appreciate your suggestion to split the
> changes into at least two commits. Based on your advice, I'm
> considering dividing the changes as follows:
> 
> Commit 1: Add mmsys support
> This commit would include:
> (1) Defining driver data and adding compatible strings for different
> subsystems (DISPSYS0, DISPSYS1, OVLSYS0, OVLSYS1, VDISP_AO)
> (2) Adding functions to control top clocks and ddp clocks
> (3) Updating the probe function to initialize clocks and enable runtime
> PM if its node has the power-domains property
> (4) Adding functions to configure ddp components and set default
> configurations
> 
> Commit 2: Add mmsys tables support for MT8196
> This commit would focus on:
> (5) Adding the routing table for each mmsys in MT8196
> 
> Does this division align with your expectations?

Yes, but if you want, you can even do more than two commits - just make it
readable; each commit needs a precise scope, only changes that *need to*
be together go in a single commit.

>>>
>>> Signed-off-by: Nancy Lin <nancy.lin@mediatek.com>
>>> Signed-off-by: Paul-pl Chen <paul-pl.chen@mediatek.com>
>>> ---
>>>    drivers/soc/mediatek/mt8196-mmsys.h    | 451
>>> +++++++++++++++++++++++++
>>>    drivers/soc/mediatek/mtk-mmsys.c       | 203 ++++++++++-
>>>    drivers/soc/mediatek/mtk-mmsys.h       |  18 +
>>>    include/linux/soc/mediatek/mtk-mmsys.h |  60 ++++
>>>    4 files changed, 731 insertions(+), 1 deletion(-)
>>>    create mode 100644 drivers/soc/mediatek/mt8196-mmsys.h
>>>
>>> diff --git a/drivers/soc/mediatek/mt8196-mmsys.h
>>> b/drivers/soc/mediatek/mt8196-mmsys.h
>>> new file mode 100644
>>> index 000000000000..ff841ae9939a
>>> --- /dev/null
>>> +++ b/drivers/soc/mediatek/mt8196-mmsys.h
>>> @@ -0,0 +1,451 @@
>>
>> ..snip..
>>
>>> +static const struct mtk_mmsys_default
>>> mmsys_mt8196_disp0_default_table[] = {
>>> +     {MT8196_OVLSYS_GCE_EVENT_SEL, MT8196_EVENT_GCE_EN, GENMASK(1,
>>> 0)},
>>> +     {MT8196_DISP0_BYPASS_MUX_SHADOW,
>>> +      MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW,
>>> +      MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW},
>>> +     {MT8196_DISP0_DLI_RELAY0, MT8196_DLI_RELAY_1T2P, GENMASK(31,
>>> 30)},
>>> +     {MT8196_DISP0_DLI_RELAY1, MT8196_DLI_RELAY_1T2P, GENMASK(31,
>>> 30)},
>>> +     {MT8196_DISP0_DLI_RELAY8, MT8196_DLI_RELAY_1T2P, GENMASK(31,
>>> 30)},
>>> +     {MT8196_DISP0_DLO_RELAY1, MT8196_DLI_RELAY_1T2P, GENMASK(31,
>>> 30)},
>>> +     {MT8196_DISP0_DLO_RELAY2, MT8196_DLI_RELAY_1T2P, GENMASK(31,
>>> 30)},
>>> +     {MT8196_DISP0_DLO_RELAY3, MT8196_DLI_RELAY_1T2P, GENMASK(31,
>>> 30)},
>>> +};
>>> +
>>> +static const struct mtk_mmsys_default
>>> mmsys_mt8196_disp1_default_table[] = {
>>> +     {MT8196_OVLSYS_GCE_EVENT_SEL, MT8196_EVENT_GCE_EN, GENMASK(1,
>>> 0)},
>>> +     {MT8196_DISP1_INT_MERGE, 0, BIT(0)},
>>> +     {MT8196_DISP1_BYPASS_MUX_SHADOW,
>>> +      MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW,
>>> +      MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW},
>>> +     {MT8196_DISP1_DLI_RELAY21, MT8196_DLI_RELAY_1T2P, GENMASK(31,
>>> 30)},
>>> +     {MT8196_DISP1_DLI_RELAY22, MT8196_DLI_RELAY_1T2P, GENMASK(31,
>>> 30)},
>>> +     {MT8196_DISP1_DLI_RELAY23, MT8196_DLI_RELAY_1T2P, GENMASK(31,
>>> 30)},
>>> +     {MT8196_DISP1_GCE_FRAME_DONE_SEL0, MT8196_FRAME_DONE_DVO,
>>> GENMASK(5, 0)},
>>> +     {MT8196_DISP1_GCE_FRAME_DONE_SEL1,
>>> MT8196_FRAME_DONE_DP_INTF0, GENMASK(5, 0)},
>>> +};
>>> +
>>> +static const struct mtk_mmsys_routes
>>> mmsys_mt8196_ovl0_routing_table[] = {
>>> +     {
>>> +             DDP_COMPONENT_OVL0_EXDMA2,
>>> DDP_COMPONENT_OVL0_BLENDER1,
>>
>> There's a new MMSYS_ROUTE macro that was introduced because tables
>> contained
>> wrong values in multiple instances and in multiple SoCs: please use
>> it here and
>> for all routing tables.
>>
> Sure, I will use the new MMSYS_ROUTE macro " MMSYS_ROUTE " to replace
> the old routing table.
>>> +             MT8196_OVL_RSZ_IN_CB2_MOUT_EN,
>>> MT8196_DISP_OVL_EXDMA2_1_TO_OVL_EXDMA_OUT_CB3,
>>> +             MT8196_DISP_OVL_EXDMA2_1_TO_OVL_EXDMA_OUT_CB3
>>
>> ..snip..
>>
>>> +};
>>> +#endif /* __SOC_MEDIATEK_MT8196_MMSYS_H */
>>> diff --git a/drivers/soc/mediatek/mtk-mmsys.c
>>> b/drivers/soc/mediatek/mtk-mmsys.c
>>> index bb4639ca0b8c..1d3ca4f9f237 100644
>>> --- a/drivers/soc/mediatek/mtk-mmsys.c
>>> +++ b/drivers/soc/mediatek/mtk-mmsys.c
>>> @@ -4,12 +4,14 @@
>>>     * Author: James Liao <jamesjj.liao@mediatek.com>
>>>     */
>>>
>>> +#include <linux/clk.h>
>>>    #include <linux/delay.h>
>>>    #include <linux/device.h>
>>>    #include <linux/io.h>
>>>    #include <linux/module.h>
>>>    #include <linux/of.h>
>>>    #include <linux/platform_device.h>
>>> +#include <linux/pm_runtime.h>
>>>    #include <linux/reset-controller.h>
>>>    #include <linux/soc/mediatek/mtk-mmsys.h>
>>>
>>> @@ -21,6 +23,7 @@
>>>    #include "mt8188-mmsys.h"
>>>    #include "mt8192-mmsys.h"
>>>    #include "mt8195-mmsys.h"
>>> +#include "mt8196-mmsys.h"
>>>    #include "mt8365-mmsys.h"
>>>
>>>    #define MMSYS_SW_RESET_PER_REG 32
>>> @@ -144,6 +147,54 @@ static const struct mtk_mmsys_driver_data
>>> mt8195_vppsys1_driver_data = {
>>>        .is_vppsys = true,
>>>    };
>>>
>>> +static const struct mtk_mmsys_driver_data
>>> mt8196_dispsys0_driver_data = {
>>> +     .clk_driver = "clk-mt8196-disp0",
>>> +     .routes = mmsys_mt8196_disp0_routing_table,
>>> +     .num_routes = ARRAY_SIZE(mmsys_mt8196_disp0_routing_table),
>>> +     .async_info = mmsys_mt8196_disp0_async_comp_table,
>>> +     .num_async_info =
>>> ARRAY_SIZE(mmsys_mt8196_disp0_async_comp_table),
>>> +     .def_config = mmsys_mt8196_disp0_default_table,
>>> +     .num_def_config =
>>> ARRAY_SIZE(mmsys_mt8196_disp0_default_table),
>>> +     .num_top_clk = 1,
>>> +};
>>> +
>>> +static const struct mtk_mmsys_driver_data
>>> mt8196_dispsys1_driver_data = {
>>> +     .clk_driver = "clk-mt8196-disp1",
>>> +     .routes = mmsys_mt8196_disp1_routing_table,
>>> +     .num_routes = ARRAY_SIZE(mmsys_mt8196_disp1_routing_table),
>>> +     .async_info = mmsys_mt8196_disp1_async_comp_table,
>>> +     .num_async_info =
>>> ARRAY_SIZE(mmsys_mt8196_disp1_async_comp_table),
>>> +     .def_config = mmsys_mt8196_disp1_default_table,
>>> +     .num_def_config =
>>> ARRAY_SIZE(mmsys_mt8196_disp1_default_table),
>>> +     .num_top_clk = 1,
>>> +};
>>> +
>>> +static const struct mtk_mmsys_driver_data
>>> mt8196_ovlsys0_driver_data = {
>>> +     .clk_driver = "clk-mt8196-ovl0",
>>> +     .routes = mmsys_mt8196_ovl0_routing_table,
>>> +     .num_routes = ARRAY_SIZE(mmsys_mt8196_ovl0_routing_table),
>>> +     .async_info = mmsys_mt8196_ovl0_async_comp_table,
>>> +     .num_async_info =
>>> ARRAY_SIZE(mmsys_mt8196_ovl0_async_comp_table),
>>> +     .def_config = mmsys_mt8196_ovl0_default_table,
>>> +     .num_def_config =
>>> ARRAY_SIZE(mmsys_mt8196_ovl0_default_table),
>>> +};
>>> +
>>> +static const struct mtk_mmsys_driver_data
>>> mt8196_ovlsys1_driver_data = {
>>> +     .clk_driver = "clk-mt8196-ovl1",
>>> +     .routes = mmsys_mt8196_ovl1_routing_table,
>>> +     .num_routes = ARRAY_SIZE(mmsys_mt8196_ovl1_routing_table),
>>> +     .async_info = mmsys_mt8196_ovl1_async_comp_table,
>>> +     .num_async_info =
>>> ARRAY_SIZE(mmsys_mt8196_ovl1_async_comp_table),
>>> +     .def_config = mmsys_mt8196_ovl0_default_table,
>>> +     .num_def_config =
>>> ARRAY_SIZE(mmsys_mt8196_ovl0_default_table),
>>> +};
>>> +
>>> +static const struct mtk_mmsys_driver_data
>>> mt8196_vdisp_ao_driver_data = {
>>> +     .clk_driver = "clk-mt8196-vdisp_ao",
>>> +     .def_config = mmsys_mt8196_vdisp_ao_default_table,
>>> +     .num_def_config =
>>> ARRAY_SIZE(mmsys_mt8196_vdisp_ao_default_table),
>>> +};
>>> +
>>>    static const struct mtk_mmsys_driver_data
>>> mt8365_mmsys_driver_data = {
>>>        .clk_driver = "clk-mt8365-mm",
>>>        .routes = mt8365_mmsys_routing_table,
>>> @@ -158,6 +209,9 @@ struct mtk_mmsys {
>>>        spinlock_t lock; /* protects mmsys_sw_rst_b reg */
>>>        struct reset_controller_dev rcdev;
>>>        struct cmdq_client_reg cmdq_base;
>>> +     struct clk **async_clk;
>>> +     int num_async_clk;
>>> +     struct clk **top_clk;
>>>    };
>>>
>>>    static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys, u32
>>> offset, u32 mask, u32 val,
>>> @@ -180,6 +234,99 @@ static void mtk_mmsys_update_bits(struct
>>> mtk_mmsys *mmsys, u32 offset, u32 mask,
>>>        writel_relaxed(tmp, mmsys->regs + offset);
>>>    }
>>>
>>> +int mtk_mmsys_top_clk_enable(struct device *dev)
>>> +{
>>> +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
>>> +     int ret, i;
>>> +
>>> +     if (!mmsys->data->num_top_clk)
>>> +             return 0;
>>> +
>>> +     for (i = 0; i < mmsys->data->num_top_clk; i++)
>>> +             ret = clk_prepare_enable(mmsys->top_clk[i]);
>>> +     return ret;
>>> +}
>>> +EXPORT_SYMBOL_GPL(mtk_mmsys_top_clk_enable);
>>> +
>>> +void mtk_mmsys_top_clk_disable(struct device *dev)
>>> +{
>>> +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
>>> +     int i;
>>> +
>>> +     for (i = 0; i < mmsys->data->num_top_clk; i++)
>>> +             clk_disable_unprepare(mmsys->top_clk[i]);
>>> +}
>>> +EXPORT_SYMBOL_GPL(mtk_mmsys_top_clk_disable);
>>> +
>>> +int mtk_mmsys_ddp_clk_enable(struct device *dev, enum
>>> mtk_ddp_comp_id comp_id)
>>> +{
>>> +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
>>> +     const struct mtk_mmsys_async_info *async = mmsys->data-
>>>> async_info;
>>> +
>>> +     int i;
>>> +
>>> +     if (!mmsys->data->num_async_info)
>>> +             return 0;
>>> +
>>> +     for (i = 0; i < mmsys->data->num_async_info; i++)
>>> +             if (comp_id == async[i].comp_id)
>>> +                     return clk_prepare_enable(mmsys-
>>>> async_clk[async[i].index]);
>>
>> Why can't you add the clocks in the mediatek-drm nodes and handle
>> enablement in the
>> drm driver?!
>>
> The "async" is not like other components under mediate-drm that have
> independent functions.It only controls which clocks need to be enabled
> when the path MUX goes through certain routes.
> 
> That's why it's placed in mtk-mmsys. It's only activated when it needs
> to be connected to the necessary path MUX.
> 
> Currently, the path order is represented through component IDs.
> Therefore, to indicate its relative position on the DDP path, we
> defined a component ID for it to use.
> 

I'm still not convinced - this explanation still doesn't exclude the possibility
of doing that in mediatek-drm, really.

Having one big node containing clocks for multiple hardware IPs doesn't correctly
describe the hardware in the devicetree as well, and this is because those clocks
don't belong to the big VDO, but to the single hardware components that are
children of a VDO.

While this means that the clocks are still contained in a VDO macro-block, they
are relative to a sub-block and enable register access of a sub-block, not of
the VDO macro-block.


>>> +     return 0;
>>> +}
>>> +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_clk_enable);
>>> +
>>> +void mtk_mmsys_ddp_clk_disable(struct device *dev, enum
>>> mtk_ddp_comp_id comp_id)
>>> +{
>>> +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
>>> +     const struct mtk_mmsys_async_info *async = mmsys->data-
>>>> async_info;
>>> +     int i;
>>> +
>>> +     if (!mmsys->data->num_async_info)
>>> +             return;
>>> +
>>> +     for (i = 0; i < mmsys->data->num_async_info; i++)
>>> +             if (comp_id == async[i].comp_id)
>>> +                     clk_disable_unprepare(mmsys-
>>>> async_clk[async[i].index]);
>>> +}
>>> +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_clk_disable);
>>> +
>>> +void mtk_mmsys_ddp_config(struct device *dev, enum mtk_ddp_comp_id
>>> comp_id,
>>> +                       int width, int height, struct cmdq_pkt
>>> *cmdq_pkt)
>>> +{
>>> +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
>>> +     const struct mtk_mmsys_async_info *async = mmsys->data-
>>>> async_info;
>>> +     int i;
>>> +
>>> +     if (!mmsys->data->num_async_info)
>>> +             return;
>>> +
>>> +     for (i = 0; i < mmsys->data->num_async_info; i++)
>>> +             if (comp_id == async[i].comp_id)
>>> +                     break;
>>> +
>>> +     if (i == mmsys->data->num_async_info)
>>> +             return;
>>> +
>>> +     mtk_mmsys_update_bits(mmsys, async[i].offset, async[i].mask,
>>> +                           height << 16 | width, cmdq_pkt);
>>
>> linux/bitfield.h provides macros that you should use for those
>> register fields.
>>
> 
> We use "mtk_mmsys_update_bits" to check if a cmdq packet exists.
> If the cmdq packet exists, the function will make settings through
> cmdq.
> If cmdq is NULL, it will directly make settings through the CPU.
> 
> Regarding your comment
> "linux/bitfield.h provides macros that you should use for those
> register fields", are they suggesting that:
> 
> [1] We should use the macros provided by linux/bitfield.h to replace
> expressions like "height << 16"
> 

You have to use those macros to replace expressions like "height << 16".

val = FIELD_PREP(SOMETHING, height);
val |= FIELD_PREP(SOMETHING_ELSE, width);

mtk_mmsys_update_bits(mmsys, async[i].offset, async[i].mask, val, cmdq_pkt);

Regards,
Angelo

> or [2] We should rewrite mtk_mmsys_update_bits using kernel APIs
>>> +}
>>> +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_config);
>>> +
>>> +void mtk_mmsys_default_config(struct device *dev)
>>> +{
>>> +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
>>> +     const struct mtk_mmsys_default *def_config = mmsys->data-
>>>> def_config;
>>> +     int i;
>>> +
>>> +     if (!mmsys->data->num_def_config)
>>> +             return;
>>> +
>>> +     for (i = 0; i < mmsys->data->num_def_config; i++)
>>> +             mtk_mmsys_update_bits(mmsys, def_config[i].offset,
>>> def_config[i].mask,
>>> +                                   def_config[i].val, NULL);
>>> +}
>>> +EXPORT_SYMBOL_GPL(mtk_mmsys_default_config);
>>> +
>>>    void mtk_mmsys_ddp_connect(struct device *dev,
>>>                           enum mtk_ddp_comp_id cur,
>>>                           enum mtk_ddp_comp_id next)
>>> @@ -390,7 +537,7 @@ static int mtk_mmsys_probe(struct
>>> platform_device *pdev)
>>>        struct platform_device *clks;
>>>        struct platform_device *drm;
>>>        struct mtk_mmsys *mmsys;
>>> -     int ret;
>>> +     int ret, i;
>>>
>>>        mmsys = devm_kzalloc(dev, sizeof(*mmsys), GFP_KERNEL);
>>>        if (!mmsys)
>>> @@ -432,6 +579,49 @@ static int mtk_mmsys_probe(struct
>>> platform_device *pdev)
>>>                return PTR_ERR(clks);
>>>        mmsys->clks_pdev = clks;
>>>
>>> +     if (mmsys->data->num_top_clk) {
>>> +             struct device_node *node;
>>> +
>>> +             node = of_get_child_by_name(dev->of_node, "top");
>>
>> No, you can't do that if there's no binding to support that.
>>
> We will add the "async" component in the MMSYS YAML file.
> "async" is a nessceary clock in the specific routing display
> path MUX configuration
>>
>>> +             if (!node) {
>>> +                     dev_err(&pdev->dev, "Couldn't find top
>>> node\n");
>>> +                     return -EINVAL;
>>> +             }
>>> +
>>> +             mmsys->top_clk = devm_kmalloc_array(dev, mmsys->data-
>>>> num_top_clk,
>>> +                                                 sizeof(*mmsys-
>>>> top_clk), GFP_KERNEL);
>>> +             if (!mmsys->top_clk)
>>> +                     return -ENOMEM;
>>> +
>>> +             for (i = 0; i < mmsys->data->num_top_clk; i++) {
>>> +                     mmsys->top_clk[i] = of_clk_get(node, i);
>>> +                     if (IS_ERR(mmsys->top_clk[i]))
>>> +                             return PTR_ERR(mmsys->top_clk[i]);
>>> +             }
>>> +     }
>>> +
>>> +     if (mmsys->data->num_async_info) {
>>> +             struct device_node *node;
>>> +
>>> +             node = of_get_child_by_name(dev->of_node, "async");
>>> +             if (!node) {
>>> +                     dev_err(&pdev->dev, "Couldn't find async
>>> node\n");
>>> +                     return -EINVAL;
>>> +             }
>>> +
>>
>> Also this looks like you have children providing only clocks?!
>> I really need to look at the bindings to decide, but this looks
>> wrong.
>>
> We will add the "async" component in the MMSYS YAML file.
> "async" is a nessceary clock in the specific routing display
> path MUX configuration
>> Regards,
>> Angelo
>>
>>
>> Best Regards,
> Paul


Re: [PATCH v2 06/15] soc: mediatek: add mmsys support for MT8196
Posted by Paul-pl Chen (陳柏霖) 8 months, 1 week ago
On Wed, 2025-04-02 at 11:33 +0200, AngeloGioacchino Del Regno wrote:
> 
> External email : Please do not click links or open attachments until
> you have verified the sender or the content.
> 
> 
> Il 02/04/25 06:06, Paul-pl Chen (陳柏霖) ha scritto:
> > On Mon, 2025-03-24 at 18:09 +0100, AngeloGioacchino Del Regno
> > wrote:
> > > 
> > > External email : Please do not click links or open attachments
> > > until
> > > you have verified the sender or the content.
> > > 
> > > 
> > > Il 21/03/25 10:33, paul-pl.chen ha scritto:
> > > > From: Nancy Lin <nancy.lin@mediatek.com>
> > > > 
> > > > 1. Defining driver data and adding compatible string
> > > > for different subsystems
> > > > (DISPSYS0, DISPSYS1, OVLSYS0, OVLSYS1, VDISP_AO)
> > > > 2. Adding functions to control top clocks and ddp clocks.
> > > > 3. Updating the probe function to initialize clocks and
> > > > enable runtime PM if its node has the power-domains property.
> > > > 4. Adding functions to configure ddp components and
> > > > set default configurations.
> > > > 5. Adding the routing table for each mmsys in MT8196.
> > > 
> > > You need at least two commits for all that you're doing here...
> > > and
> > > adding MT8196
> > > tables should be the last one.
> > > 
> > Hi AngeloGioacchino,
> > 
> > Thank you for your feedback. I appreciate your suggestion to split
> > the
> > changes into at least two commits. Based on your advice, I'm
> > considering dividing the changes as follows:
> > 
> > Commit 1: Add mmsys support
> > This commit would include:
> > (1) Defining driver data and adding compatible strings for
> > different
> > subsystems (DISPSYS0, DISPSYS1, OVLSYS0, OVLSYS1, VDISP_AO)
> > (2) Adding functions to control top clocks and ddp clocks
> > (3) Updating the probe function to initialize clocks and enable
> > runtime
> > PM if its node has the power-domains property
> > (4) Adding functions to configure ddp components and set default
> > configurations
> > 
> > Commit 2: Add mmsys tables support for MT8196
> > This commit would focus on:
> > (5) Adding the routing table for each mmsys in MT8196
> > 
> > Does this division align with your expectations?
> 
> Yes, but if you want, you can even do more than two commits - just
> make it
> readable; each commit needs a precise scope, only changes that *need
> to*
> be together go in a single commit.
> 
Got it, thanks!

> > > > 
> > > > Signed-off-by: Nancy Lin <nancy.lin@mediatek.com>
> > > > Signed-off-by: Paul-pl Chen <paul-pl.chen@mediatek.com>
> > > > ---
> > > >    drivers/soc/mediatek/mt8196-mmsys.h    | 451
> > > > +++++++++++++++++++++++++
> > > >    drivers/soc/mediatek/mtk-mmsys.c       | 203 ++++++++++-
> > > >    drivers/soc/mediatek/mtk-mmsys.h       |  18 +
> > > >    include/linux/soc/mediatek/mtk-mmsys.h |  60 ++++
> > > >    4 files changed, 731 insertions(+), 1 deletion(-)
> > > >    create mode 100644 drivers/soc/mediatek/mt8196-mmsys.h
> > > > 
> > > > diff --git a/drivers/soc/mediatek/mt8196-mmsys.h
> > > > b/drivers/soc/mediatek/mt8196-mmsys.h
> > > > new file mode 100644
> > > > index 000000000000..ff841ae9939a
> > > > --- /dev/null
> > > > +++ b/drivers/soc/mediatek/mt8196-mmsys.h
> > > > @@ -0,0 +1,451 @@
> > > 
> > > ..snip..
> > > 
> > > > +static const struct mtk_mmsys_default
> > > > mmsys_mt8196_disp0_default_table[] = {
> > > > +     {MT8196_OVLSYS_GCE_EVENT_SEL, MT8196_EVENT_GCE_EN,
> > > > GENMASK(1,
> > > > 0)},
> > > > +     {MT8196_DISP0_BYPASS_MUX_SHADOW,
> > > > +      MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW,
> > > > +      MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW},
> > > > +     {MT8196_DISP0_DLI_RELAY0, MT8196_DLI_RELAY_1T2P,
> > > > GENMASK(31,
> > > > 30)},
> > > > +     {MT8196_DISP0_DLI_RELAY1, MT8196_DLI_RELAY_1T2P,
> > > > GENMASK(31,
> > > > 30)},
> > > > +     {MT8196_DISP0_DLI_RELAY8, MT8196_DLI_RELAY_1T2P,
> > > > GENMASK(31,
> > > > 30)},
> > > > +     {MT8196_DISP0_DLO_RELAY1, MT8196_DLI_RELAY_1T2P,
> > > > GENMASK(31,
> > > > 30)},
> > > > +     {MT8196_DISP0_DLO_RELAY2, MT8196_DLI_RELAY_1T2P,
> > > > GENMASK(31,
> > > > 30)},
> > > > +     {MT8196_DISP0_DLO_RELAY3, MT8196_DLI_RELAY_1T2P,
> > > > GENMASK(31,
> > > > 30)},
> > > > +};
> > > > +
> > > > +static const struct mtk_mmsys_default
> > > > mmsys_mt8196_disp1_default_table[] = {
> > > > +     {MT8196_OVLSYS_GCE_EVENT_SEL, MT8196_EVENT_GCE_EN,
> > > > GENMASK(1,
> > > > 0)},
> > > > +     {MT8196_DISP1_INT_MERGE, 0, BIT(0)},
> > > > +     {MT8196_DISP1_BYPASS_MUX_SHADOW,
> > > > +      MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW,
> > > > +      MT8196_CB_BYPASS_MUX_SHADOW | MT8196_BYPASS_MUX_SHADOW},
> > > > +     {MT8196_DISP1_DLI_RELAY21, MT8196_DLI_RELAY_1T2P,
> > > > GENMASK(31,
> > > > 30)},
> > > > +     {MT8196_DISP1_DLI_RELAY22, MT8196_DLI_RELAY_1T2P,
> > > > GENMASK(31,
> > > > 30)},
> > > > +     {MT8196_DISP1_DLI_RELAY23, MT8196_DLI_RELAY_1T2P,
> > > > GENMASK(31,
> > > > 30)},
> > > > +     {MT8196_DISP1_GCE_FRAME_DONE_SEL0, MT8196_FRAME_DONE_DVO,
> > > > GENMASK(5, 0)},
> > > > +     {MT8196_DISP1_GCE_FRAME_DONE_SEL1,
> > > > MT8196_FRAME_DONE_DP_INTF0, GENMASK(5, 0)},
> > > > +};
> > > > +
> > > > +static const struct mtk_mmsys_routes
> > > > mmsys_mt8196_ovl0_routing_table[] = {
> > > > +     {
> > > > +             DDP_COMPONENT_OVL0_EXDMA2,
> > > > DDP_COMPONENT_OVL0_BLENDER1,
> > > 
> > > There's a new MMSYS_ROUTE macro that was introduced because
> > > tables
> > > contained
> > > wrong values in multiple instances and in multiple SoCs: please
> > > use
> > > it here and
> > > for all routing tables.
> > > 
> > Sure, I will use the new MMSYS_ROUTE macro " MMSYS_ROUTE " to
> > replace
> > the old routing table.
> > > > +             MT8196_OVL_RSZ_IN_CB2_MOUT_EN,
> > > > MT8196_DISP_OVL_EXDMA2_1_TO_OVL_EXDMA_OUT_CB3,
> > > > +             MT8196_DISP_OVL_EXDMA2_1_TO_OVL_EXDMA_OUT_CB3
> > > 
> > > ..snip..
> > > 
> > > > +};
> > > > +#endif /* __SOC_MEDIATEK_MT8196_MMSYS_H */
> > > > diff --git a/drivers/soc/mediatek/mtk-mmsys.c
> > > > b/drivers/soc/mediatek/mtk-mmsys.c
> > > > index bb4639ca0b8c..1d3ca4f9f237 100644
> > > > --- a/drivers/soc/mediatek/mtk-mmsys.c
> > > > +++ b/drivers/soc/mediatek/mtk-mmsys.c
> > > > @@ -4,12 +4,14 @@
> > > >     * Author: James Liao <jamesjj.liao@mediatek.com>
> > > >     */
> > > > 
> > > > +#include <linux/clk.h>
> > > >    #include <linux/delay.h>
> > > >    #include <linux/device.h>
> > > >    #include <linux/io.h>
> > > >    #include <linux/module.h>
> > > >    #include <linux/of.h>
> > > >    #include <linux/platform_device.h>
> > > > +#include <linux/pm_runtime.h>
> > > >    #include <linux/reset-controller.h>
> > > >    #include <linux/soc/mediatek/mtk-mmsys.h>
> > > > 
> > > > @@ -21,6 +23,7 @@
> > > >    #include "mt8188-mmsys.h"
> > > >    #include "mt8192-mmsys.h"
> > > >    #include "mt8195-mmsys.h"
> > > > +#include "mt8196-mmsys.h"
> > > >    #include "mt8365-mmsys.h"
> > > > 
> > > >    #define MMSYS_SW_RESET_PER_REG 32
> > > > @@ -144,6 +147,54 @@ static const struct mtk_mmsys_driver_data
> > > > mt8195_vppsys1_driver_data = {
> > > >        .is_vppsys = true,
> > > >    };
> > > > 
> > > > +static const struct mtk_mmsys_driver_data
> > > > mt8196_dispsys0_driver_data = {
> > > > +     .clk_driver = "clk-mt8196-disp0",
> > > > +     .routes = mmsys_mt8196_disp0_routing_table,
> > > > +     .num_routes =
> > > > ARRAY_SIZE(mmsys_mt8196_disp0_routing_table),
> > > > +     .async_info = mmsys_mt8196_disp0_async_comp_table,
> > > > +     .num_async_info =
> > > > ARRAY_SIZE(mmsys_mt8196_disp0_async_comp_table),
> > > > +     .def_config = mmsys_mt8196_disp0_default_table,
> > > > +     .num_def_config =
> > > > ARRAY_SIZE(mmsys_mt8196_disp0_default_table),
> > > > +     .num_top_clk = 1,
> > > > +};
> > > > +
> > > > +static const struct mtk_mmsys_driver_data
> > > > mt8196_dispsys1_driver_data = {
> > > > +     .clk_driver = "clk-mt8196-disp1",
> > > > +     .routes = mmsys_mt8196_disp1_routing_table,
> > > > +     .num_routes =
> > > > ARRAY_SIZE(mmsys_mt8196_disp1_routing_table),
> > > > +     .async_info = mmsys_mt8196_disp1_async_comp_table,
> > > > +     .num_async_info =
> > > > ARRAY_SIZE(mmsys_mt8196_disp1_async_comp_table),
> > > > +     .def_config = mmsys_mt8196_disp1_default_table,
> > > > +     .num_def_config =
> > > > ARRAY_SIZE(mmsys_mt8196_disp1_default_table),
> > > > +     .num_top_clk = 1,
> > > > +};
> > > > +
> > > > +static const struct mtk_mmsys_driver_data
> > > > mt8196_ovlsys0_driver_data = {
> > > > +     .clk_driver = "clk-mt8196-ovl0",
> > > > +     .routes = mmsys_mt8196_ovl0_routing_table,
> > > > +     .num_routes =
> > > > ARRAY_SIZE(mmsys_mt8196_ovl0_routing_table),
> > > > +     .async_info = mmsys_mt8196_ovl0_async_comp_table,
> > > > +     .num_async_info =
> > > > ARRAY_SIZE(mmsys_mt8196_ovl0_async_comp_table),
> > > > +     .def_config = mmsys_mt8196_ovl0_default_table,
> > > > +     .num_def_config =
> > > > ARRAY_SIZE(mmsys_mt8196_ovl0_default_table),
> > > > +};
> > > > +
> > > > +static const struct mtk_mmsys_driver_data
> > > > mt8196_ovlsys1_driver_data = {
> > > > +     .clk_driver = "clk-mt8196-ovl1",
> > > > +     .routes = mmsys_mt8196_ovl1_routing_table,
> > > > +     .num_routes =
> > > > ARRAY_SIZE(mmsys_mt8196_ovl1_routing_table),
> > > > +     .async_info = mmsys_mt8196_ovl1_async_comp_table,
> > > > +     .num_async_info =
> > > > ARRAY_SIZE(mmsys_mt8196_ovl1_async_comp_table),
> > > > +     .def_config = mmsys_mt8196_ovl0_default_table,
> > > > +     .num_def_config =
> > > > ARRAY_SIZE(mmsys_mt8196_ovl0_default_table),
> > > > +};
> > > > +
> > > > +static const struct mtk_mmsys_driver_data
> > > > mt8196_vdisp_ao_driver_data = {
> > > > +     .clk_driver = "clk-mt8196-vdisp_ao",
> > > > +     .def_config = mmsys_mt8196_vdisp_ao_default_table,
> > > > +     .num_def_config =
> > > > ARRAY_SIZE(mmsys_mt8196_vdisp_ao_default_table),
> > > > +};
> > > > +
> > > >    static const struct mtk_mmsys_driver_data
> > > > mt8365_mmsys_driver_data = {
> > > >        .clk_driver = "clk-mt8365-mm",
> > > >        .routes = mt8365_mmsys_routing_table,
> > > > @@ -158,6 +209,9 @@ struct mtk_mmsys {
> > > >        spinlock_t lock; /* protects mmsys_sw_rst_b reg */
> > > >        struct reset_controller_dev rcdev;
> > > >        struct cmdq_client_reg cmdq_base;
> > > > +     struct clk **async_clk;
> > > > +     int num_async_clk;
> > > > +     struct clk **top_clk;
> > > >    };
> > > > 
> > > >    static void mtk_mmsys_update_bits(struct mtk_mmsys *mmsys,
> > > > u32
> > > > offset, u32 mask, u32 val,
> > > > @@ -180,6 +234,99 @@ static void mtk_mmsys_update_bits(struct
> > > > mtk_mmsys *mmsys, u32 offset, u32 mask,
> > > >        writel_relaxed(tmp, mmsys->regs + offset);
> > > >    }
> > > > 
> > > > +int mtk_mmsys_top_clk_enable(struct device *dev)
> > > > +{
> > > > +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > > > +     int ret, i;
> > > > +
> > > > +     if (!mmsys->data->num_top_clk)
> > > > +             return 0;
> > > > +
> > > > +     for (i = 0; i < mmsys->data->num_top_clk; i++)
> > > > +             ret = clk_prepare_enable(mmsys->top_clk[i]);
> > > > +     return ret;
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(mtk_mmsys_top_clk_enable);
> > > > +
> > > > +void mtk_mmsys_top_clk_disable(struct device *dev)
> > > > +{
> > > > +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > > > +     int i;
> > > > +
> > > > +     for (i = 0; i < mmsys->data->num_top_clk; i++)
> > > > +             clk_disable_unprepare(mmsys->top_clk[i]);
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(mtk_mmsys_top_clk_disable);
> > > > +
> > > > +int mtk_mmsys_ddp_clk_enable(struct device *dev, enum
> > > > mtk_ddp_comp_id comp_id)
> > > > +{
> > > > +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > > > +     const struct mtk_mmsys_async_info *async = mmsys->data-
> > > > > async_info;
> > > > +
> > > > +     int i;
> > > > +
> > > > +     if (!mmsys->data->num_async_info)
> > > > +             return 0;
> > > > +
> > > > +     for (i = 0; i < mmsys->data->num_async_info; i++)
> > > > +             if (comp_id == async[i].comp_id)
> > > > +                     return clk_prepare_enable(mmsys-
> > > > > async_clk[async[i].index]);
> > > 
> > > Why can't you add the clocks in the mediatek-drm nodes and handle
> > > enablement in the
> > > drm driver?!
> > > 
> > The "async" is not like other components under mediate-drm that
> > have
> > independent functions.It only controls which clocks need to be
> > enabled
> > when the path MUX goes through certain routes.
> > 
> > That's why it's placed in mtk-mmsys. It's only activated when it
> > needs
> > to be connected to the necessary path MUX.
> > 
> > Currently, the path order is represented through component IDs.
> > Therefore, to indicate its relative position on the DDP path, we
> > defined a component ID for it to use.
> > 

> I'm still not convinced - this explanation still doesn't exclude the
> possibility
> of doing that in mediatek-drm, really.
> 
> Having one big node containing clocks for multiple hardware IPs
> doesn't correctly
> describe the hardware in the devicetree as well, and this is because
> those clocks
> don't belong to the big VDO, but to the single hardware components
> that are
> children of a VDO.
> 
> While this means that the clocks are still contained in a VDO macro-
> block, they
> are relative to a sub-block and enable register access of a sub-
> block, not of
> the VDO macro-block.
> 
> 
Below is the DTS node defined as "async" for MT8196, based on the DTS
node "ovlsys1_config_clk async."

		ovlsys1_config_clk: syscon@32c00000 {
			compatible = "mediatek,mt8196-ovlsys1",
"syscon";
			reg = <0 0x32c00000 0 0x1000>;
			mm-hw-ccf-regmap = <&mm_hwv>;
			mboxes = <&gce0 2 CMDQ_THR_PRIO_4>, <&gce0 10
CMDQ_THR_PRIO_4>;
			power-domains = <&hfrpsys
MT8196_POWER_DOMAIN_OVL1_DORMANT>;
			#clock-cells = <1>;

			async {
				clocks = <&ovlsys1_config_clk
CLK_OVL_DLO5_DISP>,
					 <&ovlsys1_config_clk
CLK_OVL_DLO6_DISP>;
			};
		};

The clock configuration for this "async" will affect the connections in
the "mmsys_mt8196_ovl0_routing_table,"
specifically "MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY5" and
"MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY6."

Patch:
https://patchwork.kernel.org/project/linux-mediatek/patch/20250321093435.94835-7-paul-pl.chen@mediatek.com/
Driver Code:
static const struct mtk_mmsys_routes mmsys_mt8196_ovl0_routing_table[]
= {
         //Snip
        {
		DDP_COMPONENT_OVL0_OUTPROC0,
DDP_COMPONENT_OVL0_DLO_ASYNC5,
		MT8196_OVL_OUTPROC_OUT_CB0_MOUT_EN,
MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY5,
		MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY5
	}, {
		DDP_COMPONENT_OVL0_OUTPROC1,
DDP_COMPONENT_OVL0_DLO_ASYNC6,
		MT8196_OVL_OUTPROC_OUT_CB1_MOUT_EN,
MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY6,
		MT8196_DISP_OVL_OUT_PROC_CB_TO_OVL_DLO_RELAY6
	}
}


> > > > +     return 0;
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_clk_enable);
> > > > +
> > > > +void mtk_mmsys_ddp_clk_disable(struct device *dev, enum
> > > > mtk_ddp_comp_id comp_id)
> > > > +{
> > > > +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > > > +     const struct mtk_mmsys_async_info *async = mmsys->data-
> > > > > async_info;
> > > > +     int i;
> > > > +
> > > > +     if (!mmsys->data->num_async_info)
> > > > +             return;
> > > > +
> > > > +     for (i = 0; i < mmsys->data->num_async_info; i++)
> > > > +             if (comp_id == async[i].comp_id)
> > > > +                     clk_disable_unprepare(mmsys-
> > > > > async_clk[async[i].index]);
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_clk_disable);
> > > > +
> > > > +void mtk_mmsys_ddp_config(struct device *dev, enum
> > > > mtk_ddp_comp_id
> > > > comp_id,
> > > > +                       int width, int height, struct cmdq_pkt
> > > > *cmdq_pkt)
> > > > +{
> > > > +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > > > +     const struct mtk_mmsys_async_info *async = mmsys->data-
> > > > > async_info;
> > > > +     int i;
> > > > +
> > > > +     if (!mmsys->data->num_async_info)
> > > > +             return;
> > > > +
> > > > +     for (i = 0; i < mmsys->data->num_async_info; i++)
> > > > +             if (comp_id == async[i].comp_id)
> > > > +                     break;
> > > > +
> > > > +     if (i == mmsys->data->num_async_info)
> > > > +             return;
> > > > +
> > > > +     mtk_mmsys_update_bits(mmsys, async[i].offset,
> > > > async[i].mask,
> > > > +                           height << 16 | width, cmdq_pkt);
> > > 
> > > linux/bitfield.h provides macros that you should use for those
> > > register fields.
> > > 
> > 
> > We use "mtk_mmsys_update_bits" to check if a cmdq packet exists.
> > If the cmdq packet exists, the function will make settings through
> > cmdq.
> > If cmdq is NULL, it will directly make settings through the CPU.
> > 
> > Regarding your comment
> > "linux/bitfield.h provides macros that you should use for those
> > register fields", are they suggesting that:
> > 
> > [1] We should use the macros provided by linux/bitfield.h to
> > replace
> > expressions like "height << 16"
> > 
> 
> You have to use those macros to replace expressions like "height <<
> 16".
> 
> val = FIELD_PREP(SOMETHING, height);
> val |= FIELD_PREP(SOMETHING_ELSE, width);
> 
> mtk_mmsys_update_bits(mmsys, async[i].offset, async[i].mask, val,
> cmdq_pkt);
> 
> Regards,
> Angelo
> 
> 
> Thanks for the feednack and example.

Best Regards, 
Paul
> 
> 
> > or [2] We should rewrite mtk_mmsys_update_bits using kernel APIs
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(mtk_mmsys_ddp_config);
> > > > +
> > > > +void mtk_mmsys_default_config(struct device *dev)
> > > > +{
> > > > +     struct mtk_mmsys *mmsys = dev_get_drvdata(dev);
> > > > +     const struct mtk_mmsys_default *def_config = mmsys->data-
> > > > > def_config;
> > > > +     int i;
> > > > +
> > > > +     if (!mmsys->data->num_def_config)
> > > > +             return;
> > > > +
> > > > +     for (i = 0; i < mmsys->data->num_def_config; i++)
> > > > +             mtk_mmsys_update_bits(mmsys,
> > > > def_config[i].offset,
> > > > def_config[i].mask,
> > > > +                                   def_config[i].val, NULL);
> > > > +}
> > > > +EXPORT_SYMBOL_GPL(mtk_mmsys_default_config);
> > > > +
> > > >    void mtk_mmsys_ddp_connect(struct device *dev,
> > > >                           enum mtk_ddp_comp_id cur,
> > > >                           enum mtk_ddp_comp_id next)
> > > > @@ -390,7 +537,7 @@ static int mtk_mmsys_probe(struct
> > > > platform_device *pdev)
> > > >        struct platform_device *clks;
> > > >        struct platform_device *drm;
> > > >        struct mtk_mmsys *mmsys;
> > > > -     int ret;
> > > > +     int ret, i;
> > > > 
> > > >        mmsys = devm_kzalloc(dev, sizeof(*mmsys), GFP_KERNEL);
> > > >        if (!mmsys)
> > > > @@ -432,6 +579,49 @@ static int mtk_mmsys_probe(struct
> > > > platform_device *pdev)
> > > >                return PTR_ERR(clks);
> > > >        mmsys->clks_pdev = clks;
> > > > 
> > > > +     if (mmsys->data->num_top_clk) {
> > > > +             struct device_node *node;
> > > > +
> > > > +             node = of_get_child_by_name(dev->of_node, "top");
> > > 
> > > No, you can't do that if there's no binding to support that.
> > > 
> > We will add the "async" component in the MMSYS YAML file.
> > "async" is a nessceary clock in the specific routing display
> > path MUX configuration
> > > 
> > > > +             if (!node) {
> > > > +                     dev_err(&pdev->dev, "Couldn't find top
> > > > node\n");
> > > > +                     return -EINVAL;
> > > > +             }
> > > > +
> > > > +             mmsys->top_clk = devm_kmalloc_array(dev, mmsys-
> > > > >data-
> > > > > num_top_clk,
> > > > +                                                
> > > > sizeof(*mmsys-
> > > > > top_clk), GFP_KERNEL);
> > > > +             if (!mmsys->top_clk)
> > > > +                     return -ENOMEM;
> > > > +
> > > > +             for (i = 0; i < mmsys->data->num_top_clk; i++) {
> > > > +                     mmsys->top_clk[i] = of_clk_get(node, i);
> > > > +                     if (IS_ERR(mmsys->top_clk[i]))
> > > > +                             return PTR_ERR(mmsys-
> > > > >top_clk[i]);
> > > > +             }
> > > > +     }
> > > > +
> > > > +     if (mmsys->data->num_async_info) {
> > > > +             struct device_node *node;
> > > > +
> > > > +             node = of_get_child_by_name(dev->of_node,
> > > > "async");
> > > > +             if (!node) {
> > > > +                     dev_err(&pdev->dev, "Couldn't find async
> > > > node\n");
> > > > +                     return -EINVAL;
> > > > +             }
> > > > +
> > > 
> > > Also this looks like you have children providing only clocks?!
> > > I really need to look at the bindings to decide, but this looks
> > > wrong.
> > > 
> > We will add the "async" component in the MMSYS YAML file.
> > "async" is a nessceary clock in the specific routing display
> > path MUX configuration
> > > Regards,
> > > Angelo
> > > 
> > > 
> > > Best Regards,
> > Paul
> 
>