feat(mt8188): add DCM driver

DCM means dynamic clock management, and it can dynamically
slow down or gate clocks during CPU or bus idle.

1. Add MCUSYS related DCM drivers.
2. Enable MCUSYS related DCM by default.

Change-Id: I131354d72bbc190af504e9639bcc85a720e2bb17
diff --git a/plat/mediatek/drivers/dcm/mt8188/mtk_dcm_utils.c b/plat/mediatek/drivers/dcm/mt8188/mtk_dcm_utils.c
new file mode 100644
index 0000000..c054de9
--- /dev/null
+++ b/plat/mediatek/drivers/dcm/mt8188/mtk_dcm_utils.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mtk_dcm_utils.h>
+
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_MASK		BIT(17)
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_MASK		(BIT(15) | BIT(16) | BIT(17) | \
+						 BIT(18) | BIT(21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG2_MASK		(BIT(15) | BIT(16) | BIT(17) | BIT(18))
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_ON		BIT(17)
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_ON		(BIT(15) | BIT(16) | BIT(17) | \
+						 BIT(18) | BIT(21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG2_ON		(BIT(15) | BIT(16) | BIT(17) | BIT(18))
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_OFF		(0x0 << 17)
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_OFF		((0x0 << 15) | (0x0 << 16) | \
+						 (0x0 << 17) | (0x0 << 18) | \
+						 (0x0 << 21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG2_OFF		((0x0 << 15) | (0x0 << 16) | \
+						 (0x0 << 17) | (0x0 << 18))
+
+bool dcm_mp_cpusys_top_adb_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= dcm_check_state(MP_CPUSYS_TOP_MP_ADB_DCM_CFG0,
+			       MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+			       MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
+	ret &= dcm_check_state(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4,
+			       MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+			       MP_CPUSYS_TOP_ADB_DCM_REG1_ON);
+	ret &= dcm_check_state(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+			       MP_CPUSYS_TOP_ADB_DCM_REG2_MASK,
+			       MP_CPUSYS_TOP_ADB_DCM_REG2_ON);
+
+	return ret;
+}
+
+void dcm_mp_cpusys_top_adb_dcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_adb_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG0,
+				   MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4,
+				   MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+				   MP_CPUSYS_TOP_ADB_DCM_REG1_ON);
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+				   MP_CPUSYS_TOP_ADB_DCM_REG2_MASK,
+				   MP_CPUSYS_TOP_ADB_DCM_REG2_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_adb_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG0,
+				   MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_ADB_DCM_REG0_OFF);
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4,
+				   MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+				   MP_CPUSYS_TOP_ADB_DCM_REG1_OFF);
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+				   MP_CPUSYS_TOP_ADB_DCM_REG2_MASK,
+				   MP_CPUSYS_TOP_ADB_DCM_REG2_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_APB_DCM_REG0_MASK	BIT(5)
+#define MP_CPUSYS_TOP_APB_DCM_REG1_MASK	BIT(8)
+#define MP_CPUSYS_TOP_APB_DCM_REG2_MASK	BIT(16)
+#define MP_CPUSYS_TOP_APB_DCM_REG0_ON	BIT(5)
+#define MP_CPUSYS_TOP_APB_DCM_REG1_ON	BIT(8)
+#define MP_CPUSYS_TOP_APB_DCM_REG2_ON	BIT(16)
+#define MP_CPUSYS_TOP_APB_DCM_REG0_OFF	(0x0 << 5)
+#define MP_CPUSYS_TOP_APB_DCM_REG1_OFF	(0x0 << 8)
+#define MP_CPUSYS_TOP_APB_DCM_REG2_OFF	(0x0 << 16)
+
+bool dcm_mp_cpusys_top_apb_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= dcm_check_state(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+			       MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
+			       MP_CPUSYS_TOP_APB_DCM_REG0_ON);
+	ret &= dcm_check_state(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+			       MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
+			       MP_CPUSYS_TOP_APB_DCM_REG1_ON);
+	ret &= dcm_check_state(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+			       MP_CPUSYS_TOP_APB_DCM_REG2_MASK,
+			       MP_CPUSYS_TOP_APB_DCM_REG2_ON);
+
+	return ret;
+}
+
+void dcm_mp_cpusys_top_apb_dcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_apb_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+				   MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_APB_DCM_REG0_ON);
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+				   MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
+				   MP_CPUSYS_TOP_APB_DCM_REG1_ON);
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+				   MP_CPUSYS_TOP_APB_DCM_REG2_MASK,
+				   MP_CPUSYS_TOP_APB_DCM_REG2_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_apb_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+				   MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_APB_DCM_REG0_OFF);
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+				   MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
+				   MP_CPUSYS_TOP_APB_DCM_REG1_OFF);
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+				   MP_CPUSYS_TOP_APB_DCM_REG2_MASK,
+				   MP_CPUSYS_TOP_APB_DCM_REG2_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK (BIT(11) | BIT(24) | BIT(25))
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON (BIT(11) | BIT(24) | BIT(25))
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_OFF ((0x0 << 11) | \
+						(0x0 << 24) | \
+						(0x0 << 25))
+
+bool dcm_mp_cpusys_top_bus_pll_div_dcm_is_on(void)
+{
+	return dcm_check_state(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+			       MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK,
+			       MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_bus_pll_div_dcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_bus_pll_div_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+				   MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_bus_pll_div_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+				   MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK	BIT(0)
+#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON	BIT(0)
+#define MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_OFF	(0x0 << 0)
+
+bool dcm_mp_cpusys_top_core_stall_dcm_is_on(void)
+{
+	return dcm_check_state(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+			       MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
+			       MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_core_stall_dcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_core_stall_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+				   MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_core_stall_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+				   MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK	(0xffff << 0)
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON	(0xffff << 0)
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_OFF	(0x0 << 0)
+
+bool dcm_mp_cpusys_top_cpubiu_dcm_is_on(void)
+{
+	return dcm_check_state(MP_CPUSYS_TOP_MCSIC_DCM0,
+			       MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK,
+			       MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_cpubiu_dcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_cpubiu_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MCSIC_DCM0,
+				   MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpubiu_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MCSIC_DCM0,
+				   MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_CPUBIU_DCM_REG0_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK (BIT(24) | BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON (BIT(24) | BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_OFF ((0x0 << 24) | (0x0 << 25))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void)
+{
+	return dcm_check_state(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0,
+			       MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK,
+			       MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_0_dcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_0_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0,
+				   MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_0_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0,
+				   MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK (BIT(24) | BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON (BIT(24) | BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_OFF ((0x0 << 24) | (0x0 << 25))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void)
+{
+	return dcm_check_state(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1,
+			       MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK,
+			       MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_1_dcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_1_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1,
+				   MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_1_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1,
+				   MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK	BIT(4)
+#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON	BIT(4)
+#define MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_OFF	(0x0 << 4)
+
+bool dcm_mp_cpusys_top_fcm_stall_dcm_is_on(void)
+{
+	return dcm_check_state(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+			       MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK,
+			       MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_fcm_stall_dcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_fcm_stall_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+				   MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_fcm_stall_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG7,
+				   MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK	BIT(31)
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON		BIT(31)
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_OFF	(0x0U << 31)
+
+bool dcm_mp_cpusys_top_last_cor_idle_dcm_is_on(void)
+{
+	return dcm_check_state(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+			       MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
+			       MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_last_cor_idle_dcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_last_cor_idle_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+				   MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_last_cor_idle_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG,
+				   MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_MASK (BIT(1) | BIT(4))
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_ON (BIT(1) | BIT(4))
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_OFF ((0x0 << 1) | (0x0 << 4))
+
+bool dcm_mp_cpusys_top_misc_dcm_is_on(void)
+{
+	return dcm_check_state(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+			       MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
+			       MP_CPUSYS_TOP_MISC_DCM_REG0_ON);
+}
+
+void dcm_mp_cpusys_top_misc_dcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_misc_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+				   MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_MISC_DCM_REG0_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_misc_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+				   MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
+				   MP_CPUSYS_TOP_MISC_DCM_REG0_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK BIT(3)
+#define MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_ON BIT(3)
+#define MP_CPUSYS_TOP_MP0_QDCM_REG1_ON (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF ((0x0 << 3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG1_OFF ((0x0 << 0) | (0x0 << 1) | \
+					 (0x0 << 2) | (0x0 << 3))
+
+bool dcm_mp_cpusys_top_mp0_qdcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= dcm_check_state(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+			       MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+			       MP_CPUSYS_TOP_MP0_QDCM_REG0_ON);
+	ret &= dcm_check_state(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+			       MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK,
+			       MP_CPUSYS_TOP_MP0_QDCM_REG1_ON);
+
+	return ret;
+}
+
+void dcm_mp_cpusys_top_mp0_qdcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_mp0_qdcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+				   MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+				   MP_CPUSYS_TOP_MP0_QDCM_REG0_ON);
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+				   MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK,
+				   MP_CPUSYS_TOP_MP0_QDCM_REG1_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_mp0_qdcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0,
+				   MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+				   MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF);
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+				   MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK,
+				   MP_CPUSYS_TOP_MP0_QDCM_REG1_OFF);
+	}
+}
+
+#define CPCCFG_REG_EMI_WFIFO_REG0_MASK (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+#define CPCCFG_REG_EMI_WFIFO_REG0_ON (BIT(0) | BIT(1) | BIT(2) | BIT(3))
+#define CPCCFG_REG_EMI_WFIFO_REG0_OFF ((0x0 << 0) | (0x0 << 1) | \
+				       (0x0 << 2) | (0x0 << 3))
+
+bool dcm_cpccfg_reg_emi_wfifo_is_on(void)
+{
+	return dcm_check_state(CPCCFG_REG_EMI_WFIFO,
+			       CPCCFG_REG_EMI_WFIFO_REG0_MASK,
+			       CPCCFG_REG_EMI_WFIFO_REG0_ON);
+}
+
+void dcm_cpccfg_reg_emi_wfifo(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'cpccfg_reg_emi_wfifo'" */
+		mmio_clrsetbits_32(CPCCFG_REG_EMI_WFIFO,
+				   CPCCFG_REG_EMI_WFIFO_REG0_MASK,
+				   CPCCFG_REG_EMI_WFIFO_REG0_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'cpccfg_reg_emi_wfifo'" */
+		mmio_clrsetbits_32(CPCCFG_REG_EMI_WFIFO,
+				   CPCCFG_REG_EMI_WFIFO_REG0_MASK,
+				   CPCCFG_REG_EMI_WFIFO_REG0_OFF);
+	}
+}
diff --git a/plat/mediatek/drivers/dcm/mt8188/mtk_dcm_utils.h b/plat/mediatek/drivers/dcm/mt8188/mtk_dcm_utils.h
new file mode 100644
index 0000000..5d758dd
--- /dev/null
+++ b/plat/mediatek/drivers/dcm/mt8188/mtk_dcm_utils.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_DCM_UTILS_H
+#define MTK_DCM_UTILS_H
+
+#include <stdbool.h>
+
+#include <mtk_dcm.h>
+#include <platform_def.h>
+
+/* Base */
+#define MP_CPUSYS_TOP_BASE	(MCUCFG_BASE + 0x8000)
+#define CPCCFG_REG_BASE		(MCUCFG_BASE + 0xA800)
+
+/* Register Definition */
+#define CPCCFG_REG_EMI_WFIFO		(CPCCFG_REG_BASE + 0x100)
+#define MP_CPUSYS_TOP_CPU_PLLDIV_CFG0	(MP_CPUSYS_TOP_BASE + 0x22a0)
+#define MP_CPUSYS_TOP_CPU_PLLDIV_CFG1	(MP_CPUSYS_TOP_BASE + 0x22a4)
+#define MP_CPUSYS_TOP_BUS_PLLDIV_CFG	(MP_CPUSYS_TOP_BASE + 0x22e0)
+#define MP_CPUSYS_TOP_MCSIC_DCM0	(MP_CPUSYS_TOP_BASE + 0x2440)
+#define MP_CPUSYS_TOP_MP_ADB_DCM_CFG0	(MP_CPUSYS_TOP_BASE + 0x2500)
+#define MP_CPUSYS_TOP_MP_ADB_DCM_CFG4	(MP_CPUSYS_TOP_BASE + 0x2510)
+#define MP_CPUSYS_TOP_MP_MISC_DCM_CFG0	(MP_CPUSYS_TOP_BASE + 0x2518)
+#define MP_CPUSYS_TOP_MCUSYS_DCM_CFG0	(MP_CPUSYS_TOP_BASE + 0x25c0)
+#define MP_CPUSYS_TOP_MP0_DCM_CFG0	(MP_CPUSYS_TOP_BASE + 0x4880)
+#define MP_CPUSYS_TOP_MP0_DCM_CFG7	(MP_CPUSYS_TOP_BASE + 0x489c)
+
+/* MP_CPUSYS_TOP */
+bool dcm_mp_cpusys_top_adb_dcm_is_on(void);
+void dcm_mp_cpusys_top_adb_dcm(bool on);
+bool dcm_mp_cpusys_top_apb_dcm_is_on(void);
+void dcm_mp_cpusys_top_apb_dcm(bool on);
+bool dcm_mp_cpusys_top_bus_pll_div_dcm_is_on(void);
+void dcm_mp_cpusys_top_bus_pll_div_dcm(bool on);
+bool dcm_mp_cpusys_top_core_stall_dcm_is_on(void);
+void dcm_mp_cpusys_top_core_stall_dcm(bool on);
+bool dcm_mp_cpusys_top_cpubiu_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpubiu_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_0_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_1_dcm(bool on);
+bool dcm_mp_cpusys_top_fcm_stall_dcm_is_on(void);
+void dcm_mp_cpusys_top_fcm_stall_dcm(bool on);
+bool dcm_mp_cpusys_top_last_cor_idle_dcm_is_on(void);
+void dcm_mp_cpusys_top_last_cor_idle_dcm(bool on);
+bool dcm_mp_cpusys_top_misc_dcm_is_on(void);
+void dcm_mp_cpusys_top_misc_dcm(bool on);
+bool dcm_mp_cpusys_top_mp0_qdcm_is_on(void);
+void dcm_mp_cpusys_top_mp0_qdcm(bool on);
+/* CPCCFG_REG */
+bool dcm_cpccfg_reg_emi_wfifo_is_on(void);
+void dcm_cpccfg_reg_emi_wfifo(bool on);
+
+#endif
diff --git a/plat/mediatek/drivers/dcm/mtk_dcm.c b/plat/mediatek/drivers/dcm/mtk_dcm.c
new file mode 100644
index 0000000..ca79a20
--- /dev/null
+++ b/plat/mediatek/drivers/dcm/mtk_dcm.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/mtk_init/mtk_init.h>
+#include <mtk_dcm.h>
+#include <mtk_dcm_utils.h>
+
+static void dcm_armcore(bool mode)
+{
+	dcm_mp_cpusys_top_bus_pll_div_dcm(mode);
+	dcm_mp_cpusys_top_cpu_pll_div_0_dcm(mode);
+	dcm_mp_cpusys_top_cpu_pll_div_1_dcm(mode);
+}
+
+static void dcm_mcusys(bool on)
+{
+	dcm_mp_cpusys_top_adb_dcm(on);
+	dcm_mp_cpusys_top_apb_dcm(on);
+	dcm_mp_cpusys_top_cpubiu_dcm(on);
+	dcm_mp_cpusys_top_misc_dcm(on);
+	dcm_mp_cpusys_top_mp0_qdcm(on);
+
+	/* CPCCFG_REG */
+	dcm_cpccfg_reg_emi_wfifo(on);
+	dcm_mp_cpusys_top_last_cor_idle_dcm(on);
+}
+
+static void dcm_stall(bool on)
+{
+	dcm_mp_cpusys_top_core_stall_dcm(on);
+	dcm_mp_cpusys_top_fcm_stall_dcm(on);
+}
+
+static bool check_dcm_state(void)
+{
+	bool ret = true;
+
+	ret &= dcm_mp_cpusys_top_bus_pll_div_dcm_is_on();
+	ret &= dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on();
+	ret &= dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on();
+
+	ret &= dcm_mp_cpusys_top_adb_dcm_is_on();
+	ret &= dcm_mp_cpusys_top_apb_dcm_is_on();
+	ret &= dcm_mp_cpusys_top_cpubiu_dcm_is_on();
+	ret &= dcm_mp_cpusys_top_misc_dcm_is_on();
+	ret &= dcm_mp_cpusys_top_mp0_qdcm_is_on();
+	ret &= dcm_cpccfg_reg_emi_wfifo_is_on();
+	ret &= dcm_mp_cpusys_top_last_cor_idle_dcm_is_on();
+
+	ret &= dcm_mp_cpusys_top_core_stall_dcm_is_on();
+	ret &= dcm_mp_cpusys_top_fcm_stall_dcm_is_on();
+
+	return ret;
+}
+
+bool dcm_check_state(uintptr_t addr, unsigned int mask, unsigned int compare)
+{
+	return ((mmio_read_32(addr) & mask) == compare);
+}
+
+int dcm_set_init(void)
+{
+	int ret;
+
+	dcm_armcore(true);
+	dcm_mcusys(true);
+	dcm_stall(true);
+
+	if (check_dcm_state() == false) {
+		ERROR("Failed to set default dcm on!!\n");
+		ret = -1;
+	} else {
+		INFO("%s, dcm pass\n", __func__);
+		ret = 0;
+	}
+
+	return ret;
+}
+MTK_PLAT_SETUP_0_INIT(dcm_set_init);
diff --git a/plat/mediatek/drivers/dcm/mtk_dcm.h b/plat/mediatek/drivers/dcm/mtk_dcm.h
new file mode 100644
index 0000000..05f8d45
--- /dev/null
+++ b/plat/mediatek/drivers/dcm/mtk_dcm.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_DCM_H
+#define MTK_DCM_H
+
+#include <stdbool.h>
+
+bool dcm_check_state(uintptr_t addr, unsigned int mask, unsigned int compare);
+int dcm_set_init(void);
+
+#endif /* #ifndef MTK_DCM_H */
diff --git a/plat/mediatek/drivers/dcm/rules.mk b/plat/mediatek/drivers/dcm/rules.mk
new file mode 100644
index 0000000..a8ee05e
--- /dev/null
+++ b/plat/mediatek/drivers/dcm/rules.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := mtk_dcm
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/mtk_dcm.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/${MTK_SOC}/mtk_dcm_utils.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}
+PLAT_INCLUDES += -I${LOCAL_DIR}/${MTK_SOC}
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/mt8188/platform.mk b/plat/mediatek/mt8188/platform.mk
index a76dff3..97f303c 100644
--- a/plat/mediatek/mt8188/platform.mk
+++ b/plat/mediatek/mt8188/platform.mk
@@ -24,6 +24,7 @@
 MODULES-y += $(MTK_PLAT)/lib/pm
 MODULES-y += $(MTK_PLAT)/lib/system_reset
 MODULES-y += $(MTK_PLAT)/drivers/cirq
+MODULES-y += $(MTK_PLAT)/drivers/dcm
 MODULES-y += $(MTK_PLAT)/drivers/dp
 MODULES-y += $(MTK_PLAT)/drivers/gic600
 MODULES-y += $(MTK_PLAT)/drivers/gpio