Merge changes from topic "uart1_console" into integration

* changes:
  feat(versal): add UART1 as console
  feat(zynqmp): add uart1 as console
diff --git a/.cz.json b/.cz.json
index 5ac961e..3c28d3c 100644
--- a/.cz.json
+++ b/.cz.json
@@ -809,6 +809,10 @@
                 {
                     "title": "STM32 Image",
                     "scopes": ["stm32image", "tools/stm32image"]
+                },
+                {
+                    "title": "fiptool",
+                    "scopes": ["fiptool"]
                 }
             ]
         },
diff --git a/docs/about/release-information.rst b/docs/about/release-information.rst
index a50b033..b3553ae 100644
--- a/docs/about/release-information.rst
+++ b/docs/about/release-information.rst
@@ -48,6 +48,8 @@
 +-----------------+---------------------------+------------------------------+
 | v2.6            | 4th week of Nov '21       | 2nd week of Nov '21          |
 +-----------------+---------------------------+------------------------------+
+| v2.7            | 2nd week of May '22       | 4th week of Apr '22          |
++-----------------+---------------------------+------------------------------+
 
 Removal of Deprecated Interfaces
 --------------------------------
diff --git a/docs/design/cpu-specific-build-macros.rst b/docs/design/cpu-specific-build-macros.rst
index 9d0dd5e..7075ca6 100644
--- a/docs/design/cpu-specific-build-macros.rst
+++ b/docs/design/cpu-specific-build-macros.rst
@@ -441,6 +441,19 @@
 -  ``ERRATA_N2_2280757``: This applies errata 2280757 workaround to Neoverse-N2
    CPU. This needs to be enabled for revision r0p0 of the CPU and is still open.
 
+For Cortex-X2, the following errata build flags are defined :
+
+-  ``ERRATA_X2_2002765``: This applies errata 2002765 workaround to Cortex-X2
+   CPU. This needs to be enabled for revisions r0p0, r1p0, and r2p0 of the CPU,
+   it is still open.
+
+-  ``ERRATA_X2_2058056``: This applies errata 2058056 workaround to Cortex-X2
+   CPU. This needs to be enabled for revisions r0p0, r1p0, and r2p0 of the CPU,
+   it is still open.
+
+-  ``ERRATA_X2_2083908``: This applies errata 2083908 workaround to Cortex-X2
+   CPU. This needs to be enabled for revision r2p0 of the CPU, it is still open.
+
 DSU Errata Workarounds
 ----------------------
 
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
new file mode 100644
index 0000000..4cbc0f7
--- /dev/null
+++ b/drivers/clk/clk.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ * Author(s): Ludovic Barre, <ludovic.barre@st.com> for STMicroelectronics.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <drivers/clk.h>
+
+static const struct clk_ops *ops;
+
+int clk_enable(unsigned long id)
+{
+	assert((ops != NULL) && (ops->enable != NULL));
+
+	return ops->enable(id);
+}
+
+void clk_disable(unsigned long id)
+{
+	assert((ops != NULL) && (ops->disable != NULL));
+
+	ops->disable(id);
+}
+
+unsigned long clk_get_rate(unsigned long id)
+{
+	assert((ops != NULL) && (ops->get_rate != NULL));
+
+	return ops->get_rate(id);
+}
+
+int clk_get_parent(unsigned long id)
+{
+	assert((ops != NULL) && (ops->get_parent != NULL));
+
+	return ops->get_parent(id);
+}
+
+bool clk_is_enabled(unsigned long id)
+{
+	assert((ops != NULL) && (ops->is_enabled != NULL));
+
+	return ops->is_enabled(id);
+}
+
+/*
+ * Initialize the clk. The fields in the provided clk
+ * ops pointer must be valid.
+ */
+void clk_register(const struct clk_ops *ops_ptr)
+{
+	assert((ops_ptr != NULL) &&
+	       (ops_ptr->enable != NULL) &&
+	       (ops_ptr->disable != NULL) &&
+	       (ops_ptr->get_rate != NULL) &&
+	       (ops_ptr->get_parent != NULL) &&
+	       (ops_ptr->is_enabled != NULL));
+
+	ops = ops_ptr;
+}
diff --git a/drivers/st/clk/stm32mp1_clk.c b/drivers/st/clk/stm32mp1_clk.c
index 5d4b8fb..684ab1a 100644
--- a/drivers/st/clk/stm32mp1_clk.c
+++ b/drivers/st/clk/stm32mp1_clk.c
@@ -17,6 +17,7 @@
 #include <arch_helpers.h>
 #include <common/debug.h>
 #include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
 #include <drivers/delay_timer.h>
 #include <drivers/generic_delay_timer.h>
 #include <drivers/st/stm32mp_clkfunc.h>
@@ -1157,17 +1158,19 @@
 	stm32mp1_clk_unlock(&refcount_lock);
 }
 
-void stm32mp_clk_enable(unsigned long id)
+static int stm32mp_clk_enable(unsigned long id)
 {
 	__stm32mp1_clk_enable(id, true);
+
+	return 0;
 }
 
-void stm32mp_clk_disable(unsigned long id)
+static void stm32mp_clk_disable(unsigned long id)
 {
 	__stm32mp1_clk_disable(id, true);
 }
 
-bool stm32mp_clk_is_enabled(unsigned long id)
+static bool stm32mp_clk_is_enabled(unsigned long id)
 {
 	int i;
 
@@ -1183,15 +1186,55 @@
 	return __clk_is_enabled(gate_ref(i));
 }
 
-unsigned long stm32mp_clk_get_rate(unsigned long id)
+static unsigned long stm32mp_clk_get_rate(unsigned long id)
 {
+	uintptr_t rcc_base = stm32mp_rcc_base();
 	int p = stm32mp1_clk_get_parent(id);
+	uint32_t prescaler, timpre;
+	unsigned long parent_rate;
 
 	if (p < 0) {
 		return 0;
 	}
 
+	parent_rate = get_clock_rate(p);
+
+	switch (id) {
+	case TIM2_K:
+	case TIM3_K:
+	case TIM4_K:
+	case TIM5_K:
+	case TIM6_K:
+	case TIM7_K:
+	case TIM12_K:
+	case TIM13_K:
+	case TIM14_K:
+		prescaler = mmio_read_32(rcc_base + RCC_APB1DIVR) &
+			    RCC_APBXDIV_MASK;
+		timpre = mmio_read_32(rcc_base + RCC_TIMG1PRER) &
+			 RCC_TIMGXPRER_TIMGXPRE;
+		break;
+
+	case TIM1_K:
+	case TIM8_K:
+	case TIM15_K:
+	case TIM16_K:
+	case TIM17_K:
+		prescaler = mmio_read_32(rcc_base + RCC_APB2DIVR) &
+			    RCC_APBXDIV_MASK;
+		timpre = mmio_read_32(rcc_base + RCC_TIMG2PRER) &
+			 RCC_TIMGXPRER_TIMGXPRE;
+		break;
+
-	return get_clock_rate(p);
+	default:
+		return parent_rate;
+	}
+
+	if (prescaler == 0U) {
+		return parent_rate;
+	}
+
+	return parent_rate * (timpre + 1U) * 2U;
 }
 
 static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on)
@@ -2264,11 +2307,21 @@
 	}
 }
 
+static const struct clk_ops stm32mp_clk_ops = {
+	.enable		= stm32mp_clk_enable,
+	.disable	= stm32mp_clk_disable,
+	.is_enabled	= stm32mp_clk_is_enabled,
+	.get_rate	= stm32mp_clk_get_rate,
+	.get_parent	= stm32mp1_clk_get_parent,
+};
+
 int stm32mp1_clk_probe(void)
 {
 	stm32mp1_osc_init();
 
 	sync_earlyboot_clocks_state();
 
+	clk_register(&stm32mp_clk_ops);
+
 	return 0;
 }
diff --git a/drivers/st/clk/stm32mp_clkfunc.c b/drivers/st/clk/stm32mp_clkfunc.c
index 0db0dee..c83b8ad 100644
--- a/drivers/st/clk/stm32mp_clkfunc.c
+++ b/drivers/st/clk/stm32mp_clkfunc.c
@@ -11,6 +11,7 @@
 #include <platform_def.h>
 
 #include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
 #include <drivers/st/stm32_gpio.h>
 #include <drivers/st/stm32mp_clkfunc.h>
 
@@ -325,5 +326,5 @@
 		return 0UL;
 	}
 
-	return stm32mp_clk_get_rate((unsigned long)clk_id);
+	return clk_get_rate((unsigned long)clk_id);
 }
diff --git a/drivers/st/crypto/stm32_hash.c b/drivers/st/crypto/stm32_hash.c
index 317fd9e..6a1d476 100644
--- a/drivers/st/crypto/stm32_hash.c
+++ b/drivers/st/crypto/stm32_hash.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,6 +14,7 @@
 
 #include <arch_helpers.h>
 #include <common/debug.h>
+#include <drivers/clk.h>
 #include <drivers/delay_timer.h>
 #include <drivers/st/stm32_hash.h>
 #include <drivers/st/stm32mp_reset.h>
@@ -189,7 +190,7 @@
 		return 0;
 	}
 
-	stm32mp_clk_enable(stm32_hash.clock);
+	clk_enable(stm32_hash.clock);
 
 	if (stm32_remain.length != 0U) {
 		uint32_t copysize;
@@ -231,7 +232,7 @@
 	}
 
 exit:
-	stm32mp_clk_disable(stm32_hash.clock);
+	clk_disable(stm32_hash.clock);
 
 	return ret;
 }
@@ -240,12 +241,12 @@
 {
 	int ret;
 
-	stm32mp_clk_enable(stm32_hash.clock);
+	clk_enable(stm32_hash.clock);
 
 	if (stm32_remain.length != 0U) {
 		ret = hash_write_data(stm32_remain.buffer);
 		if (ret != 0) {
-			stm32mp_clk_disable(stm32_hash.clock);
+			clk_disable(stm32_hash.clock);
 			return ret;
 		}
 
@@ -260,7 +261,7 @@
 
 	ret = hash_get_digest(digest);
 
-	stm32mp_clk_disable(stm32_hash.clock);
+	clk_disable(stm32_hash.clock);
 
 	return ret;
 }
@@ -280,11 +281,11 @@
 
 void stm32_hash_init(enum stm32_hash_algo_mode mode)
 {
-	stm32mp_clk_enable(stm32_hash.clock);
+	clk_enable(stm32_hash.clock);
 
 	hash_hw_init(mode);
 
-	stm32mp_clk_disable(stm32_hash.clock);
+	clk_disable(stm32_hash.clock);
 
 	zeromem(&stm32_remain, sizeof(stm32_remain));
 }
@@ -321,7 +322,7 @@
 	stm32_hash.base = hash_info.base;
 	stm32_hash.clock = hash_info.clock;
 
-	stm32mp_clk_enable(stm32_hash.clock);
+	clk_enable(stm32_hash.clock);
 
 	if (hash_info.reset >= 0) {
 		uint32_t id = (uint32_t)hash_info.reset;
@@ -335,7 +336,7 @@
 		}
 	}
 
-	stm32mp_clk_disable(stm32_hash.clock);
+	clk_disable(stm32_hash.clock);
 
 	return 0;
 }
diff --git a/drivers/st/ddr/stm32mp1_ddr.c b/drivers/st/ddr/stm32mp1_ddr.c
index 7d89d02..3db47c4 100644
--- a/drivers/st/ddr/stm32mp1_ddr.c
+++ b/drivers/st/ddr/stm32mp1_ddr.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2018-2021, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
  */
@@ -12,6 +12,7 @@
 #include <arch.h>
 #include <arch_helpers.h>
 #include <common/debug.h>
+#include <drivers/clk.h>
 #include <drivers/delay_timer.h>
 #include <drivers/st/stm32mp_pmic.h>
 #include <drivers/st/stm32mp1_ddr.h>
@@ -627,7 +628,7 @@
 	 */
 
 	/* Change Bypass Mode Frequency Range */
-	if (stm32mp_clk_get_rate(DDRPHYC) < 100000000U) {
+	if (clk_get_rate(DDRPHYC) < 100000000U) {
 		mmio_clrbits_32((uintptr_t)&priv->phy->dllgcr,
 				DDRPHYC_DLLGCR_BPS200);
 	} else {
diff --git a/drivers/st/ddr/stm32mp1_ram.c b/drivers/st/ddr/stm32mp1_ram.c
index b21c894..064e318 100644
--- a/drivers/st/ddr/stm32mp1_ram.c
+++ b/drivers/st/ddr/stm32mp1_ram.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (C) 2018-2021, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
  */
@@ -13,6 +13,7 @@
 #include <arch_helpers.h>
 #include <common/debug.h>
 #include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
 #include <drivers/st/stm32mp1_ddr.h>
 #include <drivers/st/stm32mp1_ddr_helpers.h>
 #include <drivers/st/stm32mp1_ram.h>
@@ -29,7 +30,7 @@
 
 	ddr_enable_clock();
 
-	ddrphy_clk = stm32mp_clk_get_rate(DDRPHYC);
+	ddrphy_clk = clk_get_rate(DDRPHYC);
 
 	VERBOSE("DDR: mem_speed (%d kHz), RCC %ld kHz\n",
 		mem_speed, ddrphy_clk / 1000U);
diff --git a/drivers/st/fmc/stm32_fmc2_nand.c b/drivers/st/fmc/stm32_fmc2_nand.c
index 453069b..e9ab6da 100644
--- a/drivers/st/fmc/stm32_fmc2_nand.c
+++ b/drivers/st/fmc/stm32_fmc2_nand.c
@@ -14,6 +14,7 @@
 #include <platform_def.h>
 
 #include <common/debug.h>
+#include <drivers/clk.h>
 #include <drivers/delay_timer.h>
 #include <drivers/raw_nand.h>
 #include <drivers/st/stm32_fmc2_nand.h>
@@ -162,7 +163,7 @@
 static void stm32_fmc2_nand_setup_timing(void)
 {
 	struct stm32_fmc2_nand_timings tims;
-	unsigned long hclk = stm32mp_clk_get_rate(stm32_fmc2.clock_id);
+	unsigned long hclk = clk_get_rate(stm32_fmc2.clock_id);
 	unsigned long hclkp = FMC2_PSEC_PER_MSEC / (hclk / 1000U);
 	unsigned long timing, tar, tclr, thiz, twait;
 	unsigned long tset_mem, tset_att, thold_mem, thold_att;
@@ -909,7 +910,7 @@
 	}
 
 	/* Enable Clock */
-	stm32mp_clk_enable(stm32_fmc2.clock_id);
+	clk_enable(stm32_fmc2.clock_id);
 
 	/* Reset IP */
 	ret = stm32mp_reset_assert(stm32_fmc2.reset_id, TIMEOUT_US_1_MS);
diff --git a/drivers/st/gpio/stm32_gpio.c b/drivers/st/gpio/stm32_gpio.c
index 51276f4..5c54762 100644
--- a/drivers/st/gpio/stm32_gpio.c
+++ b/drivers/st/gpio/stm32_gpio.c
@@ -14,6 +14,7 @@
 
 #include <common/bl_common.h>
 #include <common/debug.h>
+#include <drivers/clk.h>
 #include <drivers/st/stm32_gpio.h>
 #include <drivers/st/stm32mp_clkfunc.h>
 #include <lib/mmio.h>
@@ -208,7 +209,7 @@
 
 	assert(pin <= GPIO_PIN_MAX);
 
-	stm32mp_clk_enable(clock);
+	clk_enable(clock);
 
 	mmio_clrbits_32(base + GPIO_MODE_OFFSET,
 			((uint32_t)GPIO_MODE_MASK << (pin << 1)));
@@ -254,7 +255,7 @@
 	VERBOSE("GPIO %u mode alternate high to 0x%x\n", bank,
 		mmio_read_32(base + GPIO_AFRH_OFFSET));
 
-	stm32mp_clk_disable(clock);
+	clk_disable(clock);
 
 	if (status == DT_SECURE) {
 		stm32mp_register_secure_gpio(bank, pin);
@@ -273,7 +274,7 @@
 
 	assert(pin <= GPIO_PIN_MAX);
 
-	stm32mp_clk_enable(clock);
+	clk_enable(clock);
 
 	if (secure) {
 		mmio_setbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
@@ -281,7 +282,7 @@
 		mmio_clrbits_32(base + GPIO_SECR_OFFSET, BIT(pin));
 	}
 
-	stm32mp_clk_disable(clock);
+	clk_disable(clock);
 }
 
 void set_gpio_reset_cfg(uint32_t bank, uint32_t pin)
diff --git a/drivers/st/i2c/stm32_i2c.c b/drivers/st/i2c/stm32_i2c.c
index ed88052..bf6c3ee 100644
--- a/drivers/st/i2c/stm32_i2c.c
+++ b/drivers/st/i2c/stm32_i2c.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2016-2021, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -13,6 +13,7 @@
 #include <platform_def.h>
 
 #include <common/debug.h>
+#include <drivers/clk.h>
 #include <drivers/delay_timer.h>
 #include <drivers/st/stm32_gpio.h>
 #include <drivers/st/stm32_i2c.h>
@@ -158,7 +159,7 @@
 
 	hi2c->i2c_state = I2C_STATE_BUSY;
 
-	stm32mp_clk_enable(hi2c->clock);
+	clk_enable(hi2c->clock);
 
 	/* Disable the selected I2C peripheral */
 	mmio_clrbits_32(hi2c->i2c_base_addr + I2C_CR1, I2C_CR1_PE);
@@ -220,11 +221,11 @@
 						I2C_ANALOGFILTER_DISABLE);
 	if (rc != 0) {
 		ERROR("Cannot initialize I2C analog filter (%d)\n", rc);
-		stm32mp_clk_disable(hi2c->clock);
+		clk_disable(hi2c->clock);
 		return rc;
 	}
 
-	stm32mp_clk_disable(hi2c->clock);
+	clk_disable(hi2c->clock);
 
 	return rc;
 }
@@ -548,7 +549,7 @@
 		return -EINVAL;
 	}
 
-	stm32mp_clk_enable(hi2c->clock);
+	clk_enable(hi2c->clock);
 
 	hi2c->lock = 1;
 
@@ -648,7 +649,7 @@
 
 bail:
 	hi2c->lock = 0;
-	stm32mp_clk_disable(hi2c->clock);
+	clk_disable(hi2c->clock);
 
 	return rc;
 }
@@ -729,7 +730,7 @@
 		return  -EINVAL;
 	}
 
-	stm32mp_clk_enable(hi2c->clock);
+	clk_enable(hi2c->clock);
 
 	hi2c->lock = 1;
 
@@ -817,7 +818,7 @@
 
 bail:
 	hi2c->lock = 0;
-	stm32mp_clk_disable(hi2c->clock);
+	clk_disable(hi2c->clock);
 
 	return rc;
 }
@@ -882,7 +883,7 @@
 		return rc;
 	}
 
-	stm32mp_clk_enable(hi2c->clock);
+	clk_enable(hi2c->clock);
 
 	hi2c->lock = 1;
 	hi2c->i2c_mode = I2C_MODE_NONE;
@@ -974,7 +975,7 @@
 
 bail:
 	hi2c->lock = 0;
-	stm32mp_clk_disable(hi2c->clock);
+	clk_disable(hi2c->clock);
 
 	return rc;
 }
diff --git a/drivers/st/iwdg/stm32_iwdg.c b/drivers/st/iwdg/stm32_iwdg.c
index c052b4d..74451d7 100644
--- a/drivers/st/iwdg/stm32_iwdg.c
+++ b/drivers/st/iwdg/stm32_iwdg.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2017-2021, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -15,6 +15,7 @@
 #include <arch_helpers.h>
 #include <common/debug.h>
 #include <drivers/arm/gicv2.h>
+#include <drivers/clk.h>
 #include <drivers/delay_timer.h>
 #include <drivers/st/stm32_iwdg.h>
 #include <drivers/st/stm32mp_clkfunc.h>
@@ -61,12 +62,12 @@
 
 		/* 0x00000000 is not a valid address for IWDG peripherals */
 		if (iwdg->base != 0U) {
-			stm32mp_clk_enable(iwdg->clock);
+			clk_enable(iwdg->clock);
 
 			mmio_write_32(iwdg->base + IWDG_KR_OFFSET,
 				      IWDG_KR_RELOAD_KEY);
 
-			stm32mp_clk_disable(iwdg->clock);
+			clk_disable(iwdg->clock);
 		}
 	}
 }
diff --git a/drivers/st/mmc/stm32_sdmmc2.c b/drivers/st/mmc/stm32_sdmmc2.c
index d3adeab..9db97d4 100644
--- a/drivers/st/mmc/stm32_sdmmc2.c
+++ b/drivers/st/mmc/stm32_sdmmc2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2018-2021, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -15,6 +15,7 @@
 #include <arch.h>
 #include <arch_helpers.h>
 #include <common/debug.h>
+#include <drivers/clk.h>
 #include <drivers/delay_timer.h>
 #include <drivers/mmc.h>
 #include <drivers/st/stm32_gpio.h>
@@ -714,7 +715,7 @@
 		return -ENOMEM;
 	}
 
-	stm32mp_clk_enable(sdmmc2_params.clock_id);
+	clk_enable(sdmmc2_params.clock_id);
 
 	rc = stm32mp_reset_assert(sdmmc2_params.reset_id, TIMEOUT_US_1_MS);
 	if (rc != 0) {
@@ -727,7 +728,7 @@
 	}
 	mdelay(1);
 
-	sdmmc2_params.clk_rate = stm32mp_clk_get_rate(sdmmc2_params.clock_id);
+	sdmmc2_params.clk_rate = clk_get_rate(sdmmc2_params.clock_id);
 	sdmmc2_params.device_info->ocr_voltage = OCR_3_2_3_3 | OCR_3_3_3_4;
 
 	return mmc_init(&stm32_sdmmc2_ops, sdmmc2_params.clk_rate,
diff --git a/drivers/st/spi/stm32_qspi.c b/drivers/st/spi/stm32_qspi.c
index 4b1a029..d3c26d9 100644
--- a/drivers/st/spi/stm32_qspi.c
+++ b/drivers/st/spi/stm32_qspi.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
  */
@@ -11,6 +11,7 @@
 
 #include <common/debug.h>
 #include <common/fdt_wrappers.h>
+#include <drivers/clk.h>
 #include <drivers/delay_timer.h>
 #include <drivers/spi_mem.h>
 #include <drivers/st/stm32_gpio.h>
@@ -364,7 +365,7 @@
 
 static int stm32_qspi_set_speed(unsigned int hz)
 {
-	unsigned long qspi_clk = stm32mp_clk_get_rate(stm32_qspi.clock_id);
+	unsigned long qspi_clk = clk_get_rate(stm32_qspi.clock_id);
 	uint32_t prescaler = UINT8_MAX;
 	uint32_t csht;
 	int ret;
@@ -494,7 +495,7 @@
 	stm32_qspi.clock_id = (unsigned long)info.clock;
 	stm32_qspi.reset_id = (unsigned int)info.reset;
 
-	stm32mp_clk_enable(stm32_qspi.clock_id);
+	clk_enable(stm32_qspi.clock_id);
 
 	ret = stm32mp_reset_assert(stm32_qspi.reset_id, TIMEOUT_US_1_MS);
 	if (ret != 0) {
diff --git a/include/drivers/clk.h b/include/drivers/clk.h
new file mode 100644
index 0000000..a18f41f
--- /dev/null
+++ b/include/drivers/clk.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2021, STMicroelectronics - All Rights Reserved
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CLK_H
+#define CLK_H
+
+#include <stdbool.h>
+
+struct clk_ops {
+	int (*enable)(unsigned long id);
+	void (*disable)(unsigned long id);
+	unsigned long (*get_rate)(unsigned long id);
+	int (*get_parent)(unsigned long id);
+	bool (*is_enabled)(unsigned long id);
+};
+
+int clk_enable(unsigned long id);
+void clk_disable(unsigned long id);
+unsigned long clk_get_rate(unsigned long id);
+bool clk_is_enabled(unsigned long id);
+int clk_get_parent(unsigned long id);
+
+void clk_register(const struct clk_ops *ops);
+
+#endif /* CLK_H */
diff --git a/include/lib/cpus/aarch64/cortex_x2.h b/include/lib/cpus/aarch64/cortex_x2.h
index 9ce1223..bf1b460 100644
--- a/include/lib/cpus/aarch64/cortex_x2.h
+++ b/include/lib/cpus/aarch64/cortex_x2.h
@@ -15,9 +15,23 @@
 #define CORTEX_X2_CPUECTLR_EL1					S3_0_C15_C1_4
 
 /*******************************************************************************
+ * CPU Extended Control register 2 specific definitions
+ ******************************************************************************/
+#define CORTEX_X2_CPUECTLR2_EL1					S3_0_C15_C1_5
+
+#define CORTEX_X2_CPUECTLR2_EL1_PF_MODE_SHIFT			U(11)
+#define CORTEX_X2_CPUECTLR2_EL1_PF_MODE_WIDTH			U(4)
+#define CORTEX_X2_CPUECTLR2_EL1_PF_MODE_CNSRV			ULL(0x9)
+
+/*******************************************************************************
  * CPU Power Control register specific definitions
  ******************************************************************************/
 #define CORTEX_X2_CPUPWRCTLR_EL1				S3_0_C15_C2_7
 #define CORTEX_X2_CPUPWRCTLR_EL1_CORE_PWRDN_BIT			U(1)
 
+/*******************************************************************************
+ * CPU Auxiliary Control Register 5 definitions
+ ******************************************************************************/
+#define CORTEX_X2_CPUACTLR5_EL1					S3_0_C15_C8_0
+
 #endif /* CORTEX_X2_H */
diff --git a/lib/cpus/aarch64/cortex_x2.S b/lib/cpus/aarch64/cortex_x2.S
index 87a9bdf..88116c3 100644
--- a/lib/cpus/aarch64/cortex_x2.S
+++ b/lib/cpus/aarch64/cortex_x2.S
@@ -21,6 +21,98 @@
 #error "Cortex X2 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
 #endif
 
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex X2 Errata #2002765.
+	 * This applies to revisions r0p0, r1p0, and r2p0 and
+	 * is open.
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0, x1, x17
+	 * --------------------------------------------------
+	 */
+func errata_cortex_x2_2002765_wa
+	/* Check workaround compatibility. */
+	mov	x17, x30
+	bl	check_errata_2002765
+	cbz	x0, 1f
+
+	ldr	x0, =0x6
+	msr	S3_6_C15_C8_0, x0 /* CPUPSELR_EL3 */
+	ldr	x0, =0xF3A08002
+	msr	S3_6_C15_C8_2, x0 /* CPUPOR_EL3 */
+	ldr	x0, =0xFFF0F7FE
+	msr	S3_6_C15_C8_3, x0 /* CPUPMR_EL3 */
+	ldr	x0, =0x40000001003ff
+	msr	S3_6_C15_C8_1, x0 /* CPUPCR_EL3 */
+	isb
+
+1:
+	ret	x17
+endfunc errata_cortex_x2_2002765_wa
+
+func check_errata_2002765
+	/* Applies to r0p0 - r2p0 */
+	mov	x1, #0x20
+	b	cpu_rev_var_ls
+endfunc check_errata_2002765
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex X2 Errata #2058056.
+	 * This applies to revisions r0p0, r1p0, and r2p0 and
+	 * is open.
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0, x1, x17
+	 * --------------------------------------------------
+	 */
+func errata_cortex_x2_2058056_wa
+	/* Check workaround compatibility. */
+	mov	x17, x30
+	bl	check_errata_2058056
+	cbz	x0, 1f
+
+	mrs	x1, CORTEX_X2_CPUECTLR2_EL1
+	mov	x0, #CORTEX_X2_CPUECTLR2_EL1_PF_MODE_CNSRV
+	bfi	x1, x0, #CORTEX_X2_CPUECTLR2_EL1_PF_MODE_SHIFT, #CORTEX_X2_CPUECTLR2_EL1_PF_MODE_WIDTH
+	msr	CORTEX_X2_CPUECTLR2_EL1, x1
+
+1:
+	ret	x17
+endfunc errata_cortex_x2_2058056_wa
+
+func check_errata_2058056
+	/* Applies to r0p0 - r2p0 */
+	mov	x1, #0x20
+	b	cpu_rev_var_ls
+endfunc check_errata_2058056
+
+	/* --------------------------------------------------
+	 * Errata Workaround for Cortex X2 Errata #2083908.
+	 * This applies to revision r2p0 and is open.
+	 * x0: variant[4:7] and revision[0:3] of current cpu.
+	 * Shall clobber: x0-x2, x17
+	 * --------------------------------------------------
+	 */
+func errata_cortex_x2_2083908_wa
+	/* Check workaround compatibility. */
+	mov	x17, x30
+	bl	check_errata_2083908
+	cbz	x0, 1f
+
+	/* Apply the workaround by setting bit 13 in CPUACTLR5_EL1. */
+	mrs	x1, CORTEX_X2_CPUACTLR5_EL1
+	orr	x1, x1, #BIT(13)
+	msr	CORTEX_X2_CPUACTLR5_EL1, x1
+
+1:
+	ret	x17
+endfunc errata_cortex_x2_2083908_wa
+
+func check_errata_2083908
+	/* Applies to r2p0 */
+	mov	x1, #0x20
+	mov	x2, #0x20
+	b	cpu_rev_var_range
+endfunc check_errata_2083908
+
 	/* ----------------------------------------------------
 	 * HW will do the cache maintenance while powering down
 	 * ----------------------------------------------------
@@ -42,15 +134,51 @@
 	 */
 #if REPORT_ERRATA
 func cortex_x2_errata_report
+	stp	x8, x30, [sp, #-16]!
+
+	bl	cpu_get_rev_var
+	mov	x8, x0
+
+	/*
+	 * Report all errata. The revision-variant information is passed to
+	 * checking functions of each errata.
+	 */
+	report_errata ERRATA_X2_2002765, cortex_x2, 2002765
+	report_errata ERRATA_X2_2058056, cortex_x2, 2058056
+	report_errata ERRATA_X2_2083908, cortex_x2, 2083908
+
+	ldp	x8, x30, [sp], #16
 	ret
 endfunc cortex_x2_errata_report
 #endif
 
 func cortex_x2_reset_func
+	mov	x19, x30
+
 	/* Disable speculative loads */
 	msr	SSBS, xzr
 	isb
-	ret
+
+	/* Get the CPU revision and stash it in x18. */
+	bl	cpu_get_rev_var
+	mov	x18, x0
+
+#if ERRATA_X2_2002765
+	mov	x0, x18
+	bl	errata_cortex_x2_2002765_wa
+#endif
+
+#if ERRATA_X2_2058056
+	mov	x0, x18
+	bl	errata_cortex_x2_2058056_wa
+#endif
+
+#if ERRATA_X2_2083908
+	mov	x0, x18
+	bl	errata_cortex_x2_2083908_wa
+#endif
+
+	ret x19
 endfunc cortex_x2_reset_func
 
 	/* ---------------------------------------------
diff --git a/lib/cpus/cpu-ops.mk b/lib/cpus/cpu-ops.mk
index a5b8aae..dd06cb8 100644
--- a/lib/cpus/cpu-ops.mk
+++ b/lib/cpus/cpu-ops.mk
@@ -495,6 +495,18 @@
 # to revision r0p0, r1p0 and r2p0 of the Cortex-A710 cpu and is still open.
 ERRATA_A710_2017096	?=0
 
+# Flag to apply erratum 2002765 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0, and r2p0 of the Cortex-X2 cpu and is still open.
+ERRATA_X2_2002765   ?=0
+
+# Flag to apply erratum 2058056 workaround during reset. This erratum applies
+# to revisions r0p0, r1p0, and r2p0 of the Cortex-X2 cpu and is still open.
+ERRATA_X2_2058056   ?=0
+
+# Flag to apply erratum 2083908 workaround during reset. This erratum applies
+# to revision r2p0 of the Cortex-X2 cpu and is still open.
+ERRATA_X2_2083908   ?=0
+
 # Flag to apply DSU erratum 798953. This erratum applies to DSUs revision r0p0.
 # Applying the workaround results in higher DSU power consumption on idle.
 ERRATA_DSU_798953	?=0
@@ -920,6 +932,18 @@
 $(eval $(call assert_boolean,ERRATA_A710_2017096))
 $(eval $(call add_define,ERRATA_A710_2017096))
 
+# Process ERRATA_X2_2002765 flag
+$(eval $(call assert_boolean,ERRATA_X2_2002765))
+$(eval $(call add_define,ERRATA_X2_2002765))
+
+# Process ERRATA_X2_2058056 flag
+$(eval $(call assert_boolean,ERRATA_X2_2058056))
+$(eval $(call add_define,ERRATA_X2_2058056))
+
+# Process ERRATA_X2_2083908 flag
+$(eval $(call assert_boolean,ERRATA_X2_2083908))
+$(eval $(call add_define,ERRATA_X2_2083908))
+
 # Process ERRATA_DSU_798953 flag
 $(eval $(call assert_boolean,ERRATA_DSU_798953))
 $(eval $(call add_define,ERRATA_DSU_798953))
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 0d2c319..b7f9c61 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -142,7 +142,8 @@
 					lib/cpus/aarch64/cortex_a65ae.S		\
 					lib/cpus/aarch64/cortex_a78c.S		\
 					lib/cpus/aarch64/cortex_hayes.S		\
-					lib/cpus/aarch64/cortex_hunter.S
+					lib/cpus/aarch64/cortex_hunter.S	\
+					lib/cpus/aarch64/cortex_x2.S
 	endif
 	# AArch64/AArch32 cores
 	FVP_CPU_LIBS	+=	lib/cpus/aarch64/cortex_a55.S		\
diff --git a/plat/mediatek/mt8186/aarch64/platform_common.c b/plat/mediatek/mt8186/aarch64/platform_common.c
index 745e547..9b9697f 100644
--- a/plat/mediatek/mt8186/aarch64/platform_common.c
+++ b/plat/mediatek/mt8186/aarch64/platform_common.c
@@ -13,8 +13,6 @@
 	/* for TF text, RO, RW */
 	MAP_REGION_FLAT(MTK_DEV_RNG0_BASE, MTK_DEV_RNG0_SIZE,
 			MT_DEVICE | MT_RW | MT_SECURE),
-	MAP_REGION_FLAT(MTK_DEV_RNG1_BASE, MTK_DEV_RNG1_SIZE,
-			MT_DEVICE | MT_RW | MT_SECURE),
 	MAP_REGION_FLAT(MTK_DEV_RNG2_BASE, MTK_DEV_RNG2_SIZE,
 			MT_DEVICE | MT_RW | MT_SECURE),
 	{ 0 }
diff --git a/plat/mediatek/mt8186/bl31_plat_setup.c b/plat/mediatek/mt8186/bl31_plat_setup.c
index 3fd1c71..b70245f 100644
--- a/plat/mediatek/mt8186/bl31_plat_setup.c
+++ b/plat/mediatek/mt8186/bl31_plat_setup.c
@@ -11,10 +11,16 @@
 #include <common/bl_common.h>
 #include <common/debug.h>
 #include <common/desc_image_load.h>
+#include <drivers/generic_delay_timer.h>
 #include <drivers/ti/uart/uart_16550.h>
 #include <lib/coreboot.h>
 
 /* Platform Includes */
+#include <emi_mpu.h>
+#include <mt_gic_v3.h>
+#include <mt_timer.h>
+#include <mtgpio.h>
+#include <mtk_dcm.h>
 #include <plat_params.h>
 #include <plat_private.h>
 
@@ -79,6 +85,17 @@
  ******************************************************************************/
 void bl31_platform_setup(void)
 {
+	dcm_set_default();
+
+	/* Initialize the GIC driver, CPU and distributor interfaces */
+	mt_gic_driver_init();
+	mt_gic_init();
+
+	mt_gpio_init();
+	mt_systimer_init();
+	generic_delay_timer_init();
+
+	emi_mpu_init();
 }
 
 /*******************************************************************************
diff --git a/plat/mediatek/mt8186/drivers/dcm/mtk_dcm.c b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm.c
new file mode 100644
index 0000000..5dde5c5
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.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_cpubiu_dbg_cg(on);
+	dcm_mp_cpusys_top_misc_dcm(on);
+	dcm_mp_cpusys_top_mp0_qdcm(on);
+	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_cpubiu_dbg_cg_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;
+}
+
+void dcm_set_default(void)
+{
+	dcm_armcore(true);
+	dcm_mcusys(true);
+	dcm_stall(true);
+
+	INFO("%s: %d", __func__, check_dcm_state());
+}
diff --git a/plat/mediatek/mt8186/drivers/dcm/mtk_dcm.h b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm.h
new file mode 100644
index 0000000..6abcff4
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_DCM_H
+#define MTK_DCM_H
+
+#include <stdbool.h>
+
+void dcm_set_default(void);
+
+#endif /* #ifndef MTK_DCM_H */
diff --git a/plat/mediatek/mt8186/drivers/dcm/mtk_dcm_utils.c b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm_utils.c
new file mode 100644
index 0000000..ae0e964
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm_utils.c
@@ -0,0 +1,490 @@
+/*
+ * Copyright (c) 2021, 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(16) |	\
+					 BIT(17) |	\
+					 BIT(18) |	\
+					 BIT(21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_MASK (BIT(16) |	\
+					 BIT(17) |	\
+					 BIT(18))
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_ON (BIT(16) |	\
+				       BIT(17) |	\
+				       BIT(18) |	\
+				       BIT(21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_ON (BIT(16) |	\
+				       BIT(17) |	\
+				       BIT(18))
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_OFF ((0x0 << 16) |	\
+					(0x0 << 17) |	\
+					(0x0 << 18) |	\
+					(0x0 << 21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_OFF ((0x0 << 16) |	\
+					(0x0 << 17) |	\
+					(0x0 << 18))
+
+bool dcm_mp_cpusys_top_adb_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4) &
+		MP_CPUSYS_TOP_ADB_DCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
+	ret &= ((mmio_read_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0) &
+		MP_CPUSYS_TOP_ADB_DCM_REG1_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_ADB_DCM_REG1_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_CFG4,
+			MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+			MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+			MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+			MP_CPUSYS_TOP_ADB_DCM_REG1_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_adb_dcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP_ADB_DCM_CFG4,
+			MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+			MP_CPUSYS_TOP_ADB_DCM_REG0_OFF);
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0,
+			MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+			MP_CPUSYS_TOP_ADB_DCM_REG1_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 &= ((mmio_read_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0) &
+		MP_CPUSYS_TOP_APB_DCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_APB_DCM_REG0_ON);
+	ret &= ((mmio_read_32(MP_CPUSYS_TOP_MCUSYS_DCM_CFG0) &
+		MP_CPUSYS_TOP_APB_DCM_REG1_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_APB_DCM_REG1_ON);
+	ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP0_DCM_CFG0) &
+		MP_CPUSYS_TOP_APB_DCM_REG2_MASK) ==
+		(unsigned int) 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)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG) &
+		MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON);
+
+	return ret;
+}
+
+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)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP0_DCM_CFG7) &
+		MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_ON);
+
+	return ret;
+}
+
+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_DBG_CG_REG0_MASK (BIT(0))
+#define MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_ON ((0x0 << 0))
+#define MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_OFF (BIT(0))
+
+bool dcm_mp_cpusys_top_cpubiu_dbg_cg_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(MP_CPUSYS_TOP_MCSI_CFG2) &
+		MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_ON);
+
+	return ret;
+}
+
+void dcm_mp_cpusys_top_cpubiu_dbg_cg(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_cpubiu_dbg_cg'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MCSI_CFG2,
+			MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_MASK,
+			MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpubiu_dbg_cg'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MCSI_CFG2,
+			MP_CPUSYS_TOP_CPUBIU_DBG_CG_REG0_MASK,
+			MP_CPUSYS_TOP_CPUBIU_DBG_CG_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)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(MP_CPUSYS_TOP_MCSIC_DCM0) &
+		MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON);
+
+	return ret;
+}
+
+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(11) |	\
+						   BIT(24) |	\
+						   BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON (BIT(11) |	\
+						 BIT(24) |	\
+						 BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_OFF ((0x0 << 11) |	\
+						  (0x0 << 24) |	\
+						  (0x0 << 25))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG0) &
+		MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON);
+
+	return ret;
+}
+
+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(11) |	\
+						   BIT(24) |	\
+						   BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON (BIT(11) |	\
+						 BIT(24) |	\
+						 BIT(25))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_OFF ((0x0 << 11) |	\
+						  (0x0 << 24) |	\
+						  (0x0 << 25))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(MP_CPUSYS_TOP_CPU_PLLDIV_CFG1) &
+		MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON);
+
+	return ret;
+}
+
+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)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP0_DCM_CFG7) &
+		MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_FCM_STALL_DCM_REG0_ON);
+
+	return ret;
+}
+
+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 ((0x0 << 31))
+
+bool dcm_mp_cpusys_top_last_cor_idle_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(MP_CPUSYS_TOP_BUS_PLLDIV_CFG) &
+		MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON);
+
+	return ret;
+}
+
+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(0) |	\
+					  BIT(1) |	\
+					  BIT(2) |	\
+					  BIT(3) |	\
+					  BIT(4))
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_ON (BIT(0) |	\
+					BIT(1) |	\
+					BIT(2) |	\
+					BIT(3) |	\
+					BIT(4))
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_OFF ((0x0 << 0) |	\
+					 (0x0 << 1) |	\
+					 (0x0 << 2) |	\
+					 (0x0 << 3) |	\
+					 (0x0 << 4))
+
+bool dcm_mp_cpusys_top_misc_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP_MISC_DCM_CFG0) &
+		MP_CPUSYS_TOP_MISC_DCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_MISC_DCM_REG0_ON);
+
+	return ret;
+}
+
+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(0) |	\
+			BIT(1) |			\
+			BIT(2) |			\
+			BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_ON (BIT(0) |	\
+			BIT(1) |			\
+			BIT(2) |			\
+			BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF ((0x0 << 0) |	\
+			(0x0 << 1) |			\
+			(0x0 << 2) |			\
+			(0x0 << 3))
+
+bool dcm_mp_cpusys_top_mp0_qdcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(MP_CPUSYS_TOP_MP0_DCM_CFG0) &
+		MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_MP0_QDCM_REG0_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_MP0_DCM_CFG0,
+			MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+			MP_CPUSYS_TOP_MP0_QDCM_REG0_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_mp0_qdcm'" */
+		mmio_clrsetbits_32(MP_CPUSYS_TOP_MP0_DCM_CFG0,
+			MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+			MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF);
+	}
+}
+
+#define CPCCFG_REG_EMI_WFIFO_REG0_MASK (BIT(0) | BIT(2))
+#define CPCCFG_REG_EMI_WFIFO_REG0_ON (BIT(0) | BIT(2))
+#define CPCCFG_REG_EMI_WFIFO_REG0_OFF ((0x0 << 0) | (0x0 << 2))
+
+bool dcm_cpccfg_reg_emi_wfifo_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(CPCCFG_REG_EMI_WFIFO) &
+		CPCCFG_REG_EMI_WFIFO_REG0_MASK) ==
+		(unsigned int) CPCCFG_REG_EMI_WFIFO_REG0_ON);
+
+	return ret;
+}
+
+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/mt8186/drivers/dcm/mtk_dcm_utils.h b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm_utils.h
new file mode 100644
index 0000000..ba76594
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/dcm/mtk_dcm_utils.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2021, 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	0xc538000
+#define CPCCFG_REG_BASE		0xc53a800
+
+/* Register Definition */
+#define CPCCFG_REG_EMI_WFIFO		(CPCCFG_REG_BASE + 0x100)
+#define MP_CPUSYS_TOP_BUS_PLLDIV_CFG	(MP_CPUSYS_TOP_BASE + 0x22e0)
+#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_MCSIC_DCM0	(MP_CPUSYS_TOP_BASE + 0x2440)
+#define MP_CPUSYS_TOP_MCSI_CFG2		(MP_CPUSYS_TOP_BASE + 0x2418)
+#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)
+#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)
+
+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_dbg_cg_is_on(void);
+void dcm_mp_cpusys_top_cpubiu_dbg_cg(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);
+bool dcm_cpccfg_reg_emi_wfifo_is_on(void);
+void dcm_cpccfg_reg_emi_wfifo(bool on);
+#endif
diff --git a/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.c b/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.c
new file mode 100644
index 0000000..989ecf1
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2021, 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>
+
+#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 == 0U) && ((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;
+}
+
+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;
+}
+
+void emi_mpu_init(void)
+{
+	/* TODO: more setting for EMI MPU. */
+}
diff --git a/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.h b/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.h
new file mode 100644
index 0000000..415146e
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/emi_mpu/emi_mpu.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMI_MPU_H
+#define EMI_MPU_H
+
+#include <platform_def.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 EMI_MPU_START			(0x000)
+#define EMI_MPU_END			(0x93C)
+
+#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 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
+
+#define EMI_MPU_DGROUP_NUM		(EMI_MPU_DOMAIN_NUM / 8)
+
+#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];
+};
+
+void emi_mpu_init(void);
+
+#endif
diff --git a/plat/mediatek/mt8186/drivers/gpio/mtgpio.c b/plat/mediatek/mt8186/drivers/gpio/mtgpio.c
new file mode 100644
index 0000000..134476a
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/gpio/mtgpio.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <mtgpio.h>
+#include <platform_def.h>
+
+uintptr_t mt_gpio_find_reg_addr(uint32_t pin)
+{
+	uintptr_t reg_addr = 0U;
+	struct mt_pin_info gpio_info;
+
+	assert(pin < MAX_GPIO_PIN);
+
+	gpio_info = mt_pin_infos[pin];
+
+	switch (gpio_info.base & 0x0f) {
+	case 0:
+		reg_addr = IOCFG_LT_BASE;
+		break;
+	case 1:
+		reg_addr = IOCFG_LM_BASE;
+		break;
+	case 2:
+		reg_addr = IOCFG_LB_BASE;
+		break;
+	case 3:
+		reg_addr = IOCFG_BL_BASE;
+		break;
+	case 4:
+		reg_addr = IOCFG_RB_BASE;
+		break;
+	case 5:
+		reg_addr = IOCFG_RT_BASE;
+		break;
+	default:
+		break;
+	}
+
+	return reg_addr;
+}
diff --git a/plat/mediatek/mt8186/drivers/gpio/mtgpio.h b/plat/mediatek/mt8186/drivers/gpio/mtgpio.h
new file mode 100644
index 0000000..4430a58
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/gpio/mtgpio.h
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_GPIO_H
+#define MT_GPIO_H
+
+#include <mtgpio_common.h>
+
+/* Enumeration for GPIO pin */
+typedef enum GPIO_PIN {
+	GPIO_UNSUPPORTED = -1,
+	GPIO0, GPIO1, GPIO2, GPIO3, GPIO4, GPIO5, GPIO6,
+	GPIO7, GPIO8, GPIO9, GPIO10, GPIO11, GPIO12, GPIO13, GPIO14,
+	GPIO15, GPIO16, GPIO17, GPIO18, GPIO19, GPIO20, GPIO21, GPIO22,
+	GPIO23, GPIO24, GPIO25, GPIO26, GPIO27, GPIO28, GPIO29, GPIO30,
+	GPIO31, GPIO32, GPIO33, GPIO34, GPIO35, GPIO36, GPIO37, GPIO38,
+	GPIO39, GPIO40, GPIO41, GPIO42, GPIO43, GPIO44, GPIO45, GPIO46,
+	GPIO47, GPIO48, GPIO49, GPIO50, GPIO51, GPIO52, GPIO53, GPIO54,
+	GPIO55, GPIO56, GPIO57, GPIO58, GPIO59, GPIO60, GPIO61, GPIO62,
+	GPIO63, GPIO64, GPIO65, GPIO66, GPIO67, GPIO68, GPIO69, GPIO70,
+	GPIO71, GPIO72, GPIO73, GPIO74, GPIO75, GPIO76, GPIO77, GPIO78,
+	GPIO79, GPIO80, GPIO81, GPIO82, GPIO83, GPIO84, GPIO85, GPIO86,
+	GPIO87, GPIO88, GPIO89, GPIO90, GPIO91, GPIO92, GPIO93, GPIO94,
+	GPIO95, GPIO96, GPIO97, GPIO98, GPIO99, GPIO100, GPIO101, GPIO102,
+	GPIO103, GPIO104, GPIO105, GPIO106, GPIO107, GPIO108, GPIO109, GPIO110,
+	GPIO111, GPIO112, GPIO113, GPIO114, GPIO115, GPIO116, GPIO117, GPIO118,
+	GPIO119, GPIO120, GPIO121, GPIO122, GPIO123, GPIO124, GPIO125, GPIO126,
+	GPIO127, GPIO128, GPIO129, GPIO130, GPIO131, GPIO132, GPIO133, GPIO134,
+	GPIO135, GPIO136, GPIO137, GPIO138, GPIO139, GPIO140, GPIO141, GPIO142,
+	GPIO143, GPIO144, GPIO145, GPIO146, GPIO147, GPIO148, GPIO149, GPIO150,
+	GPIO151, GPIO152, GPIO153, GPIO154, GPIO155, GPIO156, GPIO157, GPIO158,
+	GPIO159, GPIO160, GPIO161, GPIO162, GPIO163, GPIO164, GPIO165, GPIO166,
+	GPIO167, GPIO168, GPIO169, GPIO170, GPIO171, GPIO172, GPIO173, GPIO174,
+	GPIO175, GPIO176, GPIO177, GPIO178, GPIO179, GPIO180, GPIO181, GPIO182,
+	GPIO183, GPIO184,
+	MT_GPIO_BASE_MAX
+} GPIO_PIN;
+
+static const struct mt_pin_info mt_pin_infos[] = {
+	PIN(0, 0, 13, 0x16, 0x40),
+	PIN(1, 0, 14, 0x16, 0x40),
+	PIN(2, 0, 17, 0x16, 0x40),
+	PIN(3, 0, 18, 0x16, 0x40),
+	PIN(4, 0, 19, 0x16, 0x40),
+	PIN(5, 0, 20, 0x16, 0x40),
+	PIN(6, 0, 19, 0x24, 0x40),
+	PIN(7, 0, 20, 0x24, 0x40),
+	PIN(8, 0, 21, 0x24, 0x40),
+	PIN(9, 0, 22, 0x24, 0x40),
+	PIN(10, 0, 16, 0x24, 0x40),
+	PIN(11, 0, 17, 0x24, 0x40),
+	PIN(12, 0, 18, 0x24, 0x40),
+	PIN(13, 0, 0, 0x23, 0x60),
+	PIN(14, 0, 1, 0x23, 0x60),
+	PIN(15, 0, 15, 0x16, 0x40),
+	PIN(16, 0, 16, 0x16, 0x40),
+	PIN(17, 0, 9, 0x25, 0x70),
+	PIN(18, 0, 10, 0x25, 0x70),
+	PIN(19, 0, 3, 0x25, 0x70),
+	PIN(20, 0, 6, 0x25, 0x70),
+	PIN(21, 0, 4, 0x25, 0x70),
+	PIN(22, 0, 7, 0x25, 0x70),
+	PIN(23, 0, 5, 0x25, 0x70),
+	PIN(24, 0, 8, 0x25, 0x70),
+	PIN(25, 0, 18, 0x25, 0x70),
+	PIN(26, 0, 15, 0x25, 0x70),
+	PIN(27, 0, 17, 0x25, 0x70),
+	PIN(28, 0, 16, 0x25, 0x70),
+	PIN(29, 0, 0, 0x16, 0x40),
+	PIN(30, 0, 1, 0x16, 0x40),
+	PIN(31, 0, 2, 0x16, 0x40),
+	PIN(32, 0, 25, 0x12, 0x50),
+	PIN(33, 0, 27, 0x12, 0x50),
+	PIN(34, 0, 26, 0x12, 0x50),
+	PIN(35, 0, 28, 0x12, 0x50),
+	PIN(36, 0, 9, 0x12, 0x50),
+	PIN(37, 0, 10, 0x12, 0x50),
+	PIN(38, 0, 12, 0x12, 0x50),
+	PIN(39, 0, 11, 0x12, 0x50),
+	PIN(40, 0, 13, 0x12, 0x50),
+	PIN(41, 0, 14, 0x12, 0x50),
+	PIN(42, 0, 16, 0x12, 0x50),
+	PIN(43, 0, 15, 0x12, 0x50),
+	PIN(44, 0, 28, 0x25, 0x70),
+	PIN(45, 0, 29, 0x25, 0x70),
+	PIN(46, 0, 31, 0x25, 0x70),
+	PIN(47, 0, 30, 0x25, 0x70),
+	PIN(48, 0, 17, 0x12, 0x50),
+	PIN(49, 0, 18, 0x12, 0x50),
+	PIN(50, 0, 20, 0x12, 0x50),
+	PIN(51, 0, 19, 0x12, 0x50),
+	PIN(52, 0, 12, 0x23, 0x60),
+	PIN(53, 0, 13, 0x23, 0x60),
+	PIN(54, 0, 15, 0x23, 0x60),
+	PIN(55, 0, 14, 0x23, 0x60),
+	PIN(56, 0, 12, 0x25, 0x70),
+	PIN(57, 0, 11, 0x25, 0x70),
+	PIN(58, 0, 13, 0x25, 0x70),
+	PIN(59, 0, 14, 0x25, 0x70),
+	PIN(60, 0, 21, 0x23, 0x60),
+	PIN(61, 0, 16, 0x23, 0x60),
+	PIN(62, 0, 22, 0x23, 0x60),
+	PIN(63, 0, 17, 0x23, 0x60),
+	PIN(64, 0, 18, 0x23, 0x60),
+	PIN(65, 0, 19, 0x23, 0x60),
+	PIN(66, 0, 20, 0x23, 0x60),
+	PIN(67, 1, 10, 0x21, 0x70),
+	PIN(68, 1, 0, 0x21, 0x70),
+	PIN(69, 1, 1, 0x21, 0x70),
+	PIN(70, 1, 11, 0x21, 0x70),
+	PIN(71, 1, 2, 0x21, 0x70),
+	PIN(72, 1, 3, 0x21, 0x70),
+	PIN(73, 1, 4, 0x21, 0x70),
+	PIN(74, 1, 5, 0x21, 0x70),
+	PIN(75, 1, 6, 0x21, 0x70),
+	PIN(76, 1, 7, 0x21, 0x70),
+	PIN(77, 1, 8, 0x21, 0x70),
+	PIN(78, 1, 9, 0x21, 0x70),
+	PIN(79, 1, 0, 0x25, 0x80),
+	PIN(80, 1, 1, 0x25, 0x80),
+	PIN(81, 1, 2, 0x25, 0x80),
+	PIN(82, 1, 3, 0x25, 0x80),
+	PIN(83, 0, 3, 0x16, 0x40),
+	PIN(84, 1, 0, 0x23, 0x70),
+	PIN(85, 1, 1, 0x23, 0x70),
+	PIN(86, 1, 2, 0x23, 0x70),
+	PIN(87, 1, 3, 0x23, 0x70),
+	PIN(88, 1, 4, 0x23, 0x70),
+	PIN(89, 1, 5, 0x23, 0x70),
+	PIN(90, 0, 2, 0x23, 0x60),
+	PIN(91, 0, 23, 0x23, 0x60),
+	PIN(92, 0, 25, 0x23, 0x60),
+	PIN(93, 0, 3, 0x23, 0x60),
+	PIN(94, 0, 24, 0x23, 0x60),
+	PIN(95, 0, 26, 0x23, 0x60),
+	PIN(96, 0, 1, 0x12, 0x50),
+	PIN(97, 0, 0, 0x12, 0x50),
+	PIN(98, 0, 2, 0x12, 0x50),
+	PIN(99, 0, 14, 0x24, 0x40),
+	PIN(100, 0, 15, 0x24, 0x40),
+	PIN(101, 0, 13, 0x24, 0x40),
+	PIN(102, 0, 12, 0x24, 0x40),
+	PIN(103, 0, 0, 0x24, 0x40),
+	PIN(104, 0, 1, 0x24, 0x40),
+	PIN(105, 0, 4, 0x24, 0x40),
+	PIN(106, 0, 5, 0x24, 0x40),
+	PIN(107, 0, 6, 0x24, 0x40),
+	PIN(108, 0, 7, 0x24, 0x40),
+	PIN(109, 0, 8, 0x24, 0x40),
+	PIN(110, 0, 9, 0x24, 0x40),
+	PIN(111, 0, 10, 0x24, 0x40),
+	PIN(112, 0, 11, 0x24, 0x40),
+	PIN(113, 0, 2, 0x24, 0x40),
+	PIN(114, 0, 3, 0x24, 0x40),
+	PIN(115, 0, 4, 0x23, 0x60),
+	PIN(116, 0, 7, 0x23, 0x60),
+	PIN(117, 0, 5, 0x23, 0x60),
+	PIN(118, 0, 6, 0x23, 0x60),
+	PIN(119, 0, 22, 0x25, 0x70),
+	PIN(120, 0, 19, 0x25, 0x70),
+	PIN(121, 0, 20, 0x25, 0x70),
+	PIN(122, 0, 21, 0x25, 0x70),
+	PIN(123, 0, 23, 0x25, 0x70),
+	PIN(124, 0, 0, 0x25, 0x70),
+	PIN(125, 0, 1, 0x25, 0x70),
+	PIN(126, 0, 2, 0x25, 0x70),
+	PIN(127, 0, 8, 0x23, 0x60),
+	PIN(128, 0, 10, 0x23, 0x60),
+	PIN(129, 0, 24, 0x25, 0x70),
+	PIN(130, 0, 26, 0x25, 0x70),
+	PIN(131, 0, 25, 0x25, 0x70),
+	PIN(132, 0, 27, 0x25, 0x70),
+	PIN(133, 0, 9, 0x21, 0x60),
+	PIN(134, 0, 12, 0x21, 0x60),
+	PIN(135, 0, 21, 0x16, 0x40),
+	PIN(136, 0, 24, 0x16, 0x40),
+	PIN(137, 0, 10, 0x21, 0x60),
+	PIN(138, 0, 13, 0x21, 0x60),
+	PIN(139, 0, 7, 0x12, 0x50),
+	PIN(140, 0, 8, 0x12, 0x50),
+	PIN(141, 0, 9, 0x23, 0x60),
+	PIN(142, 0, 11, 0x23, 0x60),
+	PIN(143, 0, 22, 0x16, 0x40),
+	PIN(144, 0, 25, 0x16, 0x40),
+	PIN(145, 0, 23, 0x16, 0x40),
+	PIN(146, 0, 26, 0x16, 0x40),
+	PIN(147, 0, 23, 0x24, 0x40),
+	PIN(148, 0, 24, 0x24, 0x40),
+	PIN(149, 0, 25, 0x24, 0x40),
+	PIN(150, 0, 26, 0x24, 0x40),
+	PIN(151, 0, 27, 0x24, 0x40),
+	PIN(152, 0, 28, 0x24, 0x40),
+	PIN(153, 0, 29, 0x24, 0x40),
+	PIN(154, 0, 30, 0x24, 0x40),
+	PIN(155, 0, 31, 0x24, 0x40),
+	PIN(156, 0, 0, 0x24, 0x50),
+	PIN(157, 0, 4, 0x12, 0x50),
+	PIN(158, 0, 3, 0x12, 0x50),
+	PIN(159, 0, 6, 0x12, 0x50),
+	PIN(160, 0, 5, 0x12, 0x50),
+	PIN(161, 0, 23, 0x12, 0x50),
+	PIN(162, 0, 24, 0x12, 0x50),
+	PIN(163, 0, 11, 0x21, 0x60),
+	PIN(164, 0, 8, 0x21, 0x60),
+	PIN(165, 0, 16, 0x21, 0x60),
+	PIN(166, 0, 1, 0x21, 0x60),
+	PIN(167, 0, 7, 0x21, 0x60),
+	PIN(168, 0, 4, 0x21, 0x60),
+	PIN(169, 0, 5, 0x21, 0x60),
+	PIN(170, 0, 0, 0x21, 0x60),
+	PIN(171, 0, 6, 0x21, 0x60),
+	PIN(172, 0, 2, 0x21, 0x60),
+	PIN(173, 0, 3, 0x21, 0x60),
+	PIN(174, 0, 7, 0x16, 0x40),
+	PIN(175, 0, 8, 0x16, 0x40),
+	PIN(176, 0, 4, 0x16, 0x40),
+	PIN(177, 0, 5, 0x16, 0x40),
+	PIN(178, 0, 6, 0x16, 0x40),
+	PIN(179, 0, 9, 0x16, 0x40),
+	PIN(180, 0, 10, 0x16, 0x40),
+	PIN(181, 0, 11, 0x16, 0x40),
+	PIN(182, 0, 12, 0x16, 0x40),
+	PIN(183, 0, 21, 0x12, 0x50),
+	PIN(184, 0, 22, 0x12, 0x50),
+};
+
+#endif /* MT_GPIO_H */
diff --git a/plat/mediatek/mt8186/drivers/mcdi/build.mk b/plat/mediatek/mt8186/drivers/mcdi/build.mk
new file mode 100644
index 0000000..45acb5d
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/build.mk
@@ -0,0 +1,31 @@
+#
+# Copyright (c) 2021, MediaTek Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+MCDI_TINYSYS_TYPE = sspm
+MCDI_TINYSYS_MBOX_TYPE = share_sram
+
+CUR_MCDI_FOLDER = ${MTK_PLAT_SOC}/drivers/mcdi
+
+BL31_MT_LPM_PLAT_CFLAGS += -I${CUR_MCDI_FOLDER}/
+
+BL31_MT_LPM_PLAT_SOURCE += \
+	${CUR_MCDI_FOLDER}/mt_cpu_pm.c	\
+	${CUR_MCDI_FOLDER}/mt_cpu_pm_cpc.c \
+	${CUR_MCDI_FOLDER}/mt_mcdi.c	\
+	${CUR_MCDI_FOLDER}/mt_lp_irqremain.c
+
+
+ifeq ($(MCDI_TINYSYS_TYPE), sspm)
+BL31_MT_LPM_PLAT_CFLAGS += -DMCDI_TINYSYS_SSPM
+BL31_MT_LPM_PLAT_SOURCE += ${CUR_MCDI_FOLDER}/mt_cpu_pm_mbox_sspm.c
+else
+BL31_MT_LPM_PLAT_CFLAGS += -DMCDI_TINYSYS_MCUPM
+BL31_MT_LPM_PLAT_SOURCE += ${CUR_MCDI_FOLDER}/mt_cpu_pm_mbox.c
+endif
+
+ifeq ($(MCDI_TINYSYS_MBOX_TYPE), share_sram)
+BL31_MT_LPM_PLAT_CFLAGS += -DMCDI_TINYSYS_MBOX_SHARE_SRAM
+endif
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.c b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.c
new file mode 100644
index 0000000..c6c2e38
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <lib/psci/psci.h>
+#include <lib/spinlock.h>
+
+#include <mt_cpu_pm_cpc.h>
+#include <mt_mcdi.h>
+#include <plat_mtk_lpm.h>
+#include <plat_pm.h>
+
+DEFINE_SYSREG_RW_FUNCS(dbgprcr_el1);
+
+static int plat_mt_lp_cpu_rc;
+
+static int pwr_state_prompt(unsigned int cpu, const psci_power_state_t *state)
+{
+	return 0;
+}
+
+static int pwr_state_reflect(unsigned int cpu, const psci_power_state_t *state)
+{
+	mtk_cpc_core_on_hint_clr(cpu);
+
+	if (IS_SYSTEM_SUSPEND_STATE(state)) {
+		mtk_cpc_time_sync();
+	}
+
+	return 0;
+}
+
+static int pwr_cpu_pwron(unsigned int cpu, const psci_power_state_t *state)
+{
+	return 0;
+}
+
+static int pwr_cpu_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
+{
+	/* clear DBGPRCR.CORENPDRQ to allow CPU power down  */
+	write_dbgprcr_el1(0ULL);
+
+	return 0;
+}
+
+static int pwr_cluster_pwron(unsigned int cpu, const psci_power_state_t *state)
+{
+	return 0;
+}
+
+static int pwr_cluster_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
+{
+	return 0;
+}
+
+static int pwr_mcusys_pwron(unsigned int cpu, const psci_power_state_t *state)
+{
+	if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
+		return -1;
+	}
+
+	mtk_cpc_mcusys_off_reflect();
+
+	return 0;
+}
+
+static int pwr_mcusys_pwron_finished(unsigned int cpu,
+					const psci_power_state_t *state)
+{
+	if (!IS_MCUSYS_OFF_STATE(state) || (plat_mt_lp_cpu_rc < 0)) {
+		return -1;
+	}
+
+	return 0;
+}
+
+static int pwr_mcusys_pwrdwn(unsigned int cpu, const psci_power_state_t *state)
+{
+	if (!IS_MCUSYS_OFF_STATE(state)) {
+		goto mt_pwr_mcusysoff_break;
+	}
+
+	if (mcdi_try_init() != 0) { /* not ready to process mcusys-off */
+		goto mt_pwr_mcusysoff_break;
+	}
+
+	return 0;
+
+mt_pwr_mcusysoff_break:
+
+	plat_mt_lp_cpu_rc = -1;
+
+	return -1;
+}
+
+static const struct mt_lpm_tz plat_pm = {
+	.pwr_prompt			= pwr_state_prompt,
+	.pwr_reflect			= pwr_state_reflect,
+	.pwr_cpu_on			= pwr_cpu_pwron,
+	.pwr_cpu_dwn			= pwr_cpu_pwrdwn,
+	.pwr_cluster_on			= pwr_cluster_pwron,
+	.pwr_cluster_dwn		= pwr_cluster_pwrdwn,
+	.pwr_mcusys_dwn			= pwr_mcusys_pwrdwn,
+	.pwr_mcusys_on			= pwr_mcusys_pwron,
+	.pwr_mcusys_on_finished		= pwr_mcusys_pwron_finished
+};
+
+const struct mt_lpm_tz *mt_plat_cpu_pm_init(void)
+{
+	mtk_cpc_init();
+
+	if (mcdi_try_init() == 0) {
+		INFO("MCDI init done.\n");
+	}
+
+	return &plat_pm;
+}
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.h b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.h
new file mode 100644
index 0000000..83a7a53
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __MT_CPU_PM_H__
+#define __MT_CPU_PM_H__
+
+#define MCUSYS_STATUS_PDN		(1 << 0UL)
+#define MCUSYS_STATUS_CPUSYS_PROTECT	(1 << 8UL)
+#define MCUSYS_STATUS_MCUSYS_PROTECT	(1 << 9UL)
+
+/* cpu_pm function ID*/
+enum mt_cpu_pm_user_id {
+	MCUSYS_STATUS,
+	CPC_COMMAND,
+	IRQ_REMAIN_LIST_ALLOC,
+	IRQ_REMAIN_IRQ_ADD,
+	IRQ_REMAIN_IRQ_SUBMIT,
+	MBOX_INFO,
+};
+
+/* cpu_pm lp function ID */
+enum mt_cpu_pm_lp_smc_id {
+	LP_CPC_COMMAND,
+	IRQS_REMAIN_ALLOC,
+	IRQS_REMAIN_CTRL,
+	IRQS_REMAIN_IRQ,
+	IRQS_REMAIN_WAKEUP_CAT,
+	IRQS_REMAIN_WAKEUP_SRC,
+};
+
+#endif
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_cpc.c b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_cpc.c
new file mode 100644
index 0000000..2b0f071
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_cpc.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <string.h>
+
+#include <drivers/delay_timer.h>
+
+#include <mt_cpu_pm_cpc.h>
+#include <mt_timer.h>
+
+struct mtk_cpc_dev {
+	int auto_off;
+	unsigned int auto_thres_tick;
+};
+
+static struct mtk_cpc_dev cpc;
+
+static int mtk_cpc_last_core_prot(uint32_t prot_req,
+				uint32_t resp_reg, uint32_t resp_ofs)
+{
+	uint32_t sta, retry;
+
+	retry = 0U;
+
+	while (retry++ < RETRY_CNT_MAX) {
+
+		mmio_write_32(CPC_MCUSYS_LAST_CORE_REQ, prot_req);
+
+		udelay(1U);
+
+		sta = (mmio_read_32(resp_reg) >> resp_ofs) & CPC_PROT_RESP_MASK;
+
+		if (sta == PROT_SUCCESS) {
+			return CPC_SUCCESS;
+		} else if (sta == PROT_GIVEUP) {
+			return CPC_ERR_FAIL;
+		}
+	}
+
+	return CPC_ERR_TIMEOUT;
+}
+
+int mtk_cpu_pm_mcusys_prot_aquire(void)
+{
+	return mtk_cpc_last_core_prot(
+			MCUSYS_PROT_SET,
+			CPC_MCUSYS_LAST_CORE_RESP,
+			MCUSYS_RESP_OFS);
+}
+
+void mtk_cpu_pm_mcusys_prot_release(void)
+{
+	mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, MCUSYS_PROT_CLR);
+}
+
+int mtk_cpu_pm_cluster_prot_aquire(unsigned int cluster)
+{
+	return mtk_cpc_last_core_prot(
+			CPUSYS_PROT_SET,
+			CPC_MCUSYS_MP_LAST_CORE_RESP,
+			CPUSYS_RESP_OFS);
+}
+
+void mtk_cpu_pm_cluster_prot_release(unsigned int cluster)
+{
+	mmio_write_32(CPC_MCUSYS_PWR_ON_MASK, CPUSYS_PROT_CLR);
+}
+
+static void mtk_cpc_cluster_cnt_backup(void)
+{
+	uint32_t backup_cnt;
+	uint32_t curr_cnt;
+	uint32_t cnt_mask = GENMASK(14, 0);
+	uint32_t clr_mask = GENMASK(1, 0);
+
+	/* Single Cluster */
+	backup_cnt = mmio_read_32(CPC_CLUSTER_CNT_BACKUP);
+	curr_cnt = mmio_read_32(CPC_MCUSYS_CLUSTER_COUNTER);
+
+	/* Get off count if dormant count is 0 */
+	if ((curr_cnt & cnt_mask) == 0U) {
+		curr_cnt = (curr_cnt >> 16) & cnt_mask;
+	} else {
+		curr_cnt = curr_cnt & cnt_mask;
+	}
+
+	mmio_write_32(CPC_CLUSTER_CNT_BACKUP, backup_cnt + curr_cnt);
+	mmio_write_32(CPC_MCUSYS_CLUSTER_COUNTER_CLR, clr_mask);
+}
+
+static inline void mtk_cpc_mcusys_off_en(void)
+{
+	mmio_write_32(CPC_MCUSYS_PWR_CTRL, 1U);
+}
+
+static inline void mtk_cpc_mcusys_off_dis(void)
+{
+	mmio_write_32(CPC_MCUSYS_PWR_CTRL, 0U);
+}
+
+void mtk_cpc_mcusys_off_reflect(void)
+{
+	mtk_cpc_mcusys_off_dis();
+	mtk_cpu_pm_mcusys_prot_release();
+}
+
+int mtk_cpc_mcusys_off_prepare(void)
+{
+	if (mtk_cpu_pm_mcusys_prot_aquire() != CPC_SUCCESS) {
+		return CPC_ERR_FAIL;
+	}
+
+	mtk_cpc_cluster_cnt_backup();
+	mtk_cpc_mcusys_off_en();
+
+	return CPC_SUCCESS;
+}
+
+void mtk_cpc_core_on_hint_set(unsigned int cpu)
+{
+	mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_SET, BIT(cpu));
+}
+
+void mtk_cpc_core_on_hint_clr(unsigned int cpu)
+{
+	mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu));
+}
+
+static void mtk_cpc_dump_timestamp(void)
+{
+	uint32_t id;
+
+	for (id = 0U; id < CPC_TRACE_ID_NUM; id++) {
+		mmio_write_32(CPC_MCUSYS_TRACE_SEL, id);
+
+		memcpy((void *)(uintptr_t)CPC_TRACE_SRAM(id),
+				(const void *)(uintptr_t)CPC_MCUSYS_TRACE_DATA,
+				CPC_TRACE_SIZE);
+	}
+}
+
+void mtk_cpc_time_sync(void)
+{
+	uint64_t kt;
+	uint32_t systime_l, systime_h;
+
+	kt = sched_clock();
+	systime_l = mmio_read_32(CNTSYS_L_REG);
+	systime_h = mmio_read_32(CNTSYS_H_REG);
+
+	/* sync kernel timer to cpc */
+	mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE, (uint32_t)kt);
+	mmio_write_32(CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE, (uint32_t)(kt >> 32));
+	/* sync system timer to cpc */
+	mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE, systime_l);
+	mmio_write_32(CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE, systime_h);
+}
+
+static void mtk_cpc_config(uint32_t cfg, uint32_t data)
+{
+	uint32_t val;
+	uint32_t reg = 0U;
+
+	switch (cfg) {
+	case CPC_SMC_CONFIG_PROF:
+		reg = CPC_MCUSYS_CPC_DBG_SETTING;
+		val = mmio_read_32(reg);
+		val = (data != 0U) ? (val | CPC_PROF_EN) : (val & ~CPC_PROF_EN);
+		break;
+	case CPC_SMC_CONFIG_AUTO_OFF:
+		reg = CPC_MCUSYS_CPC_FLOW_CTRL_CFG;
+		val = mmio_read_32(reg);
+		if (data != 0U) {
+			val |= CPC_AUTO_OFF_EN;
+			cpc.auto_off = 1;
+		} else {
+			val &= ~CPC_AUTO_OFF_EN;
+			cpc.auto_off = 0;
+		}
+		break;
+	case CPC_SMC_CONFIG_AUTO_OFF_THRES:
+		reg = CPC_MCUSYS_CPC_OFF_THRES;
+		cpc.auto_thres_tick = us_to_ticks(data);
+		val = cpc.auto_thres_tick;
+		break;
+	case CPC_SMC_CONFIG_CNT_CLR:
+		reg = CPC_MCUSYS_CLUSTER_COUNTER_CLR;
+		val = GENMASK(1, 0);	/* clr_mask */
+		break;
+	case CPC_SMC_CONFIG_TIME_SYNC:
+		mtk_cpc_time_sync();
+		break;
+	default:
+		break;
+	}
+
+	if (reg != 0U) {
+		mmio_write_32(reg, val);
+	}
+}
+
+static uint32_t mtk_cpc_read_config(uint32_t cfg)
+{
+	uint32_t res = 0U;
+
+	switch (cfg) {
+	case CPC_SMC_CONFIG_PROF:
+		res = (mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING) & CPC_PROF_EN) ?
+			1U : 0U;
+		break;
+	case CPC_SMC_CONFIG_AUTO_OFF:
+		res = cpc.auto_off;
+		break;
+	case CPC_SMC_CONFIG_AUTO_OFF_THRES:
+		res = ticks_to_us(cpc.auto_thres_tick);
+		break;
+	case CPC_SMC_CONFIG_CNT_CLR:
+		break;
+	default:
+		break;
+	}
+
+	return res;
+}
+
+uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2)
+{
+	uint64_t res = 0ULL;
+
+	switch (act) {
+	case CPC_SMC_EVENT_DUMP_TRACE_DATA:
+		mtk_cpc_dump_timestamp();
+		break;
+	case CPC_SMC_EVENT_GIC_DPG_SET:
+		/* isolated_status = x2; */
+		break;
+	case CPC_SMC_EVENT_CPC_CONFIG:
+		mtk_cpc_config((uint32_t)arg1, (uint32_t)arg2);
+		break;
+	case CPC_SMC_EVENT_READ_CONFIG:
+		res = mtk_cpc_read_config((uint32_t)arg1);
+		break;
+	default:
+		break;
+	}
+
+	return res;
+}
+
+void mtk_cpc_init(void)
+{
+	mmio_write_32(CPC_MCUSYS_CPC_DBG_SETTING,
+			mmio_read_32(CPC_MCUSYS_CPC_DBG_SETTING)
+			| CPC_DBG_EN
+			| CPC_CALC_EN);
+
+	cpc.auto_off = 1;
+	cpc.auto_thres_tick = us_to_ticks(8000);
+
+	mmio_write_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG,
+			mmio_read_32(CPC_MCUSYS_CPC_FLOW_CTRL_CFG)
+			| CPC_OFF_PRE_EN
+			| (cpc.auto_off ? CPC_AUTO_OFF_EN : 0U));
+
+	mmio_write_32(CPC_MCUSYS_CPC_OFF_THRES, cpc.auto_thres_tick);
+}
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_cpc.h b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_cpc.h
new file mode 100644
index 0000000..488b1d1
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_cpc.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_CPU_PM_CPC_H
+#define MT_CPU_PM_CPC_H
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mcucfg.h>
+#include <platform_def.h>
+
+#define NEED_CPUSYS_PROT_WORKAROUND	1
+
+/* system sram registers */
+#define CPUIDLE_SRAM_REG(r)	(0x11B000 + (r))
+
+/* db dump */
+#define CPC_TRACE_SIZE		U(0x20)
+#define CPC_TRACE_ID_NUM	U(10)
+#define CPC_TRACE_SRAM(id)	(CPUIDLE_SRAM_REG(0x10) + (id) * CPC_TRACE_SIZE)
+
+/* buckup off count */
+#define CPC_CLUSTER_CNT_BACKUP	CPUIDLE_SRAM_REG(0x1F0)
+#define CPC_MCUSYS_CNT		CPUIDLE_SRAM_REG(0x1F4)
+
+/* CPC_MCUSYS_CPC_FLOW_CTRL_CFG(0xA814): debug setting */
+#define CPC_PWR_ON_SEQ_DIS	BIT(1)
+#define CPC_PWR_ON_PRIORITY	BIT(2)
+#define CPC_AUTO_OFF_EN		BIT(5)
+#define CPC_DORMANT_WAIT_EN	BIT(14)
+#define CPC_CTRL_EN		BIT(16)
+#define CPC_OFF_PRE_EN		BIT(29)
+
+/* CPC_MCUSYS_LAST_CORE_REQ(0xA818) : last core protection */
+#define CPUSYS_PROT_SET		BIT(0)
+#define MCUSYS_PROT_SET		BIT(8)
+#define CPUSYS_PROT_CLR		BIT(8)
+#define MCUSYS_PROT_CLR		BIT(9)
+
+#define CPC_PROT_RESP_MASK	U(0x3)
+#define CPUSYS_RESP_OFS		U(16)
+#define MCUSYS_RESP_OFS		U(30)
+
+#define cpusys_resp(r)		(((r) >> CPUSYS_RESP_OFS) & CPC_PROT_RESP_MASK)
+#define mcusys_resp(r)		(((r) >> MCUSYS_RESP_OFS) & CPC_PROT_RESP_MASK)
+
+#define RETRY_CNT_MAX		U(1000)
+
+#define PROT_RETRY		U(0)
+#define PROT_SUCCESS		U(1)
+#define PROT_GIVEUP		U(2)
+
+/* CPC_MCUSYS_CPC_DBG_SETTING(0xAB00): debug setting */
+#define CPC_PROF_EN		BIT(0)
+#define CPC_DBG_EN		BIT(1)
+#define CPC_FREEZE		BIT(2)
+#define CPC_CALC_EN		BIT(3)
+
+enum {
+	CPC_SUCCESS = 0U,
+	CPC_ERR_FAIL = 1U,
+	CPC_ERR_TIMEOUT = 2U,
+	NF_CPC_ERR = 3U,
+};
+
+enum {
+	CPC_SMC_EVENT_DUMP_TRACE_DATA = 0U,
+	CPC_SMC_EVENT_GIC_DPG_SET = 1U,
+	CPC_SMC_EVENT_CPC_CONFIG = 2U,
+	CPC_SMC_EVENT_READ_CONFIG = 3U,
+	NF_CPC_SMC_EVENT = 4U,
+};
+
+enum {
+	CPC_SMC_CONFIG_PROF = 0U,
+	CPC_SMC_CONFIG_AUTO_OFF = 1U,
+	CPC_SMC_CONFIG_AUTO_OFF_THRES = 2U,
+	CPC_SMC_CONFIG_CNT_CLR = 3U,
+	CPC_SMC_CONFIG_TIME_SYNC = 4U,
+	NF_CPC_SMC_CONFIG = 5U,
+};
+
+#define us_to_ticks(us)		((us) * 13)
+#define ticks_to_us(tick)	((tick) / 13)
+
+int mtk_cpu_pm_cluster_prot_aquire(unsigned int cluster);
+void mtk_cpu_pm_cluster_prot_release(unsigned int cluster);
+
+void mtk_cpc_mcusys_off_reflect(void);
+int mtk_cpc_mcusys_off_prepare(void);
+
+void mtk_cpc_core_on_hint_set(unsigned int cpu);
+void mtk_cpc_core_on_hint_clr(unsigned int cpu);
+void mtk_cpc_time_sync(void);
+
+uint64_t mtk_cpc_handler(uint64_t act, uint64_t arg1, uint64_t arg2);
+void mtk_cpc_init(void);
+
+#endif /* MT_CPU_PM_CPC_H */
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_mbox.c b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_mbox.c
new file mode 100644
index 0000000..789fafb
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_mbox.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mmio.h>
+#include <mt_cpu_pm_mbox.h>
+#include <platform_def.h>
+#include <sspm_reg.h>
+
+#define MCUPM_MBOX_3_BASE	(MTK_MCUPM_SRAM_BASE + 0xFCE0)
+
+#define _sspm_mbox_write(id, val) \
+		mmio_write_32(SSPM_MBOX_3_BASE + 4 * (id), val)
+#define _sspm_mbox_read(id) \
+		mmio_read_32(SSPM_MBOX_3_BASE + 4 * (id))
+
+#define _mcupm_mbox_write(id, val) \
+		mmio_write_32(MCUPM_MBOX_3_BASE + 4 * (id), val)
+#define _mcupm_mbox_read(id) \
+		mmio_read_32(MCUPM_MBOX_3_BASE + 4 * (id))
+
+
+#define MCUPM_MBOX_OFFSET_PDN		(0x0C55FDA8)
+#define MCUPM_POWER_DOWN		(0x4D50444E)
+
+void mtk_set_sspm_lp_cmd(void *buf, unsigned int size)
+{
+	unsigned int *p = (unsigned int *)buf;
+	int i;
+
+	for (i = 0; i < size; i++) {
+		_sspm_mbox_write(SSPM_MBOX_SPM_CMD + i, p[i]);
+	}
+}
+
+void mtk_clr_sspm_lp_cmd(unsigned int size)
+{
+	int i;
+
+	for (i = 0; i < size; i++) {
+		_sspm_mbox_write(SSPM_MBOX_SPM_CMD + i, 0);
+	}
+}
+
+void mtk_set_cpu_pm_pll_mode(unsigned int mode)
+{
+	if (mode < NF_MCUPM_ARMPLL_MODE) {
+		_mcupm_mbox_write(MCUPM_MBOX_ARMPLL_MODE, mode);
+	}
+}
+
+int mtk_get_cpu_pm_pll_mode(void)
+{
+	return _mcupm_mbox_read(MCUPM_MBOX_ARMPLL_MODE);
+}
+
+void mtk_set_cpu_pm_buck_mode(unsigned int mode)
+{
+	if (mode < NF_MCUPM_BUCK_MODE) {
+		_mcupm_mbox_write(MCUPM_MBOX_BUCK_MODE, mode);
+	}
+}
+
+int mtk_get_cpu_pm_buck_mode(void)
+{
+	return _mcupm_mbox_read(MCUPM_MBOX_BUCK_MODE);
+}
+
+void mtk_set_cpu_pm_preffered_cpu(unsigned int cpuid)
+{
+	return _mcupm_mbox_read(MCUPM_MBOX_WAKEUP_CPU);
+}
+
+int mtk_set_cpu_pm_mbox_addr(uint64_t phy_addr)
+{
+	return 0;
+}
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_mbox.h b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_mbox.h
new file mode 100644
index 0000000..63a43af
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_mbox.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef __MT_CPU_PM_MBOX_H__
+#define __MT_CPU_PM_MBOX_H__
+
+/* SSPM Mbox */
+/* AP Write */
+#define SSPM_MBOX_SPM_CMD	(0U)
+#define SSPM_MBOX_SPM_ARGS1	(1U)
+#define SSPM_MBOX_SPM_ARGS2	(2U)
+#define SSPM_MBOX_SPM_ARGS3	(3U)
+#define SSPM_MBOX_SPM_ARGS4	(4U)
+#define SSPM_MBOX_SPM_ARGS5	(5U)
+#define SSPM_MBOX_SPM_ARGS6	(6U)
+#define SSPM_MBOX_SPM_ARGS7	(7U)
+#define SSPM_MBOX_AP_READY	(17U)
+
+#define SSPM_MBOX_SPM_CMD_SIZE	(8U)
+
+void mtk_set_sspm_lp_cmd(void *buf, unsigned int size);
+void mtk_clr_sspm_lp_cmd(unsigned int size);
+
+/* MCUPM Mbox */
+/* AP Write */
+#define MCUPM_MBOX_AP_READY		(0U)
+#define MCUPM_MBOX_RESERVED_1		(1U)
+#define MCUPM_MBOX_RESERVED_2		(2U)
+#define MCUPM_MBOX_RESERVED_3		(3U)
+#define MCUPM_MBOX_PWR_CTRL_EN		(4U)
+#define MCUPM_MBOX_L3_CACHE_MODE	(5U)
+#define MCUPM_MBOX_BUCK_MODE		(6U)
+#define MCUPM_MBOX_ARMPLL_MODE		(7U)
+/* AP Read */
+#define MCUPM_MBOX_TASK_STA		(8U)
+#define MCUPM_MBOX_RESERVED_9		(9U)
+#define MCUPM_MBOX_RESERVED_10		(10U)
+#define MCUPM_MBOX_RESERVED_11		(11U)
+/* CPC mode - Read/Write */
+#define MCUPM_MBOX_WAKEUP_CPU		(12U)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_PWR_CTRL_EN (4) */
+#define MCUPM_MCUSYS_CTRL		(1U << 0)
+#define MCUPM_BUCK_CTRL			(1U << 1)
+#define MCUPM_ARMPLL_CTRL		(1U << 2)
+#define MCUPM_PWR_CTRL_MASK		((1U << 3) - 1U)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_L3_CACHE_MODE (5) */
+#define MCUPM_L3_OFF_MODE		(0U) /* default */
+#define MCUPM_L3_DORMANT_MODE		(1U)
+#define NF_MCUPM_L3_MODE		(2U)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_BUCK_MODE (6) */
+#define MCUPM_BUCK_NORMAL_MODE		(0U) /* default */
+#define MCUPM_BUCK_LP_MODE		(1U)
+#define MCUPM_BUCK_OFF_MODE		(2U)
+#define NF_MCUPM_BUCK_MODE		(3U)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_ARMPLL_MODE (7) */
+#define MCUPM_ARMPLL_ON			(0U) /* default */
+#define MCUPM_ARMPLL_GATING		(1U)
+#define MCUPM_ARMPLL_OFF		(2U)
+#define NF_MCUPM_ARMPLL_MODE		(3U)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_TASK_STA (9) */
+#define MCUPM_TASK_UNINIT		(0U)
+#define MCUPM_TASK_INIT			(1U)
+#define MCUPM_TASK_INIT_FINISH		(2U)
+#define MCUPM_TASK_WAIT			(3U)
+#define MCUPM_TASK_RUN			(4U)
+#define MCUPM_TASK_PAUSE		(5U)
+
+void mtk_set_cpu_pm_pll_mode(unsigned int mode);
+int mtk_get_cpu_pm_pll_mode(void);
+void mtk_set_cpu_pm_buck_mode(unsigned int mode);
+int mtk_get_cpu_pm_buck_mode(void);
+void mtk_set_cpu_pm_preffered_cpu(unsigned int cpuid);
+int mtk_set_cpu_pm_mbox_addr(uint64_t phy_addr);
+
+#endif
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_mbox_sspm.c b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_mbox_sspm.c
new file mode 100644
index 0000000..34c281d
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_cpu_pm_mbox_sspm.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mmio.h>
+#include <mt_cpu_pm.h>
+#include <mt_cpu_pm_mbox.h>
+#include <platform_def.h>
+#include <sspm_reg.h>
+
+#ifdef MCDI_TINYSYS_MBOX_SHARE_SRAM
+struct cpu_pm_mbox {
+	unsigned int ap_ready;
+	unsigned int reserved1;
+	unsigned int reserved2;
+	unsigned int reserved3;
+	unsigned int pwr_ctrl_en;
+	unsigned int l3_cache_mode;
+	unsigned int buck_mode;
+	unsigned int armpll_mode;
+	unsigned int task_sta;
+	unsigned int reserved9;
+	unsigned int reserved10;
+	unsigned int reserved11;
+	unsigned int wakeup_cpu;
+};
+
+struct cpu_pm_mbox *_cpu_pm_box = (struct cpu_pm_mbox *)SSPM_MBOX_3_BASE;
+#endif
+
+void mtk_set_cpu_pm_pll_mode(unsigned int mode)
+{
+#ifdef MCDI_TINYSYS_MBOX_SHARE_SRAM
+	if (_cpu_pm_box) {
+		_cpu_pm_box->armpll_mode = mode;
+	}
+#endif
+}
+
+int mtk_get_cpu_pm_pll_mode(void)
+{
+#ifdef MCDI_TINYSYS_MBOX_SHARE_SRAM
+	if (!_cpu_pm_box) {
+		return 0;
+	}
+	return _cpu_pm_box->armpll_mode;
+#endif
+}
+
+void mtk_set_cpu_pm_buck_mode(unsigned int mode)
+{
+#ifdef MCDI_TINYSYS_MBOX_SHARE_SRAM
+	if (_cpu_pm_box) {
+		_cpu_pm_box->buck_mode = mode;
+	}
+#endif
+}
+
+int mtk_get_cpu_pm_buck_mode(void)
+{
+#ifdef MCDI_TINYSYS_MBOX_SHARE_SRAM
+	if (!_cpu_pm_box) {
+		return 0;
+	}
+	return _cpu_pm_box->buck_mode;
+#endif
+}
+
+void mtk_set_cpu_pm_preffered_cpu(unsigned int cpuid)
+{
+#ifdef MCDI_TINYSYS_MBOX_SHARE_SRAM
+	if (_cpu_pm_box) {
+		_cpu_pm_box->wakeup_cpu = cpuid;
+	}
+#endif
+}
+
+int mtk_set_cpu_pm_mbox_addr(uint64_t phy_addr)
+{
+#ifdef MCDI_TINYSYS_MBOX_SHARE_SRAM
+	if (_cpu_pm_box || (phy_addr == 0)) {
+		return -1;
+	}
+
+	_cpu_pm_box = (struct cpu_pm_mbox *)(MTK_SSPM_BASE + phy_addr);
+#endif
+	return 0;
+}
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_mcdi.c b/plat/mediatek/mt8186/drivers/mcdi/mt_mcdi.c
new file mode 100644
index 0000000..0103612
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_mcdi.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cdefs.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mt_mcdi.h>
+
+/* Read/Write */
+#define APMCU_MCUPM_MBOX_AP_READY	U(0)
+#define APMCU_MCUPM_MBOX_RESERVED_1	U(1)
+#define APMCU_MCUPM_MBOX_RESERVED_2	U(2)
+#define APMCU_MCUPM_MBOX_RESERVED_3	U(3)
+#define APMCU_MCUPM_MBOX_PWR_CTRL_EN	U(4)
+#define APMCU_MCUPM_MBOX_L3_CACHE_MODE	U(5)
+#define APMCU_MCUPM_MBOX_BUCK_MODE	U(6)
+#define APMCU_MCUPM_MBOX_ARMPLL_MODE	U(7)
+/* Read only */
+#define APMCU_MCUPM_MBOX_TASK_STA	U(8)
+#define APMCU_MCUPM_MBOX_RESERVED_9	U(9)
+#define APMCU_MCUPM_MBOX_RESERVED_10	U(10)
+#define APMCU_MCUPM_MBOX_RESERVED_11	U(11)
+
+/* CPC mode - Read/Write */
+#define APMCU_MCUPM_MBOX_WAKEUP_CPU	U(12)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_PWR_CTRL_EN */
+#define MCUPM_MCUSYS_CTRL		BIT(0)
+#define MCUPM_BUCK_CTRL			BIT(1)
+#define MCUPM_ARMPLL_CTRL		BIT(2)
+#define MCUPM_CM_CTRL			BIT(3)
+#define MCUPM_PWR_CTRL_MASK		GENMASK(3, 0)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_BUCK_MODE */
+#define MCUPM_BUCK_NORMAL_MODE		U(0) /* default */
+#define MCUPM_BUCK_LP_MODE		U(1)
+#define MCUPM_BUCK_OFF_MODE		U(2)
+#define NF_MCUPM_BUCK_MODE		U(3)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_ARMPLL_MODE */
+#define MCUPM_ARMPLL_ON			U(0) /* default */
+#define MCUPM_ARMPLL_GATING		U(1)
+#define MCUPM_ARMPLL_OFF		U(2)
+#define NF_MCUPM_ARMPLL_MODE		U(3)
+
+/* Mbox Slot: APMCU_MCUPM_MBOX_TASK_STA */
+#define MCUPM_TASK_UNINIT		U(0)
+#define MCUPM_TASK_INIT			U(1)
+#define MCUPM_TASK_INIT_FINISH		U(2)
+#define MCUPM_TASK_WAIT			U(3)
+#define MCUPM_TASK_RUN			U(4)
+#define MCUPM_TASK_PAUSE		U(5)
+
+#define SSPM_MBOX_3_BASE		U(0x10420000)
+
+#define MCDI_NOT_INIT			U(0)
+#define MCDI_INIT_1			U(1)
+#define MCDI_INIT_2			U(2)
+#define MCDI_INIT_DONE			U(3)
+
+static int mcdi_init_status __section("tzfw_coherent_mem");
+
+static inline uint32_t mcdi_mbox_read(uint32_t id)
+{
+	return mmio_read_32(SSPM_MBOX_3_BASE + (id << 2));
+}
+
+static inline void mcdi_mbox_write(uint32_t id, uint32_t val)
+{
+	mmio_write_32(SSPM_MBOX_3_BASE + (id << 2), val);
+}
+
+static void mtk_mcupm_pwr_ctrl_setting(uint32_t dev)
+{
+	mcdi_mbox_write(APMCU_MCUPM_MBOX_PWR_CTRL_EN, dev);
+}
+
+static void mtk_set_mcupm_pll_mode(uint32_t mode)
+{
+	if (mode < NF_MCUPM_ARMPLL_MODE) {
+		mcdi_mbox_write(APMCU_MCUPM_MBOX_ARMPLL_MODE, mode);
+	}
+}
+
+static void mtk_set_mcupm_buck_mode(uint32_t mode)
+{
+	if (mode < NF_MCUPM_BUCK_MODE) {
+		mcdi_mbox_write(APMCU_MCUPM_MBOX_BUCK_MODE, mode);
+	}
+}
+
+static int mtk_mcupm_is_ready(void)
+{
+	unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA);
+
+	return ((sta == MCUPM_TASK_WAIT) || (sta == MCUPM_TASK_INIT_FINISH));
+}
+
+static int mcdi_init_1(void)
+{
+	unsigned int sta = mcdi_mbox_read(APMCU_MCUPM_MBOX_TASK_STA);
+
+	if (sta != MCUPM_TASK_INIT) {
+		return -1;
+	}
+
+	mtk_set_mcupm_pll_mode(MCUPM_ARMPLL_OFF);
+	mtk_set_mcupm_buck_mode(MCUPM_BUCK_OFF_MODE);
+
+	mtk_mcupm_pwr_ctrl_setting(
+			 MCUPM_MCUSYS_CTRL |
+			 MCUPM_BUCK_CTRL |
+			 MCUPM_ARMPLL_CTRL);
+
+	mcdi_mbox_write(APMCU_MCUPM_MBOX_AP_READY, 1);
+
+	return 0;
+}
+
+static int mcdi_init_2(void)
+{
+	return mtk_mcupm_is_ready() ? 0 : -1;
+}
+
+int mcdi_try_init(void)
+{
+	if (mcdi_init_status == MCDI_INIT_DONE) {
+		return 0;
+	}
+
+	if (mcdi_init_status == MCDI_NOT_INIT) {
+		mcdi_init_status = MCDI_INIT_1;
+	}
+
+	if (mcdi_init_status == MCDI_INIT_1 && mcdi_init_1() == 0) {
+		mcdi_init_status = MCDI_INIT_2;
+	}
+
+	if (mcdi_init_status == MCDI_INIT_2 && mcdi_init_2() == 0) {
+		mcdi_init_status = MCDI_INIT_DONE;
+	}
+
+	INFO("mcdi ready for mcusys-off-idle and system suspend\n");
+
+	return (mcdi_init_status == MCDI_INIT_DONE) ? 0 : mcdi_init_status;
+}
diff --git a/plat/mediatek/mt8186/drivers/mcdi/mt_mcdi.h b/plat/mediatek/mt8186/drivers/mcdi/mt_mcdi.h
new file mode 100644
index 0000000..0e6444a
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/mcdi/mt_mcdi.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MT_MCDI_H
+#define MT_MCDI_H
+
+int mcdi_try_init(void);
+
+#endif /* MT_MCDI_H */
diff --git a/plat/mediatek/mt8186/drivers/pmic/pmic.c b/plat/mediatek/mt8186/drivers/pmic/pmic.c
new file mode 100644
index 0000000..4f7ab13
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/pmic/pmic.c
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <pmic.h>
+#include <pmic_wrap_init.h>
+
+uint32_t pmic_get_hwcid(void)
+{
+	uint32_t val = 0;
+
+	pwrap_read(PMIC_RG_HWCID_ADDR, &val);
+
+	return val;
+}
+
+void pmic_power_off(void)
+{
+	pwrap_write(PMIC_PWRHOLD, 0x0);
+}
diff --git a/plat/mediatek/mt8186/drivers/pmic/pmic.h b/plat/mediatek/mt8186/drivers/pmic/pmic.h
new file mode 100644
index 0000000..91ccb19
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/pmic/pmic.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMIC_H
+#define PMIC_H
+
+#include <stdint.h>
+
+#define PMIC_RG_HWCID_ADDR 0x8
+#define PMIC_PWRHOLD 0xa08
+
+/* external API */
+uint32_t pmic_get_hwcid(void);
+void pmic_power_off(void);
+
+#endif /* PMIC_H */
diff --git a/plat/mediatek/mt8186/drivers/pmic/pmic_wrap_init.h b/plat/mediatek/mt8186/drivers/pmic/pmic_wrap_init.h
new file mode 100644
index 0000000..e837456
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/pmic/pmic_wrap_init.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMIC_WRAP_INIT_H
+#define PMIC_WRAP_INIT_H
+
+#include <stdint.h>
+
+#include "platform_def.h"
+
+/* external API */
+int32_t pwrap_read(uint32_t adr, uint32_t *rdata);
+int32_t pwrap_write(uint32_t adr, uint32_t wdata);
+
+static struct mt8186_pmic_wrap_regs *const mtk_pwrap = (void *)PMIC_WRAP_BASE;
+
+/* timeout setting */
+enum {
+	TIMEOUT_RESET       = 50,	/* us */
+	TIMEOUT_READ        = 50,	/* us */
+	TIMEOUT_WAIT_IDLE   = 50	/* us */
+};
+
+/* PMIC_WRAP registers */
+struct mt8186_pmic_wrap_regs {
+	uint32_t unused[776];
+	uint32_t wacs2_cmd;
+	uint32_t wacs2_rdata;
+	uint32_t wacs2_vldclr;
+};
+
+enum {
+	RDATA_WACS_RDATA_SHIFT = 0,
+	RDATA_WACS_FSM_SHIFT = 16,
+	RDATA_WACS_REQ_SHIFT = 19,
+	RDATA_SYNC_IDLE_SHIFT = 20,
+	RDATA_INIT_DONE_SHIFT = 22,
+	RDATA_SYS_IDLE_SHIFT = 23,
+};
+
+enum {
+	RDATA_WACS_RDATA_MASK = 0xffff,
+	RDATA_WACS_FSM_MASK = 0x7,
+	RDATA_WACS_REQ_MASK = 0x1,
+	RDATA_SYNC_IDLE_MASK = 0x1,
+	RDATA_INIT_DONE_MASK = 0x1,
+	RDATA_SYS_IDLE_MASK = 0x1,
+};
+
+/* WACS_FSM */
+enum {
+	WACS_FSM_IDLE            = 0x00,
+	WACS_FSM_REQ             = 0x02,
+	WACS_FSM_WFDLE           = 0x04,
+	WACS_FSM_WFVLDCLR        = 0x06,
+	WACS_INIT_DONE           = 0x01,
+	WACS_SYNC_IDLE           = 0x01,
+	WACS_SYNC_BUSY           = 0x00
+};
+
+/* error information flag */
+enum {
+	E_PWR_INVALID_ARG             = 1,
+	E_PWR_INVALID_RW              = 2,
+	E_PWR_INVALID_ADDR            = 3,
+	E_PWR_INVALID_WDAT            = 4,
+	E_PWR_INVALID_OP_MANUAL       = 5,
+	E_PWR_NOT_IDLE_STATE          = 6,
+	E_PWR_NOT_INIT_DONE           = 7,
+	E_PWR_NOT_INIT_DONE_READ      = 8,
+	E_PWR_WAIT_IDLE_TIMEOUT       = 9,
+	E_PWR_WAIT_IDLE_TIMEOUT_READ  = 10,
+	E_PWR_INIT_SIDLY_FAIL         = 11,
+	E_PWR_RESET_TIMEOUT           = 12,
+	E_PWR_TIMEOUT                 = 13,
+	E_PWR_INIT_RESET_SPI          = 20,
+	E_PWR_INIT_SIDLY              = 21,
+	E_PWR_INIT_REG_CLOCK          = 22,
+	E_PWR_INIT_ENABLE_PMIC        = 23,
+	E_PWR_INIT_DIO                = 24,
+	E_PWR_INIT_CIPHER             = 25,
+	E_PWR_INIT_WRITE_TEST         = 26,
+	E_PWR_INIT_ENABLE_CRC         = 27,
+	E_PWR_INIT_ENABLE_DEWRAP      = 28,
+	E_PWR_INIT_ENABLE_EVENT       = 29,
+	E_PWR_READ_TEST_FAIL          = 30,
+	E_PWR_WRITE_TEST_FAIL         = 31,
+	E_PWR_SWITCH_DIO              = 32
+};
+
+#endif /* PMIC_WRAP_INIT_H */
diff --git a/plat/mediatek/mt8186/drivers/rtc/rtc.c b/plat/mediatek/mt8186/drivers/rtc/rtc.c
new file mode 100644
index 0000000..4fcf58e
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/rtc/rtc.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <rtc.h>
+
+static void RTC_Config_Interface(uint32_t addr, uint16_t data,
+			    uint16_t MASK, uint16_t SHIFT)
+{
+	uint16_t pmic_reg = 0;
+
+	pmic_reg = RTC_Read(addr);
+
+	pmic_reg &= ~(MASK << SHIFT);
+	pmic_reg |= (data << SHIFT);
+
+	RTC_Write(addr, pmic_reg);
+}
+
+static void rtc_disable_2sec_reboot(void)
+{
+	uint16_t reboot;
+
+	reboot = (RTC_Read(RTC_AL_SEC) & ~RTC_BBPU_2SEC_EN) &
+		 ~RTC_BBPU_AUTO_PDN_SEL;
+	RTC_Write(RTC_AL_SEC, reboot);
+	RTC_Write_Trigger();
+}
+
+static void rtc_xosc_write(uint16_t val, bool reload)
+{
+	uint16_t bbpu;
+
+	RTC_Write(RTC_OSC32CON, RTC_OSC32CON_UNLOCK1);
+	rtc_busy_wait();
+	RTC_Write(RTC_OSC32CON, RTC_OSC32CON_UNLOCK2);
+	rtc_busy_wait();
+
+	RTC_Write(RTC_OSC32CON, val);
+	rtc_busy_wait();
+
+	if (reload) {
+		bbpu = RTC_Read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD;
+		RTC_Write(RTC_BBPU, bbpu);
+		RTC_Write_Trigger();
+	}
+}
+
+static void rtc_enable_k_eosc(void)
+{
+	uint16_t osc32;
+	uint16_t rtc_eosc_cali_td = 8; /* eosc cali period time */
+
+	/* Truning on eosc cali mode clock */
+	RTC_Config_Interface(PMIC_RG_TOP_CON, 1,
+			PMIC_RG_SRCLKEN_IN0_HW_MODE_MASK,
+			PMIC_RG_SRCLKEN_IN0_HW_MODE_SHIFT);
+	RTC_Config_Interface(PMIC_RG_TOP_CON, 1,
+			PMIC_RG_SRCLKEN_IN1_HW_MODE_MASK,
+			PMIC_RG_SRCLKEN_IN1_HW_MODE_SHIFT);
+	RTC_Config_Interface(PMIC_RG_SCK_TOP_CKPDN_CON0, 0,
+			PMIC_RG_RTC_EOSC32_CK_PDN_MASK,
+			PMIC_RG_RTC_EOSC32_CK_PDN_SHIFT);
+
+	switch (rtc_eosc_cali_td) {
+	case 1:
+		RTC_Config_Interface(PMIC_RG_EOSC_CALI_CON0, 0x3,
+			PMIC_RG_EOSC_CALI_TD_MASK, PMIC_RG_EOSC_CALI_TD_SHIFT);
+		break;
+	case 2:
+		RTC_Config_Interface(PMIC_RG_EOSC_CALI_CON0, 0x4,
+			PMIC_RG_EOSC_CALI_TD_MASK, PMIC_RG_EOSC_CALI_TD_SHIFT);
+		break;
+	case 4:
+		RTC_Config_Interface(PMIC_RG_EOSC_CALI_CON0, 0x5,
+			PMIC_RG_EOSC_CALI_TD_MASK, PMIC_RG_EOSC_CALI_TD_SHIFT);
+		break;
+	case 16:
+		RTC_Config_Interface(PMIC_RG_EOSC_CALI_CON0, 0x7,
+			PMIC_RG_EOSC_CALI_TD_MASK, PMIC_RG_EOSC_CALI_TD_SHIFT);
+		break;
+	default:
+		RTC_Config_Interface(PMIC_RG_EOSC_CALI_CON0, 0x6,
+			PMIC_RG_EOSC_CALI_TD_MASK, PMIC_RG_EOSC_CALI_TD_SHIFT);
+		break;
+	}
+	/* Switch the DCXO from 32k-less mode to RTC mode,
+	 * otherwise, EOSC cali will fail
+	 */
+	/* RTC mode will have only OFF mode and FPM */
+	RTC_Config_Interface(PMIC_RG_DCXO_CW02, 0, PMIC_RG_XO_EN32K_MAN_MASK,
+		PMIC_RG_XO_EN32K_MAN_SHIFT);
+	RTC_Write(RTC_BBPU,
+		  RTC_Read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD);
+	RTC_Write_Trigger();
+	/* Enable K EOSC mode for normal power off and then plug out battery */
+	RTC_Write(RTC_AL_YEA, ((RTC_Read(RTC_AL_YEA) | RTC_K_EOSC_RSV_0)
+				& (~RTC_K_EOSC_RSV_1)) | RTC_K_EOSC_RSV_2);
+	RTC_Write_Trigger();
+
+	osc32 = RTC_Read(RTC_OSC32CON);
+	rtc_xosc_write(osc32 | RTC_EMBCK_SRC_SEL, true);
+	INFO("[RTC] RTC_enable_k_eosc\n");
+}
+
+void rtc_power_off_sequence(void)
+{
+	uint16_t bbpu;
+
+	rtc_disable_2sec_reboot();
+	rtc_enable_k_eosc();
+
+	/* clear alarm */
+	bbpu = RTC_BBPU_KEY | RTC_BBPU_CLR | RTC_BBPU_PWREN;
+	if (Writeif_unlock()) {
+		RTC_Write(RTC_BBPU, bbpu);
+
+		RTC_Write(RTC_AL_MASK, RTC_AL_MASK_DOW);
+		RTC_Write_Trigger();
+		mdelay(1);
+
+		bbpu = RTC_Read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD;
+		RTC_Write(RTC_BBPU, bbpu);
+		RTC_Write_Trigger();
+		INFO("[RTC] BBPU=0x%x, IRQ_EN=0x%x, AL_MSK=0x%x, AL_SEC=0x%x\n",
+		     RTC_Read(RTC_BBPU), RTC_Read(RTC_IRQ_EN),
+		     RTC_Read(RTC_AL_MASK), RTC_Read(RTC_AL_SEC));
+	}
+}
diff --git a/plat/mediatek/mt8186/drivers/rtc/rtc.h b/plat/mediatek/mt8186/drivers/rtc/rtc.h
new file mode 100644
index 0000000..b48dbb9
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/rtc/rtc.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RTC_H
+#define RTC_H
+
+#define PMIC_RG_SRCLKEN_IN0_HW_MODE_MASK	(1U)
+#define PMIC_RG_SRCLKEN_IN0_HW_MODE_SHIFT	(1U)
+#define PMIC_RG_SRCLKEN_IN1_HW_MODE_MASK	(1U)
+#define PMIC_RG_SRCLKEN_IN1_HW_MODE_SHIFT	(3U)
+#define PMIC_RG_RTC_EOSC32_CK_PDN_MASK		(1U)
+#define PMIC_RG_RTC_EOSC32_CK_PDN_SHIFT		(2U)
+#define PMIC_RG_EOSC_CALI_TD_MASK		(7U)
+#define PMIC_RG_EOSC_CALI_TD_SHIFT		(5U)
+#define PMIC_RG_XO_EN32K_MAN_MASK		(1U)
+#define PMIC_RG_XO_EN32K_MAN_SHIFT		(0U)
+
+/* RTC registers */
+enum {
+	RTC_BBPU = 0x0588,
+	RTC_IRQ_STA = 0x058A,
+	RTC_IRQ_EN = 0x058C,
+	RTC_CII_EN = 0x058E
+};
+
+enum {
+	RTC_AL_SEC = 0x05A0,
+	RTC_AL_MIN = 0x05A2,
+	RTC_AL_HOU = 0x05A4,
+	RTC_AL_DOM = 0x05A6,
+	RTC_AL_DOW = 0x05A8,
+	RTC_AL_MTH = 0x05AA,
+	RTC_AL_YEA = 0x05AC,
+	RTC_AL_MASK = 0x0590
+};
+
+enum {
+	RTC_OSC32CON = 0x05AE,
+	RTC_CON = 0x05C4,
+	RTC_WRTGR = 0x05C2
+};
+
+enum {
+	RTC_PDN1 = 0x05B4,
+	RTC_PDN2 = 0x05B6,
+	RTC_SPAR0 = 0x05B8,
+	RTC_SPAR1 = 0x05BA,
+	RTC_PROT = 0x05BC,
+	RTC_DIFF = 0x05BE,
+	RTC_CALI = 0x05C0
+};
+
+enum {
+	RTC_OSC32CON_UNLOCK1 = 0x1A57,
+	RTC_OSC32CON_UNLOCK2 = 0x2B68
+};
+
+enum {
+	RTC_PROT_UNLOCK1 = 0x586A,
+	RTC_PROT_UNLOCK2 = 0x9136
+};
+
+enum {
+	RTC_BBPU_PWREN	= 1U << 0,
+	RTC_BBPU_CLR	= 1U << 1,
+	RTC_BBPU_INIT	= 1U << 2,
+	RTC_BBPU_AUTO	= 1U << 3,
+	RTC_BBPU_CLRPKY	= 1U << 4,
+	RTC_BBPU_RELOAD	= 1U << 5,
+	RTC_BBPU_CBUSY	= 1U << 6
+};
+
+enum {
+	RTC_AL_MASK_SEC = 1U << 0,
+	RTC_AL_MASK_MIN = 1U << 1,
+	RTC_AL_MASK_HOU = 1U << 2,
+	RTC_AL_MASK_DOM = 1U << 3,
+	RTC_AL_MASK_DOW = 1U << 4,
+	RTC_AL_MASK_MTH = 1U << 5,
+	RTC_AL_MASK_YEA = 1U << 6
+};
+
+enum {
+	RTC_BBPU_AUTO_PDN_SEL = 1U << 6,
+	RTC_BBPU_2SEC_CK_SEL = 1U << 7,
+	RTC_BBPU_2SEC_EN = 1U << 8,
+	RTC_BBPU_2SEC_MODE = 0x3 << 9,
+	RTC_BBPU_2SEC_STAT_CLEAR = 1U << 11,
+	RTC_BBPU_2SEC_STAT_STA = 1U << 12
+};
+
+enum {
+	RTC_BBPU_KEY	= 0x43 << 8
+};
+
+enum {
+	RTC_EMBCK_SRC_SEL	= 1 << 8,
+	RTC_EMBCK_SEL_MODE	= 3 << 6,
+	RTC_XOSC32_ENB		= 1 << 5,
+	RTC_REG_XOSC32_ENB	= 1 << 15
+};
+
+enum {
+	RTC_K_EOSC_RSV_0	= 1 << 8,
+	RTC_K_EOSC_RSV_1	= 1 << 9,
+	RTC_K_EOSC_RSV_2	= 1 << 10
+};
+
+/* PMIC TOP Register Definition */
+enum {
+	PMIC_RG_TOP_CON = 0x001E,
+	PMIC_RG_TOP_CKPDN_CON1 = 0x0112,
+	PMIC_RG_TOP_CKPDN_CON1_SET = 0x0114,
+	PMIC_RG_TOP_CKPDN_CON1_CLR = 0x0116,
+	PMIC_RG_TOP_CKSEL_CON0 = 0x0118,
+	PMIC_RG_TOP_CKSEL_CON0_SET = 0x011A,
+	PMIC_RG_TOP_CKSEL_CON0_CLR = 0x011C
+};
+
+/* PMIC SCK Register Definition */
+enum {
+	PMIC_RG_SCK_TOP_CKPDN_CON0 = 0x051A,
+	PMIC_RG_SCK_TOP_CKPDN_CON0_SET = 0x051C,
+	PMIC_RG_SCK_TOP_CKPDN_CON0_CLR = 0x051E,
+	PMIC_RG_EOSC_CALI_CON0 = 0x540
+};
+
+/* PMIC DCXO Register Definition */
+enum {
+	PMIC_RG_DCXO_CW00 = 0x0788,
+	PMIC_RG_DCXO_CW02 = 0x0790
+};
+
+/* external API */
+uint16_t RTC_Read(uint32_t addr);
+void RTC_Write(uint32_t addr, uint16_t data);
+int32_t rtc_busy_wait(void);
+int32_t RTC_Write_Trigger(void);
+int32_t Writeif_unlock(void);
+void rtc_power_off_sequence(void);
+
+#endif /* RTC_H */
diff --git a/plat/mediatek/mt8186/drivers/spmc/mtspmc.c b/plat/mediatek/mt8186/drivers/spmc/mtspmc.c
new file mode 100644
index 0000000..91ef096
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spmc/mtspmc.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include <mcucfg.h>
+#include <mtspmc.h>
+#include <mtspmc_private.h>
+#include <plat/common/platform.h>
+
+void mcucfg_disable_gic_wakeup(unsigned int cluster, unsigned int cpu)
+{
+	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu));
+}
+
+void mcucfg_enable_gic_wakeup(unsigned int cluster, unsigned int cpu)
+{
+	mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu));
+	/* Clear cpu's cpc sw hint */
+	mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu));
+}
+
+void mcucfg_set_bootaddr(unsigned int cluster, unsigned int cpu, uintptr_t bootaddr)
+{
+	assert(cluster == 0U);
+
+	mmio_write_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR), bootaddr);
+}
+
+uintptr_t mcucfg_get_bootaddr(unsigned int cluster, unsigned int cpu)
+{
+	assert(cluster == 0U);
+
+	return (uintptr_t)mmio_read_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR));
+}
+
+void mcucfg_init_archstate(unsigned int cluster, unsigned int cpu, bool arm64)
+{
+	uint32_t reg;
+
+	assert(cluster == 0U);
+
+	reg = per_cluster(cluster, MCUCFG_INITARCH);
+
+	if (arm64) {
+		mmio_setbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu));
+	} else {
+		mmio_clrbits_32(reg, MCUCFG_INITARCH_CPU_BIT(cpu));
+	}
+}
+
+/*
+ * Return subsystem's power state.
+ *
+ * @mask: mask to SPM_CPU_PWR_STATUS to query the power state
+ *        of one subsystem.
+ * RETURNS:
+ * 0 (the subsys was powered off)
+ * 1 (the subsys was powered on)
+ */
+bool spm_get_powerstate(uint32_t mask)
+{
+	return (mmio_read_32(SPM_CPU_PWR_STATUS) & mask);
+}
+
+bool spm_get_cluster_powerstate(unsigned int cluster)
+{
+	assert(cluster == 0U);
+
+	return spm_get_powerstate(MP0_CPUTOP);
+}
+
+bool spm_get_cpu_powerstate(unsigned int cluster, unsigned int cpu)
+{
+	uint32_t mask = BIT(cpu);
+
+	assert(cluster == 0U);
+
+	return spm_get_powerstate(mask);
+}
+
+int spmc_init(void)
+{
+	unsigned int cpu = plat_my_core_pos();
+
+
+	INFO("SPM: enable CPC mode\n");
+
+	mmio_write_32(SPM_POWERON_CONFIG_EN, PROJECT_CODE | BCLK_CG_EN);
+
+	mmio_setbits_32(per_cpu(0, 1, SPM_CPU_PWR), PWR_RST_B);
+	mmio_setbits_32(per_cpu(0, 2, SPM_CPU_PWR), PWR_RST_B);
+	mmio_setbits_32(per_cpu(0, 3, SPM_CPU_PWR), PWR_RST_B);
+	mmio_setbits_32(per_cpu(0, 4, SPM_CPU_PWR), PWR_RST_B);
+	mmio_setbits_32(per_cpu(0, 5, SPM_CPU_PWR), PWR_RST_B);
+	mmio_setbits_32(per_cpu(0, 6, SPM_CPU_PWR), PWR_RST_B);
+	mmio_setbits_32(per_cpu(0, 7, SPM_CPU_PWR), PWR_RST_B);
+
+	mmio_clrbits_32(SPM_MCUSYS_PWR_CON, RESETPWRON_CONFIG);
+	mmio_clrbits_32(SPM_MP0_CPUTOP_PWR_CON, RESETPWRON_CONFIG);
+	mmio_clrbits_32(per_cpu(0, 0, SPM_CPU_PWR), RESETPWRON_CONFIG);
+
+	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, CPC_CTRL_ENABLE);
+
+	/* Clear bootup cpu's cpc sw hint */
+	mmio_write_32(CPC_MCUSYS_CPU_ON_SW_HINT_CLR, BIT(cpu));
+
+	return 0;
+}
+
+/*
+ * Power on a core with specified cluster and core index
+ *
+ * @cluster: the cluster ID of the CPU which to be powered on
+ * @cpu: the CPU ID of the CPU which to be powered on
+ */
+void spm_poweron_cpu(unsigned int cluster, unsigned int cpu)
+{
+	/* info CPC that CPU hotplug on */
+	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN);
+
+	/* Set mp0_spmc_pwr_on_cpuX = 1 */
+	mmio_setbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON);
+
+	/* wait for power on ack */
+	while (!spm_get_cpu_powerstate(cluster, cpu))
+		;
+
+	/* info CPC that CPU hotplug off */
+	mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN);
+}
+
+/*
+ * Power off a core with specified cluster and core index
+ *
+ * @cluster: the cluster ID of the CPU which to be powered off
+ * @cpu: the CPU ID of the CPU which to be powered off
+ */
+void spm_poweroff_cpu(unsigned int cluster, unsigned int cpu)
+{
+	/* Set mp0_spmc_pwr_on_cpuX = 0 */
+	mmio_clrbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON);
+}
+
+/*
+ * Power off a cluster with specified index
+ *
+ * @cluster: the cluster index which to be powered off
+ */
+void spm_poweroff_cluster(unsigned int cluster)
+{
+	/* No need to power on/off cluster on single cluster platform */
+	assert(false);
+}
+
+/*
+ * Power on a cluster with specified index
+ *
+ * @cluster: the cluster index which to be powered on
+ */
+void spm_poweron_cluster(unsigned int cluster)
+{
+	/* No need to power on/off cluster on single cluster platform */
+	assert(false);
+}
diff --git a/plat/mediatek/mt8186/drivers/spmc/mtspmc.h b/plat/mediatek/mt8186/drivers/spmc/mtspmc.h
new file mode 100644
index 0000000..768599b
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spmc/mtspmc.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTSPMC_H
+#define MTSPMC_H
+
+#include <stdint.h>
+
+int spmc_init(void);
+
+void spm_poweron_cpu(unsigned int cluster, unsigned int cpu);
+void spm_poweroff_cpu(unsigned int cluster, unsigned int cpu);
+
+void spm_poweroff_cluster(unsigned int cluster);
+void spm_poweron_cluster(unsigned int cluster);
+
+bool spm_get_cpu_powerstate(unsigned int cluster, unsigned int cpu);
+bool spm_get_cluster_powerstate(unsigned int cluster);
+bool spm_get_powerstate(uint32_t mask);
+
+void mcucfg_init_archstate(unsigned int cluster, unsigned int cpu, bool arm64);
+void mcucfg_set_bootaddr(unsigned int cluster, unsigned int cpu, uintptr_t bootaddr);
+uintptr_t mcucfg_get_bootaddr(unsigned int cluster, unsigned int cpu);
+
+void mcucfg_disable_gic_wakeup(unsigned int cluster, unsigned int cpu);
+void mcucfg_enable_gic_wakeup(unsigned int cluster, unsigned int cpu);
+
+#endif /* MTSPMC_H */
diff --git a/plat/mediatek/mt8186/drivers/spmc/mtspmc_private.h b/plat/mediatek/mt8186/drivers/spmc/mtspmc_private.h
new file mode 100644
index 0000000..472b54c
--- /dev/null
+++ b/plat/mediatek/mt8186/drivers/spmc/mtspmc_private.h
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTSPMC_PRIVATE_H
+#define MTSPMC_PRIVATE_H
+
+#include <lib/utils_def.h>
+#include <platform_def.h>
+
+unsigned long read_cpuectlr(void);
+void write_cpuectlr(unsigned long cpuectlr);
+
+unsigned long read_cpupwrctlr_el1(void);
+void write_cpupwrctlr_el1(unsigned long cpuectlr);
+
+/* per_cpu/cluster helper */
+struct per_cpu_reg {
+	unsigned int cluster_addr;
+	unsigned int cpu_stride;
+};
+
+#define per_cpu(cluster, cpu, reg)	\
+	(reg[cluster].cluster_addr + (cpu << reg[cluster].cpu_stride))
+
+#define per_cluster(cluster, reg)	(reg[cluster].cluster_addr)
+
+#define SPM_REG(ofs)			(uint32_t)(SPM_BASE + (ofs))
+#define MCUCFG_REG(ofs)			(uint32_t)(MCUCFG_BASE + (ofs))
+#define INFRACFG_AO_REG(ofs)		(uint32_t)(INFRACFG_AO_BASE + (ofs))
+
+/* SPMC related registers */
+#define SPM_POWERON_CONFIG_EN		SPM_REG(0x000)
+/* bit-fields of SPM_POWERON_CONFIG_EN */
+#define PROJECT_CODE			(U(0xb16) << 16)
+#define BCLK_CG_EN			BIT(0)
+
+#define SPM_PWR_STATUS			SPM_REG(0x16c)
+#define SPM_PWR_STATUS_2ND		SPM_REG(0x170)
+#define SPM_CPU_PWR_STATUS		SPM_REG(0x174)
+
+/* bit-fields of SPM_PWR_STATUS */
+#define MD				BIT(0)
+#define CONN				BIT(1)
+#define DDRPHY				BIT(2)
+#define DISP				BIT(3)
+#define MFG				BIT(4)
+#define ISP				BIT(5)
+#define INFRA				BIT(6)
+#define VDEC				BIT(7)
+#define MP0_CPUTOP			BIT(8)
+#define MP0_CPU0			BIT(9)
+#define MP0_CPU1			BIT(10)
+#define MP0_CPU2			BIT(11)
+#define MP0_CPU3			BIT(12)
+#define MCUSYS				BIT(14)
+#define MP0_CPU4			BIT(15)
+#define MP0_CPU5			BIT(16)
+#define MP0_CPU6			BIT(17)
+#define MP0_CPU7			BIT(18)
+#define VEN				BIT(21)
+
+/* SPMC related registers */
+#define SPM_MCUSYS_PWR_CON		SPM_REG(0x200)
+#define SPM_MP0_CPUTOP_PWR_CON		SPM_REG(0x204)
+#define SPM_MP0_CPU0_PWR_CON		SPM_REG(0x208)
+#define SPM_MP0_CPU1_PWR_CON		SPM_REG(0x20c)
+#define SPM_MP0_CPU2_PWR_CON		SPM_REG(0x210)
+#define SPM_MP0_CPU3_PWR_CON		SPM_REG(0x214)
+#define SPM_MP0_CPU4_PWR_CON		SPM_REG(0x218)
+#define SPM_MP0_CPU5_PWR_CON		SPM_REG(0x21c)
+#define SPM_MP0_CPU6_PWR_CON		SPM_REG(0x220)
+#define SPM_MP0_CPU7_PWR_CON		SPM_REG(0x224)
+
+/* 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)
+
+/* per_cpu registers for SPM_MP0_CPU_PWR_CON */
+static const struct per_cpu_reg SPM_CPU_PWR[] = {
+	{ .cluster_addr = SPM_MP0_CPU0_PWR_CON, .cpu_stride = 2U }
+};
+
+/* per_cluster registers for SPM_MP0_CPUTOP_PWR_CON */
+static const struct per_cpu_reg SPM_CLUSTER_PWR[] = {
+	{ .cluster_addr = SPM_MP0_CPUTOP_PWR_CON, .cpu_stride = 0U }
+};
+
+/* MCUCFG related registers */
+#define MCUCFG_MP0_CLUSTER_CFG5		MCUCFG_REG(0xc8e4)
+/* reset vectors */
+#define MCUCFG_MP0_CLUSTER_CFG8		MCUCFG_REG(0xc900)
+#define MCUCFG_MP0_CLUSTER_CFG10	MCUCFG_REG(0xc908)
+#define MCUCFG_MP0_CLUSTER_CFG12	MCUCFG_REG(0xc910)
+#define MCUCFG_MP0_CLUSTER_CFG14	MCUCFG_REG(0xc918)
+#define MCUCFG_MP0_CLUSTER_CFG16	MCUCFG_REG(0xc920)
+#define MCUCFG_MP0_CLUSTER_CFG18	MCUCFG_REG(0xc928)
+#define MCUCFG_MP0_CLUSTER_CFG20	MCUCFG_REG(0xc930)
+#define MCUCFG_MP0_CLUSTER_CFG22	MCUCFG_REG(0xc938)
+
+/* per_cpu registers for MCUCFG_MP0_CLUSTER_CFG */
+static const struct per_cpu_reg MCUCFG_BOOTADDR[] = {
+	{ .cluster_addr = MCUCFG_MP0_CLUSTER_CFG8, .cpu_stride = 3U }
+};
+
+/* per_cpu registers for MCUCFG_MP0_CLUSTER_CFG5 */
+static const struct per_cpu_reg MCUCFG_INITARCH[] = {
+	{ .cluster_addr = MCUCFG_MP0_CLUSTER_CFG5, .cpu_stride = 0U }
+};
+
+#define MCUCFG_INITARCH_CPU_BIT(cpu)	BIT(16U + cpu)
+/* CPC control */
+#define MCUCFG_CPC_FLOW_CTRL_CFG	MCUCFG_REG(0xa814)
+#define MCUCFG_CPC_SPMC_PWR_STATUS	MCUCFG_REG(0xa840)
+
+/* bit-fields of CPC_FLOW_CTRL_CFG */
+#define CPC_CTRL_ENABLE			BIT(16)
+#define SSPM_ALL_PWR_CTRL_EN		BIT(13) /* for cpu-hotplug */
+#define GIC_WAKEUP_IGNORE(cpu)		BIT(21 + cpu)
+
+/* bit-fields of CPC_SPMC_PWR_STATUS */
+#define CORE_SPMC_PWR_ON_ACK		GENMASK(11, 0)
+
+/* APB module infracfg_ao */
+#define INFRA_TOPAXI_PROTECTEN		INFRACFG_AO_REG(0x0220)
+#define INFRA_TOPAXI_PROTECTEN_STA0	INFRACFG_AO_REG(0x0224)
+#define INFRA_TOPAXI_PROTECTEN_STA1	INFRACFG_AO_REG(0x0228)
+#define INFRA_TOPAXI_PROTECTEN_SET	INFRACFG_AO_REG(0x02a0)
+#define INFRA_TOPAXI_PROTECTEN_CLR	INFRACFG_AO_REG(0x02a4)
+#define INFRA_TOPAXI_PROTECTEN_1	INFRACFG_AO_REG(0x0250)
+#define INFRA_TOPAXI_PROTECTEN_STA0_1	INFRACFG_AO_REG(0x0254)
+#define INFRA_TOPAXI_PROTECTEN_STA1_1	INFRACFG_AO_REG(0x0258)
+#define INFRA_TOPAXI_PROTECTEN_1_SET	INFRACFG_AO_REG(0x02a8)
+#define INFRA_TOPAXI_PROTECTEN_1_CLR	INFRACFG_AO_REG(0x02ac)
+
+/* bit-fields of INFRA_TOPAXI_PROTECTEN */
+#define MP0_SPMC_PROT_STEP1_0_MASK	BIT(12)
+#define MP0_SPMC_PROT_STEP1_1_MASK	(BIT(26) | BIT(12))
+
+/* SPARK */
+#define VOLTAGE_04			U(0x40)
+#define VOLTAGE_05			U(0x60)
+
+#define PTP3_CPU0_SPMC_SW_CFG		MCUCFG_REG(0x200)
+#define CPU0_ILDO_CONTROL5		MCUCFG_REG(0x334)
+#define CPU0_ILDO_CONTROL8		MCUCFG_REG(0x340)
+
+/* bit-fields of CPU0_ILDO_CONTROL5 */
+#define ILDO_RET_VOSEL			GENMASK(7, 0)
+
+/* bit-fields of PTP3_CPU_SPMC_SW_CFG */
+#define SW_SPARK_EN			BIT(0)
+
+/* bit-fields of CPU0_ILDO_CONTROL8 */
+#define ILDO_BYPASS_B			BIT(0)
+
+static const struct per_cpu_reg MCUCFG_SPARK[] = {
+	{ .cluster_addr = PTP3_CPU0_SPMC_SW_CFG, .cpu_stride = 11U }
+};
+
+static const struct per_cpu_reg ILDO_CONTROL5[] = {
+	{ .cluster_addr = CPU0_ILDO_CONTROL5, .cpu_stride = 11U }
+};
+
+static const struct per_cpu_reg ILDO_CONTROL8[] = {
+	{ .cluster_addr = CPU0_ILDO_CONTROL8, .cpu_stride = 11U }
+};
+
+#endif /* MTSPMC_PRIVATE_H */
diff --git a/plat/mediatek/mt8186/include/mcucfg.h b/plat/mediatek/mt8186/include/mcucfg.h
new file mode 100644
index 0000000..78a01a8
--- /dev/null
+++ b/plat/mediatek/mt8186/include/mcucfg.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MCUCFG_H
+#define MCUCFG_H
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+#endif /* __ASSEMBLER__ */
+
+#include <platform_def.h>
+
+#define MCUCFG_REG(ofs)			(uint32_t)(MCUCFG_BASE + (ofs))
+
+#define MP2_MISC_CONFIG_BOOT_ADDR_L(cpu) (MCUCFG_REG(0x2290) + ((cpu) * 8))
+#define MP2_MISC_CONFIG_BOOT_ADDR_H(cpu) (MCUCFG_REG(0x2294) + ((cpu) * 8))
+
+#define MP2_CPUCFG			MCUCFG_REG(0x2208)
+
+#define MP2_CPU0_STANDBYWFE		BIT(4)
+#define MP2_CPU1_STANDBYWFE		BIT(5)
+
+#define MP0_CPUTOP_SPMC_CTL		MCUCFG_REG(0x788)
+#define MP1_CPUTOP_SPMC_CTL		MCUCFG_REG(0x78C)
+#define MP1_CPUTOP_SPMC_SRAM_CTL	MCUCFG_REG(0x790)
+
+#define sw_spark_en			BIT(0)
+#define sw_no_wait_for_q_channel	BIT(1)
+#define sw_fsm_override			BIT(2)
+#define sw_logic_pre1_pdb		BIT(3)
+#define sw_logic_pre2_pdb		BIT(4)
+#define sw_logic_pdb			BIT(5)
+#define sw_iso				BIT(6)
+#define sw_sram_sleepb			(U(0x3F) << 7)
+#define sw_sram_isointb			BIT(13)
+#define sw_clk_dis			BIT(14)
+#define sw_ckiso			BIT(15)
+#define sw_pd				(U(0x3F) << 16)
+#define sw_hot_plug_reset		BIT(22)
+#define sw_pwr_on_override_en		BIT(23)
+#define sw_pwr_on			BIT(24)
+#define sw_coq_dis			BIT(25)
+#define logic_pdbo_all_off_ack		BIT(26)
+#define logic_pdbo_all_on_ack		BIT(27)
+#define logic_pre2_pdbo_all_on_ack	BIT(28)
+#define logic_pre1_pdbo_all_on_ack	BIT(29)
+
+
+#define CPUSYSx_CPUx_SPMC_CTL(cluster, cpu) \
+	(MCUCFG_REG(0x1c30) + cluster * 0x2000 + cpu * 4)
+
+#define CPUSYS0_CPU0_SPMC_CTL		MCUCFG_REG(0x1c30)
+#define CPUSYS0_CPU1_SPMC_CTL		MCUCFG_REG(0x1c34)
+#define CPUSYS0_CPU2_SPMC_CTL		MCUCFG_REG(0x1c38)
+#define CPUSYS0_CPU3_SPMC_CTL		MCUCFG_REG(0x1c3C)
+
+#define CPUSYS1_CPU0_SPMC_CTL		MCUCFG_REG(0x3c30)
+#define CPUSYS1_CPU1_SPMC_CTL		MCUCFG_REG(0x3c34)
+#define CPUSYS1_CPU2_SPMC_CTL		MCUCFG_REG(0x3c38)
+#define CPUSYS1_CPU3_SPMC_CTL		MCUCFG_REG(0x3c3C)
+
+#define cpu_sw_spark_en			BIT(0)
+#define cpu_sw_no_wait_for_q_channel	BIT(1)
+#define cpu_sw_fsm_override		BIT(2)
+#define cpu_sw_logic_pre1_pdb		BIT(3)
+#define cpu_sw_logic_pre2_pdb		BIT(4)
+#define cpu_sw_logic_pdb		BIT(5)
+#define cpu_sw_iso			BIT(6)
+#define cpu_sw_sram_sleepb		BIT(7)
+#define cpu_sw_sram_isointb		BIT(8)
+#define cpu_sw_clk_dis			BIT(9)
+#define cpu_sw_ckiso			BIT(10)
+#define cpu_sw_pd			(U(0x1F) << 11)
+#define cpu_sw_hot_plug_reset		BIT(16)
+#define cpu_sw_powr_on_override_en	BIT(17)
+#define cpu_sw_pwr_on			BIT(18)
+#define cpu_spark2ldo_allswoff		BIT(19)
+#define cpu_pdbo_all_on_ack		BIT(20)
+#define cpu_pre2_pdbo_allon_ack		BIT(21)
+#define cpu_pre1_pdbo_allon_ack		BIT(22)
+
+/* CPC related registers */
+#define CPC_MCUSYS_CPC_OFF_THRES		MCUCFG_REG(0xa714)
+#define CPC_MCUSYS_PWR_CTRL			MCUCFG_REG(0xa804)
+#define CPC_MCUSYS_CPC_FLOW_CTRL_CFG		MCUCFG_REG(0xa814)
+#define CPC_MCUSYS_LAST_CORE_REQ		MCUCFG_REG(0xa818)
+#define CPC_MCUSYS_MP_LAST_CORE_RESP		MCUCFG_REG(0xa81c)
+#define CPC_MCUSYS_LAST_CORE_RESP		MCUCFG_REG(0xa824)
+#define CPC_MCUSYS_PWR_ON_MASK			MCUCFG_REG(0xa828)
+#define CPC_MCUSYS_CPU_ON_SW_HINT_SET		MCUCFG_REG(0xa8a8)
+#define CPC_MCUSYS_CPU_ON_SW_HINT_CLR		MCUCFG_REG(0xa8ac)
+#define CPC_MCUSYS_CPC_DBG_SETTING		MCUCFG_REG(0xab00)
+#define CPC_MCUSYS_CPC_KERNEL_TIME_L_BASE	MCUCFG_REG(0xab04)
+#define CPC_MCUSYS_CPC_KERNEL_TIME_H_BASE	MCUCFG_REG(0xab08)
+#define CPC_MCUSYS_CPC_SYSTEM_TIME_L_BASE	MCUCFG_REG(0xab0c)
+#define CPC_MCUSYS_CPC_SYSTEM_TIME_H_BASE	MCUCFG_REG(0xab10)
+#define CPC_MCUSYS_TRACE_SEL			MCUCFG_REG(0xab14)
+#define CPC_MCUSYS_TRACE_DATA			MCUCFG_REG(0xab20)
+#define CPC_MCUSYS_CLUSTER_COUNTER		MCUCFG_REG(0xab70)
+#define CPC_MCUSYS_CLUSTER_COUNTER_CLR		MCUCFG_REG(0xab74)
+#define SPARK2LDO				MCUCFG_REG(0x2700)
+/* APB module mcucfg */
+#define MP0_CA7_CACHE_CONFIG		MCUCFG_REG(0x000)
+#define MP0_AXI_CONFIG			MCUCFG_REG(0x02C)
+#define MP0_MISC_CONFIG0		MCUCFG_REG(0x030)
+#define MP0_MISC_CONFIG1		MCUCFG_REG(0x034)
+#define MP0_MISC_CONFIG2		MCUCFG_REG(0x038)
+#define MP0_MISC_CONFIG_BOOT_ADDR(cpu)	(MP0_MISC_CONFIG2 + ((cpu) * 8))
+#define MP0_MISC_CONFIG3		MCUCFG_REG(0x03C)
+#define MP0_MISC_CONFIG9		MCUCFG_REG(0x054)
+#define MP0_CA7_MISC_CONFIG		MCUCFG_REG(0x064)
+
+#define MP0_RW_RSVD0			MCUCFG_REG(0x06C)
+
+
+#define MP1_CA7_CACHE_CONFIG		MCUCFG_REG(0x200)
+#define MP1_AXI_CONFIG			MCUCFG_REG(0x22C)
+#define MP1_MISC_CONFIG0		MCUCFG_REG(0x230)
+#define MP1_MISC_CONFIG1		MCUCFG_REG(0x234)
+#define MP1_MISC_CONFIG2		MCUCFG_REG(0x238)
+#define MP1_MISC_CONFIG_BOOT_ADDR(cpu)	(MP1_MISC_CONFIG2 + ((cpu) * 8))
+#define MP1_MISC_CONFIG3		MCUCFG_REG(0x23C)
+#define MP1_MISC_CONFIG9		MCUCFG_REG(0x254)
+#define MP1_CA7_MISC_CONFIG		MCUCFG_REG(0x264)
+
+#define CCI_ADB400_DCM_CONFIG		MCUCFG_REG(0x740)
+#define SYNC_DCM_CONFIG			MCUCFG_REG(0x744)
+
+#define MP0_CLUSTER_CFG0		MCUCFG_REG(0xC8D0)
+
+#define MP0_SPMC			MCUCFG_REG(0x788)
+#define MP1_SPMC			MCUCFG_REG(0x78C)
+#define MP2_AXI_CONFIG			MCUCFG_REG(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_REG(0x1c00)
+#define CPUSYS0_SPARKEN			MCUCFG_REG(0x1c04)
+#define CPUSYS0_AMUXSEL			MCUCFG_REG(0x1c08)
+#define CPUSYS1_SPARKVRETCNTRL		MCUCFG_REG(0x3c00)
+#define CPUSYS1_SPARKEN			MCUCFG_REG(0x3c04)
+#define CPUSYS1_AMUXSEL			MCUCFG_REG(0x3c08)
+
+#define MP2_PWR_RST_CTL			MCUCFG_REG(0x2008)
+#define MP2_PTP3_CPUTOP_SPMC0		MCUCFG_REG(0x22A0)
+#define MP2_PTP3_CPUTOP_SPMC1		MCUCFG_REG(0x22A4)
+
+#define MP2_COQ				MCUCFG_REG(0x22BC)
+#define MP2_COQ_SW_DIS			BIT(0)
+
+#define MP2_CA15M_MON_SEL		MCUCFG_REG(0x2400)
+#define MP2_CA15M_MON_L			MCUCFG_REG(0x2404)
+
+#define CPUSYS2_CPU0_SPMC_CTL		MCUCFG_REG(0x2430)
+#define CPUSYS2_CPU1_SPMC_CTL		MCUCFG_REG(0x2438)
+#define CPUSYS2_CPU0_SPMC_STA		MCUCFG_REG(0x2434)
+#define CPUSYS2_CPU1_SPMC_STA		MCUCFG_REG(0x243C)
+
+#define MP0_CA7L_DBG_PWR_CTRL		MCUCFG_REG(0x068)
+#define MP1_CA7L_DBG_PWR_CTRL		MCUCFG_REG(0x268)
+#define BIG_DBG_PWR_CTRL		MCUCFG_REG(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			(18U)
+#define B_SW_PD				(U(0x3f) << B_SW_PD_OFFSET)
+
+#define B_SW_SRAM_SLEEPB_OFFSET		(12U)
+#define B_SW_SRAM_SLEEPB		(U(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		(6U)
+#define B_FSM_STATE_OUT_MASK		(U(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_CPUCFG_64BIT_SHIFT = 12U,
+	MP1_CPUCFG_64BIT_SHIFT = 28U,
+	MP0_CPUCFG_64BIT = U(0xf) << MP0_CPUCFG_64BIT_SHIFT,
+	MP1_CPUCFG_64BIT = U(0xf) << MP1_CPUCFG_64BIT_SHIFT
+};
+
+enum {
+	MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT = 0U,
+	MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT = 4U,
+	MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT = 8U,
+	MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT = 12U,
+	MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT = 16U,
+
+	MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK =
+		U(0xf) << MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK =
+		U(0xf) << MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK =
+		U(0xf) << MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK =
+		U(0xf) << MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT,
+	MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK =
+		U(0xf) << MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT
+};
+
+enum {
+	MP1_AINACTS_SHIFT = 4U,
+	MP1_AINACTS = 1U << MP1_AINACTS_SHIFT
+};
+
+enum {
+	MP1_SW_CG_GEN_SHIFT = 12U,
+	MP1_SW_CG_GEN = 1U << MP1_SW_CG_GEN_SHIFT
+};
+
+enum {
+	MP1_L2RSTDISABLE_SHIFT = 14U,
+	MP1_L2RSTDISABLE = 1U << MP1_L2RSTDISABLE_SHIFT
+};
+#endif /* __ASSEMBLER__ */
+
+#endif  /* MCUCFG_H */
diff --git a/plat/mediatek/mt8186/include/plat_mtk_lpm.h b/plat/mediatek/mt8186/include/plat_mtk_lpm.h
new file mode 100644
index 0000000..347f358
--- /dev/null
+++ b/plat/mediatek/mt8186/include/plat_mtk_lpm.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MTK_LPM_H
+#define PLAT_MTK_LPM_H
+
+#include <lib/psci/psci.h>
+#include <lib/utils_def.h>
+
+#define MT_IRQ_REMAIN_MAX	U(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];
+};
+
+#define PLAT_RC_STATUS_READY		BIT(0)
+#define PLAT_RC_STATUS_FEATURE_EN	BIT(1)
+#define PLAT_RC_STATUS_UART_NONSLEEP	BIT(31)
+
+struct mt_lpm_tz {
+	int (*pwr_prompt)(unsigned int cpu, const psci_power_state_t *state);
+	int (*pwr_reflect)(unsigned int cpu, const psci_power_state_t *state);
+
+	int (*pwr_cpu_on)(unsigned int cpu, const psci_power_state_t *state);
+	int (*pwr_cpu_dwn)(unsigned int cpu, const psci_power_state_t *state);
+
+	int (*pwr_cluster_on)(unsigned int cpu,
+					const psci_power_state_t *state);
+	int (*pwr_cluster_dwn)(unsigned int cpu,
+					const psci_power_state_t *state);
+
+	int (*pwr_mcusys_on)(unsigned int cpu, const psci_power_state_t *state);
+	int (*pwr_mcusys_on_finished)(unsigned int cpu,
+					const psci_power_state_t *state);
+	int (*pwr_mcusys_dwn)(unsigned int cpu,
+					const psci_power_state_t *state);
+};
+
+const struct mt_lpm_tz *mt_plat_cpu_pm_init(void);
+
+#endif /* PLAT_MTK_LPM_H */
diff --git a/plat/mediatek/mt8186/include/plat_pm.h b/plat/mediatek/mt8186/include/plat_pm.h
new file mode 100644
index 0000000..436db34
--- /dev/null
+++ b/plat/mediatek/mt8186/include/plat_pm.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PM_H
+#define PLAT_PM_H
+
+#include <lib/utils_def.h>
+
+#define MT_PLAT_PWR_STATE_CPU			U(1)
+#define MT_PLAT_PWR_STATE_CLUSTER		U(2)
+#define MT_PLAT_PWR_STATE_MCUSYS		U(3)
+#define MT_PLAT_PWR_STATE_SUSPEND2IDLE		U(8)
+#define MT_PLAT_PWR_STATE_SYSTEM_SUSPEND	U(9)
+
+#define MTK_LOCAL_STATE_RUN			U(0)
+#define MTK_LOCAL_STATE_RET			U(1)
+#define MTK_LOCAL_STATE_OFF			U(2)
+
+#define MTK_AFFLVL_CPU				U(0)
+#define MTK_AFFLVL_CLUSTER			U(1)
+#define MTK_AFFLVL_MCUSYS			U(2)
+#define MTK_AFFLVL_SYSTEM			U(3)
+
+#define IS_CLUSTER_OFF_STATE(s)					\
+		is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_CLUSTER])
+#define IS_MCUSYS_OFF_STATE(s)					\
+		is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_MCUSYS])
+#define IS_SYSTEM_SUSPEND_STATE(s)				\
+		is_local_state_off(s->pwr_domain_state[MTK_AFFLVL_SYSTEM])
+
+#define IS_PLAT_SUSPEND_ID(stateid)				\
+		((stateid == MT_PLAT_PWR_STATE_SUSPEND2IDLE)	\
+		|| (stateid == MT_PLAT_PWR_STATE_SYSTEM_SUSPEND))
+
+#endif /* PLAT_PM_H */
diff --git a/plat/mediatek/mt8186/include/plat_sip_calls.h b/plat/mediatek/mt8186/include/plat_sip_calls.h
new file mode 100644
index 0000000..598a5b8
--- /dev/null
+++ b/plat/mediatek/mt8186/include/plat_sip_calls.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_SIP_CALLS_H
+#define PLAT_SIP_CALLS_H
+
+/*******************************************************************************
+ * Plat SiP function constants
+ ******************************************************************************/
+#define MTK_PLAT_SIP_NUM_CALLS    0
+
+#endif /* PLAT_SIP_CALLS_H */
diff --git a/plat/mediatek/mt8186/include/platform_def.h b/plat/mediatek/mt8186/include/platform_def.h
index bf1bbef..479a8d4 100644
--- a/plat/mediatek/mt8186/include/platform_def.h
+++ b/plat/mediatek/mt8186/include/platform_def.h
@@ -15,20 +15,52 @@
 
 /* Aggregate of all devices for MMU mapping */
 #define MTK_DEV_RNG0_BASE	IO_PHYS
-#define MTK_DEV_RNG0_SIZE	0x400000
-#define MTK_DEV_RNG1_BASE	(IO_PHYS + 0x1000000)
-#define MTK_DEV_RNG1_SIZE	0xa110000
+#define MTK_DEV_RNG0_SIZE	0x10000000
 #define MTK_DEV_RNG2_BASE	MT_GIC_BASE
 #define MTK_DEV_RNG2_SIZE	0x600000
 
+#define SPM_BASE		(IO_PHYS + 0x00006000)
 
 /*******************************************************************************
+ * GPIO related constants
+ ******************************************************************************/
+#define GPIO_BASE		(IO_PHYS + 0x00005000)
+#define IOCFG_LT_BASE		(IO_PHYS + 0x00002000)
+#define IOCFG_LM_BASE		(IO_PHYS + 0x00002200)
+#define IOCFG_LB_BASE		(IO_PHYS + 0x00002400)
+#define IOCFG_BL_BASE		(IO_PHYS + 0x00002600)
+#define IOCFG_RB_BASE		(IO_PHYS + 0x00002A00)
+#define IOCFG_RT_BASE		(IO_PHYS + 0x00002C00)
+
+/*******************************************************************************
  * UART related constants
  ******************************************************************************/
 #define UART0_BASE			(IO_PHYS + 0x01002000)
 
 #define UART_BAUDRATE			115200
 
+/*******************************************************************************
+ * PWRAP related constants
+ ******************************************************************************/
+#define PMIC_WRAP_BASE			(IO_PHYS + 0x0000D000)
+
+/*******************************************************************************
+ * EMI MPU related constants
+ ******************************************************************************/
+#define EMI_MPU_BASE		(IO_PHYS + 0x0021B000)
+
+/*******************************************************************************
+ * GIC-600 & interrupt handling related constants
+ ******************************************************************************/
+/* Base MTK_platform compatible GIC memory map */
+#define BASE_GICD_BASE			MT_GIC_BASE
+#define MT_GIC_RDIST_BASE		(MT_GIC_BASE + 0x40000)
+
+#define SYS_CIRQ_BASE			(IO_PHYS + 0x204000)
+#define CIRQ_REG_NUM			11
+#define CIRQ_IRQ_NUM			326
+#define CIRQ_SPI_START			64
+#define MD_WDT_IRQ_BIT_ID		107
 /*******************************************************************************
  * System counter frequency related constants
  ******************************************************************************/
diff --git a/plat/mediatek/mt8186/plat_pm.c b/plat/mediatek/mt8186/plat_pm.c
index 61d2cc9..e8d834d 100644
--- a/plat/mediatek/mt8186/plat_pm.c
+++ b/plat/mediatek/mt8186/plat_pm.c
@@ -4,15 +4,397 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+/* common headers */
+#include <assert.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/gpio.h>
 #include <lib/psci/psci.h>
 
+/* platform specific headers */
+#include <mt_gic_v3.h>
+#include <mtspmc.h>
+#include <plat/common/platform.h>
+#include <plat_mtk_lpm.h>
+#include <plat_params.h>
+#include <plat_pm.h>
+#include <pmic.h>
+#include <rtc.h>
+
+/*
+ * Cluster state request:
+ * [0] : The CPU requires cluster power down
+ * [1] : The CPU requires 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)
+
+/* platform secure entry point */
+static uintptr_t secure_entrypoint;
+/* per-CPU power state */
+static unsigned int plat_power_state[PLATFORM_CORE_COUNT];
+
+/* platform CPU power domain - ops */
+static const struct mt_lpm_tz *plat_mt_pm;
+
+static inline int plat_mt_pm_invoke(int (*func)(unsigned int cpu,
+						const psci_power_state_t *state),
+				    int cpu, const psci_power_state_t *state)
+{
+	int ret = -1;
+
+	if (func != NULL) {
+		ret = func(cpu, state);
+	}
+	return ret;
+}
+
+/*
+ * Common MTK_platform operations to power on/off a
+ * CPU in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
+ */
+static void plat_cpu_pwrdwn_common(unsigned int cpu,
+		const psci_power_state_t *state, unsigned int req_pstate)
+{
+	assert(cpu == plat_my_core_pos());
+	assert(plat_mt_pm != NULL);
+
+	(void)plat_mt_pm_invoke(plat_mt_pm->pwr_cpu_dwn, cpu, state);
+
+	if ((psci_get_pstate_pwrlvl(req_pstate) >= MTK_AFFLVL_CLUSTER) ||
+			(req_pstate == 0U)) { /* hotplug off */
+		coordinate_cluster_pwroff();
+	}
+
+	/* Prevent interrupts from spuriously waking up this CPU */
+	mt_gic_rdistif_save();
+	gicv3_cpuif_disable(cpu);
+	gicv3_rdistif_off(cpu);
+}
+
+static void plat_cpu_pwron_common(unsigned int cpu,
+		const psci_power_state_t *state, unsigned int req_pstate)
+{
+	assert(cpu == plat_my_core_pos());
+	assert(plat_mt_pm != NULL);
+
+	(void)plat_mt_pm_invoke(plat_mt_pm->pwr_cpu_on, cpu, state);
+
+	coordinate_cluster_pwron();
+
+	/*
+	 * If mcusys does power down before then restore
+	 * all CPUs' GIC Redistributors
+	 */
+	if (IS_MCUSYS_OFF_STATE(state)) {
+		mt_gic_rdistif_restore_all();
+	} else {
+		gicv3_rdistif_on(cpu);
+		gicv3_cpuif_enable(cpu);
+		mt_gic_rdistif_init();
+		mt_gic_rdistif_restore();
+	}
+}
+
+/*
+ * Common MTK_platform operations to power on/off a
+ * cluster in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
+ */
+static void plat_cluster_pwrdwn_common(unsigned int cpu,
+		const psci_power_state_t *state, unsigned int req_pstate)
+{
+	assert(cpu == plat_my_core_pos());
+	assert(plat_mt_pm != NULL);
+
+	if (plat_mt_pm_invoke(plat_mt_pm->pwr_cluster_dwn, cpu, state) != 0) {
+		coordinate_cluster_pwron();
+
+		/*
+		 * TODO:
+		 * Return on fail and add a 'return' here before
+		 * adding any code following the if-block.
+		 */
+	}
+}
+
+static void plat_cluster_pwron_common(unsigned int cpu,
+		const psci_power_state_t *state, unsigned int req_pstate)
+{
+	assert(cpu == plat_my_core_pos());
+	assert(plat_mt_pm != NULL);
+
+	if (plat_mt_pm_invoke(plat_mt_pm->pwr_cluster_on, cpu, state) != 0) {
+		/*
+		 * TODO:
+		 * return on fail and add a 'return' here before
+		 * adding any code following the if-block.
+		 */
+	}
+}
+
+/*
+ * Common MTK_platform operations to power on/off a
+ * mcusys in response to a CPU_ON, CPU_OFF or CPU_SUSPEND request.
+ */
+static void plat_mcusys_pwrdwn_common(unsigned int cpu,
+		const psci_power_state_t *state, unsigned int req_pstate)
+{
+	assert(cpu == plat_my_core_pos());
+	assert(plat_mt_pm != NULL);
+
+	if (plat_mt_pm_invoke(plat_mt_pm->pwr_mcusys_dwn, cpu, state) != 0) {
+		return;		/* return on fail */
+	}
+
+	mt_gic_distif_save();
+	gic_sgi_save_all();
+}
+
+static void plat_mcusys_pwron_common(unsigned int cpu,
+		const psci_power_state_t *state, unsigned int req_pstate)
+{
+	assert(cpu == plat_my_core_pos());
+	assert(plat_mt_pm != NULL);
+
+	if (plat_mt_pm_invoke(plat_mt_pm->pwr_mcusys_on, cpu, state) != 0) {
+		/* return on fail */
+		return;
+	}
+
+	mt_gic_init();
+	mt_gic_distif_restore();
+	gic_sgi_restore_all();
+
+	(void)plat_mt_pm_invoke(plat_mt_pm->pwr_mcusys_on_finished, cpu, state);
+}
+
+/* plat_psci_ops implementation */
+static void plat_cpu_standby(plat_local_state_t cpu_state)
+{
+	uint64_t scr;
+
+	scr = read_scr_el3();
+	write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT);
+
+	isb();
+	dsb();
+	wfi();
+
+	write_scr_el3(scr);
+}
+
+static int plat_power_domain_on(u_register_t mpidr)
+{
+	unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+	unsigned int cluster = 0U;
+
+	if (cpu >= PLATFORM_CORE_COUNT) {
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	if (!spm_get_cluster_powerstate(cluster)) {
+		spm_poweron_cluster(cluster);
+	}
+
+	/* init CPU reset arch as AARCH64 */
+	mcucfg_init_archstate(cluster, cpu, true);
+	mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint);
+	spm_poweron_cpu(cluster, cpu);
+
+	return PSCI_E_SUCCESS;
+}
+
+static void plat_power_domain_on_finish(const psci_power_state_t *state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+	unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+
+	assert(cpu < PLATFORM_CORE_COUNT);
+
+	/* Allow IRQs to wakeup this core in IDLE flow */
+	mcucfg_enable_gic_wakeup(0U, cpu);
+
+	if (IS_CLUSTER_OFF_STATE(state)) {
+		plat_cluster_pwron_common(cpu, state, 0U);
+	}
+
+	plat_cpu_pwron_common(cpu, state, 0U);
+}
+
+static void plat_power_domain_off(const psci_power_state_t *state)
+{
+	unsigned long mpidr = read_mpidr_el1();
+	unsigned int cpu = (unsigned int)plat_core_pos_by_mpidr(mpidr);
+
+	assert(cpu < PLATFORM_CORE_COUNT);
+
+	plat_cpu_pwrdwn_common(cpu, state, 0U);
+	spm_poweroff_cpu(0U, cpu);
+
+	/* prevent unintended IRQs from waking up the hot-unplugged core */
+	mcucfg_disable_gic_wakeup(0U, cpu);
+
+	if (IS_CLUSTER_OFF_STATE(state)) {
+		plat_cluster_pwrdwn_common(cpu, state, 0U);
+	}
+}
+
+static void plat_power_domain_suspend(const psci_power_state_t *state)
+{
+	unsigned int cpu = plat_my_core_pos();
+
+	assert(cpu < PLATFORM_CORE_COUNT);
+	assert(plat_mt_pm != NULL);
+
+	(void)plat_mt_pm_invoke(plat_mt_pm->pwr_prompt, cpu, state);
+
+	/* Perform the common CPU specific operations */
+	plat_cpu_pwrdwn_common(cpu, state, plat_power_state[cpu]);
+
+	if (IS_CLUSTER_OFF_STATE(state)) {
+		/* Perform the common cluster specific operations */
+		plat_cluster_pwrdwn_common(cpu, state, plat_power_state[cpu]);
+	}
+
+	if (IS_MCUSYS_OFF_STATE(state)) {
+		/* Perform the common mcusys specific operations */
+		plat_mcusys_pwrdwn_common(cpu, state, plat_power_state[cpu]);
+	}
+}
+
+static void plat_power_domain_suspend_finish(const psci_power_state_t *state)
+{
+	unsigned int cpu = plat_my_core_pos();
+
+	assert(cpu < PLATFORM_CORE_COUNT);
+	assert(plat_mt_pm != NULL);
+
+	if (IS_MCUSYS_OFF_STATE(state)) {
+		/* Perform the common mcusys specific operations */
+		plat_mcusys_pwron_common(cpu, state, plat_power_state[cpu]);
+	}
+
+	if (IS_CLUSTER_OFF_STATE(state)) {
+		/* Perform the common cluster specific operations */
+		plat_cluster_pwron_common(cpu, state, plat_power_state[cpu]);
+	}
+
+	/* Perform the common CPU specific operations */
+	plat_cpu_pwron_common(cpu, state, plat_power_state[cpu]);
+
+	(void)plat_mt_pm_invoke(plat_mt_pm->pwr_reflect, cpu, state);
+}
+
+static int plat_validate_power_state(unsigned int power_state,
+					psci_power_state_t *req_state)
+{
+	unsigned int pstate = psci_get_pstate_type(power_state);
+	unsigned int aff_lvl = psci_get_pstate_pwrlvl(power_state);
+	unsigned int cpu = plat_my_core_pos();
+
+	if (aff_lvl > PLAT_MAX_PWR_LVL) {
+		return PSCI_E_INVALID_PARAMS;
+	}
+
+	if (pstate == PSTATE_TYPE_STANDBY) {
+		req_state->pwr_domain_state[0] = PLAT_MAX_RET_STATE;
+	} else {
+		unsigned int i;
+		unsigned int pstate_id = psci_get_pstate_id(power_state);
+		plat_local_state_t s = MTK_LOCAL_STATE_OFF;
+
+		/* Use pstate_id to be power domain state */
+		if (pstate_id > s) {
+			s = (plat_local_state_t)pstate_id;
+		}
+
+		for (i = 0U; i <= aff_lvl; i++) {
+			req_state->pwr_domain_state[i] = s;
+		}
+	}
+
+	plat_power_state[cpu] = power_state;
+	return PSCI_E_SUCCESS;
+}
+
+static void plat_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	unsigned int lv;
+	unsigned int cpu = plat_my_core_pos();
+
+	for (lv = PSCI_CPU_PWR_LVL; lv <= PLAT_MAX_PWR_LVL; lv++) {
+		req_state->pwr_domain_state[lv] = PLAT_MAX_OFF_STATE;
+	}
+
+	plat_power_state[cpu] =
+			psci_make_powerstate(
+				MT_PLAT_PWR_STATE_SYSTEM_SUSPEND,
+				PSTATE_TYPE_POWERDOWN, PLAT_MAX_PWR_LVL);
+
+	flush_dcache_range((uintptr_t)
+			&plat_power_state[cpu],
+			sizeof(plat_power_state[cpu]));
+}
+
+/*******************************************************************************
+ * MTK handlers to shutdown/reboot the system
+ ******************************************************************************/
+static void __dead2 plat_mtk_system_reset(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 plat_mtk_system_off(void)
+{
+	INFO("MTK System Off\n");
+
+	rtc_power_off_sequence();
+	pmic_power_off();
+
+	wfi();
+	ERROR("MTK System Off: operation not handled.\n");
+	panic();
+}
+
 static const plat_psci_ops_t plat_psci_ops = {
+	.cpu_standby			= plat_cpu_standby,
+	.pwr_domain_on			= plat_power_domain_on,
+	.pwr_domain_on_finish		= plat_power_domain_on_finish,
+	.pwr_domain_off			= plat_power_domain_off,
+	.pwr_domain_suspend		= plat_power_domain_suspend,
+	.pwr_domain_suspend_finish	= plat_power_domain_suspend_finish,
+	.validate_power_state		= plat_validate_power_state,
+	.get_sys_suspend_power_state	= plat_get_sys_suspend_power_state,
+	.system_off			= plat_mtk_system_off,
+	.system_reset			= plat_mtk_system_reset,
 };
 
 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
 			const plat_psci_ops_t **psci_ops)
 {
 	*psci_ops = &plat_psci_ops;
+	secure_entrypoint = sec_entrypoint;
+
+	/*
+	 * init the warm reset config for boot CPU
+	 * reset arch as AARCH64
+	 * reset addr as function bl31_warm_entrypoint()
+	 */
+	mcucfg_init_archstate(0U, 0U, true);
+	mcucfg_set_bootaddr(0U, 0U, secure_entrypoint);
+
+	spmc_init();
+	plat_mt_pm = mt_plat_cpu_pm_init();
 
 	return 0;
 }
diff --git a/plat/mediatek/mt8186/plat_sip_calls.c b/plat/mediatek/mt8186/plat_sip_calls.c
new file mode 100644
index 0000000..716f3d9
--- /dev/null
+++ b/plat/mediatek/mt8186/plat_sip_calls.c
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+
+uintptr_t mediatek_plat_sip_handler(uint32_t smc_fid,
+				u_register_t x1,
+				u_register_t x2,
+				u_register_t x3,
+				u_register_t x4,
+				void *cookie,
+				void *handle,
+				u_register_t flags)
+{
+	switch (smc_fid) {
+	default:
+		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
+		break;
+	}
+
+	SMC_RET1(handle, SMC_UNK);
+}
diff --git a/plat/mediatek/mt8186/platform.mk b/plat/mediatek/mt8186/platform.mk
index 2d20213..79c6834 100644
--- a/plat/mediatek/mt8186/platform.mk
+++ b/plat/mediatek/mt8186/platform.mk
@@ -8,8 +8,19 @@
 MTK_PLAT_SOC := ${MTK_PLAT}/${PLAT}
 
 PLAT_INCLUDES := -I${MTK_PLAT}/common/                            \
+                 -I${MTK_PLAT}/common/drivers/gic600/             \
+                 -I${MTK_PLAT}/common/drivers/gpio/             \
+                 -I${MTK_PLAT}/common/drivers/timer/              \
+                 -I${MTK_PLAT_SOC}/drivers/dcm/                   \
+                 -I${MTK_PLAT_SOC}/drivers/emi_mpu/               \
+                 -I${MTK_PLAT_SOC}/drivers/gpio/               \
+                 -I${MTK_PLAT_SOC}/drivers/mcdi/                  \
+                 -I${MTK_PLAT_SOC}/drivers/pmic/                  \
+                 -I${MTK_PLAT_SOC}/drivers/rtc/                   \
+                 -I${MTK_PLAT_SOC}/drivers/spmc/                  \
                  -I${MTK_PLAT_SOC}/include/
 
+GICV3_SUPPORT_GIC600        :=      1
 include drivers/arm/gic/v3/gicv3.mk
 include lib/xlat_tables_v2/xlat_tables.mk
 
@@ -20,17 +31,38 @@
 
 
 BL31_SOURCES += common/desc_image_load.c                              \
+                drivers/delay_timer/delay_timer.c                     \
+                drivers/gpio/gpio.c                                   \
+                drivers/delay_timer/generic_delay_timer.c             \
                 drivers/ti/uart/aarch64/16550_console.S               \
                 lib/bl_aux_params/bl_aux_params.c                     \
                 lib/cpus/aarch64/cortex_a55.S                         \
                 lib/cpus/aarch64/cortex_a76.S                         \
                 plat/common/plat_gicv3.c                              \
+                ${MTK_PLAT}/common/drivers/gic600/mt_gic_v3.c         \
+                ${MTK_PLAT}/common/drivers/gpio/mtgpio_common.c       \
+                ${MTK_PLAT}/common/drivers/pmic_wrap/pmic_wrap_init.c \
+                ${MTK_PLAT}/common/drivers/rtc/rtc_common.c           \
                 ${MTK_PLAT}/common/mtk_plat_common.c                  \
+                ${MTK_PLAT}/common/mtk_sip_svc.c                      \
                 ${MTK_PLAT}/common/params_setup.c                     \
+                ${MTK_PLAT}/common/drivers/timer/mt_timer.c           \
+                ${MTK_PLAT}/common/mtk_cirq.c           	      \
                 ${MTK_PLAT_SOC}/aarch64/platform_common.c             \
                 ${MTK_PLAT_SOC}/aarch64/plat_helpers.S                \
                 ${MTK_PLAT_SOC}/bl31_plat_setup.c                     \
+                ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm.c                 \
+                ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm_utils.c           \
+                ${MTK_PLAT_SOC}/drivers/emi_mpu/emi_mpu.c             \
+                ${MTK_PLAT_SOC}/drivers/gpio/mtgpio.c                 \
+                ${MTK_PLAT_SOC}/drivers/mcdi/mt_cpu_pm.c              \
+                ${MTK_PLAT_SOC}/drivers/mcdi/mt_cpu_pm_cpc.c          \
+                ${MTK_PLAT_SOC}/drivers/mcdi/mt_mcdi.c                \
+                ${MTK_PLAT_SOC}/drivers/pmic/pmic.c                   \
+                ${MTK_PLAT_SOC}/drivers/rtc/rtc.c                     \
+                ${MTK_PLAT_SOC}/drivers/spmc/mtspmc.c                 \
                 ${MTK_PLAT_SOC}/plat_pm.c                             \
+                ${MTK_PLAT_SOC}/plat_sip_calls.c                      \
                 ${MTK_PLAT_SOC}/plat_topology.c
 
 # Configs for A76 and A55
@@ -40,6 +72,16 @@
 ERRATA_A55_1530923 := 1
 ERRATA_A55_1221012 := 1
 
+ERRATA_A76_1257314 := 1
+ERRATA_A76_1262606 := 1
+ERRATA_A76_1262888 := 1
+ERRATA_A76_1275112 := 1
+ERRATA_A76_1286807 := 1
+ERRATA_A76_1791580 := 1
+ERRATA_A76_1165522 := 1
+ERRATA_A76_1868343 := 1
+ERRATA_A76_1946160 := 1
+
 # indicate the reset vector address can be programmed
 PROGRAMMABLE_RESET_ADDRESS := 1
 
diff --git a/plat/st/common/include/stm32mp_common.h b/plat/st/common/include/stm32mp_common.h
index fbd0dda..9ca5d16 100644
--- a/plat/st/common/include/stm32mp_common.h
+++ b/plat/st/common/include/stm32mp_common.h
@@ -92,15 +92,6 @@
 /* Print board information */
 void stm32mp_print_boardinfo(void);
 
-/*
- * Util for clock gating and to get clock rate for stm32 and platform drivers
- * @id: Target clock ID, ID used in clock DT bindings
- */
-bool stm32mp_clk_is_enabled(unsigned long id);
-void stm32mp_clk_enable(unsigned long id);
-void stm32mp_clk_disable(unsigned long id);
-unsigned long stm32mp_clk_get_rate(unsigned long id);
-
 /* Initialise the IO layer and register platform IO devices */
 void stm32mp_io_setup(void);
 
diff --git a/plat/st/common/stm32mp_common.c b/plat/st/common/stm32mp_common.c
index 072155f..918c289 100644
--- a/plat/st/common/stm32mp_common.c
+++ b/plat/st/common/stm32mp_common.c
@@ -9,6 +9,7 @@
 
 #include <arch_helpers.h>
 #include <common/debug.h>
+#include <drivers/clk.h>
 #include <drivers/delay_timer.h>
 #include <drivers/st/stm32_console.h>
 #include <drivers/st/stm32mp_clkfunc.h>
@@ -188,13 +189,13 @@
 	}
 #endif
 
-	stm32mp_clk_enable((unsigned long)dt_uart_info.clock);
+	clk_enable((unsigned long)dt_uart_info.clock);
 
 #if defined(IMAGE_BL2)
 	reset_uart((uint32_t)dt_uart_info.reset);
 #endif
 
-	clk_rate = stm32mp_clk_get_rate((unsigned long)dt_uart_info.clock);
+	clk_rate = clk_get_rate((unsigned long)dt_uart_info.clock);
 
 	if (console_stm32_register(dt_uart_info.base, clk_rate,
 				   STM32MP_UART_BAUDRATE, &console) == 0) {
diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk
index 3a76d28..aa91646 100644
--- a/plat/st/stm32mp1/platform.mk
+++ b/plat/st/stm32mp1/platform.mk
@@ -189,6 +189,7 @@
 PLAT_BL_COMMON_SOURCES	+=	lib/cpus/aarch32/cortex_a7.S
 
 PLAT_BL_COMMON_SOURCES	+=	drivers/arm/tzc/tzc400.c				\
+				drivers/clk/clk.c					\
 				drivers/delay_timer/delay_timer.c			\
 				drivers/delay_timer/generic_delay_timer.c		\
 				drivers/st/bsec/bsec.c					\
diff --git a/plat/st/stm32mp1/stm32mp1_fconf_firewall.c b/plat/st/stm32mp1/stm32mp1_fconf_firewall.c
index caf9ff1..a1969eb 100644
--- a/plat/st/stm32mp1/stm32mp1_fconf_firewall.c
+++ b/plat/st/stm32mp1/stm32mp1_fconf_firewall.c
@@ -9,7 +9,7 @@
 #include <common/debug.h>
 #include <common/fdt_wrappers.h>
 #include <drivers/arm/tzc400.h>
-#include <drivers/st/stm32mp1_clk.h>
+#include <drivers/clk.h>
 #include <dt-bindings/clock/stm32mp1-clks.h>
 #include <lib/fconf/fconf.h>
 #include <lib/object_pool.h>
@@ -31,8 +31,8 @@
 
 void stm32mp1_arch_security_setup(void)
 {
-	stm32mp_clk_enable(TZC1);
-	stm32mp_clk_enable(TZC2);
+	clk_enable(TZC1);
+	clk_enable(TZC2);
 
 	tzc400_init(STM32MP1_TZC_BASE);
 	tzc400_disable_filters();
diff --git a/plat/st/stm32mp1/stm32mp1_pm.c b/plat/st/stm32mp1/stm32mp1_pm.c
index 31a9ae7..ed4d5e5 100644
--- a/plat/st/stm32mp1/stm32mp1_pm.c
+++ b/plat/st/stm32mp1/stm32mp1_pm.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,7 +14,7 @@
 #include <common/debug.h>
 #include <drivers/arm/gic_common.h>
 #include <drivers/arm/gicv2.h>
-#include <drivers/st/stm32mp1_clk.h>
+#include <drivers/clk.h>
 #include <dt-bindings/clock/stm32mp1-clks.h>
 #include <lib/mmio.h>
 #include <lib/psci/psci.h>
@@ -74,7 +74,7 @@
 		return PSCI_E_INVALID_ADDRESS;
 	}
 
-	stm32mp_clk_enable(RTCAPB);
+	clk_enable(RTCAPB);
 
 	cntfrq_core0 = read_cntfrq_el0();
 
@@ -84,7 +84,7 @@
 	/* Write magic number in backup register */
 	mmio_write_32(bkpr_core1_magic, BOOT_API_A7_CORE1_MAGIC_NUMBER);
 
-	stm32mp_clk_disable(RTCAPB);
+	clk_disable(RTCAPB);
 
 	/* Generate an IT to core 1 */
 	gicv2_raise_sgi(ARM_IRQ_SEC_SGI_0, STM32MP_SECONDARY_CPU);
diff --git a/plat/st/stm32mp1/stm32mp1_private.c b/plat/st/stm32mp1/stm32mp1_private.c
index 50112d0..e58528e 100644
--- a/plat/st/stm32mp1/stm32mp1_private.c
+++ b/plat/st/stm32mp1/stm32mp1_private.c
@@ -6,6 +6,7 @@
 
 #include <assert.h>
 
+#include <drivers/clk.h>
 #include <drivers/st/stm32_gpio.h>
 #include <drivers/st/stm32_iwdg.h>
 #include <lib/mmio.h>
@@ -566,14 +567,14 @@
 {
 	uint32_t bkpr_itf_idx = tamp_bkpr(TAMP_BOOT_MODE_BACKUP_REG_ID);
 
-	stm32mp_clk_enable(RTCAPB);
+	clk_enable(RTCAPB);
 
 	mmio_clrsetbits_32(bkpr_itf_idx,
 			   TAMP_BOOT_MODE_ITF_MASK,
 			   ((interface << 4) | (instance & 0xFU)) <<
 			   TAMP_BOOT_MODE_ITF_SHIFT);
 
-	stm32mp_clk_disable(RTCAPB);
+	clk_disable(RTCAPB);
 }
 
 void stm32_get_boot_interface(uint32_t *interface, uint32_t *instance)
@@ -583,12 +584,12 @@
 	if (itf == 0U) {
 		uint32_t bkpr = tamp_bkpr(TAMP_BOOT_MODE_BACKUP_REG_ID);
 
-		stm32mp_clk_enable(RTCAPB);
+		clk_enable(RTCAPB);
 
 		itf = (mmio_read_32(bkpr) & TAMP_BOOT_MODE_ITF_MASK) >>
 			TAMP_BOOT_MODE_ITF_SHIFT;
 
-		stm32mp_clk_disable(RTCAPB);
+		clk_disable(RTCAPB);
 	}
 
 	*interface = itf >> 4;
diff --git a/plat/st/stm32mp1/stm32mp1_scmi.c b/plat/st/stm32mp1/stm32mp1_scmi.c
index 6d60bd4..98585dc 100644
--- a/plat/st/stm32mp1/stm32mp1_scmi.c
+++ b/plat/st/stm32mp1/stm32mp1_scmi.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020, STMicroelectronics - All Rights Reserved
+ * Copyright (c) 2019-2021, STMicroelectronics - All Rights Reserved
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,6 +8,7 @@
 
 #include <platform_def.h>
 
+#include <drivers/clk.h>
 #include <drivers/scmi-msg.h>
 #include <drivers/scmi.h>
 #include <drivers/st/stm32mp1_clk.h>
@@ -274,7 +275,7 @@
 	if (array == NULL) {
 		*nb_elts = 1U;
 	} else if (*nb_elts == 1U) {
-		*array = stm32mp_clk_get_rate(clock->clock_id);
+		*array = clk_get_rate(clock->clock_id);
 	} else {
 		return SCMI_GENERIC_ERROR;
 	}
@@ -292,7 +293,7 @@
 		return 0U;
 	}
 
-	return stm32mp_clk_get_rate(clock->clock_id);
+	return clk_get_rate(clock->clock_id);
 }
 
 int32_t plat_scmi_clock_get_state(unsigned int agent_id, unsigned int scmi_id)
@@ -323,13 +324,13 @@
 	if (enable_not_disable) {
 		if (!clock->enabled) {
 			VERBOSE("SCMI clock %u enable\n", scmi_id);
-			stm32mp_clk_enable(clock->clock_id);
+			clk_enable(clock->clock_id);
 			clock->enabled = true;
 		}
 	} else {
 		if (clock->enabled) {
 			VERBOSE("SCMI clock %u disable\n", scmi_id);
-			stm32mp_clk_disable(clock->clock_id);
+			clk_disable(clock->clock_id);
 			clock->enabled = false;
 		}
 	}
@@ -461,7 +462,7 @@
 			/* Sync SCMI clocks with their targeted initial state */
 			if (clk->enabled &&
 			    stm32mp_nsec_can_access_clock(clk->clock_id)) {
-				stm32mp_clk_enable(clk->clock_id);
+				clk_enable(clk->clock_id);
 			}
 		}
 
diff --git a/plat/st/stm32mp1/stm32mp1_security.c b/plat/st/stm32mp1/stm32mp1_security.c
index 19ef4f0..c84bffc 100644
--- a/plat/st/stm32mp1/stm32mp1_security.c
+++ b/plat/st/stm32mp1/stm32mp1_security.c
@@ -10,6 +10,7 @@
 
 #include <common/debug.h>
 #include <drivers/arm/tzc400.h>
+#include <drivers/clk.h>
 #include <drivers/st/stm32mp1_clk.h>
 #include <dt-bindings/clock/stm32mp1-clks.h>
 #include <dt-bindings/soc/stm32mp15-tzc400.h>
@@ -106,8 +107,8 @@
  ******************************************************************************/
 static void early_init_tzc400(void)
 {
-	stm32mp_clk_enable(TZC1);
-	stm32mp_clk_enable(TZC2);
+	clk_enable(TZC1);
+	clk_enable(TZC2);
 
 	/* Region 0 set to cover all DRAM secure at 0xC000_0000 */
 	init_tzc400_begin(TZC_REGION_S_RDWR);
diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c
index d92c31d..5c240b5 100644
--- a/tools/fiptool/fiptool.c
+++ b/tools/fiptool/fiptool.c
@@ -537,7 +537,7 @@
 	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
 		image_t *image = desc->image;
 
-		if (image == NULL)
+		if (image == NULL || (image->toc_e.size == 0ULL))
 			continue;
 		payload_size += image->toc_e.size;
 		entry_offset = (entry_offset + align - 1) & ~(align - 1);