Merge changes from topic "mediatek upstream" into integration

* changes:
  refactor(mt8188): move platform_def.h to mt8188/include
  feat(mt8188): add MCUSYS support
  feat(mt8188): add armv8.2 support
  feat(mt8188): add DFD control in SiP service
  feat(mt8188): add EMI MPU basic drivers
  feat(mt8188): add DCM driver
  feat(mt8188): add reset and poweroff functions
  feat(mediatek): add more flexibility of mtk_pm.c
  feat(mediatek): add more options for build helper
  feat(mt8188): add LPM driver support
  feat(mt8188): apply ERRATA for CA-78
  fix(mediatek): remove unused cold_boot.[c|h]
  fix(mediatek): wrap cold_boot.h with MTK_SIP_KERNEL_BOOT_ENABLE
  feat(mt8186): add EMI MPU support for SCP and DSP
diff --git a/plat/mediatek/build_helpers/options.mk b/plat/mediatek/build_helpers/options.mk
index eb579e5..7b63a3e 100644
--- a/plat/mediatek/build_helpers/options.mk
+++ b/plat/mediatek/build_helpers/options.mk
@@ -15,3 +15,10 @@
 $(eval $(call add_defined_option,MTK_SOC))
 $(eval $(call add_defined_option,UART_CLOCK))
 $(eval $(call add_defined_option,UART_BAUDRATE))
+$(eval $(call add_defined_option,CONFIG_MTK_MCUSYS))
+$(eval $(call add_defined_option,CONFIG_MTK_PM_SUPPORT))
+$(eval $(call add_defined_option,CONFIG_MTK_CPU_PM_SUPPORT))
+$(eval $(call add_defined_option,CONFIG_MTK_SMP_EN))
+$(eval $(call add_defined_option,CONFIG_MTK_CPU_SUSPEND_EN))
+$(eval $(call add_defined_option,CONFIG_MTK_PM_ARCH))
+$(eval $(call add_defined_option,CONFIG_MTK_CPU_PM_ARCH))
diff --git a/plat/mediatek/common/cold_boot.c b/plat/mediatek/common/cold_boot.c
deleted file mode 100644
index ff585fe..0000000
--- a/plat/mediatek/common/cold_boot.c
+++ /dev/null
@@ -1,336 +0,0 @@
-/*
- * Copyright (c) 2022, Mediatek Inc. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-#include <errno.h>
-#include <inttypes.h>
-#include <stdint.h>
-#include <common/debug.h>
-#include <common/runtime_svc.h>
-#include <lib/el3_runtime/context_mgmt.h>
-
-/* Vendors headers */
-#include <cold_boot.h>
-#include <lib/mtk_init/mtk_init.h>
-#include <mtk_sip_svc.h>
-
-static struct kernel_info k_info;
-static entry_point_info_t bl32_image_ep_info;
-static entry_point_info_t bl33_image_ep_info;
-static bool el1_is_2nd_bootloader = true;
-static struct atf_arg_t atfarg;
-
-static int init_mtk_bl32_arg(void)
-{
-	struct mtk_bl_param_t *p_mtk_bl_param;
-	struct atf_arg_t *p_atfarg;
-
-	p_mtk_bl_param = (struct mtk_bl_param_t *) get_mtk_bl31_fw_config(BOOT_ARG_FROM_BL2);
-	if (p_mtk_bl_param == NULL) {
-		ERROR("p_mtk_bl_param is NULL!\n");
-		return -1;
-	}
-	p_atfarg = (struct atf_arg_t *)p_mtk_bl_param->atf_arg_addr;
-	if (p_atfarg == NULL) {
-		ERROR("bl32 argument is NULL!\n");
-		return -1;
-	}
-	memcpy((void *)&atfarg, (void *)p_atfarg, sizeof(struct atf_arg_t));
-	return 0;
-}
-MTK_EARLY_PLAT_INIT(init_mtk_bl32_arg);
-
-static void save_kernel_info(uint64_t pc, uint64_t r0, uint64_t r1, uint64_t k32_64)
-{
-	k_info.k32_64 = k32_64;
-	k_info.pc = pc;
-
-	if (k32_64 == LINUX_KERNEL_32) {
-		/* for 32 bits kernel */
-		k_info.r0 = 0;
-		/* machtype */
-		k_info.r1 = r0;
-		/* tags */
-		k_info.r2 = r1;
-	} else {
-		/* for 64 bits kernel */
-		k_info.r0 = r0;
-		k_info.r1 = r1;
-	}
-}
-
-static uint32_t plat_get_spsr_for_bl32_64_entry(void)
-{
-	return SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
-}
-
-#if MTK_BL33_IS_64BIT
-static uint32_t plat_get_spsr_for_bl33_entry(void)
-{
-	uint32_t spsr;
-	uint32_t mode;
-
-	mode = MODE_EL1;
-	spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
-	return spsr;
-}
-#else
-static uint32_t plat_get_spsr_for_bl33_entry(void)
-{
-	unsigned int mode;
-	uint32_t spsr;
-	unsigned int ee;
-	unsigned long daif;
-
-	INFO("Secondary bootloader is AArch32\n");
-	mode = MODE32_svc;
-	ee = 0;
-	/*
-	 * TODO: Choose async. exception bits if HYP mode is not
-	 * implemented according to the values of SCR.{AW, FW} bits
-	 */
-	daif = DAIF_ABT_BIT | DAIF_IRQ_BIT | DAIF_FIQ_BIT;
-
-	spsr = SPSR_MODE32(mode, 0, ee, daif);
-	return spsr;
-}
-#endif
-
-static void populate_bl32_image_ep(entry_point_info_t *bl32_ep_instance,
-		struct mtk_bl_param_t *p_mtk_bl_param)
-{
-	entry_point_info_t *populated_ep_bl32 = bl32_ep_instance;
-
-	if (p_mtk_bl_param == NULL) {
-		ERROR("p_mtk_bl_param is NULL!\n");
-		panic();
-	}
-	SET_SECURITY_STATE(bl32_ep_instance->h.attr, SECURE);
-	SET_PARAM_HEAD(populated_ep_bl32,
-		       PARAM_EP,
-		       VERSION_1,
-		       populated_ep_bl32->h.attr);
-	populated_ep_bl32->pc = atfarg.tee_entry;
-	populated_ep_bl32->spsr = plat_get_spsr_for_bl32_64_entry();
-}
-
-static void populate_bl33_image_ep(entry_point_info_t *bl33_ep_instance,
-		struct mtk_bl_param_t *p_mtk_bl_param)
-{
-	entry_point_info_t *populated_ep_bl33 = bl33_ep_instance;
-
-	if (p_mtk_bl_param == NULL) {
-		ERROR("p_mtk_bl_param is NULL!\n");
-		panic();
-	}
-	SET_SECURITY_STATE(bl33_ep_instance->h.attr, NON_SECURE);
-	SET_PARAM_HEAD(populated_ep_bl33,
-		       PARAM_EP,
-		       VERSION_1,
-		       populated_ep_bl33->h.attr);
-	populated_ep_bl33->pc = p_mtk_bl_param->bl33_start_addr;
-	/* standardize 2nd bootloader input argument */
-	populated_ep_bl33->args.arg0 = p_mtk_bl_param->bootarg_loc;
-	/* compatible to old GZ version */
-	populated_ep_bl33->args.arg4 = p_mtk_bl_param->bootarg_loc;
-	populated_ep_bl33->args.arg5 = p_mtk_bl_param->bootarg_size;
-	populated_ep_bl33->spsr = plat_get_spsr_for_bl33_entry();
-}
-
-static int populate_bl_images_ep(struct mtk_bl_param_t *p_mtk_bl_param)
-{
-	/*
-	 * Tell BL31 where the non-trusted software image
-	 * is located and the entry state information
-	 */
-	populate_bl33_image_ep(&bl33_image_ep_info, p_mtk_bl_param);
-	populate_bl32_image_ep(&bl32_image_ep_info, p_mtk_bl_param);
-	return 0;
-}
-
-static int populate_bl_images_ep_init(void)
-{
-	return populate_bl_images_ep(get_mtk_bl31_fw_config(BOOT_ARG_FROM_BL2));
-}
-MTK_PLAT_SETUP_0_INIT(populate_bl_images_ep_init);
-
-static entry_point_info_t *bl31_plat_get_next_kernel64_ep_info(void)
-{
-	entry_point_info_t *next_image_info;
-	unsigned long el_status;
-	unsigned int mode;
-
-	el_status = 0;
-	mode = 0;
-
-	/* Kernel image is always non-secured */
-	next_image_info = &bl33_image_ep_info;
-
-	/* Figure out what mode we enter the non-secure world in */
-	el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT;
-	el_status &= ID_AA64PFR0_ELX_MASK;
-
-	INFO("Kernel_EL %d\n", el_status?2:1);
-	if (el_status) {
-		mode = MODE_EL2;
-	} else {
-		mode = MODE_EL1;
-	}
-	INFO("Kernel is 64Bit\n");
-	next_image_info->spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
-	next_image_info->pc = k_info.pc;
-	next_image_info->args.arg0 = k_info.r0;
-	next_image_info->args.arg1 = k_info.r1;
-
-	INFO("pc=0x%lx, r0=0x%" PRIx64 ", r1=0x%" PRIx64 "\n",
-	     next_image_info->pc,
-	     next_image_info->args.arg0,
-	     next_image_info->args.arg1);
-
-	SET_SECURITY_STATE(next_image_info->h.attr, NON_SECURE);
-
-	/* None of the images on this platform can have 0x0 as the entrypoint */
-	if (next_image_info->pc) {
-		return next_image_info;
-	}
-
-	return NULL;
-}
-
-static entry_point_info_t *bl31_plat_get_next_kernel32_ep_info(void)
-{
-	entry_point_info_t *next_image_info;
-	unsigned int mode;
-
-	mode = 0;
-
-	/* Kernel image is always non-secured */
-	next_image_info = &bl33_image_ep_info;
-
-	/* Figure out what mode we enter the non-secure world in */
-	mode = MODE32_hyp;
-	/*
-	 * TODO: Consider the possibility of specifying the SPSR in
-	 * the FIP ToC and allowing the platform to have a say as
-	 * well.
-	 */
-
-	INFO("Kernel is 32Bit\n");
-	next_image_info->spsr = SPSR_MODE32(mode, SPSR_T_ARM, SPSR_E_LITTLE,
-					    (DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT));
-	next_image_info->pc = k_info.pc;
-	next_image_info->args.arg0 = k_info.r0;
-	next_image_info->args.arg1 = k_info.r1;
-	next_image_info->args.arg2 = k_info.r2;
-
-	INFO("pc=0x%lx, r0=0x%" PRIx64 ", r1=0x%" PRIx64 ", r2=0x%" PRIx64 "\n",
-	     next_image_info->pc,
-	     next_image_info->args.arg0,
-	     next_image_info->args.arg1,
-	     next_image_info->args.arg2);
-
-	SET_SECURITY_STATE(next_image_info->h.attr, NON_SECURE);
-
-	/* None of the images on this platform can have 0x0 as the entrypoint */
-	if (next_image_info->pc) {
-		return next_image_info;
-	}
-
-	return NULL;
-}
-
-static void bl31_prepare_kernel_entry(uint64_t k32_64)
-{
-	entry_point_info_t *next_image_info = NULL;
-	uint32_t image_type;
-
-	/* Determine which image to execute next */
-	image_type = NON_SECURE; /* bl31_get_next_image_type(); */
-
-	/* Leave 2nd bootloader then jump to kernel */
-	el1_is_2nd_bootloader = false;
-
-	/* Program EL3 registers to enable entry into the next EL */
-	if (k32_64 == LINUX_KERNEL_32) {
-		next_image_info = bl31_plat_get_next_kernel32_ep_info();
-	} else {
-		next_image_info = bl31_plat_get_next_kernel64_ep_info();
-	}
-
-	assert(next_image_info);
-	assert(image_type == GET_SECURITY_STATE(next_image_info->h.attr));
-
-	INFO("BL31: Preparing for EL3 exit to %s world, Kernel\n",
-	     (image_type == SECURE) ? "secure" : "normal");
-	INFO("BL31: Next image address = 0x%" PRIx64 "\n",
-	     next_image_info->pc);
-	INFO("BL31: Next image spsr = 0x%x\n", next_image_info->spsr);
-	cm_init_my_context(next_image_info);
-	cm_prepare_el3_exit(image_type);
-}
-
-bool is_el1_2nd_bootloader(void)
-{
-	return el1_is_2nd_bootloader;
-}
-
-/*******************************************************************************
- * Return a pointer to the 'entry_point_info' structure of the next image for
- * the security state specified. BL33 corresponds to the non-secure image type
- * while BL32 corresponds to the secure image type. A NULL pointer is returned
- * if the image does not exist.
- ******************************************************************************/
-entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
-{
-	entry_point_info_t *next_image_info;
-
-	next_image_info = (type == NON_SECURE) ? &bl33_image_ep_info : &bl32_image_ep_info;
-
-	/* None of the images on this platform can have 0x0 as the entrypoint */
-	if (next_image_info->pc) {
-		return next_image_info;
-	}
-	return NULL;
-}
-
-u_register_t boot_to_kernel(u_register_t x1,
-			    u_register_t x2,
-			    u_register_t x3,
-			    u_register_t x4,
-			    void *handle,
-			    struct smccc_res *smccc_ret)
-{
-	static uint8_t kernel_boot_once_flag;
-
-	/* only support in booting flow */
-	if (kernel_boot_once_flag == 0) {
-		kernel_boot_once_flag = 1;
-
-		INFO("save kernel info\n");
-		save_kernel_info(x1, x2, x3, x4);
-		bl31_prepare_kernel_entry(x4);
-		INFO("el3_exit\n");
-		/*
-		 * FIXME: no better way so far to prevent from
-		 * SiP root handler wipe x0~x3 if not assign smccc_ret
-		 * return register
-		 */
-		smccc_ret->a1 = x3;
-
-		mtk_init_one_level(MTK_INIT_LVL_BL33_DEFER);
-
-#if MTK_CONSOLE_RUNTIME_DISABLE
-		INFO("Turn off BL31 console\n");
-		mtk_console_core_end();
-#endif
-
-		/* Re-assign as x0 register entering Linux kernel */
-		return x2;
-	}
-	return 0;
-}
-/* Register SiP SMC service */
-DECLARE_SMC_HANDLER(MTK_SIP_KERNEL_BOOT, boot_to_kernel);
diff --git a/plat/mediatek/common/mtk_smc_handlers.c b/plat/mediatek/common/mtk_smc_handlers.c
index 24b978c..51a960f 100644
--- a/plat/mediatek/common/mtk_smc_handlers.c
+++ b/plat/mediatek/common/mtk_smc_handlers.c
@@ -6,9 +6,11 @@
 
 #include <assert.h>
 #include <errno.h>
+#if MTK_SIP_KERNEL_BOOT_ENABLE
+#include <cold_boot.h>
+#endif
 #include <common/debug.h>
 #include <common/runtime_svc.h>
-#include <cold_boot.h>
 #include <lib/mtk_init/mtk_init.h>
 #include <mtk_sip_svc.h>
 
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/drivers/dfd/dfd.c b/plat/mediatek/drivers/dfd/dfd.c
new file mode 100644
index 0000000..5770d50
--- /dev/null
+++ b/plat/mediatek/drivers/dfd/dfd.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <dfd.h>
+#include <mtk_sip_svc.h>
+#include <plat_dfd.h>
+
+static u_register_t dfd_smc_dispatcher(u_register_t arg0, u_register_t arg1,
+				       u_register_t arg2, u_register_t arg3,
+				       void *handle, struct smccc_res *smccc_ret)
+{
+	int ret = MTK_SIP_E_SUCCESS;
+
+	switch (arg0) {
+	case PLAT_MTK_DFD_SETUP_MAGIC:
+		INFO("[%s] DFD setup call from kernel\n", __func__);
+		dfd_setup(arg1, arg2, arg3);
+		break;
+	case PLAT_MTK_DFD_READ_MAGIC:
+		/* only allow to access DFD register base + 0x200 */
+		if (arg1 <= 0x200) {
+			ret = mmio_read_32(MISC1_CFG_BASE + arg1);
+		}
+		break;
+	case PLAT_MTK_DFD_WRITE_MAGIC:
+		/* only allow to access DFD register base + 0x200 */
+		if (arg1 <= 0x200) {
+			sync_writel(MISC1_CFG_BASE + arg1, arg2);
+		}
+		break;
+	default:
+		ret = MTK_SIP_E_INVALID_PARAM;
+		break;
+	}
+
+	return ret;
+}
+DECLARE_SMC_HANDLER(MTK_SIP_KERNEL_DFD, dfd_smc_dispatcher);
diff --git a/plat/mediatek/drivers/dfd/dfd.h b/plat/mediatek/drivers/dfd/dfd.h
new file mode 100644
index 0000000..c088bd0
--- /dev/null
+++ b/plat/mediatek/drivers/dfd/dfd.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DFD_H
+#define DFD_H
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+
+void dfd_resume(void);
+void dfd_setup(uint64_t base_addr, uint64_t chain_length, uint64_t cache_dump);
+
+#endif /* DFD_H */
diff --git a/plat/mediatek/drivers/dfd/mt8188/plat_dfd.c b/plat/mediatek/drivers/dfd/mt8188/plat_dfd.c
new file mode 100644
index 0000000..1aa68f5
--- /dev/null
+++ b/plat/mediatek/drivers/dfd/mt8188/plat_dfd.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <dfd.h>
+#include <plat_dfd.h>
+
+static uint64_t dfd_cache_dump;
+static bool dfd_enabled;
+static uint64_t dfd_base_addr;
+static uint64_t dfd_chain_length;
+
+void dfd_setup(uint64_t base_addr, uint64_t chain_length, uint64_t cache_dump)
+{
+	mmio_write_32(MTK_DRM_LATCH_CTL1, MTK_DRM_LATCH_CTL1_VAL);
+	mmio_write_32(MTK_DRM_LATCH_CTL2, MTK_DRM_LATCH_CTL2_VAL);
+	mmio_write_32(MTK_WDT_LATCH_CTL2, MTK_WDT_LATCH_CTL2_VAL);
+
+	mmio_clrbits_32(DFD_O_INTRF_MCU_PWR_CTL_MASK, BIT(2));
+	mmio_setbits_32(DFD_V50_GROUP_0_63_DIFF, 0x1);
+	sync_writel(DFD_INTERNAL_CTL, 0x5);
+	mmio_setbits_32(DFD_INTERNAL_CTL, BIT(13));
+	mmio_setbits_32(DFD_INTERNAL_CTL, 0x1F << 3);
+	mmio_setbits_32(DFD_INTERNAL_CTL, 0x3 << 9);
+	mmio_setbits_32(DFD_INTERNAL_CTL, 0x3 << 19);
+
+	mmio_write_32(DFD_INTERNAL_PWR_ON, 0xB);
+	mmio_write_32(DFD_CHAIN_LENGTH0, chain_length);
+	mmio_write_32(DFD_INTERNAL_SHIFT_CLK_RATIO, 0x0);
+	mmio_write_32(DFD_INTERNAL_TEST_SO_OVER_64, 0x1);
+
+	mmio_write_32(DFD_TEST_SI_0, 0x0);
+	mmio_write_32(DFD_TEST_SI_1, 0x0);
+	mmio_write_32(DFD_TEST_SI_2, 0x0);
+	mmio_write_32(DFD_TEST_SI_3, 0x0);
+
+	sync_writel(DFD_POWER_CTL, 0xF9);
+	sync_writel(DFD_READ_ADDR, DFD_READ_ADDR_VAL);
+	sync_writel(DFD_V30_CTL, 0xD);
+
+	mmio_write_32(DFD_O_SET_BASEADDR_REG, base_addr >> 24);
+	mmio_write_32(DFD_O_REG_0, 0);
+
+	/* setup global variables for suspend and resume */
+	dfd_enabled = true;
+	dfd_base_addr = base_addr;
+	dfd_chain_length = chain_length;
+	dfd_cache_dump = cache_dump;
+
+	if ((cache_dump & DFD_CACHE_DUMP_ENABLE) != 0UL) {
+		mmio_write_32(MTK_DRM_LATCH_CTL2, MTK_DRM_LATCH_CTL2_CACHE_VAL);
+		sync_writel(DFD_V35_ENABLE, 0x1);
+		sync_writel(DFD_V35_TAP_NUMBER, 0xB);
+		sync_writel(DFD_V35_TAP_EN, DFD_V35_TAP_EN_VAL);
+		sync_writel(DFD_V35_SEQ0_0, DFD_V35_SEQ0_0_VAL);
+
+		/* Cache dump only mode */
+		sync_writel(DFD_V35_CTL, 0x1);
+		mmio_write_32(DFD_INTERNAL_NUM_OF_TEST_SO_GROUP, 0xF);
+		mmio_write_32(DFD_CHAIN_LENGTH0, DFD_CHAIN_LENGTH_VAL);
+		mmio_write_32(DFD_CHAIN_LENGTH1, DFD_CHAIN_LENGTH_VAL);
+		mmio_write_32(DFD_CHAIN_LENGTH2, DFD_CHAIN_LENGTH_VAL);
+		mmio_write_32(DFD_CHAIN_LENGTH3, DFD_CHAIN_LENGTH_VAL);
+
+		if ((cache_dump & DFD_PARITY_ERR_TRIGGER) != 0UL) {
+			sync_writel(DFD_HW_TRIGGER_MASK, 0xC);
+			mmio_setbits_32(DFD_INTERNAL_CTL, 0x1 << 4);
+		}
+	}
+	dsbsy();
+}
+
+void dfd_resume(void)
+{
+	if (dfd_enabled == true) {
+		dfd_setup(dfd_base_addr, dfd_chain_length, dfd_cache_dump);
+	}
+}
diff --git a/plat/mediatek/drivers/dfd/mt8188/plat_dfd.h b/plat/mediatek/drivers/dfd/mt8188/plat_dfd.h
new file mode 100644
index 0000000..5b98024
--- /dev/null
+++ b/plat/mediatek/drivers/dfd/mt8188/plat_dfd.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DFD_H
+#define PLAT_DFD_H
+
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#define sync_writel(addr, val) do { mmio_write_32((addr), (val)); dsbsy(); } while (0)
+
+#define PLAT_MTK_DFD_SETUP_MAGIC		(0x99716150)
+#define PLAT_MTK_DFD_READ_MAGIC			(0x99716151)
+#define PLAT_MTK_DFD_WRITE_MAGIC		(0x99716152)
+
+#define MTK_DRM_LATCH_CTL1			(DRM_BASE + 0x40)
+#define MTK_DRM_LATCH_CTL2			(DRM_BASE + 0x44)
+
+#define MTK_WDT_BASE				(RGU_BASE)
+#define MTK_WDT_INTERVAL			(MTK_WDT_BASE + 0x10)
+#define MTK_WDT_LATCH_CTL2			(MTK_WDT_BASE + 0x48)
+
+#define MCU_BIU_BASE				(MCUCFG_BASE)
+#define MISC1_CFG_BASE				(MCU_BIU_BASE + 0xE040)
+#define DFD_INTERNAL_CTL			(MISC1_CFG_BASE + 0x00)
+#define DFD_INTERNAL_PWR_ON			(MISC1_CFG_BASE + 0x08)
+#define DFD_CHAIN_LENGTH0			(MISC1_CFG_BASE + 0x0C)
+#define DFD_INTERNAL_SHIFT_CLK_RATIO		(MISC1_CFG_BASE + 0x10)
+#define DFD_CHAIN_LENGTH1			(MISC1_CFG_BASE + 0x1C)
+#define DFD_CHAIN_LENGTH2			(MISC1_CFG_BASE + 0x20)
+#define DFD_CHAIN_LENGTH3			(MISC1_CFG_BASE + 0x24)
+#define DFD_INTERNAL_TEST_SO_0			(MISC1_CFG_BASE + 0x28)
+#define DFD_INTERNAL_NUM_OF_TEST_SO_GROUP	(MISC1_CFG_BASE + 0x30)
+#define DFD_INTERNAL_TEST_SO_OVER_64		(MISC1_CFG_BASE + 0x34)
+#define DFD_INTERNAL_SW_NS_TRIGGER		(MISC1_CFG_BASE + 0x3c)
+#define DFD_V30_CTL				(MISC1_CFG_BASE + 0x48)
+#define DFD_V30_BASE_ADDR			(MISC1_CFG_BASE + 0x4C)
+#define DFD_POWER_CTL				(MISC1_CFG_BASE + 0x50)
+#define DFD_TEST_SI_0				(MISC1_CFG_BASE + 0x58)
+#define DFD_TEST_SI_1				(MISC1_CFG_BASE + 0x5C)
+#define DFD_CLEAN_STATUS			(MISC1_CFG_BASE + 0x60)
+#define DFD_TEST_SI_2				(MISC1_CFG_BASE + 0x1D8)
+#define DFD_TEST_SI_3				(MISC1_CFG_BASE + 0x1DC)
+#define DFD_READ_ADDR				(MISC1_CFG_BASE + 0x1E8)
+#define DFD_HW_TRIGGER_MASK			(MISC1_CFG_BASE + 0xBC)
+
+#define DFD_V35_ENABLE				(MCU_BIU_BASE + 0xE0A8)
+#define DFD_V35_TAP_NUMBER			(MCU_BIU_BASE + 0xE0AC)
+#define DFD_V35_TAP_EN				(MCU_BIU_BASE + 0xE0B0)
+#define DFD_V35_CTL				(MCU_BIU_BASE + 0xE0B4)
+#define DFD_V35_SEQ0_0				(MCU_BIU_BASE + 0xE0C0)
+#define DFD_V35_SEQ0_1				(MCU_BIU_BASE + 0xE0C4)
+#define DFD_V50_GROUP_0_63_DIFF			(MCU_BIU_BASE + 0xE2AC)
+
+#define DFD_O_PROTECT_EN_REG			(0x10001220)
+#define DFD_O_INTRF_MCU_PWR_CTL_MASK		(0x10001A3C)
+#define DFD_O_SET_BASEADDR_REG			(0x10043000)
+#define DFD_O_REG_0				(0x10001390)
+
+#define DFD_CACHE_DUMP_ENABLE			(1U)
+#define DFD_PARITY_ERR_TRIGGER			(2U)
+
+#define DFD_V35_TAP_EN_VAL			(0x43FF)
+#define DFD_V35_SEQ0_0_VAL			(0x63668820)
+#define DFD_READ_ADDR_VAL			(0x40000008)
+#define DFD_CHAIN_LENGTH_VAL			(0xFFFFFFFF)
+
+#define MTK_WDT_LATCH_CTL2_VAL			(0x9507FFFF)
+#define MTK_WDT_INTERVAL_VAL			(0x6600000A)
+#define MTK_DRM_LATCH_CTL2_VAL			(0x950607D0)
+#define MTK_DRM_LATCH_CTL2_CACHE_VAL		(0x95065DC0)
+
+#define MTK_DRM_LATCH_CTL1_VAL			(0x95000013)
+
+#endif /* PLAT_DFD_H */
diff --git a/plat/mediatek/drivers/dfd/rules.mk b/plat/mediatek/drivers/dfd/rules.mk
new file mode 100644
index 0000000..60fbc88
--- /dev/null
+++ b/plat/mediatek/drivers/dfd/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_dfd
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/dfd.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/$(MTK_SOC)/plat_dfd.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/drivers/emi_mpu/emi_mpu.h b/plat/mediatek/drivers/emi_mpu/emi_mpu.h
new file mode 100644
index 0000000..66a369e
--- /dev/null
+++ b/plat/mediatek/drivers/emi_mpu/emi_mpu.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMI_MPU_H
+#define EMI_MPU_H
+
+#include <emi_mpu_priv.h>
+#include <platform_def.h>
+
+#define NO_PROTECTION			(0)
+#define SEC_RW				(1)
+#define SEC_RW_NSEC_R			(2)
+#define SEC_RW_NSEC_W			(3)
+#define SEC_R_NSEC_R			(4)
+#define FORBIDDEN			(5)
+#define SEC_R_NSEC_RW			(6)
+
+#define LOCK				(1)
+#define UNLOCK				(0)
+
+#if (EMI_MPU_DGROUP_NUM == 1)
+#define SET_ACCESS_PERMISSION(apc_ary, lock, d7, d6, d5, d4, d3, d2, d1, d0) \
+do { \
+	apc_ary[1] = 0; \
+	apc_ary[0] = \
+		(((unsigned int)  d7) << 21) | (((unsigned int)  d6) << 18) | \
+		(((unsigned int)  d5) << 15) | (((unsigned int)  d4) << 12) | \
+		(((unsigned int)  d3) <<  9) | (((unsigned int)  d2) <<  6) | \
+		(((unsigned int)  d1) <<  3) |  ((unsigned int)  d0) | \
+		((unsigned int) lock << 31); \
+} while (0)
+#elif (EMI_MPU_DGROUP_NUM == 2)
+#define SET_ACCESS_PERMISSION(apc_ary, lock, d15, d14, d13, d12, d11, d10, \
+				d9, d8, d7, d6, d5, d4, d3, d2, d1, d0) \
+do { \
+	apc_ary[1] = \
+		(((unsigned int) d15) << 21) | (((unsigned int) d14) << 18) | \
+		(((unsigned int) d13) << 15) | (((unsigned int) d12) << 12) | \
+		(((unsigned int) d11) <<  9) | (((unsigned int) d10) <<  6) | \
+		(((unsigned int)  d9) <<  3) |  ((unsigned int)  d8); \
+	apc_ary[0] = \
+		(((unsigned int)  d7) << 21) | (((unsigned int)  d6) << 18) | \
+		(((unsigned int)  d5) << 15) | (((unsigned int)  d4) << 12) | \
+		(((unsigned int)  d3) <<  9) | (((unsigned int)  d2) <<  6) | \
+		(((unsigned int)  d1) <<  3) |  ((unsigned int)  d0) | \
+		((unsigned int) lock << 31); \
+} while (0)
+#endif
+
+struct emi_region_info_t {
+	unsigned long long start;
+	unsigned long long end;
+	unsigned int region;
+	unsigned int apc[EMI_MPU_DGROUP_NUM];
+};
+
+int emi_mpu_init(void);
+int emi_mpu_set_protection(struct emi_region_info_t *region_info);
+void set_emi_mpu_regions(void);
+
+#endif
diff --git a/plat/mediatek/drivers/emi_mpu/emi_mpu_common.c b/plat/mediatek/drivers/emi_mpu/emi_mpu_common.c
new file mode 100644
index 0000000..27b2b07
--- /dev/null
+++ b/plat/mediatek/drivers/emi_mpu/emi_mpu_common.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <emi_mpu.h>
+#include <lib/mtk_init/mtk_init.h>
+
+#if ENABLE_EMI_MPU_SW_LOCK
+static unsigned char region_lock_state[EMI_MPU_REGION_NUM];
+#endif
+
+#define EMI_MPU_START_MASK		(0x00FFFFFF)
+#define EMI_MPU_END_MASK		(0x00FFFFFF)
+#define EMI_MPU_APC_SW_LOCK_MASK	(0x00FFFFFF)
+#define EMI_MPU_APC_HW_LOCK_MASK	(0x80FFFFFF)
+
+static int _emi_mpu_set_protection(unsigned int start, unsigned int end,
+					unsigned int apc)
+{
+	unsigned int dgroup;
+	unsigned int region;
+
+	region = (start >> 24) & 0xFF;
+	start &= EMI_MPU_START_MASK;
+	dgroup = (end >> 24) & 0xFF;
+	end &= EMI_MPU_END_MASK;
+
+	if  ((region >= EMI_MPU_REGION_NUM) || (dgroup > EMI_MPU_DGROUP_NUM)) {
+		WARN("invalid region, domain\n");
+		return -1;
+	}
+
+#if ENABLE_EMI_MPU_SW_LOCK
+	if (region_lock_state[region] == 1) {
+		WARN("invalid region\n");
+		return -1;
+	}
+
+	if ((dgroup == 0) && ((apc >> 31) & 0x1)) {
+		region_lock_state[region] = 1;
+	}
+
+	apc &= EMI_MPU_APC_SW_LOCK_MASK;
+#else
+	apc &= EMI_MPU_APC_HW_LOCK_MASK;
+#endif
+
+	if ((start >= DRAM_OFFSET) && (end >= start)) {
+		start -= DRAM_OFFSET;
+		end -= DRAM_OFFSET;
+	} else {
+		WARN("invalid range\n");
+		return -1;
+	}
+
+	mmio_write_32(EMI_MPU_SA(region), start);
+	mmio_write_32(EMI_MPU_EA(region), end);
+	mmio_write_32(EMI_MPU_APC(region, dgroup), apc);
+
+#if defined(SUB_EMI_MPU_BASE)
+	mmio_write_32(SUB_EMI_MPU_SA(region), start);
+	mmio_write_32(SUB_EMI_MPU_EA(region), end);
+	mmio_write_32(SUB_EMI_MPU_APC(region, dgroup), apc);
+#endif
+	return 0;
+}
+
+static void dump_emi_mpu_regions(void)
+{
+	int region, i;
+
+	/* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */
+	for (region = 0; region < 8; ++region) {
+		INFO("region %d:\n", region);
+		INFO("\tsa: 0x%x, ea: 0x%x\n",
+		     mmio_read_32(EMI_MPU_SA(region)), mmio_read_32(EMI_MPU_EA(region)));
+
+		for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i) {
+			INFO("\tapc%d: 0x%x\n", i, mmio_read_32(EMI_MPU_APC(region, i)));
+		}
+	}
+}
+
+int emi_mpu_set_protection(struct emi_region_info_t *region_info)
+{
+	unsigned int start, end;
+	int i;
+
+	if (region_info->region >= EMI_MPU_REGION_NUM) {
+		WARN("invalid region\n");
+		return -1;
+	}
+
+	start = (unsigned int)(region_info->start >> EMI_MPU_ALIGN_BITS) |
+		(region_info->region << 24);
+
+	for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) {
+		end = (unsigned int)(region_info->end >> EMI_MPU_ALIGN_BITS) | (i << 24);
+
+		if (_emi_mpu_set_protection(start, end, region_info->apc[i]) < 0) {
+			WARN("Failed to set emi mpu protection(%d, %d, %d)\n",
+			     start, end, region_info->apc[i]);
+		}
+	}
+
+	return 0;
+}
+
+int emi_mpu_init(void)
+{
+	INFO("[%s] emi mpu initialization\n", __func__);
+
+	set_emi_mpu_regions();
+	dump_emi_mpu_regions();
+
+	return 0;
+}
+MTK_PLAT_SETUP_0_INIT(emi_mpu_init);
diff --git a/plat/mediatek/drivers/emi_mpu/mt8188/emi_mpu.c b/plat/mediatek/drivers/emi_mpu/mt8188/emi_mpu.c
new file mode 100644
index 0000000..558533d
--- /dev/null
+++ b/plat/mediatek/drivers/emi_mpu/mt8188/emi_mpu.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <emi_mpu.h>
+
+void set_emi_mpu_regions(void)
+{
+	/* TODO: set emi mpu region */
+	INFO("%s, emi mpu is not setting currently\n", __func__);
+}
diff --git a/plat/mediatek/drivers/emi_mpu/mt8188/emi_mpu_priv.h b/plat/mediatek/drivers/emi_mpu/mt8188/emi_mpu_priv.h
new file mode 100644
index 0000000..1ee7397
--- /dev/null
+++ b/plat/mediatek/drivers/emi_mpu/mt8188/emi_mpu_priv.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMI_MPU_PRIV_H
+#define EMI_MPU_PRIV_H
+
+#define ENABLE_EMI_MPU_SW_LOCK		(1)
+
+#define EMI_MPU_CTRL			(EMI_MPU_BASE + 0x000)
+#define EMI_MPU_DBG			(EMI_MPU_BASE + 0x004)
+#define EMI_MPU_SA0			(EMI_MPU_BASE + 0x100)
+#define EMI_MPU_EA0			(EMI_MPU_BASE + 0x200)
+#define EMI_MPU_SA(region)		(EMI_MPU_SA0 + (region * 4))
+#define EMI_MPU_EA(region)		(EMI_MPU_EA0 + (region * 4))
+#define EMI_MPU_APC0			(EMI_MPU_BASE + 0x300)
+#define EMI_MPU_APC(region, dgroup)	(EMI_MPU_APC0 + (region * 4) + (dgroup * 0x100))
+#define EMI_MPU_CTRL_D0			(EMI_MPU_BASE + 0x800)
+#define EMI_MPU_CTRL_D(domain)		(EMI_MPU_CTRL_D0 + (domain * 4))
+#define EMI_RG_MASK_D0			(EMI_MPU_BASE + 0x900)
+#define EMI_RG_MASK_D(domain)		(EMI_RG_MASK_D0 + (domain * 4))
+
+#define SUB_EMI_MPU_CTRL		(SUB_EMI_MPU_BASE + 0x000)
+#define SUB_EMI_MPU_DBG			(SUB_EMI_MPU_BASE + 0x004)
+#define SUB_EMI_MPU_SA0			(SUB_EMI_MPU_BASE + 0x100)
+#define SUB_EMI_MPU_EA0			(SUB_EMI_MPU_BASE + 0x200)
+#define SUB_EMI_MPU_SA(region)		(SUB_EMI_MPU_SA0 + (region * 4))
+#define SUB_EMI_MPU_EA(region)		(SUB_EMI_MPU_EA0 + (region * 4))
+#define SUB_EMI_MPU_APC0		(SUB_EMI_MPU_BASE + 0x300)
+#define SUB_EMI_MPU_APC(region, dgroup)	(SUB_EMI_MPU_APC0 + (region * 4) + (dgroup * 0x100))
+#define SUB_EMI_MPU_CTRL_D0		(SUB_EMI_MPU_BASE + 0x800)
+#define SUB_EMI_MPU_CTRL_D(domain)	(SUB_EMI_MPU_CTRL_D0 + (domain * 4))
+#define SUB_EMI_RG_MASK_D0		(SUB_EMI_MPU_BASE + 0x900)
+#define SUB_EMI_RG_MASK_D(domain)	(SUB_EMI_RG_MASK_D0 + (domain * 4))
+
+#define EMI_MPU_DOMAIN_NUM		(16)
+#define EMI_MPU_REGION_NUM		(32)
+#define EMI_MPU_ALIGN_BITS		(16)
+#define DRAM_OFFSET			(0x40000000 >> EMI_MPU_ALIGN_BITS)
+
+#define EMI_MPU_DGROUP_NUM		(EMI_MPU_DOMAIN_NUM / 8)
+
+#endif
diff --git a/plat/mediatek/drivers/emi_mpu/rules.mk b/plat/mediatek/drivers/emi_mpu/rules.mk
new file mode 100644
index 0000000..ed3d777
--- /dev/null
+++ b/plat/mediatek/drivers/emi_mpu/rules.mk
@@ -0,0 +1,16 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := emi_mpu
+LOCAL_SRCS-y := $(LOCAL_DIR)/emi_mpu_common.c
+LOCAL_SRCS-y += ${LOCAL_DIR}/${MTK_SOC}/emi_mpu.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/drivers/lpm/rules.mk b/plat/mediatek/drivers/lpm/rules.mk
new file mode 100644
index 0000000..87a212a
--- /dev/null
+++ b/plat/mediatek/drivers/lpm/rules.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := lpm
+LOCAL_SRCS-y := $(LOCAL_DIR)/mt_lp_rm.c
+
+PLAT_INCLUDES += -I${LOCAL_DIR}
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/mcusys/mcusys.c b/plat/mediatek/drivers/mcusys/mcusys.c
new file mode 100644
index 0000000..63edb23
--- /dev/null
+++ b/plat/mediatek/drivers/mcusys/mcusys.c
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+#include <mtk_mmap_pool.h>
+#include <platform_def.h>
+
+static const mmap_region_t mcusys_mmap[] MTK_MMAP_SECTION = {
+	MAP_REGION_FLAT(MCUCFG_BASE, MCUCFG_REG_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+	{0}
+};
+DECLARE_MTK_MMAP_REGIONS(mcusys_mmap);
diff --git a/plat/mediatek/drivers/mcusys/rules.mk b/plat/mediatek/drivers/mcusys/rules.mk
new file mode 100644
index 0000000..5438998
--- /dev/null
+++ b/plat/mediatek/drivers/mcusys/rules.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := mcusys
+
+PLAT_INCLUDES += -I$(LOCAL_DIR)/$(MCUSYS_VERSION)
+
+LOCAL_SRCS-y := $(LOCAL_DIR)/mcusys.c
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/drivers/mcusys/v1/mcucfg.h b/plat/mediatek/drivers/mcusys/v1/mcucfg.h
new file mode 100644
index 0000000..7aced5a
--- /dev/null
+++ b/plat/mediatek/drivers/mcusys/v1/mcucfg.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MCUCFG_V1_H
+#define MCUCFG_V1_H
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+#endif /*__ASSEMBLER__*/
+
+#include <platform_def.h>
+
+#define MP2_MISC_CONFIG_BOOT_ADDR_L(cpu)	(MCUCFG_BASE + 0x2290 + ((cpu) * 8))
+#define MP2_MISC_CONFIG_BOOT_ADDR_H(cpu)	(MCUCFG_BASE + 0x2294 + ((cpu) * 8))
+
+#define MP2_CPUCFG				(MCUCFG_BASE + 0x2208)
+
+#define MP0_CPUTOP_SPMC_CTL			(MCUCFG_BASE + 0x788)
+#define MP1_CPUTOP_SPMC_CTL			(MCUCFG_BASE + 0x78C)
+#define MP1_CPUTOP_SPMC_SRAM_CTL		(MCUCFG_BASE + 0x790)
+
+#define CPUSYSx_CPUx_SPMC_CTL(cluster, cpu)	(MCUCFG_BASE + 0x1C30 + \
+						 (cluster) * 0x2000 + (cpu) * 4)
+
+#define CPUSYS0_CPU0_SPMC_CTL			(MCUCFG_BASE + 0x1C30)
+#define CPUSYS0_CPU1_SPMC_CTL			(MCUCFG_BASE + 0x1C34)
+#define CPUSYS0_CPU2_SPMC_CTL			(MCUCFG_BASE + 0x1C38)
+#define CPUSYS0_CPU3_SPMC_CTL			(MCUCFG_BASE + 0x1C3C)
+
+#define CPUSYS1_CPU0_SPMC_CTL			(MCUCFG_BASE + 0x3C30)
+#define CPUSYS1_CPU1_SPMC_CTL			(MCUCFG_BASE + 0x3C34)
+#define CPUSYS1_CPU2_SPMC_CTL			(MCUCFG_BASE + 0x3C38)
+#define CPUSYS1_CPU3_SPMC_CTL			(MCUCFG_BASE + 0x3C3C)
+
+/* CPC related registers */
+#define CPC_MCUSYS_CPC_OFF_THRES		(MCUCFG_BASE + 0xA714)
+#define CPC_MCUSYS_PWR_CTRL			(MCUCFG_BASE + 0xA804)
+#define CPC_MCUSYS_CPC_FLOW_CTRL_CFG		(MCUCFG_BASE + 0xA814)
+#define CPC_MCUSYS_LAST_CORE_REQ		(MCUCFG_BASE + 0xA818)
+#define CPC_MCUSYS_MP_LAST_CORE_RESP		(MCUCFG_BASE + 0xA81C)
+#define CPC_MCUSYS_LAST_CORE_RESP		(MCUCFG_BASE + 0xA824)
+#define CPC_MCUSYS_PWR_ON_MASK			(MCUCFG_BASE + 0xA828)
+#define CPC_SPMC_PWR_STATUS			(MCUCFG_BASE + 0xA840)
+#define CPC_MCUSYS_CPU_ON_SW_HINT_SET		(MCUCFG_BASE + 0xA8A8)
+#define CPC_MCUSYS_CPU_ON_SW_HINT_CLR		(MCUCFG_BASE + 0xA8AC)
+#define CPC_MCUSYS_CPC_DBG_SETTING		(MCUCFG_BASE + 0xAB00)
+#define CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE	(MCUCFG_BASE + 0xAB04)
+#define CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE	(MCUCFG_BASE + 0xAB08)
+#define CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE	(MCUCFG_BASE + 0xAB0C)
+#define CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE	(MCUCFG_BASE + 0xAB10)
+#define CPC_MCUSYS_TRACE_SEL			(MCUCFG_BASE + 0xAB14)
+#define CPC_MCUSYS_TRACE_DATA			(MCUCFG_BASE + 0xAB20)
+#define CPC_MCUSYS_CLUSTER_COUNTER		(MCUCFG_BASE + 0xAB70)
+#define CPC_MCUSYS_CLUSTER_COUNTER_CLR		(MCUCFG_BASE + 0xAB74)
+
+/* CPC_MCUSYS_CPC_FLOW_CTRL_CFG bit control */
+#define CPC_CTRL_ENABLE				BIT(16)
+#define SSPM_CORE_PWR_ON_EN			BIT(7) /* for cpu-hotplug */
+#define SSPM_ALL_PWR_CTRL_EN			BIT(13) /* for cpu-hotplug */
+#define GIC_WAKEUP_IGNORE(cpu)			BIT(21 + cpu)
+
+#define CPC_MCUSYS_CPC_RESET_ON_KEEP_ON		BIT(17)
+#define CPC_MCUSYS_CPC_RESET_PWR_ON_EN		BIT(20)
+
+/* SPMC related registers */
+#define SPM_MCUSYS_PWR_CON			(MCUCFG_BASE + 0xD200)
+#define SPM_MP0_CPUTOP_PWR_CON			(MCUCFG_BASE + 0xD204)
+#define SPM_MP0_CPU0_PWR_CON			(MCUCFG_BASE + 0xD208)
+#define SPM_MP0_CPU1_PWR_CON			(MCUCFG_BASE + 0xD20C)
+#define SPM_MP0_CPU2_PWR_CON			(MCUCFG_BASE + 0xD210)
+#define SPM_MP0_CPU3_PWR_CON			(MCUCFG_BASE + 0xD214)
+#define SPM_MP0_CPU4_PWR_CON			(MCUCFG_BASE + 0xD218)
+#define SPM_MP0_CPU5_PWR_CON			(MCUCFG_BASE + 0xD21C)
+#define SPM_MP0_CPU6_PWR_CON			(MCUCFG_BASE + 0xD220)
+#define SPM_MP0_CPU7_PWR_CON			(MCUCFG_BASE + 0xD224)
+
+/* bit fields of SPM_*_PWR_CON */
+#define PWR_ON_ACK				BIT(31)
+#define VPROC_EXT_OFF				BIT(7)
+#define DORMANT_EN				BIT(6)
+#define RESETPWRON_CONFIG			BIT(5)
+#define PWR_CLK_DIS				BIT(4)
+#define PWR_ON					BIT(2)
+#define PWR_RST_B				BIT(0)
+
+#define SPARK2LDO				(MCUCFG_BASE + 0x2700)
+/* APB Module mcucfg */
+#define MP0_CA7_CACHE_CONFIG			(MCUCFG_BASE + 0x000)
+#define MP0_AXI_CONFIG				(MCUCFG_BASE + 0x02C)
+#define MP0_MISC_CONFIG0			(MCUCFG_BASE + 0x030)
+#define MP0_MISC_CONFIG1			(MCUCFG_BASE + 0x034)
+#define MP0_MISC_CONFIG2			(MCUCFG_BASE + 0x038)
+#define MP0_MISC_CONFIG_BOOT_ADDR(cpu)		(MCUCFG_BASE + 0x038 + ((cpu) * 8))
+#define MP0_MISC_CONFIG3			(MCUCFG_BASE + 0x03C)
+#define MP0_MISC_CONFIG9			(MCUCFG_BASE + 0x054)
+#define MP0_CA7_MISC_CONFIG			(MCUCFG_BASE + 0x064)
+
+#define MP0_RW_RSVD0				(MCUCFG_BASE + 0x06C)
+#define MP1_CA7_CACHE_CONFIG			(MCUCFG_BASE + 0x200)
+#define MP1_AXI_CONFIG				(MCUCFG_BASE + 0x22C)
+#define MP1_MISC_CONFIG0			(MCUCFG_BASE + 0x230)
+#define MP1_MISC_CONFIG1			(MCUCFG_BASE + 0x234)
+#define MP1_MISC_CONFIG2			(MCUCFG_BASE + 0x238)
+#define MP1_MISC_CONFIG_BOOT_ADDR(cpu)		(MCUCFG_BASE + 0x238 + ((cpu) * 8))
+#define MP1_MISC_CONFIG3			(MCUCFG_BASE + 0x23C)
+#define MP1_MISC_CONFIG9			(MCUCFG_BASE + 0x254)
+#define MP1_CA7_MISC_CONFIG			(MCUCFG_BASE + 0x264)
+
+#define CCI_ADB400_DCM_CONFIG			(MCUCFG_BASE + 0x740)
+#define SYNC_DCM_CONFIG				(MCUCFG_BASE + 0x744)
+
+#define MP0_CLUSTER_CFG0			(MCUCFG_BASE + 0xC8D0)
+
+#define MP0_SPMC				(MCUCFG_BASE + 0x788)
+#define MP1_SPMC				(MCUCFG_BASE + 0x78C)
+#define MP2_AXI_CONFIG				(MCUCFG_BASE + 0x220C)
+#define MP2_AXI_CONFIG_ACINACTM			BIT(0)
+#define MP2_AXI_CONFIG_AINACTS			BIT(4)
+
+#define MPx_AXI_CONFIG_ACINACTM			BIT(4)
+#define MPx_AXI_CONFIG_AINACTS			BIT(5)
+
+#define MPx_CA7_MISC_CONFIG_standbywfil2	BIT(28)
+
+#define MP0_CPU0_STANDBYWFE			BIT(20)
+#define MP0_CPU1_STANDBYWFE			BIT(21)
+#define MP0_CPU2_STANDBYWFE			BIT(22)
+#define MP0_CPU3_STANDBYWFE			BIT(23)
+
+#define MP1_CPU0_STANDBYWFE			BIT(20)
+#define MP1_CPU1_STANDBYWFE			BIT(21)
+#define MP1_CPU2_STANDBYWFE			BIT(22)
+#define MP1_CPU3_STANDBYWFE			BIT(23)
+
+#define CPUSYS0_SPARKVRETCNTRL			(MCUCFG_BASE+0x1c00)
+#define CPUSYS0_SPARKEN				(MCUCFG_BASE+0x1c04)
+#define CPUSYS0_AMUXSEL				(MCUCFG_BASE+0x1c08)
+#define CPUSYS1_SPARKVRETCNTRL			(MCUCFG_BASE+0x3c00)
+#define CPUSYS1_SPARKEN				(MCUCFG_BASE+0x3c04)
+#define CPUSYS1_AMUXSEL				(MCUCFG_BASE+0x3c08)
+
+#define MP2_PWR_RST_CTL				(MCUCFG_BASE + 0x2008)
+#define MP2_PTP3_CPUTOP_SPMC0			(MCUCFG_BASE + 0x22A0)
+#define MP2_PTP3_CPUTOP_SPMC1			(MCUCFG_BASE + 0x22A4)
+
+#define MP2_COQ					(MCUCFG_BASE + 0x22BC)
+#define MP2_COQ_SW_DIS				BIT(0)
+
+#define MP2_CA15M_MON_SEL			(MCUCFG_BASE + 0x2400)
+#define MP2_CA15M_MON_L				(MCUCFG_BASE + 0x2404)
+
+#define CPUSYS2_CPU0_SPMC_CTL			(MCUCFG_BASE + 0x2430)
+#define CPUSYS2_CPU1_SPMC_CTL			(MCUCFG_BASE + 0x2438)
+#define CPUSYS2_CPU0_SPMC_STA			(MCUCFG_BASE + 0x2434)
+#define CPUSYS2_CPU1_SPMC_STA			(MCUCFG_BASE + 0x243C)
+
+#define MP0_CA7L_DBG_PWR_CTRL			(MCUCFG_BASE + 0x068)
+#define MP1_CA7L_DBG_PWR_CTRL			(MCUCFG_BASE + 0x268)
+#define BIG_DBG_PWR_CTRL			(MCUCFG_BASE + 0x75C)
+
+#define MP2_SW_RST_B				BIT(0)
+#define MP2_TOPAON_APB_MASK			BIT(1)
+#define B_SW_HOT_PLUG_RESET			BIT(30)
+#define B_SW_PD_OFFSET				(18)
+#define B_SW_PD					(0x3F << B_SW_PD_OFFSET)
+
+#define B_SW_SRAM_SLEEPB_OFFSET			(12)
+#define B_SW_SRAM_SLEEPB			(0x3F << B_SW_SRAM_SLEEPB_OFFSET)
+
+#define B_SW_SRAM_ISOINTB			BIT(9)
+#define B_SW_ISO				BIT(8)
+#define B_SW_LOGIC_PDB				BIT(7)
+#define B_SW_LOGIC_PRE2_PDB			BIT(6)
+#define B_SW_LOGIC_PRE1_PDB			BIT(5)
+#define B_SW_FSM_OVERRIDE			BIT(4)
+#define B_SW_PWR_ON				BIT(3)
+#define B_SW_PWR_ON_OVERRIDE_EN			BIT(2)
+
+#define B_FSM_STATE_OUT_OFFSET			(6)
+#define B_FSM_STATE_OUT_MASK			(0x1F << B_FSM_STATE_OUT_OFFSET)
+#define B_SW_LOGIC_PDBO_ALL_OFF_ACK		BIT(5)
+#define B_SW_LOGIC_PDBO_ALL_ON_ACK		BIT(4)
+#define B_SW_LOGIC_PRE2_PDBO_ALL_ON_ACK		BIT(3)
+#define B_SW_LOGIC_PRE1_PDBO_ALL_ON_ACK		BIT(2)
+
+
+#define B_FSM_OFF				(0U << B_FSM_STATE_OUT_OFFSET)
+#define B_FSM_ON				(1U << B_FSM_STATE_OUT_OFFSET)
+#define B_FSM_RET				(2U << B_FSM_STATE_OUT_OFFSET)
+
+#ifndef __ASSEMBLER__
+/* cpu boot mode */
+enum mp0_coucfg_64bit_ctrl {
+	MP0_CPUCFG_64BIT_SHIFT = 12,
+	MP1_CPUCFG_64BIT_SHIFT = 28,
+	MP0_CPUCFG_64BIT = 0xfu << MP0_CPUCFG_64BIT_SHIFT,
+	MP1_CPUCFG_64BIT = 0xfu << MP1_CPUCFG_64BIT_SHIFT,
+};
+
+enum mp1_dis_rgu0_ctrl {
+	MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT = 0,
+	MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT = 4,
+	MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT = 8,
+	MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT = 12,
+	MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT = 16,
+	MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK = 0xF << MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK = 0xF << MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK = 0xF << MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK = 0xF << MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK = 0xF << MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT,
+};
+
+enum mp1_ainacts_ctrl {
+	MP1_AINACTS_SHIFT = 4,
+	MP1_AINACTS = 1U << MP1_AINACTS_SHIFT,
+};
+
+enum mp1_sw_cg_gen {
+	MP1_SW_CG_GEN_SHIFT = 12,
+	MP1_SW_CG_GEN = 1U << MP1_SW_CG_GEN_SHIFT,
+};
+
+enum mp1_l2rstdisable {
+	MP1_L2RSTDISABLE_SHIFT = 14,
+	MP1_L2RSTDISABLE = 1U << MP1_L2RSTDISABLE_SHIFT,
+};
+#endif /*__ASSEMBLER__*/
+
+#endif  /* MCUCFG_V1_H */
diff --git a/plat/mediatek/helpers/armv8_2/arch_helpers.S b/plat/mediatek/helpers/armv8_2/arch_helpers.S
new file mode 100644
index 0000000..02d8d53
--- /dev/null
+++ b/plat/mediatek/helpers/armv8_2/arch_helpers.S
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2022, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <assert_macros.S>
+#include <cpu_macros.S>
+#if CONFIG_MTK_MCUSYS
+#include <mcucfg.h>
+#endif
+#include <platform_def.h>
+	/*
+	 * Declare as weak function so that can be
+	 * overwritten by platform helpers
+	 */
+	.weak platform_mem_init
+	.weak plat_core_pos_by_mpidr
+	.weak plat_my_core_pos
+	.weak plat_mediatek_calc_core_pos
+	.global plat_mpidr_by_core_pos
+	.global plat_reset_handler
+
+	/* -----------------------------------------------------
+	 * unsigned long plat_mpidr_by_core_pos(uint32_t cpuid)
+	 * This function calcuate mpidr by cpu pos if cpu
+	 * topology is linear.
+	 *
+	 * Clobbers: x0-x1
+	 * -----------------------------------------------------
+	 */
+func plat_mpidr_by_core_pos
+	lsl x0, x0, #MPIDR_AFF1_SHIFT
+	mrs x1, mpidr_el1
+	and x1, x1, #MPIDR_MT_MASK
+	orr x0, x0, x1
+	ret
+endfunc plat_mpidr_by_core_pos
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_my_core_pos(void)
+	 *  This function uses the plat_arm_calc_core_pos()
+	 *  definition to get the index of the calling CPU.
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b plat_mediatek_calc_core_pos
+endfunc plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 * int plat_mediatek_calc_core_pos(u_register_t mpidr);
+	 *
+	 * In ARMv8.2, AFF2 is cluster id, AFF1 is core id and
+	 * AFF0 is thread id. There is only one cluster in ARMv8.2
+	 * and one thread in current implementation.
+	 *
+	 * With this function: CorePos = CoreID (AFF1)
+	 * we do it with x0 = (x0 >> 8) & 0xff
+	 * -----------------------------------------------------
+	 */
+func plat_mediatek_calc_core_pos
+	b plat_core_pos_by_mpidr
+endfunc plat_mediatek_calc_core_pos
+
+	/* ------------------------------------------------------
+	 * int32_t plat_core_pos_by_mpidr(u_register_t mpidr)
+	 *
+	 * This function implements a part of the critical
+	 * interface between the psci generic layer and the
+	 * platform that allows the former to query the platform
+	 * to convert an MPIDR to a unique linear index.
+	 *
+	 * Clobbers: x0-x1
+	 * ------------------------------------------------------
+	 */
+func plat_core_pos_by_mpidr
+	mov	x1, #MPIDR_AFFLVL_MASK
+	and	x0, x1, x0, lsr #MPIDR_AFF1_SHIFT
+	ret
+endfunc plat_core_pos_by_mpidr
+
+	/* --------------------------------------------------------
+	 * void platform_mem_init (void);
+	 *
+	 * Any memory init, relocation to be done before the
+	 * platform boots. Called very early in the boot process.
+	 * --------------------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
+
+func plat_reset_handler
+#if CONFIG_MTK_MCUSYS
+	mov	x10, x30
+	bl	plat_my_core_pos
+	mov	x30, x10
+	mov     w1, #0x1
+	lsl     w1, w1, w0
+	ldr	x0, =CPC_MCUSYS_CPU_ON_SW_HINT_SET
+	str     w1, [x0]
+	dsb     sy
+#endif
+
+#if CONFIG_MTK_ECC
+	mov x10, x30
+	/* enable sequence of ecc for cpus */
+	bl disable_core_ecc
+	bl ft_ecc_clear_per_core
+	bl enable_core_ecc
+	mov x30, x10
+#endif
+
+	ret
+endfunc plat_reset_handler
diff --git a/plat/mediatek/helpers/rules.mk b/plat/mediatek/helpers/rules.mk
new file mode 100644
index 0000000..ae8068e
--- /dev/null
+++ b/plat/mediatek/helpers/rules.mk
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := helpers
+LOCAL_SRCS-y += $(LOCAL_DIR)/$(ARCH_VERSION)/arch_helpers.S
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/include/armv8_2/arch_def.h b/plat/mediatek/include/armv8_2/arch_def.h
new file mode 100644
index 0000000..61f818f
--- /dev/null
+++ b/plat/mediatek/include/armv8_2/arch_def.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2022, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ARCH_DEF_H
+#define ARCH_DEF_H
+
+/* Topology constants */
+#define PLAT_MAX_PWR_LVL		(2)
+#define PLAT_MAX_RET_STATE		(1)
+#define PLAT_MAX_OFF_STATE		(2)
+
+#define PLATFORM_SYSTEM_COUNT		(1)
+#define PLATFORM_CLUSTER_COUNT		(1)
+#define PLATFORM_CLUSTER0_CORE_COUNT	(8)
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER0_CORE_COUNT)
+#define PLATFORM_MAX_CPUS_PER_CLUSTER	(8)
+#define PLATFORM_NUM_AFFS		(PLATFORM_SYSTEM_COUNT + \
+					 PLATFORM_CLUSTER_COUNT + \
+					 PLATFORM_CORE_COUNT)
+
+/*******************************************************************************
+ * Declarations and constants to access the mailboxes safely. Each mailbox is
+ * aligned on the biggest cache line size in the platform. This is known only
+ * to the platform as it might have a combination of integrated and external
+ * caches. Such alignment ensures that two maiboxes do not sit on the same cache
+ * line at any cache level. They could belong to different cpus/clusters &
+ * get written while being protected by different locks causing corruption of
+ * a valid mailbox address.
+ ******************************************************************************/
+/* Cachline size */
+#define CACHE_WRITEBACK_SHIFT		(6)
+#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
+
+#endif /* ARCH_DEF_H */
+
diff --git a/plat/mediatek/include/cold_boot.h b/plat/mediatek/include/cold_boot.h
deleted file mode 100644
index 6b94b57..0000000
--- a/plat/mediatek/include/cold_boot.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2022, Mediatek Inc. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef COLD_BOOT_H
-#define COLD_BOOT_H
-
-#include <stdint.h>
-
-/*******************************************************************************
- * Function and variable prototypes
- ******************************************************************************/
-#define LINUX_KERNEL_32	(0)
-#define LINUX_KERNEL_64	(1)
-#define DEVINFO_SIZE	(4)
-
-struct atf_arg_t {
-	uint32_t atf_magic;
-	uint32_t tee_support;
-	uint64_t tee_entry;
-	uint64_t tee_boot_arg_addr;
-	uint32_t hwuid[4]; /* HW Unique id for t-base used */
-	uint32_t HRID[8]; /* HW random id for t-base used */
-	uint32_t devinfo[DEVINFO_SIZE];
-};
-
-struct mtk_bl31_fw_config {
-	void *from_bl2; /* MTK boot tag */
-	void *soc_fw_config;
-	void *hw_config;
-	void *reserved;
-};
-
-enum {
-	BOOT_ARG_FROM_BL2,
-	BOOT_ARG_SOC_FW_CONFIG,
-	BOOT_ARG_HW_CONFIG,
-	BOOT_ARG_RESERVED
-};
-
-struct kernel_info {
-	uint64_t pc;
-	uint64_t r0;
-	uint64_t r1;
-	uint64_t r2;
-	uint64_t k32_64;
-};
-
-struct mtk_bl_param_t {
-	uint64_t bootarg_loc;
-	uint64_t bootarg_size;
-	uint64_t bl33_start_addr;
-	uint64_t atf_arg_addr;
-};
-
-void *get_mtk_bl31_fw_config(int index);
-bool is_el1_2nd_bootloader(void);
-
-#endif /* COLD_BOOT_H */
diff --git a/plat/mediatek/lib/pm/armv8_2/pwr_ctrl.c b/plat/mediatek/lib/pm/armv8_2/pwr_ctrl.c
new file mode 100644
index 0000000..7ffc4ed
--- /dev/null
+++ b/plat/mediatek/lib/pm/armv8_2/pwr_ctrl.c
@@ -0,0 +1,544 @@
+/*
+ * Copyright (c) 2022, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <common/debug.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/psci/psci.h>
+#include <lib/utils.h>
+#ifdef MTK_PUBEVENT_ENABLE
+#include <mtk_event/mtk_pubsub_events.h>
+#endif
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include <dfd.h>
+#include <lib/mtk_init/mtk_init.h>
+#include <lib/pm/mtk_pm.h>
+#include <mt_gic_v3.h>
+#include <platform_def.h>
+
+#define IS_AFFLV_PUBEVENT(_pstate) \
+	((_pstate & (MT_CPUPM_PWR_DOMAIN_MCUSYS | MT_CPUPM_PWR_DOMAIN_CLUSTER)) != 0)
+
+#ifdef MTK_PUBEVENT_ENABLE
+#define MT_CPUPM_EVENT_PWR_ON(x) ({ \
+	PUBLISH_EVENT_ARG(mt_cpupm_publish_pwr_on, (const void *)(x)); })
+
+#define MT_CPUPM_EVENT_PWR_OFF(x) ({ \
+	PUBLISH_EVENT_ARG(mt_cpupm_publish_pwr_off, (const void *)(x)); })
+
+#define MT_CPUPM_EVENT_AFFLV_PWR_ON(x) ({ \
+	PUBLISH_EVENT_ARG(mt_cpupm_publish_afflv_pwr_on, (const void *)(x)); })
+
+#define MT_CPUPM_EVENT_AFFLV_PWR_OFF(x) ({ \
+	PUBLISH_EVENT_ARG(mt_cpupm_publish_afflv_pwr_off, (const void *)(x)); })
+
+#else
+#define MT_CPUPM_EVENT_PWR_ON(x) ({ (void)x; })
+#define MT_CPUPM_EVENT_PWR_OFF(x) ({ (void)x; })
+#define MT_CPUPM_EVENT_AFFLV_PWR_ON(x) ({ (void)x; })
+#define MT_CPUPM_EVENT_AFFLV_PWR_OFF(x) ({ (void)x; })
+#endif
+
+/*
+ * The cpu require to cluster power stattus
+ * [0] : The cpu require cluster power down
+ * [1] : The cpu require cluster power on
+ */
+#define coordinate_cluster(onoff) write_clusterpwrdn_el1(onoff)
+#define coordinate_cluster_pwron() coordinate_cluster(1)
+#define coordinate_cluster_pwroff() coordinate_cluster(0)
+
+/* defaultly disable all functions */
+#define MTK_CPUPM_FN_MASK_DEFAULT	(0)
+
+struct mtk_cpu_pwr_ctrl {
+	unsigned int fn_mask;
+	struct mtk_cpu_pm_ops *ops;
+	struct mtk_cpu_smp_ops *smp;
+};
+
+static struct mtk_cpu_pwr_ctrl mtk_cpu_pwr = {
+	.fn_mask = MTK_CPUPM_FN_MASK_DEFAULT,
+	.ops = NULL,
+};
+
+#define IS_CPUIDLE_FN_ENABLE(x)	((mtk_cpu_pwr.ops != NULL) && ((mtk_cpu_pwr.fn_mask & x) != 0))
+#define IS_CPUSMP_FN_ENABLE(x)	((mtk_cpu_pwr.smp != NULL) && ((mtk_cpu_pwr.fn_mask & x) != 0))
+
+/* per-cpu power state */
+static unsigned int armv8_2_power_state[PLATFORM_CORE_COUNT];
+
+#define armv8_2_get_pwr_stateid(cpu) psci_get_pstate_id(armv8_2_power_state[cpu])
+
+static unsigned int get_mediatek_pstate(unsigned int domain, unsigned int psci_state,
+					struct mtk_cpupm_pwrstate *state)
+{
+	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_CPUPM_GET_PWR_STATE)) {
+		return mtk_cpu_pwr.ops->get_pstate(domain, psci_state, state);
+	}
+
+	return 0;
+}
+
+unsigned int armv8_2_get_pwr_afflv(const psci_power_state_t *state_info)
+{
+	int i;
+
+	for (i = (int)PLAT_MAX_PWR_LVL; i >= (int)PSCI_CPU_PWR_LVL; i--) {
+		if (is_local_state_run(state_info->pwr_domain_state[i]) == 0) {
+			return (unsigned int) i;
+		}
+	}
+
+	return PSCI_INVALID_PWR_LVL;
+}
+
+/* MediaTek mcusys power on control interface */
+static void armv8_2_mcusys_pwr_on_common(const struct mtk_cpupm_pwrstate *state)
+{
+	mt_gic_init();
+	mt_gic_distif_restore();
+	gic_sgi_restore_all();
+
+	dfd_resume();
+
+	/* Add code here that behavior before system enter mcusys'on */
+	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_RESUME_MCUSYS)) {
+		mtk_cpu_pwr.ops->mcusys_resume(state);
+	}
+}
+
+/* MediaTek mcusys power down control interface */
+static void armv8_2_mcusys_pwr_dwn_common(const struct mtk_cpupm_pwrstate *state)
+{
+	mt_gic_distif_save();
+	gic_sgi_save_all();
+
+	/* Add code here that behaves before entering mcusys off */
+	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_SUSPEND_MCUSYS)) {
+		mtk_cpu_pwr.ops->mcusys_suspend(state);
+	}
+}
+
+/* MediaTek Cluster power on control interface */
+static void armv8_2_cluster_pwr_on_common(const struct mtk_cpupm_pwrstate *state)
+{
+	/* Add code here that behavior before system enter cluster'on */
+#if defined(MTK_CM_MGR) && !defined(MTK_FPGA_EARLY_PORTING)
+	/* init cpu stall counter */
+	init_cpu_stall_counter_all();
+#endif
+
+	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_RESUME_CLUSTER)) {
+		mtk_cpu_pwr.ops->cluster_resume(state);
+	}
+}
+
+/* MediaTek Cluster power down control interface */
+static void armv8_2_cluster_pwr_dwn_common(const struct mtk_cpupm_pwrstate *state)
+{
+	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_SUSPEND_CLUSTER)) {
+		mtk_cpu_pwr.ops->cluster_suspend(state);
+	}
+}
+
+/* MediaTek CPU power on control interface */
+static void armv8_2_cpu_pwr_on_common(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
+{
+	coordinate_cluster_pwron();
+
+	gicv3_rdistif_on(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+	mt_gic_rdistif_init();
+
+	/* If MCUSYS has been powered down then restore GIC redistributor for all CPUs. */
+	if (IS_PLAT_SYSTEM_RETENTION(state->pwr.afflv)) {
+		mt_gic_rdistif_restore_all();
+	} else {
+		mt_gic_rdistif_restore();
+	}
+}
+
+/* MediaTek CPU power down control interface */
+static void armv8_2_cpu_pwr_dwn_common(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
+{
+	if ((pstate & MT_CPUPM_PWR_DOMAIN_PERCORE_DSU) != 0) {
+		coordinate_cluster_pwroff();
+	}
+
+	mt_gic_rdistif_save();
+	gicv3_cpuif_disable(plat_my_core_pos());
+	gicv3_rdistif_off(plat_my_core_pos());
+}
+
+static void armv8_2_cpu_pwr_resume(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
+{
+	armv8_2_cpu_pwr_on_common(state, pstate);
+	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_RESUME_CORE)) {
+		mtk_cpu_pwr.ops->cpu_resume(state);
+	}
+}
+
+static void armv8_2_cpu_pwr_suspend(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
+{
+	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_SUSPEND_CORE)) {
+		mtk_cpu_pwr.ops->cpu_suspend(state);
+	}
+	armv8_2_cpu_pwr_dwn_common(state, pstate);
+}
+
+static void armv8_2_cpu_pwr_on(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
+{
+	armv8_2_cpu_pwr_on_common(state, pstate);
+
+	if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_SMP_CORE_ON)) {
+		mtk_cpu_pwr.smp->cpu_on(state);
+	}
+}
+
+static void armv8_2_cpu_pwr_off(const struct mtk_cpupm_pwrstate *state, unsigned int pstate)
+{
+	if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_SMP_CORE_OFF)) {
+		mtk_cpu_pwr.smp->cpu_off(state);
+	}
+	armv8_2_cpu_pwr_dwn_common(state, pstate);
+}
+
+/* MediaTek PSCI power domain */
+static int armv8_2_power_domain_on(u_register_t mpidr)
+{
+	int ret = PSCI_E_SUCCESS;
+	int cpu = plat_core_pos_by_mpidr(mpidr);
+	uintptr_t entry = plat_pm_get_warm_entry();
+
+	if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_PWR_ON_CORE_PREPARE)) {
+		if (mtk_cpu_pwr.smp->cpu_pwr_on_prepare(cpu, entry) != 0) {
+			ret = PSCI_E_DENIED;
+		}
+	}
+	INFO("CPU %u power domain prepare on\n", cpu);
+	return ret;
+}
+
+/* MediaTek PSCI power domain */
+static void armv8_2_power_domain_on_finish(const psci_power_state_t *state)
+{
+	struct mt_cpupm_event_data nb;
+	unsigned int pstate = (MT_CPUPM_PWR_DOMAIN_CORE | MT_CPUPM_PWR_DOMAIN_PERCORE_DSU);
+	struct mtk_cpupm_pwrstate pm_state = {
+		.info = {
+			.cpuid = plat_my_core_pos(),
+			.mode = MTK_CPU_PM_SMP,
+		},
+		.pwr = {
+			.afflv = armv8_2_get_pwr_afflv(state),
+			.state_id = 0x0,
+		},
+	};
+
+	armv8_2_cpu_pwr_on(&pm_state, pstate);
+
+	nb.cpuid = pm_state.info.cpuid;
+	nb.pwr_domain = pstate;
+	MT_CPUPM_EVENT_PWR_ON(&nb);
+
+	INFO("CPU %u power domain on finished\n", pm_state.info.cpuid);
+}
+
+/* MediaTek PSCI power domain */
+static void armv8_2_power_domain_off(const psci_power_state_t *state)
+{
+	struct mt_cpupm_event_data nb;
+	unsigned int pstate = (MT_CPUPM_PWR_DOMAIN_CORE | MT_CPUPM_PWR_DOMAIN_PERCORE_DSU);
+	struct mtk_cpupm_pwrstate pm_state = {
+		.info = {
+			.cpuid = plat_my_core_pos(),
+			.mode = MTK_CPU_PM_SMP,
+		},
+		.pwr = {
+			.afflv = armv8_2_get_pwr_afflv(state),
+			.state_id = 0x0,
+		},
+	};
+	armv8_2_cpu_pwr_off(&pm_state, pstate);
+
+	nb.cpuid = pm_state.info.cpuid;
+	nb.pwr_domain = pstate;
+	MT_CPUPM_EVENT_PWR_OFF(&nb);
+
+	INFO("CPU %u power domain off\n", pm_state.info.cpuid);
+}
+
+/* MediaTek PSCI power domain */
+static void armv8_2_power_domain_suspend(const psci_power_state_t *state)
+{
+	unsigned int pstate = 0;
+	struct mt_cpupm_event_data nb;
+	struct mtk_cpupm_pwrstate pm_state = {
+		.info = {
+			.cpuid = plat_my_core_pos(),
+			.mode = MTK_CPU_PM_CPUIDLE,
+		},
+	};
+
+	pm_state.pwr.state_id = armv8_2_get_pwr_stateid(pm_state.info.cpuid);
+	pm_state.pwr.afflv = armv8_2_get_pwr_afflv(state);
+	pm_state.pwr.raw = state;
+
+	pstate = get_mediatek_pstate(CPUPM_PWR_OFF,
+				     armv8_2_power_state[pm_state.info.cpuid], &pm_state);
+
+	armv8_2_cpu_pwr_suspend(&pm_state, pstate);
+
+	if ((pstate & MT_CPUPM_PWR_DOMAIN_CLUSTER) != 0) {
+		armv8_2_cluster_pwr_dwn_common(&pm_state);
+	}
+
+	if ((pstate & MT_CPUPM_PWR_DOMAIN_MCUSYS) != 0) {
+		armv8_2_mcusys_pwr_dwn_common(&pm_state);
+	}
+
+	nb.cpuid = pm_state.info.cpuid;
+	nb.pwr_domain = pstate;
+	MT_CPUPM_EVENT_PWR_OFF(&nb);
+
+	if (IS_AFFLV_PUBEVENT(pstate)) {
+		MT_CPUPM_EVENT_AFFLV_PWR_OFF(&nb);
+	}
+}
+
+/* MediaTek PSCI power domain */
+static void armv8_2_power_domain_suspend_finish(const psci_power_state_t *state)
+{
+	unsigned int pstate = 0;
+	struct mt_cpupm_event_data nb;
+	struct mtk_cpupm_pwrstate pm_state = {
+		.info = {
+			.cpuid = plat_my_core_pos(),
+			.mode = MTK_CPU_PM_CPUIDLE,
+		},
+	};
+
+	pm_state.pwr.state_id = armv8_2_get_pwr_stateid(pm_state.info.cpuid);
+	pm_state.pwr.afflv = armv8_2_get_pwr_afflv(state);
+	pm_state.pwr.raw = state;
+
+	pstate = get_mediatek_pstate(CPUPM_PWR_ON,
+				     armv8_2_power_state[pm_state.info.cpuid], &pm_state);
+
+	if ((pstate & MT_CPUPM_PWR_DOMAIN_MCUSYS) != 0) {
+		armv8_2_mcusys_pwr_on_common(&pm_state);
+	}
+
+	if ((pstate & MT_CPUPM_PWR_DOMAIN_CLUSTER) != 0) {
+		armv8_2_cluster_pwr_on_common(&pm_state);
+	}
+
+	armv8_2_cpu_pwr_resume(&pm_state, pstate);
+
+	nb.cpuid = pm_state.info.cpuid;
+	nb.pwr_domain = pstate;
+	MT_CPUPM_EVENT_PWR_ON(&nb);
+
+	if (IS_AFFLV_PUBEVENT(pstate)) {
+		MT_CPUPM_EVENT_AFFLV_PWR_ON(&nb);
+	}
+}
+
+/* MediaTek PSCI power domain */
+static int armv8_2_validate_power_state(unsigned int power_state, psci_power_state_t *req_state)
+{
+	unsigned int i;
+	unsigned int pstate = psci_get_pstate_type(power_state);
+	unsigned int aff_lvl = psci_get_pstate_pwrlvl(power_state);
+	unsigned int my_core_pos = plat_my_core_pos();
+
+	if (mtk_cpu_pwr.ops == NULL) {
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	if (IS_CPUIDLE_FN_ENABLE(MTK_CPUPM_FN_PWR_STATE_VALID)) {
+		if (mtk_cpu_pwr.ops->pwr_state_valid(aff_lvl, pstate) != 0) {
+			return PSCI_E_INVALID_PARAMS;
+		}
+	}
+
+	if (pstate == PSTATE_TYPE_STANDBY) {
+		req_state->pwr_domain_state[0] = PLAT_MAX_RET_STATE;
+	} else {
+		for (i = PSCI_CPU_PWR_LVL; i <= aff_lvl; i++) {
+			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+		}
+	}
+	armv8_2_power_state[my_core_pos] = power_state;
+
+	return PSCI_E_SUCCESS;
+}
+
+/* MediaTek PSCI power domain */
+#if CONFIG_MTK_SUPPORT_SYSTEM_SUSPEND
+static void armv8_2_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	unsigned int i;
+	int ret;
+	unsigned int power_state;
+	unsigned int my_core_pos = plat_my_core_pos();
+
+	ret = mtk_cpu_pwr.ops->pwr_state_valid(PLAT_MAX_PWR_LVL,
+						PSTATE_TYPE_POWERDOWN);
+
+	if (ret != MTK_CPUPM_E_OK) {
+		/* Avoid suspend due to platform is not ready. */
+		req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] =
+						PLAT_MAX_RET_STATE;
+		for (i = PSCI_CPU_PWR_LVL + 1; i <= PLAT_MAX_PWR_LVL; i++) {
+			req_state->pwr_domain_state[i] = PSCI_LOCAL_STATE_RUN;
+		}
+
+		power_state = psci_make_powerstate(0, PSTATE_TYPE_STANDBY, PSCI_CPU_PWR_LVL);
+	} else {
+		for (i = PSCI_CPU_PWR_LVL; i <= PLAT_MAX_PWR_LVL; i++) {
+			req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+		}
+
+		power_state = psci_make_powerstate(MT_PLAT_PWR_STATE_SYSTEM_SUSPEND,
+						   PSTATE_TYPE_POWERDOWN, PLAT_MAX_PWR_LVL);
+	}
+
+	armv8_2_power_state[my_core_pos] = power_state;
+	flush_dcache_range((uintptr_t)&armv8_2_power_state[my_core_pos],
+			   sizeof(armv8_2_power_state[my_core_pos]));
+}
+#endif
+static void armv8_2_pm_smp_init(unsigned int cpu_id, uintptr_t entry_point)
+{
+	if (entry_point == 0) {
+		ERROR("%s, warm_entry_point is null\n", __func__);
+		panic();
+	}
+	if (IS_CPUSMP_FN_ENABLE(MTK_CPUPM_FN_SMP_INIT)) {
+		mtk_cpu_pwr.smp->init(cpu_id, entry_point);
+	}
+	INFO("[%s:%d] - Initialize finished\n", __func__, __LINE__);
+}
+
+static struct plat_pm_pwr_ctrl armv8_2_pwr_ops = {
+	.pwr_domain_suspend = armv8_2_power_domain_suspend,
+	.pwr_domain_suspend_finish = armv8_2_power_domain_suspend_finish,
+	.validate_power_state = armv8_2_validate_power_state,
+#if CONFIG_MTK_SUPPORT_SYSTEM_SUSPEND
+	.get_sys_suspend_power_state = armv8_2_get_sys_suspend_power_state,
+#endif
+};
+
+struct plat_pm_smp_ctrl armv8_2_smp_ops = {
+	.init = armv8_2_pm_smp_init,
+	.pwr_domain_on = armv8_2_power_domain_on,
+	.pwr_domain_off = armv8_2_power_domain_off,
+	.pwr_domain_on_finish = armv8_2_power_domain_on_finish,
+};
+
+#define ISSUE_CPU_PM_REG_FAIL(_success) ({ _success = false; assert(0); })
+
+#define CPM_PM_FN_CHECK(_fns, _ops, _id, _func, _result, _flag) ({ \
+	if ((_fns & _id)) { \
+		if (_ops->_func) \
+			_flag |= _id; \
+		else { \
+			ISSUE_CPU_PM_REG_FAIL(_result); \
+		} \
+	} })
+
+int register_cpu_pm_ops(unsigned int fn_flags, struct mtk_cpu_pm_ops *ops)
+{
+	bool success = true;
+	unsigned int fns = 0;
+
+	if ((ops == NULL) || (mtk_cpu_pwr.ops != NULL)) {
+		ERROR("[%s:%d] register cpu_pm fail !!\n", __FILE__, __LINE__);
+		return MTK_CPUPM_E_ERR;
+	}
+
+	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_CORE,
+			cpu_resume, success, fns);
+
+	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_CORE,
+			cpu_suspend, success, fns);
+
+	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_CLUSTER,
+			cluster_resume, success, fns);
+
+	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_CLUSTER,
+			cluster_suspend, success, fns);
+
+	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_RESUME_MCUSYS,
+			mcusys_resume, success, fns);
+
+	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SUSPEND_MCUSYS,
+			mcusys_suspend, success, fns);
+
+	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_CPUPM_GET_PWR_STATE,
+			get_pstate, success, fns);
+
+	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_PWR_STATE_VALID,
+			pwr_state_valid, success, fns);
+
+	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_INIT,
+			init, success, fns);
+
+	if (success) {
+		mtk_cpu_pwr.ops = ops;
+		mtk_cpu_pwr.fn_mask |= fns;
+		plat_pm_ops_setup_pwr(&armv8_2_pwr_ops);
+		INFO("[%s:%d] CPU pwr ops register success, support:0x%x\n",
+		     __func__, __LINE__, fns);
+	} else {
+		ERROR("[%s:%d] register cpu_pm ops fail !, fn:0x%x\n",
+		      __func__, __LINE__, fn_flags);
+		assert(0);
+	}
+	return MTK_CPUPM_E_OK;
+}
+
+int register_cpu_smp_ops(unsigned int fn_flags, struct mtk_cpu_smp_ops *ops)
+{
+	bool success = true;
+	unsigned int fns = 0;
+
+	if ((ops == NULL) || (mtk_cpu_pwr.smp != NULL)) {
+		ERROR("[%s:%d] register cpu_smp fail !!\n", __FILE__, __LINE__);
+		return MTK_CPUPM_E_ERR;
+	}
+
+	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SMP_INIT,
+			init, success, fns);
+
+	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_PWR_ON_CORE_PREPARE,
+			cpu_pwr_on_prepare, success, fns);
+
+	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SMP_CORE_ON,
+			cpu_on, success, fns);
+
+	CPM_PM_FN_CHECK(fn_flags, ops, MTK_CPUPM_FN_SMP_CORE_OFF,
+			cpu_off, success, fns);
+
+	if (success == true) {
+		mtk_cpu_pwr.smp = ops;
+		mtk_cpu_pwr.fn_mask |= fns;
+		plat_pm_ops_setup_smp(&armv8_2_smp_ops);
+		INFO("[%s:%d] CPU smp ops register success, support:0x%x\n",
+		     __func__, __LINE__, fns);
+	} else {
+		ERROR("[%s:%d] register cpu_smp ops fail !, fn:0x%x\n",
+		      __func__, __LINE__, fn_flags);
+		assert(0);
+	}
+	return MTK_CPUPM_E_OK;
+}
diff --git a/plat/mediatek/lib/pm/armv8_2/rules.mk b/plat/mediatek/lib/pm/armv8_2/rules.mk
new file mode 100644
index 0000000..0e065c5
--- /dev/null
+++ b/plat/mediatek/lib/pm/armv8_2/rules.mk
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := armv${CONFIG_MTK_PM_ARCH}
+LOCAL_SRCS-y := ${LOCAL_DIR}/pwr_ctrl.c
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/lib/pm/mtk_pm.c b/plat/mediatek/lib/pm/mtk_pm.c
index 632a1e7..3dbeb51 100644
--- a/plat/mediatek/lib/pm/mtk_pm.c
+++ b/plat/mediatek/lib/pm/mtk_pm.c
@@ -4,15 +4,117 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#include <lib/psci/psci.h>
+#include <assert.h>
+#include <plat/common/platform.h>
+#include <lib/pm/mtk_pm.h>
 
-static const plat_psci_ops_t plat_psci_ops = {
-};
+#define MTK_PM_ST_SMP_READY	BIT(0)
+#define MTK_PM_ST_PWR_READY	BIT(1)
+#define MTK_PM_ST_RESET_READY	BIT(2)
+
+static uintptr_t mtk_secure_entrypoint;
+static plat_init_func mtk_plat_smp_init;
+static plat_psci_ops_t mtk_pm_ops;
+static unsigned int mtk_pm_status;
+
+uintptr_t plat_pm_get_warm_entry(void)
+{
+	return mtk_secure_entrypoint;
+}
+
+int plat_pm_ops_setup_pwr(struct plat_pm_pwr_ctrl *ops)
+{
+	if (!ops) {
+		return MTK_CPUPM_E_FAIL;
+	}
+
+#if CONFIG_MTK_CPU_SUSPEND_EN
+	if (!mtk_pm_ops.pwr_domain_suspend) {
+		mtk_pm_ops.pwr_domain_suspend = ops->pwr_domain_suspend;
+	}
+
+	if (!mtk_pm_ops.pwr_domain_suspend_finish) {
+		mtk_pm_ops.pwr_domain_suspend_finish = ops->pwr_domain_suspend_finish;
+	}
+
+	if (!mtk_pm_ops.validate_power_state) {
+		mtk_pm_ops.validate_power_state = ops->validate_power_state;
+	}
+
+	if (!mtk_pm_ops.get_sys_suspend_power_state) {
+		mtk_pm_ops.get_sys_suspend_power_state = ops->get_sys_suspend_power_state;
+	}
+
+	mtk_pm_status |= MTK_PM_ST_PWR_READY;
+#endif
+	return MTK_CPUPM_E_OK;
+}
+
+int plat_pm_ops_setup_smp(struct plat_pm_smp_ctrl *ops)
+{
+	if (!ops) {
+		return MTK_CPUPM_E_FAIL;
+	}
+
+#if CONFIG_MTK_SMP_EN
+	if (!mtk_pm_ops.pwr_domain_on) {
+		mtk_pm_ops.pwr_domain_on = ops->pwr_domain_on;
+	}
+
+	if (!mtk_pm_ops.pwr_domain_on_finish) {
+		mtk_pm_ops.pwr_domain_on_finish = ops->pwr_domain_on_finish;
+	}
+
+	if (!mtk_pm_ops.pwr_domain_off) {
+		mtk_pm_ops.pwr_domain_off = ops->pwr_domain_off;
+	}
+
+	if (!mtk_plat_smp_init) {
+		mtk_plat_smp_init = ops->init;
+	}
+
+	mtk_pm_status |= MTK_PM_ST_SMP_READY;
+#endif
+	return MTK_CPUPM_E_OK;
+}
+
+int plat_pm_ops_setup_reset(struct plat_pm_reset_ctrl *ops)
+{
+	if (!ops) {
+		return MTK_CPUPM_E_FAIL;
+	}
+
+	if (!mtk_pm_ops.system_off) {
+		mtk_pm_ops.system_off = ops->system_off;
+	}
+
+	if (!mtk_pm_ops.system_reset) {
+		mtk_pm_ops.system_reset = ops->system_reset;
+	}
+
+	if (!mtk_pm_ops.system_reset2) {
+		mtk_pm_ops.system_reset2 = ops->system_reset2;
+	}
+
+	mtk_pm_status |= MTK_PM_ST_RESET_READY;
+
+	return MTK_CPUPM_E_OK;
+}
 
 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
 			const plat_psci_ops_t **psci_ops)
 {
-	*psci_ops = &plat_psci_ops;
+	*psci_ops = &mtk_pm_ops;
+	mtk_secure_entrypoint = sec_entrypoint;
+
+	if (mtk_plat_smp_init) {
+		unsigned int cpu_id = plat_my_core_pos();
 
+		mtk_plat_smp_init(cpu_id, mtk_secure_entrypoint);
+	}
+	INFO("%s, smp:(%d), pwr_ctrl:(%d), system_reset:(%d)\n", __func__,
+	     !!(mtk_pm_status & MTK_PM_ST_SMP_READY),
+	     !!(mtk_pm_status & MTK_PM_ST_PWR_READY),
+	     !!(mtk_pm_status & MTK_PM_ST_RESET_READY));
 	return 0;
 }
diff --git a/plat/mediatek/lib/pm/mtk_pm.h b/plat/mediatek/lib/pm/mtk_pm.h
new file mode 100644
index 0000000..0bfb493
--- /dev/null
+++ b/plat/mediatek/lib/pm/mtk_pm.h
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2022, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_PM_H
+#define MTK_PM_H
+#include <lib/psci/psci.h>
+
+#if MTK_PUBEVENT_ENABLE
+#include <mtk_event/mtk_pubsub_events.h>
+#endif
+
+#define MTK_CPUPM_E_OK				(0)
+#define MTK_CPUPM_E_UNKNOWN			(-1)
+#define MTK_CPUPM_E_ERR				(-2)
+#define MTK_CPUPM_E_FAIL			(-3)
+#define MTK_CPUPM_E_NOT_SUPPORT			(-4)
+
+
+#define MTK_CPUPM_FN_PWR_LOCK_AQUIRE		BIT(0)
+#define MTK_CPUPM_FN_INIT			BIT(1)
+#define MTK_CPUPM_FN_PWR_STATE_VALID		BIT(2)
+#define MTK_CPUPM_FN_PWR_ON_CORE_PREPARE	BIT(3)
+#define MTK_CPUPM_FN_SUSPEND_CORE		BIT(4)
+#define MTK_CPUPM_FN_RESUME_CORE		BIT(5)
+#define MTK_CPUPM_FN_SUSPEND_CLUSTER		BIT(6)
+#define MTK_CPUPM_FN_RESUME_CLUSTER		BIT(7)
+#define MTK_CPUPM_FN_SUSPEND_MCUSYS		BIT(8)
+#define MTK_CPUPM_FN_RESUME_MCUSYS		BIT(9)
+#define MTK_CPUPM_FN_CPUPM_GET_PWR_STATE	BIT(10)
+#define MTK_CPUPM_FN_SMP_INIT			BIT(11)
+#define MTK_CPUPM_FN_SMP_CORE_ON		BIT(12)
+#define MTK_CPUPM_FN_SMP_CORE_OFF		BIT(13)
+
+enum mtk_cpupm_pstate {
+	MTK_CPUPM_CORE_ON,
+	MTK_CPUPM_CORE_OFF,
+	MTK_CPUPM_CORE_SUSPEND,
+	MTK_CPUPM_CORE_RESUME,
+	MTK_CPUPM_CLUSTER_SUSPEND,
+	MTK_CPUPM_CLUSTER_RESUME,
+	MTK_CPUPM_MCUSYS_SUSPEND,
+	MTK_CPUPM_MCUSYS_RESUME,
+};
+
+enum mtk_cpu_pm_mode {
+	MTK_CPU_PM_CPUIDLE,
+	MTK_CPU_PM_SMP,
+};
+
+#define MT_IRQ_REMAIN_MAX	(32)
+#define MT_IRQ_REMAIN_CAT_LOG	BIT(31)
+
+struct mt_irqremain {
+	unsigned int count;
+	unsigned int irqs[MT_IRQ_REMAIN_MAX];
+	unsigned int wakeupsrc_cat[MT_IRQ_REMAIN_MAX];
+	unsigned int wakeupsrc[MT_IRQ_REMAIN_MAX];
+};
+
+typedef void (*plat_init_func)(unsigned int, uintptr_t);
+
+struct plat_pm_smp_ctrl {
+	plat_init_func init;
+	int (*pwr_domain_on)(u_register_t mpidr);
+	void (*pwr_domain_off)(const psci_power_state_t *target_state);
+	void (*pwr_domain_on_finish)(const psci_power_state_t *target_state);
+};
+
+struct plat_pm_pwr_ctrl {
+	void (*pwr_domain_suspend)(const psci_power_state_t *target_state);
+	void (*pwr_domain_on_finish_late)(const psci_power_state_t *target_state);
+	void (*pwr_domain_suspend_finish)(const psci_power_state_t *target_state);
+	int (*validate_power_state)(unsigned int power_state, psci_power_state_t *req_state);
+	void (*get_sys_suspend_power_state)(psci_power_state_t *req_state);
+};
+
+struct plat_pm_reset_ctrl {
+	__dead2 void (*system_off)();
+	__dead2 void (*system_reset)();
+	int (*system_reset2)(int is_vendor, int reset_type, u_register_t cookie);
+};
+
+struct mtk_cpu_pm_info {
+	unsigned int cpuid;
+	unsigned int mode;
+};
+
+struct mtk_cpu_pm_state {
+	unsigned int afflv;
+	unsigned int state_id;
+	const psci_power_state_t *raw;
+};
+
+struct mtk_cpupm_pwrstate {
+	struct mtk_cpu_pm_info info;
+	struct mtk_cpu_pm_state pwr;
+};
+
+struct mtk_cpu_smp_ops {
+	void (*init)(unsigned int cpu, uintptr_t sec_entrypoint);
+	int (*cpu_pwr_on_prepare)(unsigned int cpu, uintptr_t entry);
+	void (*cpu_on)(const struct mtk_cpupm_pwrstate *state);
+	void (*cpu_off)(const struct mtk_cpupm_pwrstate *state);
+	int (*invoke)(unsigned int funcID, void *priv);
+};
+
+#define MT_CPUPM_PWR_DOMAIN_CORE		BIT(0)
+#define MT_CPUPM_PWR_DOMAIN_PERCORE_DSU		BIT(1)
+#define MT_CPUPM_PWR_DOMAIN_PERCORE_DSU_MEM	BIT(2)
+#define MT_CPUPM_PWR_DOMAIN_CLUSTER		BIT(3)
+#define MT_CPUPM_PWR_DOMAIN_MCUSYS		BIT(4)
+#define MT_CPUPM_PWR_DOMAIN_SUSPEND		BIT(5)
+
+enum mt_cpupm_pwr_domain {
+	CPUPM_PWR_ON,
+	CPUPM_PWR_OFF,
+};
+
+typedef	unsigned int mtk_pstate_type;
+
+struct mtk_cpu_pm_ops {
+	void (*init)(unsigned int cpu, uintptr_t sec_entrypoint);
+	unsigned int (*get_pstate)(enum mt_cpupm_pwr_domain domain,
+				   const mtk_pstate_type psci_state,
+				   const struct mtk_cpupm_pwrstate *state);
+	int (*pwr_state_valid)(unsigned int afflv, unsigned int state);
+	void (*cpu_suspend)(const struct mtk_cpupm_pwrstate *state);
+	void (*cpu_resume)(const struct mtk_cpupm_pwrstate *state);
+	void (*cluster_suspend)(const struct mtk_cpupm_pwrstate *state);
+	void (*cluster_resume)(const struct mtk_cpupm_pwrstate *state);
+	void (*mcusys_suspend)(const struct mtk_cpupm_pwrstate *state);
+	void (*mcusys_resume)(const struct mtk_cpupm_pwrstate *state);
+	int (*invoke)(unsigned int funcID, void *priv);
+};
+
+int register_cpu_pm_ops(unsigned int fn_flags, struct mtk_cpu_pm_ops *ops);
+int register_cpu_smp_ops(unsigned int fn_flags, struct mtk_cpu_smp_ops *ops);
+
+struct mt_cpupm_event_data {
+	unsigned int cpuid;
+	unsigned int pwr_domain;
+};
+
+/* Extension event for platform driver */
+#if MTK_PUBEVENT_ENABLE
+/* [PUB_EVENT] Core power on */
+#define MT_CPUPM_SUBCRIBE_EVENT_PWR_ON(_fn) \
+	SUBSCRIBE_TO_EVENT(mt_cpupm_publish_pwr_on, _fn)
+
+/* [PUB_EVENT] Core power off */
+#define MT_CPUPM_SUBCRIBE_EVENT_PWR_OFF(_fn) \
+	SUBSCRIBE_TO_EVENT(mt_cpupm_publish_pwr_off, _fn)
+
+/* [PUB_EVENT] Cluster power on */
+#define MT_CPUPM_SUBCRIBE_CLUSTER_PWR_ON(_fn) \
+	SUBSCRIBE_TO_EVENT(mt_cpupm_publish_afflv_pwr_on, _fn)
+
+/* [PUB_EVENT] Cluster power off */
+#define MT_CPUPM_SUBCRIBE_CLUSTER_PWR_OFF(_fn) \
+	SUBSCRIBE_TO_EVENT(mt_cpupm_publish_afflv_pwr_off, _fn)
+
+/* [PUB_EVENT] Mcusys power on */
+#define MT_CPUPM_SUBCRIBE_MCUSYS_PWR_ON(_fn) \
+	SUBSCRIBE_TO_EVENT(mt_cpupm_publish_afflv_pwr_on, _fn)
+
+/* [PUB_EVENT] Mcusys power off */
+#define MT_CPUPM_SUBCRIBE_MCUSYS_PWR_OFF(_fn) \
+	SUBSCRIBE_TO_EVENT(mt_cpupm_publish_afflv_pwr_off, _fn)
+
+#else
+#define MT_CPUPM_SUBCRIBE_EVENT_PWR_ON(_fn)
+#define MT_CPUPM_SUBCRIBE_EVENT_PWR_OFF(_fn)
+#define MT_CPUPM_SUBCRIBE_CLUSTER_PWR_ON(_fn)
+#define MT_CPUPM_SUBCRIBE_CLUSTER_PWR_OFF(_fn)
+#define MT_CPUPM_SUBCRIBE_MCUSYS_PWR_ON(_fn)
+#define MT_CPUPM_SUBCRIBE_MCUSYS_PWR_OFF(_fn)
+#endif
+
+#define MT_PLAT_PWR_STATE_L_CPU				(0x0001)
+#define MT_PLAT_PWR_STATE_B_CPU				(0x0002)
+#define MT_PLAT_PWR_STATE_L_CLUSTER			(0x0101)
+#define MT_PLAT_PWR_STATE_B_CLUSTER			(0x0102)
+#define MT_PLAT_PWR_STATE_MCUSYS			(0x0701)
+#define MT_PLAT_PWR_STATE_SYSTEM_MEM			(0x0f01)
+#define MT_PLAT_PWR_STATE_SYSTEM_PLL			(0x0f02)
+#define MT_PLAT_PWR_STATE_SYSTEM_BUS			(0x0f03)
+#define MT_PLAT_PWR_STATE_SUSPEND2IDLE			(0x1f01)
+#define MT_PLAT_PWR_STATE_SYSTEM_SUSPEND		(0x1f02)
+
+#define IS_MT_PLAT_PWR_STATE_MCUSYS(state)		(state & 0x400)
+#define IS_MT_PLAT_PWR_STATE_SYSTEM(state)		(state & 0x800)
+#define IS_MT_PLAT_PWR_STATE_PLATFORM(state)		(state & 0x1800)
+
+#define PLAT_MT_SYSTEM_SUSPEND		PLAT_MAX_OFF_STATE
+#define PLAT_MT_CPU_SUSPEND_CLUSTER	PLAT_MAX_RET_STATE
+
+#define IS_PLAT_SYSTEM_SUSPEND(aff)	(aff == PLAT_MT_SYSTEM_SUSPEND)
+#define IS_PLAT_SYSTEM_RETENTION(aff)	(aff >= PLAT_MAX_RET_STATE)
+
+#define IS_PLAT_SUSPEND2IDLE_ID(stateid) (stateid == MT_PLAT_PWR_STATE_SUSPEND2IDLE)
+
+#define IS_PLAT_SUSPEND_ID(stateid) ((stateid == MT_PLAT_PWR_STATE_SUSPEND2IDLE) || \
+				     (stateid == MT_PLAT_PWR_STATE_SYSTEM_SUSPEND))
+
+
+int plat_pm_ops_setup_pwr(struct plat_pm_pwr_ctrl *ops);
+int plat_pm_ops_setup_reset(struct plat_pm_reset_ctrl *ops);
+int plat_pm_ops_setup_smp(struct plat_pm_smp_ctrl *ops);
+uintptr_t plat_pm_get_warm_entry(void);
+
+#endif
diff --git a/plat/mediatek/lib/pm/rules.mk b/plat/mediatek/lib/pm/rules.mk
index 77d0408..29265c4 100644
--- a/plat/mediatek/lib/pm/rules.mk
+++ b/plat/mediatek/lib/pm/rules.mk
@@ -12,3 +12,6 @@
 LOCAL_SRCS-y := ${LOCAL_DIR}/mtk_pm.c
 
 $(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
+
+SUB_RULES-$(CONFIG_MTK_PM_SUPPORT) := $(LOCAL_DIR)/armv${CONFIG_MTK_PM_ARCH}
+$(eval $(call INCLUDE_MAKEFILE,$(SUB_RULES-y)))
diff --git a/plat/mediatek/lib/system_reset/reset_cros.c b/plat/mediatek/lib/system_reset/reset_cros.c
new file mode 100644
index 0000000..40e68ba
--- /dev/null
+++ b/plat/mediatek/lib/system_reset/reset_cros.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2022, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/gpio.h>
+#include <lib/mtk_init/mtk_init.h>
+#include <lib/pm/mtk_pm.h>
+#include <plat_params.h>
+#include <pmic.h>
+#include <rtc.h>
+
+static void __dead2 mtk_system_reset_cros(void)
+{
+	struct bl_aux_gpio_info *gpio_reset = plat_get_mtk_gpio_reset();
+
+	INFO("MTK System Reset\n");
+
+	gpio_set_value(gpio_reset->index, gpio_reset->polarity);
+
+	wfi();
+	ERROR("MTK System Reset: operation not handled.\n");
+	panic();
+}
+
+static void __dead2 mtk_system_off_cros(void)
+{
+	INFO("MTK System Off\n");
+
+	rtc_power_off_sequence();
+	pmic_power_off();
+
+	wfi();
+	ERROR("MTK System Off: operation not handled.\n");
+	panic();
+}
+
+static struct plat_pm_reset_ctrl lib_reset_ctrl = {
+	.system_off = mtk_system_off_cros,
+	.system_reset = mtk_system_reset_cros,
+	.system_reset2 = NULL,
+};
+
+static int lib_reset_ctrl_init(void)
+{
+	INFO("Reset init\n");
+
+	plat_pm_ops_setup_reset(&lib_reset_ctrl);
+
+	return 0;
+}
+MTK_ARCH_INIT(lib_reset_ctrl_init);
diff --git a/plat/mediatek/lib/system_reset/rules.mk b/plat/mediatek/lib/system_reset/rules.mk
new file mode 100644
index 0000000..4f20663
--- /dev/null
+++ b/plat/mediatek/lib/system_reset/rules.mk
@@ -0,0 +1,14 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := system_reset
+
+LOCAL_SRCS-y := ${LOCAL_DIR}/reset_cros.c
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))
diff --git a/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.c b/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.c
index 989ecf1..a183483 100644
--- a/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.c
+++ b/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -96,5 +96,38 @@
 
 void emi_mpu_init(void)
 {
-	/* TODO: more setting for EMI MPU. */
+	struct emi_region_info_t region_info;
+
+	/* SCP DRAM */
+	region_info.start = 0x50000000ULL;
+	region_info.end = 0x5109FFFFULL;
+	region_info.region = 2;
+	SET_ACCESS_PERMISSION(region_info.apc, 1,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      NO_PROTECTION, FORBIDDEN, FORBIDDEN, NO_PROTECTION);
+	emi_mpu_set_protection(&region_info);
+
+	/* DSP protect address */
+	region_info.start = 0x60000000ULL;	/* dram base addr */
+	region_info.end = 0x610FFFFFULL;
+	region_info.region = 3;
+	SET_ACCESS_PERMISSION(region_info.apc, 1,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION);
+	emi_mpu_set_protection(&region_info);
+
+	/* Forbidden All */
+	region_info.start = 0x40000000ULL;	/* dram base addr */
+	region_info.end = 0x1FFFF0000ULL;
+	region_info.region = 4;
+	SET_ACCESS_PERMISSION(region_info.apc, 1,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, NO_PROTECTION);
+	emi_mpu_set_protection(&region_info);
 }
diff --git a/plat/mediatek/mt8188/aarch64/plat_helpers.S b/plat/mediatek/mt8188/aarch64/plat_helpers.S
deleted file mode 100644
index 7073ab1..0000000
--- a/plat/mediatek/mt8188/aarch64/plat_helpers.S
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <arch.h>
-#include <asm_macros.S>
-#include <platform_def.h>
-
-	.globl plat_is_my_cpu_primary
-	.globl plat_my_core_pos
-	.globl plat_mediatek_calc_core_pos
-
-func plat_is_my_cpu_primary
-	mrs	x0, mpidr_el1
-	and	x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
-	cmp	x0, #PLAT_PRIMARY_CPU
-	cset	x0, eq
-	ret
-endfunc plat_is_my_cpu_primary
-
-	/* -----------------------------------------------------
-	 *  unsigned int plat_my_core_pos(void)
-	 *  This function uses the plat_mediatek_calc_core_pos()
-	 *  definition to get the index of the calling CPU.
-	 * -----------------------------------------------------
-	 */
-func plat_my_core_pos
-	mrs	x0, mpidr_el1
-	b	plat_mediatek_calc_core_pos
-endfunc plat_my_core_pos
-
-	/* -----------------------------------------------------
-	 * unsigned int plat_mediatek_calc_core_pos(u_register_t mpidr);
-	 *
-	 * With this function: CorePos = CoreID (AFF1)
-	 * we do it with x0 = (x0 >> 8) & 0xff
-	 * -----------------------------------------------------
-	 */
-func plat_mediatek_calc_core_pos
-	mov	x1, #MPIDR_AFFLVL_MASK
-	and	x0, x1, x0, lsr #MPIDR_AFF1_SHIFT
-	ret
-endfunc plat_mediatek_calc_core_pos
diff --git a/plat/mediatek/include/mt8188/platform_def.h b/plat/mediatek/mt8188/include/platform_def.h
similarity index 86%
rename from plat/mediatek/include/mt8188/platform_def.h
rename to plat/mediatek/mt8188/include/platform_def.h
index 962d952..499c4f4 100644
--- a/plat/mediatek/include/mt8188/platform_def.h
+++ b/plat/mediatek/mt8188/include/platform_def.h
@@ -7,10 +7,13 @@
 #ifndef PLATFORM_DEF_H
 #define PLATFORM_DEF_H
 
+#include <arch_def.h>
+
 #define PLAT_PRIMARY_CPU	(0x0)
 
 #define MT_GIC_BASE		(0x0C000000)
 #define MCUCFG_BASE		(0x0C530000)
+#define MCUCFG_REG_SIZE		(0x10000)
 #define IO_PHYS			(0x10000000)
 
 /* Aggregate of all devices for MMU mapping */
@@ -23,6 +26,8 @@
  * GPIO related constants
  ******************************************************************************/
 #define GPIO_BASE		(IO_PHYS + 0x00005000)
+#define RGU_BASE		(IO_PHYS + 0x00007000)
+#define DRM_BASE		(IO_PHYS + 0x0000D000)
 #define IOCFG_RM_BASE		(IO_PHYS + 0x01C00000)
 #define IOCFG_LT_BASE		(IO_PHYS + 0x01E10000)
 #define IOCFG_LM_BASE		(IO_PHYS + 0x01E20000)
@@ -101,6 +106,12 @@
 #define DP_SEC_SIZE		(0x1000)
 
 /*******************************************************************************
+ * EMI MPU related constants
+ *******************************************************************************/
+#define EMI_MPU_BASE		(IO_PHYS + 0x00226000)
+#define SUB_EMI_MPU_BASE	(IO_PHYS + 0x00225000)
+
+/*******************************************************************************
  * System counter frequency related constants
  ******************************************************************************/
 #define SYS_COUNTER_FREQ_IN_HZ	(13000000)
@@ -116,22 +127,7 @@
  * Generic platform constants
  ******************************************************************************/
 #define PLATFORM_STACK_SIZE		(0x800)
-
 #define FIRMWARE_WELCOME_STR		"Booting Trusted Firmware\n"
-
-#define PLAT_MAX_PWR_LVL		U(3)
-#define PLAT_MAX_RET_STATE		U(1)
-#define PLAT_MAX_OFF_STATE		U(9)
-
-#define PLATFORM_SYSTEM_COUNT		U(1)
-#define PLATFORM_MCUSYS_COUNT		U(1)
-#define PLATFORM_CLUSTER_COUNT		U(1)
-#define PLATFORM_CLUSTER0_CORE_COUNT	U(8)
-#define PLATFORM_CLUSTER1_CORE_COUNT	U(0)
-
-#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER0_CORE_COUNT)
-#define PLATFORM_MAX_CPUS_PER_CLUSTER	U(8)
-
 #define SOC_CHIP_ID			U(0x8188)
 
 /*******************************************************************************
@@ -159,16 +155,4 @@
 #define MAX_XLAT_TABLES			(16)
 #define MAX_MMAP_REGIONS		(16)
 
-/*******************************************************************************
- * Declarations and constants to access the mailboxes safely. Each mailbox is
- * aligned on the biggest cache line size in the platform. This is known only
- * to the platform as it might have a combination of integrated and external
- * caches. Such alignment ensures that two maiboxes do not sit on the same cache
- * line at any cache level. They could belong to different cpus/clusters &
- * get written while being protected by different locks causing corruption of
- * a valid mailbox address.
- ******************************************************************************/
-#define CACHE_WRITEBACK_SHIFT		(6)
-#define CACHE_WRITEBACK_GRANULE		(1 << CACHE_WRITEBACK_SHIFT)
-
 #endif /* PLATFORM_DEF_H */
diff --git a/plat/mediatek/mt8188/plat_config.mk b/plat/mediatek/mt8188/plat_config.mk
index 0c1e7cd..ff4fe1d 100644
--- a/plat/mediatek/mt8188/plat_config.mk
+++ b/plat/mediatek/mt8188/plat_config.mk
@@ -29,6 +29,12 @@
 ERRATA_A78_1821534 := 1
 ERRATA_A78_2132060 := 1
 ERRATA_A78_2242635 := 1
+ERRATA_A78_2376745 := 1
+ERRATA_A78_2395406 := 1
+
+CONFIG_ARCH_ARM_V8_2 := y
+CONFIG_MTK_MCUSYS := y
+MCUSYS_VERSION := v1
 
 MACH_MT8188 := 1
 $(eval $(call add_define,MACH_MT8188))
diff --git a/plat/mediatek/mt8188/plat_topology.c b/plat/mediatek/mt8188/plat_topology.c
deleted file mode 100644
index 9fa2855..0000000
--- a/plat/mediatek/mt8188/plat_topology.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <arch.h>
-#include <arch_helpers.h>
-#include <lib/psci/psci.h>
-
-#include <plat_helpers.h>
-#include <platform_def.h>
-
-const unsigned char mtk_power_domain_tree_desc[] = {
-	/* Number of root nodes */
-	PLATFORM_SYSTEM_COUNT,
-	/* Number of children for the root node */
-	PLATFORM_MCUSYS_COUNT,
-	/* Number of children for the mcusys node */
-	PLATFORM_CLUSTER_COUNT,
-	/* Number of children for the first cluster node */
-	PLATFORM_CLUSTER0_CORE_COUNT,
-};
-
-const unsigned char *plat_get_power_domain_tree_desc(void)
-{
-	return mtk_power_domain_tree_desc;
-}
-
-/*******************************************************************************
- * This function implements a part of the critical interface between the psci
- * generic layer and the platform that allows the former to query the platform
- * to convert an MPIDR to a unique linear index. An error code (-1) is returned
- * in case the MPIDR is invalid.
- ******************************************************************************/
-int plat_core_pos_by_mpidr(u_register_t mpidr)
-{
-	unsigned int cluster_id, cpu_id;
-
-	if ((read_mpidr() & MPIDR_MT_MASK) != 0) {
-		/* ARMv8.2 arch */
-		if ((mpidr & (MPIDR_AFFLVL_MASK << MPIDR_AFF0_SHIFT)) != 0) {
-			return -1;
-		}
-		return plat_mediatek_calc_core_pos(mpidr);
-	}
-
-	mpidr &= MPIDR_AFFINITY_MASK;
-
-	if ((mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) != 0) {
-		return -1;
-	}
-
-	cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK;
-	cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK;
-
-	if (cluster_id >= PLATFORM_CLUSTER_COUNT) {
-		return -1;
-	}
-
-	/*
-	 * Validate cpu_id by checking whether it represents a CPU in
-	 * one of the two clusters present on the platform.
-	 */
-	if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER) {
-		return -1;
-	}
-
-	return (cpu_id + (cluster_id * 8));
-}
diff --git a/plat/mediatek/mt8188/platform.mk b/plat/mediatek/mt8188/platform.mk
index 84bcfac..99ba43f 100644
--- a/plat/mediatek/mt8188/platform.mk
+++ b/plat/mediatek/mt8188/platform.mk
@@ -14,7 +14,7 @@
 
 PLAT_INCLUDES := -I${MTK_PLAT}/common \
 		 -I${MTK_PLAT}/include \
-		 -I${MTK_PLAT}/include/${MTK_SOC} \
+		 -I${MTK_PLAT}/include/${ARCH_VERSION} \
 		 -I${MTK_PLAT} \
 		 -I${MTK_PLAT_SOC}/include \
 		 -Idrivers/arm/gic \
@@ -22,15 +22,23 @@
 MODULES-y += $(MTK_PLAT)/common
 MODULES-y += $(MTK_PLAT)/lib/mtk_init
 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/dfd
 MODULES-y += $(MTK_PLAT)/drivers/dp
+MODULES-y += $(MTK_PLAT)/drivers/emi_mpu
 MODULES-y += $(MTK_PLAT)/drivers/gic600
 MODULES-y += $(MTK_PLAT)/drivers/gpio
 MODULES-y += $(MTK_PLAT)/drivers/iommu
+MODULES-y += $(MTK_PLAT)/drivers/lpm
+MODULES-y += $(MTK_PLAT)/drivers/mcusys
 MODULES-y += $(MTK_PLAT)/drivers/pmic
 MODULES-y += $(MTK_PLAT)/drivers/pmic_wrap
 MODULES-y += $(MTK_PLAT)/drivers/rtc
 MODULES-y += $(MTK_PLAT)/drivers/timer
+MODULES-y += $(MTK_PLAT)/helpers
+MODULES-y += $(MTK_PLAT)/topology
 
 PLAT_BL_COMMON_SOURCES := common/desc_image_load.c \
 			  drivers/ti/uart/aarch64/16550_console.S \
@@ -47,9 +55,7 @@
 		plat/common/aarch64/crash_console_helpers.S \
 		${MTK_PLAT}/common/mtk_plat_common.c \
 		${MTK_PLAT}/common/params_setup.c \
-		${MTK_PLAT_SOC}/aarch64/plat_helpers.S \
-		$(MTK_PLAT)/$(MTK_SOC)/plat_mmap.c \
-		$(MTK_PLAT)/$(MTK_SOC)/plat_topology.c
+		$(MTK_PLAT)/$(MTK_SOC)/plat_mmap.c
 
 include plat/mediatek/build_helpers/mtk_build_helpers_epilogue.mk
 
diff --git a/plat/mediatek/topology/armv8_2/topology.c b/plat/mediatek/topology/armv8_2/topology.c
new file mode 100644
index 0000000..1627bbd
--- /dev/null
+++ b/plat/mediatek/topology/armv8_2/topology.c
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2022, Mediatek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <lib/psci/psci.h>
+#include <platform_def.h>
+
+#pragma weak plat_get_power_domain_tree_desc
+
+static const unsigned char mtk_power_domain_tree_desc[] = {
+	/* Number of root nodes */
+	PLATFORM_SYSTEM_COUNT,
+	/* Number of children for the root node */
+	PLATFORM_CLUSTER_COUNT,
+	/* Number of children for the first cluster node */
+	PLATFORM_CLUSTER0_CORE_COUNT,
+};
+
+/*******************************************************************************
+ * This function returns the default topology tree information.
+ ******************************************************************************/
+const unsigned char *plat_get_power_domain_tree_desc(void)
+{
+	return mtk_power_domain_tree_desc;
+}
diff --git a/plat/mediatek/topology/rules.mk b/plat/mediatek/topology/rules.mk
new file mode 100644
index 0000000..29f15bb
--- /dev/null
+++ b/plat/mediatek/topology/rules.mk
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2022, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+LOCAL_DIR := $(call GET_LOCAL_DIR)
+
+MODULE := topology
+LOCAL_SRCS-y := $(LOCAL_DIR)/$(ARCH_VERSION)/topology.c
+
+$(eval $(call MAKE_MODULE,$(MODULE),$(LOCAL_SRCS-y),$(MTK_BL)))