Merge changes from topic "versal-bug-fixes-and-new-apis" into integration

* changes:
  plat: xilinx: versal: Add support of register notifier
  plat: xilinx: versal: Add support to get clock rate value
  plat: xilinx: versal: Add support of set max latency for the device
  plat: versal: Add InitFinalize API call
  xilinx: versal: Updated Response of QueryData API call
  plat:xilinx:versal: Use defaults when PDI is without sw partitions
  plat: xilinx: Mask unnecessary bytes of return error code
  xilinx: versal: Skip store/restore of GIC during CPU idle
  plat: versal: Update API list in feature check
  xilinx: versal: Do not pass ACPU0 always in set_wakeup_source()
diff --git a/docs/resources/diagrams/plantuml/fip-secure-partitions.puml b/docs/resources/diagrams/plantuml/fip-secure-partitions.puml
index 40621db..9457e32 100644
--- a/docs/resources/diagrams/plantuml/fip-secure-partitions.puml
+++ b/docs/resources/diagrams/plantuml/fip-secure-partitions.puml
@@ -13,6 +13,7 @@
  ===
  UUID = xxx
  load_address = 0xaaa
+ owner = "Sip"
  ...
  ]
 }
@@ -24,9 +25,26 @@
  ===
  UUID = yyy
  load_address = 0xbbb
+ owner = "Plat"
  ]
 }
 
+artifact tb_fw_config.dts [
+ tb_fw_config.dts
+ ----
+ secure-partitions
+ ===
+ spkg_1 UUID
+ spkg_1 load_address
+ ---
+ spkg_2 UUID
+ spkg_2 load_address
+ ---
+ ...
+ ===
+ ...<rest of the nodes>
+]
+
 artifact config.json [
  SP_LAYOUT.json
  ===
@@ -41,31 +59,22 @@
 
 control sp_mk_generator
 
-artifact fconf_node [
- fconf_sp.dts
- ===
- spkg_1 UUID
- spkg_1 load_address
- ---
- spkg_2 UUID
- spkg_2 load_address
-]
-
 artifact sp_gen [
  sp_gen.mk
  ===
  FDT_SOURCE = ...
  SPTOOL_ARGS = ...
- FIP_ARG = ...
+ FIP_ARGS = ...
+ CRT_ARGS = ...
 ]
 
 control dtc
 control sptool
 
-artifact FW_CONFIG
+artifact tb_fw_config.dtb
 
 artifact spkg_1 [
- spkg_1.bin
+ sp1.pkg
  ===
  <i>header</i>
  ---
@@ -75,27 +84,56 @@
 ]
 
 artifact spkg_2 [
- spkg_2.bin
+ sp2.pkg
+ ===
+ <i>header</i>
+ ---
+ manifest
+ ---
+ binary
+]
+
+artifact signed_tb_fw_config.dtb [
+ tb_fw_config.dtb (signed)
+]
+
+artifact signed_spkg_1 [
+ sp1.pkg (signed)
+ ===
+ <i>header</i>
+ ---
+ manifest
+ ---
+ binary
+ ---
+ <i>signature</I>
+]
+
+artifact signed_spkg_2 [
+ sp2.pkg (signed)
  ===
  <i>header</i>
  ---
  manifest
  ---
  binary
+ ---
+ <i>signature</I>
 ]
 
+control crttool
 control fiptool
 
 artifact fip [
  fip.bin
  ===
- FW_CONFIG.dtb
+ tb_fw_config.dtb (signed)
  ---
  ...
  ---
- SPKG1
+ sp1.pkg  (signed & SiP owned)
  ---
- SPKG2
+ sp2.pkg  (signed & Platform owned)
  ---
  ...
 ]
@@ -103,20 +141,27 @@
 config.json .up.> SP_vendor_1
 config.json .up.> SP_vendor_2
 config.json --> sp_mk_generator
-sp_mk_generator --> fconf_node
 sp_mk_generator --> sp_gen
-
+sp_gen --> fiptool
+sp_gen --> cert_create
 sp_gen --> sptool
+
 sptool --> spkg_1
 sptool --> spkg_2
 
-fconf_node -down-> dtc
-dtc --> FW_CONFIG
+spkg_1 --> cert_create
+spkg_2 --> cert_create
+cert_create --> signed_spkg_1
+cert_create --> signed_spkg_2
 
-sp_gen --> fiptool
-FW_CONFIG --> fiptool
-spkg_1 -down-> fiptool
-spkg_2 -down-> fiptool
+tb_fw_config.dts --> dtc
+dtc --> tb_fw_config.dtb
+tb_fw_config.dtb --> cert_create
+cert_create --> signed_tb_fw_config.dtb
+
+signed_tb_fw_config.dtb --> fiptool
+signed_spkg_1 -down-> fiptool
+signed_spkg_2 -down-> fiptool
 fiptool -down-> fip
 
 @enduml
diff --git a/drivers/renesas/rcar/console/rcar_printf.c b/drivers/renesas/rcar/console/rcar_printf.c
index e75b9f4..ad074fe 100644
--- a/drivers/renesas/rcar/console/rcar_printf.c
+++ b/drivers/renesas/rcar/console/rcar_printf.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved.
+ * Copyright (c) 2015-2020, Renesas Electronics Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -19,11 +19,22 @@
 
 #define INDEX_TIMER_COUNT	(4U)
 
+#define RCAR_LOG_HEAD	(('T' << 0) | ('L' << 8) | ('O' << 16) | ('G' << 24))
+
+/*
+ * The log is initialized and used before BL31 xlat tables are initialized,
+ * therefore the log memory is a device memory at that point. Make sure the
+ * memory is correclty aligned and accessed only with up-to 32bit, aligned,
+ * writes.
+ */
+CASSERT((RCAR_BL31_LOG_BASE & 0x7) == 0, assert_bl31_log_base_unaligned);
+CASSERT((RCAR_BL31_LOG_MAX & 0x7) == 0, assert_bl31_log_max_unaligned);
+
 extern RCAR_INSTANTIATE_LOCK typedef struct log_head {
-	uint8_t head[4];
+	uint32_t head;
 	uint32_t index;
 	uint32_t size;
-	uint8_t res[4];
+	uint32_t res;
 } loghead_t;
 
 typedef struct log_map {
@@ -66,15 +77,12 @@
 
 int32_t rcar_log_init(void)
 {
-
-	static const uint8_t const_header[] = "TLOG";
-	logmap_t *t_log;
+	logmap_t *t_log = (logmap_t *)RCAR_BL31_LOG_BASE;
+	uint32_t *log_data = (uint32_t *)t_log->log_data;
 	int16_t init_flag = 0;
+	int i;
 
-	t_log = (logmap_t *) RCAR_BL31_LOG_BASE;
-	if (memcmp
-	    ((const void *)t_log->header.head, (const void *)const_header,
-	     sizeof(t_log->header.head)) != 0) {
+	if (t_log->header.head != RCAR_LOG_HEAD) {
 		/*
 		 * Log header is not "TLOG", then log area initialize
 		 */
@@ -87,11 +95,10 @@
 		init_flag = 1;
 	}
 	if (init_flag == 1) {
-		(void)memset((void *)t_log->log_data, 0,
-			     (size_t) RCAR_BL31_LOG_MAX);
-		(void)memcpy((void *)t_log->header.head,
-			     (const void *)const_header,
-			     sizeof(t_log->header.head));
+		for (i = 0; i < RCAR_BL31_LOG_MAX; i += 4)
+			*log_data++ = 0;
+
+		t_log->header.head = RCAR_LOG_HEAD;
 		t_log->header.index = 0U;
 		t_log->header.size = 0U;
 	}
diff --git a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
index 8b9c281..f4805db 100644
--- a/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
+++ b/plat/arm/board/fvp/fdts/fvp_spmc_manifest.dts
@@ -27,17 +27,14 @@
 		binary_size = <0x80000>;
 	};
 
-	chosen {
-		linux,initrd-start = <0>;
-		linux,initrd-end = <0>;
-	};
-
 	hypervisor {
 		compatible = "hafnium,hafnium";
 		vm1 {
 			is_ffa_partition;
 			debug_name = "cactus-primary";
 			load_address = <0x7000000>;
+			vcpu_count = <8>;
+			mem_size = <1048576>;
 		};
 		vm2 {
 			is_ffa_partition;
@@ -74,11 +71,6 @@
 		CPU_1
 	};
 
-	device-memory@0 {
-		device_type = "device-memory";
-		reg = <0x0 0x0 0x6000000 0x0 0x8000000 0x78000000>;
-	};
-
 	memory@6000000 {
 		device_type = "memory";
 		reg = <0x0 0x6000000 0x2000000>; /* Trusted DRAM */
diff --git a/plat/arm/board/fvp/fdts/fvp_spmc_optee_sp_manifest.dts b/plat/arm/board/fvp/fdts/fvp_spmc_optee_sp_manifest.dts
index 266adfc..57d6792 100644
--- a/plat/arm/board/fvp/fdts/fvp_spmc_optee_sp_manifest.dts
+++ b/plat/arm/board/fvp/fdts/fvp_spmc_optee_sp_manifest.dts
@@ -27,11 +27,6 @@
 		binary_size = <0x80000>;
 	};
 
-	chosen {
-		linux,initrd-start = <0>;
-		linux,initrd-end = <0>;
-	};
-
 	hypervisor {
 		compatible = "hafnium,hafnium";
 		vm1 {
@@ -39,6 +34,8 @@
 			debug_name = "op-tee";
 			load_address = <0x6280000>;
 			smc_whitelist = <0xbe000000>;
+			vcpu_count = <8>;
+			mem_size = <1048576>;
 		};
 	};
 
@@ -61,11 +58,6 @@
 		CPU_1
 	};
 
-	device-memory@0 {
-		device_type = "device-memory";
-		reg = <0x0 0x0 0x6000000 0x0 0x8000000 0x78000000>;
-	};
-
 	memory@6000000 {
 		device_type = "memory";
 		reg = <0x0 0x6000000 0x2000000>; /* Trusted DRAM */
diff --git a/fdts/optee_sp_manifest.dts b/plat/arm/board/fvp/fdts/optee_sp_manifest.dts
similarity index 72%
rename from fdts/optee_sp_manifest.dts
rename to plat/arm/board/fvp/fdts/optee_sp_manifest.dts
index 02a5ef3..928d0d3 100644
--- a/fdts/optee_sp_manifest.dts
+++ b/plat/arm/board/fvp/fdts/optee_sp_manifest.dts
@@ -30,4 +30,20 @@
 
 	/* Boot protocol */
 	gp-register-num = <0x0>;
+
+	device-regions {
+		compatible = "arm,ffa-manifest-device-regions";
+
+		uart1 {
+			base-address = <0x00000000 0x1c0a0000>;
+			pages-count = <1>;
+			attributes = <0x3>; /* read-write */
+		};
+
+		gicd {
+			base-address = <0x00000000 0x2f000000>;
+			pages-count = <16>;
+			attributes = <0x3>; /* read-write */
+		};
+	};
 };
diff --git a/plat/marvell/armada/a3k/common/a3700_common.mk b/plat/marvell/armada/a3k/common/a3700_common.mk
index 5e2f8e2..e2022fa 100644
--- a/plat/marvell/armada/a3k/common/a3700_common.mk
+++ b/plat/marvell/armada/a3k/common/a3700_common.mk
@@ -64,7 +64,7 @@
 				$(PLAT_COMMON_BASE)/a3700_sip_svc.c	\
 				$(MARVELL_DRV)
 
-ifneq (${WTP},)
+ifdef WTP
 
 DOIMAGEPATH	:= $(WTP)
 DOIMAGETOOL	:= $(DOIMAGEPATH)/wtptp/src/TBB_Linux/release/TBB_linux
@@ -85,6 +85,9 @@
 
 TIMBUILD	:= $(DOIMAGEPATH)/script/buildtim.sh
 TIM2IMG		:= $(DOIMAGEPATH)/script/tim2img.pl
+TIMDDRTOOL	:= $(DOIMAGEPATH)/tim/ddr/ddr_tool
+
+$(TIMBUILD): $(TIMDDRTOOL)
 
 # WTMI_IMG is used to specify the customized RTOS image running over
 # Service CPU (CM3 processor). By the default, it points to a
@@ -101,7 +104,7 @@
 # and sys-init image (WTMI_SYSINIT_IMG).
 WTMI_MULTI_IMG		:= $(DOIMAGEPATH)/wtmi/build/wtmi.bin
 
-WTMI_ENC_IMG		:= $(DOIMAGEPATH)/wtmi/build/wtmi-enc.bin
+WTMI_ENC_IMG		:= $(BUILD_PLAT)/wtmi-enc.bin
 BUILD_UART		:= uart-images
 
 SRCPATH			:= $(dir $(BL33))
@@ -120,15 +123,20 @@
 				$(DDR_TOPOLOGY) 0 0 $(DOIMAGE_CFG) $(TIMNCFG) $(TIMNSIG) 0
 DOIMAGE_FLAGS		:= -r $(DOIMAGE_CFG) -v -D
 
-$(DOIMAGETOOL):
+$(DOIMAGETOOL): FORCE
 	$(if $(value CRYPTOPP_PATH),,$(error "Platform '${PLAT}' for WTP image tool requires CRYPTOPP_PATH. Please set CRYPTOPP_PATH to point to the right directory"))
 	$(Q)$(MAKE) --no-print-directory -C $(CRYPTOPP_PATH) -f GNUmakefile
 	$(Q)$(MAKE) --no-print-directory -C $(DOIMAGEPATH)/wtptp/src/TBB_Linux -f TBB_linux.mak LIBDIR=$(CRYPTOPP_PATH)
 
+$(WTMI_MULTI_IMG): FORCE
+	$(Q)$(MAKE) --no-print-directory -C $(DOIMAGEPATH) WTMI_IMG=$(WTMI_IMG) WTMI
+
+$(TIMDDRTOOL): FORCE
+	$(if $(value MV_DDR_PATH),,$(error "Platform '${PLAT}' for ddr tool requires MV_DDR_PATH. Please set MV_DDR_PATH to point to the right directory"))
+	$(Q)$(MAKE) --no-print-directory -C $(DOIMAGEPATH) MV_DDR_PATH=$(MV_DDR_PATH) mv_ddr
+
-mrvl_flash: ${BUILD_PLAT}/${BOOT_IMAGE} ${DOIMAGETOOL}
-	$(if $(value MV_DDR_PATH),,$(error "Platform '${PLAT}' for target '$@' requires MV_DDR_PATH. Please set MV_DDR_PATH to point to the right directory"))
-	${Q}${MAKE} --no-print-directory -C ${DOIMAGEPATH} WTMI_IMG=$(WTMI_IMG) MV_DDR_PATH=$(MV_DDR_PATH)
-	$(shell truncate -s %4 $(WTMI_IMG))
+.PHONY: mrvl_flash
+mrvl_flash: ${BUILD_PLAT}/${BOOT_IMAGE} ${WTMI_MULTI_IMG} ${DOIMAGETOOL} ${TIMBUILD}
 	@echo
 	@echo "Building uart images"
 	$(TIMBUILD) $(TIMBLDUARTARGS)
@@ -157,8 +165,9 @@
 	@echo -e "\n\t=======================================================\n";
 	@echo -e "\t  Secure boot. Encrypting wtmi and boot-image \n";
 	@echo -e "\t=======================================================\n";
-	@truncate -s %16 $(WTMI_MULTI_IMG)
-	@openssl enc -aes-256-cbc -e -in $(WTMI_MULTI_IMG) \
+	@cp $(WTMI_MULTI_IMG) $(BUILD_PLAT)/wtmi-align.bin
+	@truncate -s %16 $(BUILD_PLAT)/wtmi-align.bin
+	@openssl enc -aes-256-cbc -e -in $(BUILD_PLAT)/wtmi-align.bin \
 	-out $(WTMI_ENC_IMG) \
 	-K `cat $(IMAGESPATH)/aes-256.txt` -nosalt \
 	-iv `cat $(IMAGESPATH)/iv.txt` -p
@@ -170,15 +179,34 @@
 endif
 	$(DOIMAGETOOL) $(DOIMAGE_FLAGS)
 	@if [ -e "$(TIMNCFG)" ]; then $(DOIMAGETOOL) -r $(TIMNCFG); fi
-	@if [ "$(MARVELL_SECURE_BOOT)" = "1" ]; then sed -i 's|$(WTMI_MULTI_IMG)|$(WTMI_ENC_IMG)|1;s|$(BOOT_IMAGE)|$(BOOT_ENC_IMAGE)|1;' $(TIMNCFG); fi
+ifeq ($(MARVELL_SECURE_BOOT),1)
+	@sed -i 's|$(WTMI_MULTI_IMG)|$(WTMI_ENC_IMG)|1;s|$(BOOT_IMAGE)|$(BOOT_ENC_IMAGE)|1;' $(TIMNCFG)
+endif
 	$(TIM2IMG) $(TIM2IMGARGS) -o $(BUILD_PLAT)/$(FLASH_IMAGE)
-	@mv -t $(BUILD_PLAT) $(TIM_IMAGE) $(DOIMAGE_CFG) $(TIMN_IMAGE) $(TIMNCFG) $(WTMI_IMG) $(WTMI_SYSINIT_IMG) $(WTMI_MULTI_IMG)
-	@if [ "$(MARVELL_SECURE_BOOT)" = "1" ]; then mv -t $(BUILD_PLAT) $(WTMI_ENC_IMG) OtpHash.txt; fi
+	@mv -t $(BUILD_PLAT) $(TIM_IMAGE) $(DOIMAGE_CFG) $(TIMN_IMAGE) $(TIMNCFG)
+	@cp -t $(BUILD_PLAT) $(WTMI_IMG) $(WTMI_SYSINIT_IMG) $(WTMI_MULTI_IMG)
+ifeq ($(MARVELL_SECURE_BOOT),1)
+	@mv -t $(BUILD_PLAT) OtpHash.txt
+endif
 	@find . -name "*.txt" | grep -E "CSK[[:alnum:]]_KeyHash.txt|Tim_msg.txt|TIMHash.txt" | xargs rm -f
 
-else # ${WTP}
+clean realclean distclean: mrvl_clean
+
+.PHONY: mrvl_clean
+mrvl_clean:
+	-$(Q)$(MAKE) --no-print-directory -C $(DOIMAGEPATH) MV_DDR_PATH=$(MV_DDR_PATH) clean
+	-$(Q)$(MAKE) --no-print-directory -C $(DOIMAGEPATH)/wtptp/src/TBB_Linux -f TBB_linux.mak LIBDIR=$(CRYPTOPP_PATH) clean
+ifdef CRYPTOPP_PATH
+	-$(Q)$(MAKE) --no-print-directory -C $(CRYPTOPP_PATH) -f GNUmakefile clean
+endif
 
+else # WTP
+
+.PHONY: mrvl_flash
 mrvl_flash:
 	$(error "Platform '${PLAT}' for target '$@' requires WTP. Please set WTP to point to the right directory")
 
-endif # ${WTP}
+endif # WTP
+
+.PHONY: FORCE
+FORCE:;
diff --git a/plat/marvell/armada/a8k/common/a8k_common.mk b/plat/marvell/armada/a8k/common/a8k_common.mk
index 58394a4..cf1516a 100644
--- a/plat/marvell/armada/a8k/common/a8k_common.mk
+++ b/plat/marvell/armada/a8k/common/a8k_common.mk
@@ -152,14 +152,20 @@
 include ${BLE_PATH}/ble.mk
 $(eval $(call MAKE_BL,e))
 
+clean realclean distclean: mrvl_clean
+
+.PHONY: mrvl_clean
 mrvl_clean:
 	@echo "  Doimage CLEAN"
 	${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${DOIMAGEPATH} clean
 
-${DOIMAGETOOL}: mrvl_clean
+${DOIMAGETOOL}: FORCE
 	@$(DOIMAGE_LIBS_CHECK)
 	${Q}${MAKE} --no-print-directory -C ${DOIMAGEPATH}
 
+.PHONY: mrvl_flash
 mrvl_flash: ${BUILD_PLAT}/${BOOT_IMAGE} ${DOIMAGETOOL}
 	${DOIMAGETOOL} ${DOIMAGE_FLAGS} ${BUILD_PLAT}/${BOOT_IMAGE} ${BUILD_PLAT}/${FLASH_IMAGE}
 
+.PHONY: FORCE
+FORCE:;
diff --git a/plat/marvell/armada/common/marvell_common.mk b/plat/marvell/armada/common/marvell_common.mk
index 7f8dffa..e5ee710 100644
--- a/plat/marvell/armada/common/marvell_common.mk
+++ b/plat/marvell/armada/common/marvell_common.mk
@@ -87,10 +87,12 @@
 endif
 
 $(BUILD_PLAT)/$(BOOT_IMAGE): $(BUILD_PLAT)/bl1.bin $(BUILD_PLAT)/$(FIP_NAME)
+	$(if $(shell find $(BUILD_PLAT)/bl1.bin -type f -size +128k),$(error "Image '$(BUILD_PLAT)/bl1.bin' is bigger than 128kB"))
 	@cp $(BUILD_PLAT)/bl1.bin $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; }
 	@truncate -s %128K $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; }
 	@cat $(BUILD_PLAT)/$(FIP_NAME) >> $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; }
 	@truncate -s %4 $(BUILD_PLAT)/$(BOOT_IMAGE) || { rm -f $(BUILD_PLAT)/$(BOOT_IMAGE); false; }
 	@echo "Built $@ successfully"
 
+.PHONY: mrvl_bootimage
 mrvl_bootimage: $(BUILD_PLAT)/$(BOOT_IMAGE)
diff --git a/plat/mediatek/common/drivers/pmic_wrap/pmic_wrap_init_v2.c b/plat/mediatek/common/drivers/pmic_wrap/pmic_wrap_init_v2.c
new file mode 100644
index 0000000..fca6913
--- /dev/null
+++ b/plat/mediatek/common/drivers/pmic_wrap/pmic_wrap_init_v2.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+
+#include "platform_def.h"
+#include "pmic_wrap_init.h"
+
+/* pmic wrap module wait_idle and read polling interval (in microseconds) */
+enum pwrap_polling_interval {
+	WAIT_IDLE_POLLING_DELAY_US	= 1,
+	READ_POLLING_DELAY_US		= 2
+};
+
+static uint32_t pwrap_check_idle(void *wacs_register, uint32_t timeout_us)
+{
+	uint32_t reg_rdata = 0U, retry;
+
+	retry = (timeout_us + WAIT_IDLE_POLLING_DELAY_US) /
+		WAIT_IDLE_POLLING_DELAY_US;
+	while (retry != 0) {
+		udelay(WAIT_IDLE_POLLING_DELAY_US);
+		reg_rdata = mmio_read_32((uintptr_t)wacs_register);
+		if (GET_WACS_FSM(reg_rdata) == SWINF_FSM_IDLE) {
+			break;
+		}
+		retry--;
+	};
+
+	if (retry == 0) {
+		/* timeout */
+		return E_PWR_WAIT_IDLE_TIMEOUT;
+	}
+
+	return 0U;
+}
+
+static uint32_t pwrap_check_vldclr(void *wacs_register, uint32_t timeout_us)
+{
+	uint32_t reg_rdata = 0U, retry;
+
+	retry = (timeout_us + READ_POLLING_DELAY_US) / READ_POLLING_DELAY_US;
+	while (retry != 0) {
+		udelay(READ_POLLING_DELAY_US);
+		reg_rdata = mmio_read_32((uintptr_t)wacs_register);
+		if (GET_WACS_FSM(reg_rdata) == SWINF_FSM_WFVLDCLR) {
+			break;
+		}
+		retry--;
+	};
+
+	if (retry == 0) {
+		/* timeout */
+		return E_PWR_WAIT_IDLE_TIMEOUT;
+	}
+
+	return 0U;
+}
+
+static int32_t pwrap_wacs2(uint32_t write, uint32_t adr, uint32_t wdata,
+			   uint32_t *rdata, uint32_t init_check)
+{
+	uint32_t reg_rdata, return_value;
+
+	if (init_check != 0) {
+		if ((mmio_read_32((uintptr_t)&mtk_pwrap->init_done) & 0x1) == 0) {
+			ERROR("initialization isn't finished\n");
+			return E_PWR_NOT_INIT_DONE;
+		}
+	}
+
+	/* Wait for Software Interface FSM state to be IDLE. */
+	return_value = pwrap_check_idle(&mtk_pwrap->wacs2_sta,
+					PWRAP_WAIT_IDLE_US);
+	if (return_value != 0) {
+		return return_value;
+	}
+
+	/* Set the write data */
+	if (write == 1) {
+		/* Set the write data. */
+		mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_wdata, wdata);
+	}
+
+	/* Send the command. */
+	mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_cmd, (write << 29) | adr);
+
+	if (write == 0) {
+		/*
+		 * Wait for Software Interface FSM state to be WFVLDCLR,
+		 * read the data and clear the valid flag.
+		 */
+		return_value = pwrap_check_vldclr(&mtk_pwrap->wacs2_sta,
+						  PWRAP_READ_US);
+		if (return_value != 0) {
+			return return_value;
+		}
+
+		if (rdata == NULL) {
+			return E_PWR_INVALID_ARG;
+		}
+
+		reg_rdata = mmio_read_32((uintptr_t)&mtk_pwrap->wacs2_rdata);
+		*rdata = reg_rdata;
+		mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_vldclr, 0x1);
+	}
+
+	return return_value;
+}
+
+/* external API for pmic_wrap user */
+int32_t pwrap_read(uint32_t adr, uint32_t *rdata)
+{
+	return pwrap_wacs2(0, adr, 0, rdata, 1);
+}
+
+int32_t pwrap_write(uint32_t adr, uint32_t wdata)
+{
+	return pwrap_wacs2(1, adr, wdata, 0, 1);
+}
diff --git a/plat/mediatek/mt8183/drivers/uart/uart.c b/plat/mediatek/common/drivers/uart/uart.c
similarity index 94%
rename from plat/mediatek/mt8183/drivers/uart/uart.c
rename to plat/mediatek/common/drivers/uart/uart.c
index 3c6a980..b940eb3 100644
--- a/plat/mediatek/mt8183/drivers/uart/uart.c
+++ b/plat/mediatek/common/drivers/uart/uart.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,7 +9,7 @@
 
 static struct mt_uart uart_save_addr[DRV_SUPPORT_UART_PORTS];
 
-static const unsigned int uart_base_addr[DRV_SUPPORT_UART_PORTS] = {
+static const uint32_t uart_base_addr[DRV_SUPPORT_UART_PORTS] = {
 	UART0_BASE,
 	UART1_BASE
 };
@@ -99,13 +99,14 @@
 
 void mt_console_uart_cg(int on)
 {
-	if (on)
+	if (on == 1) {
 		mmio_write_32(UART_CLOCK_GATE_CLR, UART0_CLOCK_GATE_BIT);
-	else
+	} else {
 		mmio_write_32(UART_CLOCK_GATE_SET, UART0_CLOCK_GATE_BIT);
+	}
 }
 
-int mt_console_uart_cg_status(void)
+uint32_t mt_console_uart_cg_status(void)
 {
 	return mmio_read_32(UART_CLOCK_GATE_STA) & UART0_CLOCK_GATE_BIT;
 }
diff --git a/plat/mediatek/mt8183/drivers/uart/uart.h b/plat/mediatek/mt8183/drivers/uart/uart.h
index be04c35..062ce3a 100644
--- a/plat/mediatek/mt8183/drivers/uart/uart.h
+++ b/plat/mediatek/mt8183/drivers/uart/uart.h
@@ -95,6 +95,6 @@
 void mt_uart_save(void);
 void mt_uart_restore(void);
 void mt_console_uart_cg(int on);
-int mt_console_uart_cg_status(void);
+uint32_t mt_console_uart_cg_status(void);
 
 #endif /* __UART_H__ */
diff --git a/plat/mediatek/mt8183/platform.mk b/plat/mediatek/mt8183/platform.mk
index f290a4e..07da1af 100644
--- a/plat/mediatek/mt8183/platform.mk
+++ b/plat/mediatek/mt8183/platform.mk
@@ -45,6 +45,7 @@
                    ${MTK_PLAT}/common/mtk_plat_common.c                  \
                    ${MTK_PLAT}/common/drivers/pmic_wrap/pmic_wrap_init.c \
                    ${MTK_PLAT}/common/drivers/rtc/rtc_common.c           \
+                   ${MTK_PLAT}/common/drivers/uart/uart.c                \
                    ${MTK_PLAT}/common/params_setup.c                     \
                    ${MTK_PLAT_SOC}/aarch64/plat_helpers.S                \
                    ${MTK_PLAT_SOC}/aarch64/platform_common.c             \
@@ -58,7 +59,6 @@
                    ${MTK_PLAT_SOC}/drivers/spm/spm_pmic_wrap.c           \
                    ${MTK_PLAT_SOC}/drivers/spm/spm_suspend.c             \
                    ${MTK_PLAT_SOC}/drivers/gpio/mtgpio.c                 \
-                   ${MTK_PLAT_SOC}/drivers/uart/uart.c                   \
                    ${MTK_PLAT_SOC}/drivers/timer/mt_timer.c              \
                    ${MTK_PLAT_SOC}/drivers/emi_mpu/emi_mpu.c             \
                    ${MTK_PLAT_SOC}/plat_pm.c                             \
diff --git a/plat/mediatek/mt8192/bl31_plat_setup.c b/plat/mediatek/mt8192/bl31_plat_setup.c
index 9a01bef..32e124f 100644
--- a/plat/mediatek/mt8192/bl31_plat_setup.c
+++ b/plat/mediatek/mt8192/bl31_plat_setup.c
@@ -11,12 +11,15 @@
 #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 <gpio/mtgpio.h>
 #include <mt_gic_v3.h>
+#include <mt_timer.h>
+#include <mtk_dcm.h>
 #include <plat_params.h>
 #include <plat_private.h>
 
@@ -81,10 +84,18 @@
  ******************************************************************************/
 void bl31_platform_setup(void)
 {
+	/* Set dcm on */
+	if (!dcm_set_default()) {
+		ERROR("Failed to set default dcm on!!\n");
+	}
+
 	/* Initialize the GIC driver, CPU and distributor interfaces */
 	mt_gic_driver_init();
 	mt_gic_init();
+
 	plat_mt8192_gpio_init();
+	mt_systimer_init();
+	generic_delay_timer_init();
 }
 
 /*******************************************************************************
diff --git a/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.c b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.c
new file mode 100644
index 0000000..dd8bf4e
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <mtk_dcm.h>
+#include <mtk_dcm_utils.h>
+
+static void dcm_armcore(bool mode)
+{
+	dcm_mp_cpusys_top_bus_pll_div_dcm(mode);
+	dcm_mp_cpusys_top_cpu_pll_div_0_dcm(mode);
+	dcm_mp_cpusys_top_cpu_pll_div_1_dcm(mode);
+}
+
+static void dcm_mcusys(bool on)
+{
+	dcm_mp_cpusys_top_adb_dcm(on);
+	dcm_mp_cpusys_top_apb_dcm(on);
+	dcm_mp_cpusys_top_cpubiu_dcm(on);
+	dcm_mp_cpusys_top_misc_dcm(on);
+	dcm_mp_cpusys_top_mp0_qdcm(on);
+	dcm_cpccfg_reg_emi_wfifo(on);
+	dcm_mp_cpusys_top_last_cor_idle_dcm(on);
+}
+
+static void dcm_stall(bool on)
+{
+	dcm_mp_cpusys_top_core_stall_dcm(on);
+	dcm_mp_cpusys_top_fcm_stall_dcm(on);
+}
+
+static bool check_dcm_state(void)
+{
+	bool ret = true;
+
+	ret &= dcm_mp_cpusys_top_bus_pll_div_dcm_is_on();
+	ret &= dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on();
+	ret &= dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on();
+
+	ret &= dcm_mp_cpusys_top_adb_dcm_is_on();
+	ret &= dcm_mp_cpusys_top_apb_dcm_is_on();
+	ret &= dcm_mp_cpusys_top_cpubiu_dcm_is_on();
+	ret &= dcm_mp_cpusys_top_misc_dcm_is_on();
+	ret &= dcm_mp_cpusys_top_mp0_qdcm_is_on();
+	ret &= dcm_cpccfg_reg_emi_wfifo_is_on();
+	ret &= dcm_mp_cpusys_top_last_cor_idle_dcm_is_on();
+
+	ret &= dcm_mp_cpusys_top_core_stall_dcm_is_on();
+	ret &= dcm_mp_cpusys_top_fcm_stall_dcm_is_on();
+
+	return ret;
+}
+
+bool dcm_set_default(void)
+{
+	dcm_armcore(true);
+	dcm_mcusys(true);
+	dcm_stall(true);
+
+	return check_dcm_state();
+}
diff --git a/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.h b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.h
new file mode 100644
index 0000000..ee98d0e
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_DCM_H
+#define MTK_DCM_H
+
+#include <stdbool.h>
+
+bool dcm_set_default(void);
+
+#endif /* #ifndef MTK_DCM_H */
diff --git a/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.c b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.c
new file mode 100644
index 0000000..15a700c
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.c
@@ -0,0 +1,562 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+#include <mtk_dcm_utils.h>
+
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_MASK (BIT(17))
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_MASK (BIT(15) | \
+			BIT(16) | \
+			BIT(17) | \
+			BIT(18) | \
+			BIT(21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG2_MASK (BIT(15) | \
+			BIT(16) | \
+			BIT(17) | \
+			BIT(18))
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_ON (BIT(17))
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_ON (BIT(15) | \
+			BIT(16) | \
+			BIT(17) | \
+			BIT(18) | \
+			BIT(21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG2_ON (BIT(15) | \
+			BIT(16) | \
+			BIT(17) | \
+			BIT(18))
+#define MP_CPUSYS_TOP_ADB_DCM_REG0_OFF ((0x0 << 17))
+#define MP_CPUSYS_TOP_ADB_DCM_REG1_OFF ((0x0 << 15) | \
+			(0x0 << 16) | \
+			(0x0 << 17) | \
+			(0x0 << 18) | \
+			(0x0 << 21))
+#define MP_CPUSYS_TOP_ADB_DCM_REG2_OFF ((0x0 << 15) | \
+			(0x0 << 16) | \
+			(0x0 << 17) | \
+			(0x0 << 18))
+
+bool dcm_mp_cpusys_top_adb_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(MP_ADB_DCM_CFG0) &
+		MP_CPUSYS_TOP_ADB_DCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
+	ret &= ((mmio_read_32(MP_ADB_DCM_CFG4) &
+		MP_CPUSYS_TOP_ADB_DCM_REG1_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_ADB_DCM_REG1_ON);
+	ret &= ((mmio_read_32(MCUSYS_DCM_CFG0) &
+		MP_CPUSYS_TOP_ADB_DCM_REG2_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_ADB_DCM_REG2_ON);
+
+	return ret;
+}
+
+void dcm_mp_cpusys_top_adb_dcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_adb_dcm'" */
+		mmio_clrsetbits_32(MP_ADB_DCM_CFG0,
+			MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+			MP_CPUSYS_TOP_ADB_DCM_REG0_ON);
+		mmio_clrsetbits_32(MP_ADB_DCM_CFG4,
+			MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+			MP_CPUSYS_TOP_ADB_DCM_REG1_ON);
+		mmio_clrsetbits_32(MCUSYS_DCM_CFG0,
+			MP_CPUSYS_TOP_ADB_DCM_REG2_MASK,
+			MP_CPUSYS_TOP_ADB_DCM_REG2_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_adb_dcm'" */
+		mmio_clrsetbits_32(MP_ADB_DCM_CFG0,
+			MP_CPUSYS_TOP_ADB_DCM_REG0_MASK,
+			MP_CPUSYS_TOP_ADB_DCM_REG0_OFF);
+		mmio_clrsetbits_32(MP_ADB_DCM_CFG4,
+			MP_CPUSYS_TOP_ADB_DCM_REG1_MASK,
+			MP_CPUSYS_TOP_ADB_DCM_REG1_OFF);
+		mmio_clrsetbits_32(MCUSYS_DCM_CFG0,
+			MP_CPUSYS_TOP_ADB_DCM_REG2_MASK,
+			MP_CPUSYS_TOP_ADB_DCM_REG2_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_APB_DCM_REG0_MASK (BIT(5))
+#define MP_CPUSYS_TOP_APB_DCM_REG1_MASK (BIT(8))
+#define MP_CPUSYS_TOP_APB_DCM_REG2_MASK (BIT(16))
+#define MP_CPUSYS_TOP_APB_DCM_REG0_ON (BIT(5))
+#define MP_CPUSYS_TOP_APB_DCM_REG1_ON (BIT(8))
+#define MP_CPUSYS_TOP_APB_DCM_REG2_ON (BIT(16))
+#define MP_CPUSYS_TOP_APB_DCM_REG0_OFF ((0x0 << 5))
+#define MP_CPUSYS_TOP_APB_DCM_REG1_OFF ((0x0 << 8))
+#define MP_CPUSYS_TOP_APB_DCM_REG2_OFF ((0x0 << 16))
+
+bool dcm_mp_cpusys_top_apb_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(MP_MISC_DCM_CFG0) &
+		MP_CPUSYS_TOP_APB_DCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_APB_DCM_REG0_ON);
+	ret &= ((mmio_read_32(MCUSYS_DCM_CFG0) &
+		MP_CPUSYS_TOP_APB_DCM_REG1_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_APB_DCM_REG1_ON);
+	ret &= ((mmio_read_32(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_MISC_DCM_CFG0,
+			MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
+			MP_CPUSYS_TOP_APB_DCM_REG0_ON);
+		mmio_clrsetbits_32(MCUSYS_DCM_CFG0,
+			MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
+			MP_CPUSYS_TOP_APB_DCM_REG1_ON);
+		mmio_clrsetbits_32(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_MISC_DCM_CFG0,
+			MP_CPUSYS_TOP_APB_DCM_REG0_MASK,
+			MP_CPUSYS_TOP_APB_DCM_REG0_OFF);
+		mmio_clrsetbits_32(MCUSYS_DCM_CFG0,
+			MP_CPUSYS_TOP_APB_DCM_REG1_MASK,
+			MP_CPUSYS_TOP_APB_DCM_REG1_OFF);
+		mmio_clrsetbits_32(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))
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_ON (BIT(11))
+#define MP_CPUSYS_TOP_BUS_PLL_DIV_DCM_REG0_OFF ((0x0 << 11))
+
+bool dcm_mp_cpusys_top_bus_pll_div_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(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(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(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(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(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(MP0_DCM_CFG7,
+			MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_MASK,
+			MP_CPUSYS_TOP_CORE_STALL_DCM_REG0_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_MASK ((0xffff << 0))
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_ON ((0xffff << 0))
+#define MP_CPUSYS_TOP_CPUBIU_DCM_REG0_OFF ((0x0 << 0))
+
+bool dcm_mp_cpusys_top_cpubiu_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(MCSI_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(MCSI_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(MCSI_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))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_ON (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_0_DCM_REG0_OFF ((0x0 << 11))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(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(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(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))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_ON (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_1_DCM_REG0_OFF ((0x0 << 11))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(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(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(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_CPU_PLL_DIV_2_DCM_REG0_MASK (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_ON (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_OFF ((0x0 << 11))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_2_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(CPU_PLLDIV_CFG2) &
+		MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_ON);
+
+	return ret;
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_2_dcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_2_dcm'" */
+		mmio_clrsetbits_32(CPU_PLLDIV_CFG2,
+			MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_MASK,
+			MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_2_dcm'" */
+		mmio_clrsetbits_32(CPU_PLLDIV_CFG2,
+			MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_MASK,
+			MP_CPUSYS_TOP_CPU_PLL_DIV_2_DCM_REG0_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_MASK (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_ON (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_OFF ((0x0 << 11))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_3_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(CPU_PLLDIV_CFG3) &
+		MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_ON);
+
+	return ret;
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_3_dcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_3_dcm'" */
+		mmio_clrsetbits_32(CPU_PLLDIV_CFG3,
+			MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_MASK,
+			MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_3_dcm'" */
+		mmio_clrsetbits_32(CPU_PLLDIV_CFG3,
+			MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_MASK,
+			MP_CPUSYS_TOP_CPU_PLL_DIV_3_DCM_REG0_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_MASK (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_ON (BIT(11))
+#define MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_OFF ((0x0 << 11))
+
+bool dcm_mp_cpusys_top_cpu_pll_div_4_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(CPU_PLLDIV_CFG4) &
+		MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_ON);
+
+	return ret;
+}
+
+void dcm_mp_cpusys_top_cpu_pll_div_4_dcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_cpu_pll_div_4_dcm'" */
+		mmio_clrsetbits_32(CPU_PLLDIV_CFG4,
+			MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_MASK,
+			MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_cpu_pll_div_4_dcm'" */
+		mmio_clrsetbits_32(CPU_PLLDIV_CFG4,
+			MP_CPUSYS_TOP_CPU_PLL_DIV_4_DCM_REG0_MASK,
+			MP_CPUSYS_TOP_CPU_PLL_DIV_4_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(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(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(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 ((0x1U << 31))
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_ON ((0x1U << 31))
+#define MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_OFF ((0x0U << 31))
+
+bool dcm_mp_cpusys_top_last_cor_idle_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(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(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(BUS_PLLDIV_CFG,
+			MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_MASK,
+			MP_CPUSYS_TOP_LAST_COR_IDLE_DCM_REG0_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_MASK (BIT(1) | \
+			BIT(4))
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_ON (BIT(1) | \
+			BIT(4))
+#define MP_CPUSYS_TOP_MISC_DCM_REG0_OFF ((0x0 << 1) | \
+			(0x0 << 4))
+
+bool dcm_mp_cpusys_top_misc_dcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(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_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_MISC_DCM_CFG0,
+			MP_CPUSYS_TOP_MISC_DCM_REG0_MASK,
+			MP_CPUSYS_TOP_MISC_DCM_REG0_OFF);
+	}
+}
+
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK (BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK (BIT(0) | \
+			BIT(1) | \
+			BIT(2) | \
+			BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_ON (BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG1_ON (BIT(0) | \
+			BIT(1) | \
+			BIT(2) | \
+			BIT(3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF ((0x0 << 3))
+#define MP_CPUSYS_TOP_MP0_QDCM_REG1_OFF ((0x0 << 0) | \
+			(0x0 << 1) | \
+			(0x0 << 2) | \
+			(0x0 << 3))
+
+bool dcm_mp_cpusys_top_mp0_qdcm_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(MP_MISC_DCM_CFG0) &
+		MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_MP0_QDCM_REG0_ON);
+	ret &= ((mmio_read_32(MP0_DCM_CFG0) &
+		MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK) ==
+		(unsigned int) MP_CPUSYS_TOP_MP0_QDCM_REG1_ON);
+
+	return ret;
+}
+
+void dcm_mp_cpusys_top_mp0_qdcm(bool on)
+{
+	if (on) {
+		/* TINFO = "Turn ON DCM 'mp_cpusys_top_mp0_qdcm'" */
+		mmio_clrsetbits_32(MP_MISC_DCM_CFG0,
+			MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+			MP_CPUSYS_TOP_MP0_QDCM_REG0_ON);
+		mmio_clrsetbits_32(MP0_DCM_CFG0,
+			MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK,
+			MP_CPUSYS_TOP_MP0_QDCM_REG1_ON);
+	} else {
+		/* TINFO = "Turn OFF DCM 'mp_cpusys_top_mp0_qdcm'" */
+		mmio_clrsetbits_32(MP_MISC_DCM_CFG0,
+			MP_CPUSYS_TOP_MP0_QDCM_REG0_MASK,
+			MP_CPUSYS_TOP_MP0_QDCM_REG0_OFF);
+		mmio_clrsetbits_32(MP0_DCM_CFG0,
+			MP_CPUSYS_TOP_MP0_QDCM_REG1_MASK,
+			MP_CPUSYS_TOP_MP0_QDCM_REG1_OFF);
+	}
+}
+
+#define CPCCFG_REG_EMI_WFIFO_REG0_MASK (BIT(0) | \
+			BIT(1) | \
+			BIT(2) | \
+			BIT(3))
+#define CPCCFG_REG_EMI_WFIFO_REG0_ON (BIT(0) | \
+			BIT(1) | \
+			BIT(2) | \
+			BIT(3))
+#define CPCCFG_REG_EMI_WFIFO_REG0_OFF ((0x0 << 0) | \
+			(0x0 << 1) | \
+			(0x0 << 2) | \
+			(0x0 << 3))
+
+bool dcm_cpccfg_reg_emi_wfifo_is_on(void)
+{
+	bool ret = true;
+
+	ret &= ((mmio_read_32(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(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(EMI_WFIFO,
+			CPCCFG_REG_EMI_WFIFO_REG0_MASK,
+			CPCCFG_REG_EMI_WFIFO_REG0_OFF);
+	}
+}
+
diff --git a/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.h b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.h
new file mode 100644
index 0000000..1cf7834
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/dcm/mtk_dcm_utils.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_DCM_UTILS_H
+#define MTK_DCM_UTILS_H
+
+#include <stdbool.h>
+
+#include <mtk_dcm.h>
+#include <platform_def.h>
+
+/* Base */
+#define MP_CPUSYS_TOP_BASE	(MCUCFG_BASE + 0x8000)
+#define CPCCFG_REG_BASE		(MCUCFG_BASE + 0xA800)
+
+/* Register Definition */
+#define CPU_PLLDIV_CFG0		(MP_CPUSYS_TOP_BASE + 0x22a0)
+#define CPU_PLLDIV_CFG1		(MP_CPUSYS_TOP_BASE + 0x22a4)
+#define CPU_PLLDIV_CFG2		(MP_CPUSYS_TOP_BASE + 0x22a8)
+#define CPU_PLLDIV_CFG3		(MP_CPUSYS_TOP_BASE + 0x22ac)
+#define CPU_PLLDIV_CFG4		(MP_CPUSYS_TOP_BASE + 0x22b0)
+#define BUS_PLLDIV_CFG		(MP_CPUSYS_TOP_BASE + 0x22e0)
+#define MCSI_DCM0		(MP_CPUSYS_TOP_BASE + 0x2440)
+#define MP_ADB_DCM_CFG0		(MP_CPUSYS_TOP_BASE + 0x2500)
+#define MP_ADB_DCM_CFG4		(MP_CPUSYS_TOP_BASE + 0x2510)
+#define MP_MISC_DCM_CFG0	(MP_CPUSYS_TOP_BASE + 0x2518)
+#define MCUSYS_DCM_CFG0		(MP_CPUSYS_TOP_BASE + 0x25c0)
+#define EMI_WFIFO		(CPCCFG_REG_BASE + 0x100)
+#define MP0_DCM_CFG0		(MP_CPUSYS_TOP_BASE + 0x4880)
+#define MP0_DCM_CFG7		(MP_CPUSYS_TOP_BASE + 0x489c)
+
+/* MP_CPUSYS_TOP */
+bool dcm_mp_cpusys_top_adb_dcm_is_on(void);
+void dcm_mp_cpusys_top_adb_dcm(bool on);
+bool dcm_mp_cpusys_top_apb_dcm_is_on(void);
+void dcm_mp_cpusys_top_apb_dcm(bool on);
+bool dcm_mp_cpusys_top_bus_pll_div_dcm_is_on(void);
+void dcm_mp_cpusys_top_bus_pll_div_dcm(bool on);
+bool dcm_mp_cpusys_top_core_stall_dcm_is_on(void);
+void dcm_mp_cpusys_top_core_stall_dcm(bool on);
+bool dcm_mp_cpusys_top_cpubiu_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpubiu_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_0_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_0_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_1_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_1_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_2_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_2_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_3_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_3_dcm(bool on);
+bool dcm_mp_cpusys_top_cpu_pll_div_4_dcm_is_on(void);
+void dcm_mp_cpusys_top_cpu_pll_div_4_dcm(bool on);
+bool dcm_mp_cpusys_top_fcm_stall_dcm_is_on(void);
+void dcm_mp_cpusys_top_fcm_stall_dcm(bool on);
+bool dcm_mp_cpusys_top_last_cor_idle_dcm_is_on(void);
+void dcm_mp_cpusys_top_last_cor_idle_dcm(bool on);
+bool dcm_mp_cpusys_top_misc_dcm_is_on(void);
+void dcm_mp_cpusys_top_misc_dcm(bool on);
+bool dcm_mp_cpusys_top_mp0_qdcm_is_on(void);
+void dcm_mp_cpusys_top_mp0_qdcm(bool on);
+/* CPCCFG_REG */
+bool dcm_cpccfg_reg_emi_wfifo_is_on(void);
+void dcm_cpccfg_reg_emi_wfifo(bool on);
+
+#endif
diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c
new file mode 100644
index 0000000..d6d4af7
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2020, 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/mt8192/drivers/mcdi/mt_cpu_pm_cpc.c b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.c
new file mode 100644
index 0000000..f8c51a1
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.c
@@ -0,0 +1,269 @@
+/*
+ * Copyright (c) 2020, 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/mt8192/drivers/mcdi/mt_cpu_pm_cpc.h b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.h
new file mode 100644
index 0000000..19dd6a2
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/mcdi/mt_cpu_pm_cpc.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2020, 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)	(uint32_t)(MTK_MCDI_SRAM_BASE + (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 = 0,
+
+	CPC_ERR_FAIL,
+	CPC_ERR_TIMEOUT,
+
+	NF_CPC_ERR
+};
+
+enum {
+	CPC_SMC_EVENT_DUMP_TRACE_DATA,
+	CPC_SMC_EVENT_GIC_DPG_SET,
+	CPC_SMC_EVENT_CPC_CONFIG,
+	CPC_SMC_EVENT_READ_CONFIG,
+
+	NF_CPC_SMC_EVENT
+};
+
+enum {
+	CPC_SMC_CONFIG_PROF,
+	CPC_SMC_CONFIG_AUTO_OFF,
+	CPC_SMC_CONFIG_AUTO_OFF_THRES,
+	CPC_SMC_CONFIG_CNT_CLR,
+	CPC_SMC_CONFIG_TIME_SYNC,
+
+	NF_CPC_SMC_CONFIG
+};
+
+#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/mt8192/drivers/mcdi/mt_mcdi.c b/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.c
new file mode 100644
index 0000000..df74122
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <cdefs.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(0x0c55fce0)
+
+#define MCDI_NOT_INIT			0
+#define MCDI_INIT_1			1
+#define MCDI_INIT_2			2
+#define MCDI_INIT_DONE			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;
+	}
+
+	return (mcdi_init_status == MCDI_INIT_DONE) ? 0 : mcdi_init_status;
+}
diff --git a/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.h b/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.h
new file mode 100644
index 0000000..f3545aa
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/mcdi/mt_mcdi.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2020, 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/mt8192/drivers/pmic/pmic.c b/plat/mediatek/mt8192/drivers/pmic/pmic.c
new file mode 100644
index 0000000..cca4413
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/pmic/pmic.c
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <pmic.h>
+#include <pmic_wrap_init.h>
+
+void pmic_power_off(void)
+{
+	pwrap_write(PMIC_PWRHOLD, 0x0);
+}
diff --git a/plat/mediatek/mt8192/drivers/pmic/pmic.h b/plat/mediatek/mt8192/drivers/pmic/pmic.h
new file mode 100644
index 0000000..aac22af
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/pmic/pmic.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PMIC_H
+#define PMIC_H
+
+#define PMIC_PWRHOLD 0xa08
+
+/* external API */
+void pmic_power_off(void);
+
+#endif /* PMIC_H */
diff --git a/plat/mediatek/mt8192/drivers/pmic/pmic_wrap_init.h b/plat/mediatek/mt8192/drivers/pmic/pmic_wrap_init.h
new file mode 100644
index 0000000..ae892ed
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/pmic/pmic_wrap_init.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2020, 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 mt8192_pmic_wrap_regs *const mtk_pwrap = (void *)PMIC_WRAP_BASE;
+
+/* PMIC_WRAP registers */
+struct mt8192_pmic_wrap_regs {
+	uint32_t init_done;
+	uint32_t reserved[799];
+	uint32_t wacs2_cmd;
+	uint32_t wacs2_wdata;
+	uint32_t reserved1[3];
+	uint32_t wacs2_rdata;
+	uint32_t reserved2[3];
+	uint32_t wacs2_vldclr;
+	uint32_t wacs2_sta;
+};
+
+#define GET_WACS_FSM(x)	((x >> 1) & 0x7)
+
+/* macro for SWINF_FSM */
+#define SWINF_FSM_IDLE		(0x00)
+#define SWINF_FSM_REQ		(0x02)
+#define SWINF_FSM_WFDLE		(0x04)
+#define SWINF_FSM_WFVLDCLR	(0x06)
+#define SWINF_INIT_DONE		(0x01)
+
+/* timeout setting */
+#define PWRAP_READ_US	1000
+#define PWRAP_WAIT_IDLE_US	1000
+
+/* error information flag */
+enum pwrap_errno {
+	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/mt8192/drivers/ptp3/mtk_ptp3_common.h b/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_common.h
new file mode 100644
index 0000000..92c71bc
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_common.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef MTK_PTP3_H
+#define MTK_PTP3_H
+
+#include <lib/mmio.h>
+#include <lib/utils_def.h>
+
+/************************************************
+ * BIT Operation and REG r/w
+ ************************************************/
+#define ptp3_read(addr)		mmio_read_32((uintptr_t)addr)
+#define ptp3_write(addr, val)	mmio_write_32((uintptr_t)addr, val)
+
+/************************************************
+ * CPU info
+ ************************************************/
+#define NR_PTP3_CFG1_CPU	U(8)
+#define PTP3_CFG1_CPU_START_ID	U(0)
+#define PTP3_CFG1_MASK		0x00100000
+
+#define NR_PTP3_CFG2_CPU	U(4)
+#define PTP3_CFG2_CPU_START_ID	U(4)
+
+#define NR_PTP3_CFG3_CPU	U(4)
+#define PTP3_CFG3_CPU_START_ID	U(4)
+
+/************************************************
+ * config enum
+ ************************************************/
+enum PTP3_CFG {
+	PTP3_CFG_ADDR,
+	PTP3_CFG_VALUE,
+	NR_PTP3_CFG,
+};
+
+/************************************
+ * prototype
+ ************************************/
+/* init trigger for ptp3 feature */
+extern void ptp3_init(unsigned int core);
+extern void ptp3_deinit(unsigned int core);
+
+#endif /* MTK_PTP3_H */
diff --git a/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_main.c b/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_main.c
new file mode 100644
index 0000000..053d210
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_main.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved. \
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "mtk_ptp3_common.h"
+
+/************************************************
+ * Central control: turn on sysPi protection
+ ************************************************/
+static unsigned int ptp3_cfg1[NR_PTP3_CFG1_CPU][NR_PTP3_CFG] = {
+	{0x0C530610, 0x110842},
+	{0x0C530E10, 0x110842},
+	{0x0C531610, 0x110842},
+	{0x0C531E10, 0x110842},
+	{0x0C532610, 0x110842},
+	{0x0C532E10, 0x110842},
+	{0x0C533610, 0x110842},
+	{0x0C533E10, 0x110842}
+};
+static unsigned int ptp3_cfg2[NR_PTP3_CFG2_CPU][NR_PTP3_CFG] = {
+	{0x0C53B830, 0x68000},
+	{0x0C53BA30, 0x68000},
+	{0x0C53BC30, 0x68000},
+	{0x0C53BE30, 0x68000}
+};
+static unsigned int ptp3_cfg3[NR_PTP3_CFG3_CPU][NR_PTP3_CFG] = {
+	{0x0C532480, 0x7C607C6},
+	{0x0C532C80, 0x7C607C6},
+	{0x0C533480, 0x7C607C6},
+	{0x0C533C80, 0x7C607C6}
+};
+
+/************************************************
+ * API
+ ************************************************/
+void ptp3_init(unsigned int core)
+{
+	unsigned int _core;
+
+	if (core >= PTP3_CFG1_CPU_START_ID) {
+		if (core < NR_PTP3_CFG1_CPU) {
+			/* update ptp3_cfg1 */
+			ptp3_write(
+				ptp3_cfg1[core][PTP3_CFG_ADDR],
+				ptp3_cfg1[core][PTP3_CFG_VALUE]);
+		}
+	}
+
+	if (core >= PTP3_CFG2_CPU_START_ID) {
+		_core = core - PTP3_CFG2_CPU_START_ID;
+
+		if (_core < NR_PTP3_CFG2_CPU) {
+			/* update ptp3_cfg2 */
+			ptp3_write(
+				ptp3_cfg2[_core][PTP3_CFG_ADDR],
+				ptp3_cfg2[_core][PTP3_CFG_VALUE]);
+		}
+	}
+
+	if (core >= PTP3_CFG3_CPU_START_ID) {
+		_core = core - PTP3_CFG3_CPU_START_ID;
+
+		if (_core < NR_PTP3_CFG3_CPU) {
+			/* update ptp3_cfg3 */
+			ptp3_write(
+				ptp3_cfg3[_core][PTP3_CFG_ADDR],
+				ptp3_cfg3[_core][PTP3_CFG_VALUE]);
+		}
+	}
+}
+
+void ptp3_deinit(unsigned int core)
+{
+	if (core >= PTP3_CFG1_CPU_START_ID) {
+		if (core < NR_PTP3_CFG1_CPU) {
+			/* update ptp3_cfg1 */
+			ptp3_write(
+				ptp3_cfg1[core][PTP3_CFG_ADDR],
+				ptp3_cfg1[core][PTP3_CFG_VALUE] &
+					 ~PTP3_CFG1_MASK);
+		}
+	}
+}
diff --git a/plat/mediatek/mt8192/drivers/spmc/mtspmc.c b/plat/mediatek/mt8192/drivers/spmc/mtspmc.c
new file mode 100644
index 0000000..7ccebd6
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spmc/mtspmc.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2020, 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>
+
+
+void mcucfg_disable_gic_wakeup(uint32_t cluster, uint32_t cpu)
+{
+	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu));
+}
+
+void mcucfg_enable_gic_wakeup(uint32_t cluster, uint32_t cpu)
+{
+	mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(cpu));
+}
+
+void mcucfg_set_bootaddr(uint32_t cluster, uint32_t cpu, uintptr_t bootaddr)
+{
+	assert(cluster == 0U);
+
+	mmio_write_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR), bootaddr);
+}
+
+uintptr_t mcucfg_get_bootaddr(uint32_t cluster, uint32_t cpu)
+{
+	assert(cluster == 0U);
+
+	return (uintptr_t)mmio_read_32(per_cpu(cluster, cpu, MCUCFG_BOOTADDR));
+}
+
+void mcucfg_init_archstate(uint32_t cluster, uint32_t 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) != 0U;
+}
+
+bool spm_get_cluster_powerstate(uint32_t cluster)
+{
+	assert(cluster == 0U);
+
+	return spm_get_powerstate(MP0_CPUTOP);
+}
+
+bool spm_get_cpu_powerstate(uint32_t cluster, uint32_t cpu)
+{
+	uint32_t mask = BIT(cpu);
+
+	assert(cluster == 0U);
+
+	return spm_get_powerstate(mask);
+}
+
+int spmc_init(void)
+{
+	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_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(1));
+	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(2));
+	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(3));
+	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(4));
+	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(5));
+	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(6));
+	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, GIC_WAKEUP_IGNORE(7));
+
+	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);
+
+	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(uint32_t cluster, uint32_t cpu)
+{
+	/* set to 0 after BIG VPROC bulk on & before B-core power on seq. */
+	if (cpu >= 4U) {
+		mmio_write_32(DREQ20_BIG_VPROC_ISO, 0U);
+	}
+
+	mmio_setbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN);
+	mmio_setbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWR_ON);
+
+	while (!spm_get_cpu_powerstate(cluster, cpu)) {
+	}
+
+	mmio_clrbits_32(MCUCFG_CPC_FLOW_CTRL_CFG, SSPM_ALL_PWR_CTRL_EN);
+
+	/* Enable Big CPU Last PC */
+	if (cpu >= 4U) {
+		mmio_clrbits_32(LAST_PC_REG(cpu), BIT(3));
+	}
+}
+
+/**
+ * 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(uint32_t cluster, uint32_t 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(uint32_t 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(uint32_t cluster)
+{
+	/* No need to power on/off cluster on single cluster platform */
+	assert(false);
+}
diff --git a/plat/mediatek/mt8192/drivers/spmc/mtspmc.h b/plat/mediatek/mt8192/drivers/spmc/mtspmc.h
new file mode 100644
index 0000000..7ed2e62
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spmc/mtspmc.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2020, 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(uint32_t cluster, uint32_t cpu);
+void spm_poweroff_cpu(uint32_t cluster, uint32_t cpu);
+
+void spm_poweroff_cluster(uint32_t cluster);
+void spm_poweron_cluster(uint32_t cluster);
+
+bool spm_get_cpu_powerstate(uint32_t cluster, uint32_t cpu);
+bool spm_get_cluster_powerstate(uint32_t cluster);
+bool spm_get_powerstate(uint32_t mask);
+
+void mcucfg_init_archstate(uint32_t cluster, uint32_t cpu, bool arm64);
+void mcucfg_set_bootaddr(uint32_t cluster, uint32_t cpu, uintptr_t bootaddr);
+uintptr_t mcucfg_get_bootaddr(uint32_t cluster, uint32_t cpu);
+
+void mcucfg_disable_gic_wakeup(uint32_t cluster, uint32_t cpu);
+void mcucfg_enable_gic_wakeup(uint32_t cluster, uint32_t cpu);
+
+#endif /* MTSPMC_H */
diff --git a/plat/mediatek/mt8192/drivers/spmc/mtspmc_private.h b/plat/mediatek/mt8192/drivers/spmc/mtspmc_private.h
new file mode 100644
index 0000000..ad78295
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/spmc/mtspmc_private.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2020, 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		MCUCFG_REG(0xd200)
+#define SPM_MP0_CPUTOP_PWR_CON		MCUCFG_REG(0xd204)
+#define SPM_MP0_CPU0_PWR_CON		MCUCFG_REG(0xd208)
+#define SPM_MP0_CPU1_PWR_CON		MCUCFG_REG(0xd20c)
+#define SPM_MP0_CPU2_PWR_CON		MCUCFG_REG(0xd210)
+#define SPM_MP0_CPU3_PWR_CON		MCUCFG_REG(0xd214)
+#define SPM_MP0_CPU4_PWR_CON		MCUCFG_REG(0xd218)
+#define SPM_MP0_CPU5_PWR_CON		MCUCFG_REG(0xd21c)
+#define SPM_MP0_CPU6_PWR_CON		MCUCFG_REG(0xd220)
+#define SPM_MP0_CPU7_PWR_CON		MCUCFG_REG(0xd224)
+
+/* bit fields of SPM_*_PWR_CON */
+#define PWR_ON_ACK			BIT(31)
+#define VPROC_EXT_OFF			BIT(7)
+#define DORMANT_EN			BIT(6)
+#define RESETPWRON_CONFIG		BIT(5)
+#define PWR_CLK_DIS			BIT(4)
+#define PWR_ON				BIT(2)
+#define PWR_RST_B			BIT(0)
+
+/**** 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 */
+/* aa64naa32 */
+#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)
+
+/* MCUSYS DREQ BIG VPROC ISO control */
+#define DREQ20_BIG_VPROC_ISO		MCUCFG_REG(0xad8c)
+
+/**** 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)
+#define LAST_PC_REG(cpu)		(MCUCFG_REG(0x308) + (cpu * 0x800))
+
+/* === 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(15, 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/mt8192/drivers/timer/mt_timer.c b/plat/mediatek/mt8192/drivers/timer/mt_timer.c
index 781f940..0860885 100644
--- a/plat/mediatek/mt8192/drivers/timer/mt_timer.c
+++ b/plat/mediatek/mt8192/drivers/timer/mt_timer.c
@@ -5,6 +5,7 @@
  */
 
 #include <arch_helpers.h>
+#include <lib/mmio.h>
 #include <mt_timer.h>
 #include <platform_def.h>
 
@@ -28,3 +29,10 @@
 		- normal_time_base;
 	return cval;
 }
+
+void mt_systimer_init(void)
+{
+	/* Enable access in NS mode */
+	mmio_write_32(CNTWACR_REG, CNT_WRITE_ACCESS_CTL_MASK);
+	mmio_write_32(CNTRACR_REG, CNT_READ_ACCESS_CTL_MASK);
+}
diff --git a/plat/mediatek/mt8192/drivers/timer/mt_timer.h b/plat/mediatek/mt8192/drivers/timer/mt_timer.h
index 7aca4a3..b353177 100644
--- a/plat/mediatek/mt8192/drivers/timer/mt_timer.h
+++ b/plat/mediatek/mt8192/drivers/timer/mt_timer.h
@@ -12,6 +12,8 @@
 #define CNTSR_REG           (SYSTIMER_BASE + 0x4)
 #define CNTSYS_L_REG        (SYSTIMER_BASE + 0x8)
 #define CNTSYS_H_REG        (SYSTIMER_BASE + 0xc)
+#define CNTWACR_REG         (SYSTIMER_BASE + 0x10)
+#define CNTRACR_REG         (SYSTIMER_BASE + 0x14)
 
 #define TIEO_EN             (1 << 3)
 #define COMP_15_EN          (1 << 10)
@@ -23,8 +25,11 @@
 #define COMP_20_MASK (COMP_20_EN | TIEO_EN)
 #define COMP_25_MASK (COMP_20_EN | COMP_25_EN)
 
+#define CNT_WRITE_ACCESS_CTL_MASK (0x3FFFFF0U)
+#define CNT_READ_ACCESS_CTL_MASK  (0x3FFFFFFU)
 
 void sched_clock_init(uint64_t normal_base, uint64_t atf_base);
 uint64_t sched_clock(void);
+void mt_systimer_init(void);
 
 #endif /* MT_TIMER_H */
diff --git a/plat/mediatek/mt8192/drivers/uart/uart.h b/plat/mediatek/mt8192/drivers/uart/uart.h
new file mode 100644
index 0000000..ac8b94d
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/uart/uart.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef UART_H
+#define UART_H
+
+#include <platform_def.h>
+
+/* UART HW information */
+#define HW_SUPPORT_UART_PORTS	2
+#define DRV_SUPPORT_UART_PORTS	2
+
+/* console UART clock cg */
+#define UART_CLOCK_GATE_SET		(INFRACFG_AO_BASE + 0x80)
+#define UART_CLOCK_GATE_CLR		(INFRACFG_AO_BASE + 0x84)
+#define UART_CLOCK_GATE_STA		(INFRACFG_AO_BASE + 0x90)
+#define UART0_CLOCK_GATE_BIT		(1U<<22)
+#define UART1_CLOCK_GATE_BIT		(1U<<23)
+
+/* UART registers */
+#define UART_RBR(_baseaddr)			(_baseaddr + 0x0)
+#define UART_THR(_baseaddr)			(_baseaddr + 0x0)
+#define UART_IER(_baseaddr)			(_baseaddr + 0x4)
+#define UART_IIR(_baseaddr)			(_baseaddr + 0x8)
+#define UART_FCR(_baseaddr)			(_baseaddr + 0x8)
+#define UART_LCR(_baseaddr)			(_baseaddr + 0xc)
+#define UART_MCR(_baseaddr)			(_baseaddr + 0x10)
+#define UART_LSR(_baseaddr)			(_baseaddr + 0x14)
+#define UART_MSR(_baseaddr)			(_baseaddr + 0x18)
+#define UART_SCR(_baseaddr)			(_baseaddr + 0x1c)
+#define UART_DLL(_baseaddr)			(_baseaddr + 0x0)
+#define UART_DLH(_baseaddr)			(_baseaddr + 0x4)
+#define UART_EFR(_baseaddr)			(_baseaddr + 0x8)
+#define UART_XON1(_baseaddr)			(_baseaddr + 0x10)
+#define UART_XON2(_baseaddr)			(_baseaddr + 0x14)
+#define UART_XOFF1(_baseaddr)			(_baseaddr + 0x18)
+#define UART_XOFF2(_baseaddr)			(_baseaddr + 0x1c)
+#define UART_AUTOBAUD(_baseaddr)		(_baseaddr + 0x20)
+#define UART_HIGHSPEED(_baseaddr)		(_baseaddr + 0x24)
+#define UART_SAMPLE_COUNT(_baseaddr)		(_baseaddr + 0x28)
+#define UART_SAMPLE_POINT(_baseaddr)		(_baseaddr + 0x2c)
+#define UART_AUTOBAUD_REG(_baseaddr)		(_baseaddr + 0x30)
+#define UART_RATE_FIX_REG(_baseaddr)		(_baseaddr + 0x34)
+#define UART_AUTO_BAUDSAMPLE(_baseaddr)		(_baseaddr + 0x38)
+#define UART_GUARD(_baseaddr)			(_baseaddr + 0x3c)
+#define UART_ESCAPE_DAT(_baseaddr)		(_baseaddr + 0x40)
+#define UART_ESCAPE_EN(_baseaddr)		(_baseaddr + 0x44)
+#define UART_SLEEP_EN(_baseaddr)		(_baseaddr + 0x48)
+#define UART_DMA_EN(_baseaddr)			(_baseaddr + 0x4c)
+#define UART_RXTRI_AD(_baseaddr)		(_baseaddr + 0x50)
+#define UART_FRACDIV_L(_baseaddr)		(_baseaddr + 0x54)
+#define UART_FRACDIV_M(_baseaddr)		(_baseaddr + 0x58)
+#define UART_FCR_RD(_baseaddr)			(_baseaddr + 0x5C)
+#define UART_USB_RX_SEL(_baseaddr)		(_baseaddr + 0xB0)
+#define UART_SLEEP_REQ(_baseaddr)		(_baseaddr + 0xB4)
+#define UART_SLEEP_ACK(_baseaddr)		(_baseaddr + 0xB8)
+#define UART_SPM_SEL(_baseaddr)			(_baseaddr + 0xBC)
+#define UART_LCR_DLAB				0x0080
+#define UART_LCR_MODE_B				0x00bf
+
+enum uart_port_ID {
+	UART_PORT0 = 0,
+	UART_PORT1
+};
+
+struct mt_uart_register {
+	uint32_t dll;
+	uint32_t dlh;
+	uint32_t ier;
+	uint32_t lcr;
+	uint32_t mcr;
+	uint32_t fcr;
+	uint32_t lsr;
+	uint32_t scr;
+	uint32_t efr;
+	uint32_t highspeed;
+	uint32_t sample_count;
+	uint32_t sample_point;
+	uint32_t fracdiv_l;
+	uint32_t fracdiv_m;
+	uint32_t escape_en;
+	uint32_t guard;
+	uint32_t rx_sel;
+};
+
+struct mt_uart {
+	unsigned long base;
+	struct mt_uart_register registers;
+};
+
+/* external API */
+void mt_uart_save(void);
+void mt_uart_restore(void);
+void mt_console_uart_cg(int on);
+uint32_t mt_console_uart_cg_status(void);
+
+#endif /* __UART_H__ */
diff --git a/plat/mediatek/mt8192/include/mcucfg.h b/plat/mediatek/mt8192/include/mcucfg.h
new file mode 100644
index 0000000..046cf73
--- /dev/null
+++ b/plat/mediatek/mt8192/include/mcucfg.h
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2020, 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/mt8192/include/plat_mt_cirq.h b/plat/mediatek/mt8192/include/plat_mt_cirq.h
index 5818601..bb8b457 100644
--- a/plat/mediatek/mt8192/include/plat_mt_cirq.h
+++ b/plat/mediatek/mt8192/include/plat_mt_cirq.h
@@ -7,24 +7,53 @@
 #ifndef PLAT_MT_CIRQ_H
 #define PLAT_MT_CIRQ_H
 
-#define SYS_CIRQ_BASE        U(0x10204000)
-#define CIRQ_IRQ_NUM         U(439)
-#define CIRQ_SPI_START       U(96)
+#include <stdint.h>
+
+enum {
+	IRQ_MASK_HEADER = 0xF1F1F1F1,
+	IRQ_MASK_FOOTER = 0xF2F2F2F2
+};
+
+struct mtk_irq_mask {
+	uint32_t header;	/* for error checking */
+	uint32_t mask0;
+	uint32_t mask1;
+	uint32_t mask2;
+	uint32_t mask3;
+	uint32_t mask4;
+	uint32_t mask5;
+	uint32_t mask6;
+	uint32_t mask7;
+	uint32_t mask8;
+	uint32_t mask9;
+	uint32_t mask10;
+	uint32_t mask11;
+	uint32_t mask12;
+	uint32_t footer;	/* for error checking */
+};
+
 /*
  * Define hardware register
  */
-#define  CIRQ_STA_BASE         U(0x000)
-#define  CIRQ_ACK_BASE         U(0x080)
-#define  CIRQ_MASK_BASE        U(0x100)
-#define  CIRQ_MASK_SET_BASE    U(0x180)
-#define  CIRQ_MASK_CLR_BASE    U(0x200)
-#define  CIRQ_SENS_BASE        U(0x280)
-#define  CIRQ_SENS_SET_BASE    U(0x300)
-#define  CIRQ_SENS_CLR_BASE    U(0x380)
-#define  CIRQ_POL_BASE         U(0x400)
-#define  CIRQ_POL_SET_BASE     U(0x480)
-#define  CIRQ_POL_CLR_BASE     U(0x500)
-#define  CIRQ_CON              U(0x600)
+
+#define  SYS_CIRQ_BASE         U(0x10204000)
+#define  CIRQ_REG_NUM          U(14)
+#define  CIRQ_IRQ_NUM          U(439)
+#define  CIRQ_SPI_START        U(64)
+#define  MD_WDT_IRQ_BIT_ID     U(110)
+
+#define  CIRQ_STA_BASE         (SYS_CIRQ_BASE + U(0x000))
+#define  CIRQ_ACK_BASE         (SYS_CIRQ_BASE + U(0x080))
+#define  CIRQ_MASK_BASE        (SYS_CIRQ_BASE + U(0x100))
+#define  CIRQ_MASK_SET_BASE    (SYS_CIRQ_BASE + U(0x180))
+#define  CIRQ_MASK_CLR_BASE    (SYS_CIRQ_BASE + U(0x200))
+#define  CIRQ_SENS_BASE        (SYS_CIRQ_BASE + U(0x280))
+#define  CIRQ_SENS_SET_BASE    (SYS_CIRQ_BASE + U(0x300))
+#define  CIRQ_SENS_CLR_BASE    (SYS_CIRQ_BASE + U(0x380))
+#define  CIRQ_POL_BASE         (SYS_CIRQ_BASE + U(0x400))
+#define  CIRQ_POL_SET_BASE     (SYS_CIRQ_BASE + U(0x480))
+#define  CIRQ_POL_CLR_BASE     (SYS_CIRQ_BASE + U(0x500))
+#define  CIRQ_CON              (SYS_CIRQ_BASE + U(0x600))
 
 /*
  * Register placement
@@ -32,8 +61,8 @@
 #define  CIRQ_CON_EN_BITS           U(0)
 #define  CIRQ_CON_EDGE_ONLY_BITS    U(1)
 #define  CIRQ_CON_FLUSH_BITS        U(2)
-#define  CIRQ_CON_EVENT_BITS        U(31)
 #define  CIRQ_CON_SW_RST_BITS       U(20)
+#define  CIRQ_CON_EVENT_BITS        U(31)
 #define  CIRQ_CON_BITS_MASK         U(0x7)
 
 /*
@@ -41,42 +70,59 @@
  */
 #define  CIRQ_CON_EN            U(0x1)
 #define  CIRQ_CON_EDGE_ONLY     U(0x1)
-#define  CIRQ_SW_RESET          U(0x1)
 #define  CIRQ_CON_FLUSH         U(0x1)
+#define  CIRQ_SW_RESET          U(0x1)
 
 /*
  * Define constant
  */
 #define  CIRQ_CTRL_REG_NUM      ((CIRQ_IRQ_NUM + 31U) / 32U)
-#define  MT_CIRQ_POL_NEG               U(0)
-#define  MT_CIRQ_POL_POS               U(1)
-#define  MT_CIRQ_EDGE_SENSITIVE        U(0)
-#define  MT_CIRQ_LEVEL_SENSITIVE       U(1)
 
-/*
- * Define macro
- */
-#define  IRQ_TO_CIRQ_NUM(irq)       ((irq) - (CIRQ_SPI_START))
-#define  CIRQ_TO_IRQ_NUM(cirq)      ((cirq) + (CIRQ_SPI_START))
+#define  MT_CIRQ_POL_NEG        U(0)
+#define  MT_CIRQ_POL_POS        U(1)
 
-/*
- * Define cirq events
- */
-struct cirq_events {
-	uint32_t spi_start;
-	uint32_t num_of_events;
-	uint32_t *wakeup_events;
-};
+#define IRQ_TO_CIRQ_NUM(irq)  ((irq) - (32U + CIRQ_SPI_START))
+#define CIRQ_TO_IRQ_NUM(cirq) ((cirq) + (32U + CIRQ_SPI_START))
+
+/* GIC sensitive */
+#define SENS_EDGE	U(0x2)
+#define SENS_LEVEL	U(0x1)
+
 
 /*
  * Define function prototypes.
  */
-void mt_cirq_enable(void);
-void mt_cirq_disable(void);
+int mt_cirq_test(void);
+void mt_cirq_dump_reg(void);
+int mt_irq_mask_restore(struct mtk_irq_mask *mask);
+int mt_irq_mask_all(struct mtk_irq_mask *mask);
 void mt_cirq_clone_gic(void);
+void mt_cirq_enable(void);
 void mt_cirq_flush(void);
-void mt_cirq_sw_reset(void);
+void mt_cirq_disable(void);
+void mt_irq_unmask_for_sleep_ex(uint32_t irq);
 void set_wakeup_sources(uint32_t *list, uint32_t num_of_events);
-void mt_cirq_dump_reg(void);
+void mt_cirq_sw_reset(void);
+
+struct cirq_reg {
+	uint32_t reg_num;
+	uint32_t used;
+	uint32_t mask;
+	uint32_t pol;
+	uint32_t sen;
+	uint32_t pending;
+	uint32_t the_link;
+};
+
+struct cirq_events {
+	uint32_t num_reg;
+	uint32_t spi_start;
+	uint32_t num_of_events;
+	uint32_t *wakeup_events;
+	struct cirq_reg table[CIRQ_REG_NUM];
+	uint32_t dist_base;
+	uint32_t cirq_base;
+	uint32_t used_reg_head;
+};
 
-#endif  /* PLAT_MT_CIRQ_H */
+#endif /* PLAT_MT_CIRQ_H */
diff --git a/plat/mediatek/mt8192/include/plat_mtk_lpm.h b/plat/mediatek/mt8192/include/plat_mtk_lpm.h
new file mode 100644
index 0000000..8ba8b93
--- /dev/null
+++ b/plat/mediatek/mt8192/include/plat_mtk_lpm.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2020, 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(8)
+#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/mt8192/include/plat_pm.h b/plat/mediatek/mt8192/include/plat_pm.h
new file mode 100644
index 0000000..a2881ce
--- /dev/null
+++ b/plat/mediatek/mt8192/include/plat_pm.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2020, 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/mt8192/include/plat_sip_calls.h b/plat/mediatek/mt8192/include/plat_sip_calls.h
new file mode 100644
index 0000000..0e42322
--- /dev/null
+++ b/plat/mediatek/mt8192/include/plat_sip_calls.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2020, 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/mt8192/include/platform_def.h b/plat/mediatek/mt8192/include/platform_def.h
index 768e7cf..51cf361 100644
--- a/plat/mediatek/mt8192/include/platform_def.h
+++ b/plat/mediatek/mt8192/include/platform_def.h
@@ -23,8 +23,13 @@
 #define MTK_DEV_RNG1_SIZE    0x10000000
 #define MTK_DEV_RNG2_BASE    0x0c000000
 #define MTK_DEV_RNG2_SIZE    0x600000
+#define MTK_MCDI_SRAM_BASE      0x11B000
+#define MTK_MCDI_SRAM_MAP_SIZE  0x1000
 
+#define INFRACFG_AO_BASE (IO_PHYS + 0x00001000)
 #define GPIO_BASE        (IO_PHYS + 0x00005000)
+#define SPM_BASE         (IO_PHYS + 0x00006000)
+#define PMIC_WRAP_BASE   (IO_PHYS + 0x00026000)
 #define IOCFG_RM_BASE    (IO_PHYS + 0x01C20000)
 #define IOCFG_BM_BASE    (IO_PHYS + 0x01D10000)
 #define IOCFG_BL_BASE    (IO_PHYS + 0x01D30000)
@@ -67,11 +72,12 @@
  ******************************************************************************/
 #define PLATFORM_STACK_SIZE    0x800
 
-#define PLAT_MAX_PWR_LVL        U(2)
+#define PLAT_MAX_PWR_LVL        U(3)
 #define PLAT_MAX_RET_STATE      U(1)
-#define PLAT_MAX_OFF_STATE      U(2)
+#define PLAT_MAX_OFF_STATE      U(9)
 
 #define PLATFORM_SYSTEM_COUNT           U(1)
+#define PLATFORM_MCUSYS_COUNT           U(1)
 #define PLATFORM_CLUSTER_COUNT          U(1)
 #define PLATFORM_CLUSTER0_CORE_COUNT    U(8)
 #define PLATFORM_CORE_COUNT             (PLATFORM_CLUSTER0_CORE_COUNT)
diff --git a/plat/mediatek/mt8192/plat_mt_cirq.c b/plat/mediatek/mt8192/plat_mt_cirq.c
index 7fc0607..9002b7e 100644
--- a/plat/mediatek/mt8192/plat_mt_cirq.c
+++ b/plat/mediatek/mt8192/plat_mt_cirq.c
@@ -7,137 +7,255 @@
 #include <arch_helpers.h>
 #include <common/debug.h>
 #include <drivers/arm/gic_common.h>
-#include <drivers/console.h>
 #include <lib/mmio.h>
 
 #include <mt_gic_v3.h>
-#include <mtk_plat_common.h>
 #include <plat_mt_cirq.h>
 #include <platform_def.h>
 
 static struct cirq_events cirq_all_events = {
-	.spi_start = CIRQ_SPI_START
+	.spi_start = CIRQ_SPI_START,
 };
-
-static inline void  mt_cirq_write32(uint32_t val, uint32_t addr)
-{
-	mmio_write_32(addr + SYS_CIRQ_BASE, val);
-}
-
-static inline uint32_t mt_cirq_read32(uint32_t addr)
-{
-	return mmio_read_32(addr + SYS_CIRQ_BASE);
-}
-
+static uint32_t already_cloned;
 /*
- * cirq_clone_flush_check_store:
- * set 1 if we need to enable clone/flush value's check
+ * mt_irq_mask_restore: restore all interrupts
+ * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
+ * Return 0 for success; return negative values for failure.
+ * (This is ONLY used for the idle current measurement by the factory mode.)
  */
-static int32_t cirq_clone_flush_check_val;
+int mt_irq_mask_restore(struct mtk_irq_mask *mask)
+{
+	if (mask == NULL) {
+		return -1;
+	}
+	if (mask->header != IRQ_MASK_HEADER) {
+		return -1;
+	}
+	if (mask->footer != IRQ_MASK_FOOTER) {
+		return -1;
+	}
 
-/*
- * cirq_pattern_clone_flush_check_show:  set 1 if we need to do pattern test.
- */
-static int32_t cirq_pattern_clone_flush_check_val;
+	 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x4),
+		mask->mask1);
+	 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x8),
+		mask->mask2);
+	 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0xc),
+		mask->mask3);
+	 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x10),
+		mask->mask4);
+	 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x14),
+		mask->mask5);
+	 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x18),
+		mask->mask6);
+	 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x1c),
+		mask->mask7);
+	 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x20),
+		mask->mask8);
+	 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x24),
+		mask->mask9);
+	 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x28),
+		mask->mask10);
+	 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x2c),
+		mask->mask11);
+	 mmio_write_32((BASE_GICD_BASE + GICD_ISENABLER + 0x30),
+		mask->mask12);
+	/* make sure dist changes happen */
+	dsb();
 
-/*
- * cirq_pattern_clone_flush_check_show:  set 1 if we need to do pattern test.
- */
-static int32_t cirq_pattern_list;
+	return 0;
+}
 
 /*
- * mt_cirq_ack_all: Ack all the interrupt on SYS_CIRQ
+ * mt_irq_mask_all: disable all interrupts
+ * @mask: pointer to struct mtk_irq_mask for storing the original mask value.
+ * Return 0 for success; return negative values for failure.
+ * (This is ONLY used for the idle current measurement by the factory mode.)
  */
-void mt_cirq_ack_all(void)
+int mt_irq_mask_all(struct mtk_irq_mask *mask)
 {
-	unsigned int i;
+	if (mask != NULL) {
+		/* for SPI */
+		mask->mask1 = mmio_read_32((BASE_GICD_BASE +
+			GICD_ISENABLER + 0x4));
+		mask->mask2 = mmio_read_32((BASE_GICD_BASE +
+			GICD_ISENABLER + 0x8));
+		mask->mask3 = mmio_read_32((BASE_GICD_BASE +
+			GICD_ISENABLER + 0xc));
+		mask->mask4 = mmio_read_32((BASE_GICD_BASE +
+			GICD_ISENABLER + 0x10));
+		mask->mask5 = mmio_read_32((BASE_GICD_BASE +
+			GICD_ISENABLER + 0x14));
+		mask->mask6 = mmio_read_32((BASE_GICD_BASE +
+			GICD_ISENABLER + 0x18));
+		mask->mask7 = mmio_read_32((BASE_GICD_BASE +
+			GICD_ISENABLER + 0x1c));
+		mask->mask8 = mmio_read_32((BASE_GICD_BASE +
+			GICD_ISENABLER + 0x20));
+		mask->mask9 = mmio_read_32((BASE_GICD_BASE +
+			GICD_ISENABLER + 0x24));
+		mask->mask10 = mmio_read_32((BASE_GICD_BASE +
+			GICD_ISENABLER + 0x28));
+		mask->mask11 = mmio_read_32((BASE_GICD_BASE +
+			GICD_ISENABLER + 0x2c));
+		mask->mask12 = mmio_read_32((BASE_GICD_BASE +
+			GICD_ISENABLER + 0x30));
 
-	for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) {
-		mt_cirq_write32(0xFFFFFFFF, CIRQ_ACK_BASE + (i * 4U));
+		/* for SPI */
+		mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x4),
+			0xFFFFFFFF);
+		mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x8),
+			0xFFFFFFFF);
+		mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0xC),
+			0xFFFFFFFF);
+		mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x10),
+			0xFFFFFFFF);
+		mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x14),
+			0xFFFFFFFF);
+		mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x18),
+			0xFFFFFFFF);
+		mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x1C),
+			0xFFFFFFFF);
+		mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x20),
+			0xFFFFFFFF);
+		mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x24),
+			0xFFFFFFFF);
+		mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x28),
+			0xFFFFFFFF);
+		mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x2c),
+			0xFFFFFFFF);
+		mmio_write_32((BASE_GICD_BASE + GICD_ICENABLER + 0x30),
+			0xFFFFFFFF);
+		/* make sure distributor changes happen */
+		dsb();
+
+		mask->header = IRQ_MASK_HEADER;
+		mask->footer = IRQ_MASK_FOOTER;
+
+		return 0;
+	} else {
+		return -1;
 	}
-	/* make sure all cirq setting take effect before doing other things */
-	dmbsy();
 }
 
-/*
- * mt_cirq_enable: Enable SYS_CIRQ
- */
-void mt_cirq_enable(void)
+static uint32_t mt_irq_get_pol(uint32_t irq)
 {
-	uint32_t st;
+#ifdef CIRQ_WITH_POLARITY
+	uint32_t reg;
+	uint32_t base = INT_POL_CTL0;
 
-	mt_cirq_ack_all();
+	if (irq < 32U) {
+		return 0;
+	}
 
-	st = mt_cirq_read32(CIRQ_CON);
-	st |= (CIRQ_CON_EN << CIRQ_CON_EN_BITS) |
-			(CIRQ_CON_EDGE_ONLY << CIRQ_CON_EDGE_ONLY_BITS);
+	reg = ((irq - 32U) / 32U);
 
-	mt_cirq_write32((st & CIRQ_CON_BITS_MASK), CIRQ_CON);
+	return  mmio_read_32(base + reg * 4U);
+#else
+	return 0;
+#endif
 }
 
-/*
- * mt_cirq_disable: Disable SYS_CIRQ
- */
-void mt_cirq_disable(void)
+unsigned int mt_irq_get_sens(unsigned int irq)
 {
-	uint32_t st;
+	unsigned int config;
 
-	st = mt_cirq_read32(CIRQ_CON);
-	st &= ~(CIRQ_CON_EN << CIRQ_CON_EN_BITS);
+	/*
+	 * 2'b10 edge
+	 * 2'b01 level
+	 */
+	config = mmio_read_32(MT_GIC_BASE + GICD_ICFGR + (irq / 16U) * 4U);
+	config = (config >> (irq % 16U) * 2U) & 0x3;
 
-	mt_cirq_write32((st & CIRQ_CON_BITS_MASK), CIRQ_CON);
+	return config;
 }
 
-/*
- * mt_cirq_get_mask: Get the specified SYS_CIRQ mask
- * @cirq_num: the SYS_CIRQ number to get
- * @return:
- *    1: this cirq is masked
- *    0: this cirq is umasked
- *    2: cirq num is out of range
- */
-__attribute__((weak)) unsigned int mt_cirq_get_mask(uint32_t cirq_num)
+static void collect_all_wakeup_events(void)
 {
-	uint32_t st;
-	unsigned int val;
+	unsigned int i;
+	uint32_t gic_irq;
+	uint32_t cirq;
+	uint32_t cirq_reg;
+	uint32_t cirq_offset;
+	uint32_t mask;
+	uint32_t pol_mask;
+	uint32_t irq_offset;
+	uint32_t irq_mask;
 
-	if (cirq_num >= CIRQ_IRQ_NUM) {
-		ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num);
-		return 2;
+	if ((cirq_all_events.wakeup_events == NULL) ||
+			cirq_all_events.num_of_events == 0U) {
+		return;
 	}
 
-	st = mt_cirq_read32((cirq_num / 32U) * 4U + CIRQ_MASK_BASE);
-	val = (st >> (cirq_num % 32U)) & 1U;
-	return val;
-}
-
-/*
- * mt_cirq_mask_all: Mask all interrupts on SYS_CIRQ.
- */
-void mt_cirq_mask_all(void)
-{
-	unsigned int i;
+	for (i = 0U; i < cirq_all_events.num_of_events; i++) {
+		if (cirq_all_events.wakeup_events[i] > 0U) {
+			gic_irq = cirq_all_events.wakeup_events[i];
+			cirq = gic_irq - cirq_all_events.spi_start - 32U;
+			cirq_reg = cirq / 32U;
+			cirq_offset = cirq % 32U;
+			mask = 0x1 << cirq_offset;
+			irq_offset = gic_irq % 32U;
+			irq_mask = 0x1 << irq_offset;
+			/*
+			 * CIRQ default masks all
+			 */
+			cirq_all_events.table[cirq_reg].mask |= mask;
+			/*
+			 * CIRQ default pol is low
+			 */
+			pol_mask = mt_irq_get_pol(
+					cirq_all_events.wakeup_events[i])
+					& irq_mask;
+			/*
+			 * 0 means rising
+			 */
+			if (pol_mask == 0U) {
+				cirq_all_events.table[cirq_reg].pol |= mask;
+			}
+			/*
+			 * CIRQ could monitor edge/level trigger
+			 * cirq register (0: edge, 1: level)
+			 */
+			if (mt_irq_get_sens(cirq_all_events.wakeup_events[i])
+				== SENS_EDGE) {
+				cirq_all_events.table[cirq_reg].sen |= mask;
+			}
 
-	for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) {
-		mt_cirq_write32(0xFFFFFFFF, CIRQ_MASK_SET_BASE + (i * 4U));
+			cirq_all_events.table[cirq_reg].used = 1U;
+			cirq_all_events.table[cirq_reg].reg_num = cirq_reg;
+		}
 	}
-	/* make sure all cirq setting take effect before doing other things */
-	dmbsy();
 }
 
 /*
- * mt_cirq_unmask_all: Unmask all interrupts on SYS_CIRQ.
+ * mt_cirq_set_pol: Set the polarity for the specified SYS_CIRQ number.
+ * @cirq_num: the SYS_CIRQ number to set
+ * @pol: polarity to set
+ * @return:
+ *    0: set pol success
+ *   -1: cirq num is out of range
  */
-void mt_cirq_unmask_all(void)
+#ifdef CIRQ_WITH_POLARITY
+static int mt_cirq_set_pol(uint32_t cirq_num, uint32_t pol)
 {
-	unsigned int i;
+	uint32_t base;
+	uint32_t bit = 1U << (cirq_num % 32U);
 
-	for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) {
-		mt_cirq_write32(0xFFFFFFFF, CIRQ_MASK_CLR_BASE + (i * 4U));
+	if (cirq_num >= CIRQ_IRQ_NUM) {
+		return -1;
+	}
+
+	if (pol == MT_CIRQ_POL_NEG) {
+		base = (cirq_num / 32U) * 4U + CIRQ_POL_CLR_BASE;
+	} else if (pol == MT_CIRQ_POL_POS) {
+		base = (cirq_num / 32U) * 4U + CIRQ_POL_SET_BASE;
+	} else {
+		return -1;
 	}
-	/* make sure all cirq setting take effect before doing other things */
-	dmbsy();
+
+	mmio_write_32(base, bit);
+	return 0;
 }
+#endif
 
 /*
  * mt_cirq_mask: Mask the specified SYS_CIRQ.
@@ -151,11 +269,11 @@
 	uint32_t bit = 1U << (cirq_num % 32U);
 
 	if (cirq_num >= CIRQ_IRQ_NUM) {
-		ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num);
 		return -1;
 	}
 
-	mt_cirq_write32(bit, (cirq_num / 32U) * 4U + CIRQ_MASK_SET_BASE);
+	mmio_write_32((cirq_num / 32U) * 4U + CIRQ_MASK_SET_BASE, bit);
+
 	return 0;
 }
 
@@ -171,324 +289,264 @@
 	uint32_t bit = 1U << (cirq_num % 32U);
 
 	if (cirq_num >= CIRQ_IRQ_NUM) {
-		ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num);
 		return -1;
 	}
 
-	mt_cirq_write32(bit, (cirq_num / 32U) * 4U + CIRQ_MASK_CLR_BASE);
+	mmio_write_32((cirq_num / 32U) * 4U + CIRQ_MASK_CLR_BASE, bit);
+
 	return 0;
 }
 
-/*
- * mt_cirq_set_sens: Set the sensitivity for the specified SYS_CIRQ number.
- * @cirq_num: the SYS_CIRQ number to set
- * @sens: sensitivity to set
- * @return:
- *    0: set sens success
- *   -1: cirq num is out of range
- */
-static int mt_cirq_set_sens(uint32_t cirq_num, uint32_t sens)
+uint32_t mt_irq_get_en(uint32_t irq)
 {
-	uint32_t base;
-	uint32_t bit = 1U << (cirq_num % 32U);
+	uint32_t addr, st, val;
 
-	if (cirq_num >= CIRQ_IRQ_NUM) {
-		ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num);
-		return -1;
-	}
+	addr = BASE_GICD_BASE + GICD_ISENABLER + (irq / 32U) * 4U;
+	st = mmio_read_32(addr);
 
-	if (sens == MT_CIRQ_EDGE_SENSITIVE) {
-		base = (cirq_num / 32U) * 4U + CIRQ_SENS_CLR_BASE;
-	} else if (sens == MT_CIRQ_LEVEL_SENSITIVE) {
-		base = (cirq_num / 32U) * 4U + CIRQ_SENS_SET_BASE;
-	} else {
-		ERROR("[CIRQ] set_sens invalid sen value %u\n", sens);
-		return -1;
-	}
+	val = (st >> (irq % 32U)) & 1U;
 
-	mt_cirq_write32(bit, base);
-	return 0;
+	return val;
 }
 
-/*
- * mt_cirq_get_sens: Get the specified SYS_CIRQ sensitivity
- * @cirq_num: the SYS_CIRQ number to get
- * @return:
- *    1: this cirq is MT_LEVEL_SENSITIVE
- *    0: this cirq is MT_EDGE_SENSITIVE
- *    2: cirq num is out of range
- */
-__attribute__((weak)) unsigned int mt_cirq_get_sens(uint32_t cirq_num)
+static void __cirq_fast_clone(void)
 {
-	uint32_t st;
-	unsigned int val;
+	struct cirq_reg *reg;
+	unsigned int i;
 
-	if (cirq_num >= CIRQ_IRQ_NUM) {
-		ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num);
-		return 2;
-	}
+	for (i = 0U; i < CIRQ_REG_NUM ; ++i) {
+		uint32_t cirq_bit;
 
-	st = mt_cirq_read32((cirq_num / 32U) * 4U + CIRQ_SENS_BASE);
-	val = (st >> (cirq_num % 32U)) & 1U;
-	return val;
-}
+		reg = &cirq_all_events.table[i];
 
-/*
- * mt_cirq_set_pol: Set the polarity for the specified SYS_CIRQ number.
- * @cirq_num: the SYS_CIRQ number to set
- * @pol: polarity to set
- * @return:
- *    0: set pol success
- *   -1: cirq num is out of range
- */
-static int mt_cirq_set_pol(uint32_t cirq_num, uint32_t pol)
-{
-	uint32_t base;
-	uint32_t bit = 1U << (cirq_num % 32U);
+		if (reg->used == 0U) {
+			continue;
+		}
 
-	if (cirq_num >= CIRQ_IRQ_NUM) {
-		ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num);
-		return -1;
-	}
+		mmio_write_32(CIRQ_SENS_CLR_BASE + (reg->reg_num * 4U),
+				    reg->sen);
 
-	if (pol == MT_CIRQ_POL_NEG) {
-		base = (cirq_num / 32U) * 4U + CIRQ_POL_CLR_BASE;
-	} else if (pol == MT_CIRQ_POL_POS) {
-		base = (cirq_num / 32U) * 4U + CIRQ_POL_SET_BASE;
-	} else {
-		ERROR("[CIRQ] set_pol invalid polarity value %u\n", pol);
-		return -1;
-	}
+		for (cirq_bit = 0U; cirq_bit < 32U; ++cirq_bit) {
+			uint32_t val, cirq_id;
+			uint32_t gic_id;
+#ifdef CIRQ_WITH_POLARITY
+			uint32_t gic_bit, pol;
+#endif
+			uint32_t en;
 
-	mt_cirq_write32(bit, base);
-	return 0;
-}
+			val = ((1U << cirq_bit) & reg->mask);
 
-/*
- * mt_cirq_get_pol: Get the specified SYS_CIRQ polarity
- * @cirq_num: the SYS_CIRQ number to get
- * @return:
- *    1: this cirq is MT_CIRQ_POL_POS
- *    0: this cirq is MT_CIRQ_POL_NEG
- *    2: cirq num is out of range
- */
-__attribute__((weak)) unsigned int mt_cirq_get_pol(uint32_t cirq_num)
-{
-	uint32_t st;
-	unsigned int val;
+			if (val == 0U) {
+				continue;
+			}
 
-	if (cirq_num >= CIRQ_IRQ_NUM) {
-		ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num);
-		return 2;
+			cirq_id = (reg->reg_num << 5U) + cirq_bit;
+			gic_id = CIRQ_TO_IRQ_NUM(cirq_id);
+#ifdef CIRQ_WITH_POLARITY
+			gic_bit = (0x1U << ((gic_id - 32U) % 32U));
+			pol = mt_irq_get_pol(gic_id) & gic_bit;
+			if (pol != 0U) {
+				mt_cirq_set_pol(cirq_id, MT_CIRQ_POL_NEG);
+			} else {
+				mt_cirq_set_pol(cirq_id, MT_CIRQ_POL_POS);
+			}
+#endif
+			en = mt_irq_get_en(gic_id);
+			if (en == 1U) {
+				mt_cirq_unmask(cirq_id);
+			} else {
+				mt_cirq_mask(cirq_id);
+			}
+		}
 	}
+}
 
-	st = mt_cirq_read32((cirq_num / 32U) * 4U + CIRQ_POL_BASE);
-	val = (st >> (cirq_num % 32U)) & 1U;
-	return val;
+static void cirq_fast_clone(void)
+{
+	if (already_cloned == 0U) {
+		collect_all_wakeup_events();
+		already_cloned = 1U;
+	}
+	__cirq_fast_clone();
 }
 
+void set_wakeup_sources(uint32_t *list, uint32_t num_of_events)
+{
+	cirq_all_events.num_of_events = num_of_events;
+	cirq_all_events.wakeup_events = list;
+}
 /*
- * mt_cirq_get_pending: Get the specified SYS_CIRQ pending
- * @cirq_num: the SYS_CIRQ number to get
- * @return:
- *    1: this cirq is pending
- *    0: this cirq is not pending
- *    2: cirq num is out of range
+ * mt_cirq_clone_gic: Copy the setting from GIC to SYS_CIRQ
  */
-static unsigned int mt_cirq_get_pending(uint32_t cirq_num)
+void mt_cirq_clone_gic(void)
 {
-	uint32_t st;
-	unsigned int val;
+	cirq_fast_clone();
+}
 
-	if (cirq_num >= CIRQ_IRQ_NUM) {
-		ERROR("[CIRQ] %s: invalid cirq %u\n", __func__, cirq_num);
-		return 2;
+uint32_t mt_irq_get_pending_vec(uint32_t start_irq)
+{
+	uint32_t base = 0U;
+	uint32_t pending_vec = 0U;
+	uint32_t reg = start_irq / 32U;
+	uint32_t LSB_num, MSB_num;
+	uint32_t LSB_vec, MSB_vec;
+
+	base = BASE_GICD_BASE;
+
+	/* if start_irq is not aligned 32, do some assembling */
+	MSB_num = start_irq % 32U;
+	if (MSB_num != 0U) {
+		LSB_num = 32U - MSB_num;
+		LSB_vec = mmio_read_32(base + GICD_ISPENDR +
+			reg * 4U) >> MSB_num;
+		MSB_vec = mmio_read_32(base + GICD_ISPENDR +
+			(reg + 1U) * 4U) << LSB_num;
+		pending_vec = MSB_vec | LSB_vec;
+	} else {
+		pending_vec = mmio_read_32(base + GICD_ISPENDR + reg * 4);
 	}
 
-	st = mt_cirq_read32((cirq_num / 32U) * 4U + CIRQ_STA_BASE);
-	val = (st >> (cirq_num % 32U)) & 1U;
-	return val;
+	return pending_vec;
 }
 
+static int mt_cirq_get_mask_vec(unsigned int i)
+{
+	return mmio_read_32((i * 4U) + CIRQ_MASK_BASE);
+}
+
 /*
- * mt_cirq_clone_pol: Copy the polarity setting from GIC to SYS_CIRQ
+ * mt_cirq_ack_all: Ack all the interrupt on SYS_CIRQ
  */
-void mt_cirq_clone_pol(void)
+void mt_cirq_ack_all(void)
 {
-	uint32_t cirq_num;
+	uint32_t ack_vec, pend_vec, mask_vec;
+	unsigned int i;
 
-	for (cirq_num = 0U; cirq_num < CIRQ_IRQ_NUM; cirq_num++) {
-		mt_cirq_set_pol(cirq_num, MT_CIRQ_POL_POS);
+	for (i = 0; i < CIRQ_CTRL_REG_NUM; i++) {
+		/*
+		 * if a irq is pending & not masked, don't ack it
+		 * , since cirq start irq might not be 32 aligned with gic,
+		 * need an exotic API to get proper vector of pending irq
+		 */
+		pend_vec = mt_irq_get_pending_vec(CIRQ_SPI_START
+			+ (i + 1U) * 32U);
+		mask_vec = mt_cirq_get_mask_vec(i);
+		/* those should be acked are: "not (pending & not masked)",
+		 */
+		ack_vec = (~pend_vec) | mask_vec;
+		mmio_write_32(CIRQ_ACK_BASE + (i * 4U), ack_vec);
 	}
-}
 
+	/*
+	 * make sure all cirq setting take effect
+	 * before doing other things
+	 */
+	dsb();
+}
 /*
- * mt_cirq_clone_sens: Copy the sensitivity setting from GIC to SYS_CIRQ
+ * mt_cirq_enable: Enable SYS_CIRQ
  */
-void mt_cirq_clone_sens(void)
+void mt_cirq_enable(void)
 {
-	uint32_t cirq_num, irq_num;
-	uint32_t st, val;
-
-	for (cirq_num = 0U; cirq_num < CIRQ_IRQ_NUM; cirq_num++) {
-		irq_num = CIRQ_TO_IRQ_NUM(cirq_num);
+	uint32_t st;
 
-		if ((cirq_num == 0U) || (irq_num % 16U == 0U)) {
-			st = mmio_read_32(BASE_GICD_BASE + GICD_ICFGR +
-				(irq_num / 16U * 4U));
-		}
+	/* level only */
+	mt_cirq_ack_all();
 
-		val = (st >> ((irq_num % 16U) * 2U)) & 0x2U;
+	st = mmio_read_32(CIRQ_CON);
+	/*
+	 * CIRQ could monitor edge/level trigger
+	 */
+	st |= (CIRQ_CON_EN << CIRQ_CON_EN_BITS);
 
-		if (val) {
-			mt_cirq_set_sens(cirq_num, MT_CIRQ_EDGE_SENSITIVE);
-		} else {
-			mt_cirq_set_sens(cirq_num, MT_CIRQ_LEVEL_SENSITIVE);
-		}
-	}
+	mmio_write_32(CIRQ_CON, (st & CIRQ_CON_BITS_MASK));
 }
 
 /*
- * mt_cirq_clone_mask: Copy the mask setting from GIC to SYS_CIRQ
+ * mt_cirq_disable: Disable SYS_CIRQ
  */
-void mt_cirq_clone_mask(void)
+void mt_cirq_disable(void)
 {
-	uint32_t cirq_num, irq_num;
-	uint32_t st, val;
+	uint32_t st;
 
-	for (cirq_num = 0U; cirq_num < CIRQ_IRQ_NUM; cirq_num++) {
-		irq_num = CIRQ_TO_IRQ_NUM(cirq_num);
+	st = mmio_read_32(CIRQ_CON);
+	st &= ~(CIRQ_CON_EN << CIRQ_CON_EN_BITS);
+	mmio_write_32(CIRQ_CON, (st & CIRQ_CON_BITS_MASK));
+}
 
-		if ((cirq_num == 0U) || (irq_num % 32U == 0U)) {
-			st = mmio_read_32(BASE_GICD_BASE +
-				GICD_ISENABLER + (irq_num / 32U * 4U));
-		}
+void mt_irq_unmask_for_sleep_ex(uint32_t irq)
+{
+	uint32_t mask;
 
-		val = (st >> (irq_num % 32)) & 1U;
+	mask = 1U << (irq % 32U);
 
-		if (val) {
-			mt_cirq_unmask(cirq_num);
-		} else {
-			mt_cirq_mask(cirq_num);
-		}
-	}
+	mmio_write_32(BASE_GICD_BASE + GICD_ISENABLER +
+		((irq / 32U) * 4U), mask);
 }
 
-/*
- * mt_cirq_clone_gic: Copy the setting from GIC to SYS_CIRQ
- */
-void mt_cirq_clone_gic(void)
+void mt_cirq_mask_all(void)
 {
-	mt_cirq_clone_sens();
-	mt_cirq_clone_mask();
+	unsigned int i;
+
+	for (i = 0U; i < CIRQ_CTRL_REG_NUM; i++) {
+		mmio_write_32(CIRQ_MASK_SET_BASE + (i * 4U), 0xFFFFFFFF);
+	}
+	dsb();
 }
 
-/*
- * mt_cirq_disable: Flush interrupt from SYS_CIRQ to GIC
- */
-void mt_cirq_flush(void)
+static void cirq_fast_sw_flush(void)
 {
+	struct cirq_reg *reg;
 	unsigned int i;
-	unsigned char cirq_p_val = 0U;
-	unsigned char irq_p_val = 0U;
-	uint32_t irq_p = 0U;
-	unsigned char pass = 1U;
-	uint32_t first_cirq_found = 0U;
-	uint32_t first_flushed_cirq;
-	uint32_t first_irq_flushedto;
-	uint32_t last_fluashed_cirq;
-	uint32_t last_irq_flushedto;
 
-	if (cirq_pattern_clone_flush_check_val == 1U) {
-		if (cirq_pattern_list < CIRQ_IRQ_NUM) {
-			mt_cirq_unmask(cirq_pattern_list);
-			mt_cirq_set_sens(cirq_pattern_list,
-				MT_CIRQ_EDGE_SENSITIVE);
-			mt_cirq_set_pol(cirq_pattern_list, MT_CIRQ_POL_NEG);
-			mt_cirq_set_pol(cirq_pattern_list, MT_CIRQ_POL_POS);
-			mt_cirq_set_pol(cirq_pattern_list, MT_CIRQ_POL_NEG);
-		} else {
-			ERROR("[CIRQ] no pattern to test,");
-			ERROR("input pattern first\n");
-		}
-		ERROR("[CIRQ] cirq_pattern %u, cirq_p %u,",
-				cirq_pattern_list,
-				mt_cirq_get_pending(cirq_pattern_list));
-		ERROR("cirq_s %u, cirq_con 0x%x\n",
-				mt_cirq_get_sens(cirq_pattern_list),
-				mt_cirq_read32(CIRQ_CON));
-	}
+	for (i = 0U; i < CIRQ_REG_NUM ; ++i) {
+		uint32_t cirq_bit;
 
-	mt_cirq_unmask_all();
+		reg = &cirq_all_events.table[i];
 
-	for (i = 0U; i < CIRQ_IRQ_NUM; i++) {
-		cirq_p_val = mt_cirq_get_pending(i);
-		if (cirq_p_val) {
-			mt_irq_set_pending(CIRQ_TO_IRQ_NUM(i));
+		if (reg->used == 0U) {
+			continue;
 		}
 
+		reg->pending = mmio_read_32(CIRQ_STA_BASE +
+			(reg->reg_num << 2U));
+		reg->pending &= reg->mask;
+
-		if (cirq_clone_flush_check_val == 1U) {
-			if (cirq_p_val == 0U) {
+		for (cirq_bit = 0U; cirq_bit < 32U; ++cirq_bit) {
+			uint32_t val, cirq_id;
+
+			val = (1U << cirq_bit) & reg->pending;
+			if (val == 0U) {
 				continue;
-		}
-			irq_p = CIRQ_TO_IRQ_NUM(i);
-			irq_p_val = mt_irq_get_pending(irq_p);
-			if (cirq_p_val != irq_p_val) {
-				ERROR("[CIRQ] CIRQ Flush Failed ");
-				ERROR("%u(cirq %d)!= %u(gic %d)\n",
-					cirq_p_val, i, irq_p_val,
-					CIRQ_TO_IRQ_NUM(i));
-				pass = 0;
-			} else {
-				ERROR("[CIRQ] CIRQ Flush Pass ");
-				ERROR("%u(cirq %d) = %u(gic %d)\n",
-					cirq_p_val, i, irq_p_val,
-					CIRQ_TO_IRQ_NUM(i));
 			}
-			if (!first_cirq_found) {
-				first_flushed_cirq = i;
-				first_irq_flushedto = irq_p;
-				first_cirq_found = 1U;
+
+			cirq_id = (reg->reg_num << 5U) + cirq_bit;
+			mt_irq_set_pending(CIRQ_TO_IRQ_NUM(cirq_id));
+			if (CIRQ_TO_IRQ_NUM(cirq_id) == MD_WDT_IRQ_BIT_ID) {
+				INFO("Set MD_WDT_IRQ pending in %s\n",
+					__func__);
 			}
-			last_fluashed_cirq = i;
-			last_irq_flushedto = irq_p;
 		}
 	}
+}
 
-	if (cirq_clone_flush_check_val == 1U) {
-		if (first_cirq_found) {
-			ERROR("[CIRQ] The first flush : CIRQ%u to IRQ%u\n",
-				first_flushed_cirq, first_irq_flushedto);
-			ERROR("[CIRQ] The last flush : CIRQ%u to IRQ%u\n",
-				last_fluashed_cirq, last_irq_flushedto);
-		} else {
-			ERROR("[CIRQ] There are no pending ");
-			ERROR("interrupt in CIRQ\n");
-			ERROR("[CIRQ] so no flush operation happened\n");
-		}
-		ERROR("[CIRQ] The Flush Max Range : CIRQ");
-		ERROR("%d to IRQ%d ~ CIRQ%d to IRQ%d\n", 0U,
-			CIRQ_TO_IRQ_NUM(0U), CIRQ_IRQ_NUM - 1U,
-			CIRQ_TO_IRQ_NUM(CIRQ_IRQ_NUM - 1U));
-		ERROR("[CIRQ] Flush Check %s, Confirm:SPI_START_OFFSET:%d\n",
-			pass == 1 ? "Pass" : "Failed", CIRQ_SPI_START);
-	}
+/*
+ * mt_cirq_disable: Flush interrupt from SYS_CIRQ to GIC
+ */
+void mt_cirq_flush(void)
+{
+	cirq_fast_sw_flush();
 	mt_cirq_mask_all();
 	mt_cirq_ack_all();
 }
 
 void mt_cirq_sw_reset(void)
 {
+#ifdef CIRQ_NEED_SW_RESET
 	uint32_t st;
 
-	st = mt_cirq_read32(CIRQ_CON);
+	st = mmio_read_32(CIRQ_CON);
 	st |= (CIRQ_SW_RESET << CIRQ_CON_SW_RST_BITS);
-
-	mt_cirq_write32(st, CIRQ_CON);
-}
-
-void set_wakeup_sources(uint32_t *list, uint32_t num_of_events)
-{
-	cirq_all_events.num_of_events = num_of_events;
-	cirq_all_events.wakeup_events = list;
+	mmio_write_32(CIRQ_CON, st);
+#endif
 }
diff --git a/plat/mediatek/mt8192/plat_pm.c b/plat/mediatek/mt8192/plat_pm.c
index becf5d3..3ea27b6 100644
--- a/plat/mediatek/mt8192/plat_pm.c
+++ b/plat/mediatek/mt8192/plat_pm.c
@@ -5,17 +5,353 @@
  */
 
 /* common headers */
+#include <assert.h>
+
 #include <arch_helpers.h>
 #include <common/debug.h>
 #include <drivers/gpio.h>
 #include <lib/psci/psci.h>
 
-/* mediatek platform specific headers */
+/* platform specific headers */
+#include <mt_gic_v3.h>
+#include <mtk_ptp3_common.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>
+
+/*
+ * 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;
+
+#define plat_mt_pm_invoke(_name, _cpu, _state) ({ \
+	int ret = -1; \
+	if (plat_mt_pm != NULL && plat_mt_pm->_name != NULL) { \
+		ret = plat_mt_pm->_name(_cpu, _state); \
+	} \
+	ret; })
+
+#define plat_mt_pm_invoke_no_check(_name, _cpu, _state) ({ \
+	if (plat_mt_pm != NULL && plat_mt_pm->_name != NULL) { \
+		(void) plat_mt_pm->_name(_cpu, _state); \
+	} \
+	})
+
+/*
+ * 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());
+
+	plat_mt_pm_invoke_no_check(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);
+	/* PTP3 config */
+	ptp3_deinit(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());
+
+	plat_mt_pm_invoke_no_check(pwr_cpu_on, cpu, state);
+
+	coordinate_cluster_pwron();
+
+	/* Enable the GIC CPU interface */
+	gicv3_rdistif_on(cpu);
+	gicv3_cpuif_enable(cpu);
+	mt_gic_rdistif_init();
+
+	/*
+	 * If mcusys does power down before then restore
+	 * all CPUs' GIC Redistributors
+	 */
+	if (IS_MCUSYS_OFF_STATE(state)) {
+		mt_gic_rdistif_restore_all();
+	} else {
+		mt_gic_rdistif_restore();
+	}
+
+	/* PTP3 config */
+	ptp3_init(cpu);
+}
+
+/*
+ * 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());
+
+	if (plat_mt_pm_invoke(pwr_cluster_dwn, cpu, state) != 0) {
+		coordinate_cluster_pwron();
+
+		/* TODO: return on fail.
+		 *       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());
+
+	if (plat_mt_pm_invoke(pwr_cluster_on, cpu, state) != 0) {
+		/* TODO: return on fail.
+		 *       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());
+
+	if (plat_mt_pm_invoke(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());
+
+	if (plat_mt_pm_invoke(pwr_mcusys_on, cpu, state) != 0) {
+		return;		/* return on fail */
+	}
+
+	mt_gic_init();
+	mt_gic_distif_restore();
+	gic_sgi_restore_all();
+
+	plat_mt_pm_invoke_no_check(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);
 
-/*******************************************************************************
- * MTK handlers to shutdown/reboot the system
- ******************************************************************************/
+	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);
+
+	plat_mt_pm_invoke_no_check(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);
+
+	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]);
+
+	plat_mt_pm_invoke_no_check(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]));
+}
+
+static void __dead2 plat_mtk_system_off(void)
+{
+	INFO("MTK System Off\n");
+
+	pmic_power_off();
+
+	wfi();
+	ERROR("MTK System Off: operation not handled.\n");
+	panic();
+}
+
 static void __dead2 plat_mtk_system_reset(void)
 {
 	struct bl_aux_gpio_info *gpio_reset = plat_get_mtk_gpio_reset();
@@ -29,18 +365,35 @@
 	panic();
 }
 
-/*******************************************************************************
- * MTK_platform handler called when an affinity instance is about to be turned
- * on. The level and mpidr determine the affinity instance.
- ******************************************************************************/
-static const plat_psci_ops_t plat_plat_pm_ops = {
-	.system_reset         = plat_mtk_system_reset,
+static const plat_psci_ops_t plat_psci_ops = {
+	.system_reset			= plat_mtk_system_reset,
+	.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,
+	.system_off			= plat_mtk_system_off,
+	.validate_power_state		= plat_validate_power_state,
+	.get_sys_suspend_power_state	= plat_get_sys_suspend_power_state
 };
 
 int plat_setup_psci_ops(uintptr_t sec_entrypoint,
 			const plat_psci_ops_t **psci_ops)
 {
-	*psci_ops = &plat_plat_pm_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/mt8192/plat_sip_calls.c b/plat/mediatek/mt8192/plat_sip_calls.c
new file mode 100644
index 0000000..f97684f
--- /dev/null
+++ b/plat/mediatek/mt8192/plat_sip_calls.c
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2020, 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/mt8192/plat_topology.c b/plat/mediatek/mt8192/plat_topology.c
index aa4975e..8c1231a 100644
--- a/plat/mediatek/mt8192/plat_topology.c
+++ b/plat/mediatek/mt8192/plat_topology.c
@@ -17,6 +17,8 @@
 	/* Number of root nodes */
 	PLATFORM_SYSTEM_COUNT,
 	/* Number of children for the root node */
+	PLATFORM_MCUSYS_COUNT,
+	/* Number of children for the mcusys node */
 	PLATFORM_CLUSTER_COUNT,
 	/* Number of children for the first cluster node */
 	PLATFORM_CLUSTER0_CORE_COUNT,
diff --git a/plat/mediatek/mt8192/platform.mk b/plat/mediatek/mt8192/platform.mk
index 7544b26..191895a 100644
--- a/plat/mediatek/mt8192/platform.mk
+++ b/plat/mediatek/mt8192/platform.mk
@@ -10,8 +10,14 @@
 PLAT_INCLUDES := -I${MTK_PLAT}/common/                            \
                  -I${MTK_PLAT_SOC}/include/                       \
                  -I${MTK_PLAT_SOC}/drivers/                       \
+                 -I${MTK_PLAT_SOC}/drivers/dcm                    \
                  -I${MTK_PLAT_SOC}/drivers/gpio/                  \
-                 -I${MTK_PLAT_SOC}/drivers/timer/
+                 -I${MTK_PLAT_SOC}/drivers/mcdi/                  \
+                 -I${MTK_PLAT_SOC}/drivers/pmic/                  \
+                 -I${MTK_PLAT_SOC}/drivers/ptp3/                  \
+                 -I${MTK_PLAT_SOC}/drivers/spmc/                  \
+                 -I${MTK_PLAT_SOC}/drivers/timer/                 \
+                 -I${MTK_PLAT_SOC}/drivers/uart/
 
 GICV3_SUPPORT_GIC600        :=      1
 include drivers/arm/gic/v3/gicv3.mk
@@ -23,25 +29,38 @@
                           plat/common/plat_psci_common.c
 
 BL31_SOURCES    += common/desc_image_load.c                              \
+                   drivers/delay_timer/delay_timer.c                     \
+                   drivers/delay_timer/generic_delay_timer.c             \
                    drivers/ti/uart/aarch64/16550_console.S               \
                    drivers/gpio/gpio.c                                   \
                    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/pmic_wrap/pmic_wrap_init_v2.c \
+                   ${MTK_PLAT}/common/drivers/uart/uart.c                \
                    ${MTK_PLAT}/common/mtk_plat_common.c                  \
+                   ${MTK_PLAT}/common/mtk_sip_svc.c                      \
                    ${MTK_PLAT}/common/params_setup.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/pmic/pmic.c                   \
                    ${MTK_PLAT_SOC}/plat_pm.c                             \
                    ${MTK_PLAT_SOC}/plat_topology.c                       \
                    ${MTK_PLAT_SOC}/plat_mt_gic.c                         \
                    ${MTK_PLAT_SOC}/plat_mt_cirq.c                        \
+                   ${MTK_PLAT_SOC}/plat_sip_calls.c                      \
+                   ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm.c                 \
+                   ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm_utils.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/ptp3/mtk_ptp3_main.c          \
+                   ${MTK_PLAT_SOC}/drivers/spmc/mtspmc.c                 \
                    ${MTK_PLAT_SOC}/drivers/timer/mt_timer.c
 
-
 # Configs for A76 and A55
 HW_ASSISTED_COHERENCY := 1
 USE_COHERENT_MEM := 0
diff --git a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
index b6d8770..8272d62 100644
--- a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
+++ b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
@@ -104,9 +104,12 @@
 		else if (ret != FSBL_HANDOFF_SUCCESS)
 			panic();
 	}
-
-	NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc);
-	NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc);
+	if (bl32_image_ep_info.pc) {
+		VERBOSE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc);
+	}
+	if (bl33_image_ep_info.pc) {
+		VERBOSE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc);
+	}
 }
 
 /* Enable the test setup */
diff --git a/plat/xilinx/zynqmp/include/zynqmp_def.h b/plat/xilinx/zynqmp/include/zynqmp_def.h
index 5e7254e..4614395 100644
--- a/plat/xilinx/zynqmp/include/zynqmp_def.h
+++ b/plat/xilinx/zynqmp/include/zynqmp_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -341,8 +341,9 @@
 #define PGGS_BASEADDR		(0xFFD80050U)
 #define PGGS_NUM_REGS		U(4)
 
-/* Warm restart boot health status register and mask */
-#define PM_BOOT_HEALTH_STATUS_REG		(GGS_BASEADDR + U(0x10))
+/* PMU GGS4 register 4 is used for warm restart boot health status */
+#define PMU_GLOBAL_GEN_STORAGE4			(GGS_BASEADDR + 0x10)
+/* Warm restart boot health status mask */
 #define PM_BOOT_HEALTH_STATUS_MASK		U(0x01)
 
 /*AFI registers */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
index 852f927..f2dfbb1 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -129,12 +129,26 @@
 		.div = NA_DIV,				\
 	}
 
-#define GENERIC_DIV(id)						\
+#define GENERIC_DIV1						\
 	{							\
-		.type = TYPE_DIV##id,				\
-		.offset = PERIPH_DIV##id##_SHIFT,		\
-		.width = PERIPH_DIV##id##_WIDTH,		\
+		.type = TYPE_DIV1,				\
+		.offset = PERIPH_DIV1_SHIFT,			\
+		.width = PERIPH_DIV1_WIDTH,			\
+		.clkflags = CLK_SET_RATE_NO_REPARENT |		\
+			    CLK_IS_BASIC,			\
+		.typeflags = CLK_DIVIDER_ONE_BASED |		\
+			     CLK_DIVIDER_ALLOW_ZERO,		\
+		.mult = NA_MULT,				\
+		.div = NA_DIV,					\
+	}
+
+#define GENERIC_DIV2						\
+	{							\
+		.type = TYPE_DIV2,				\
+		.offset = PERIPH_DIV2_SHIFT,			\
+		.width = PERIPH_DIV2_WIDTH,			\
 		.clkflags = CLK_SET_RATE_NO_REPARENT |		\
+			    CLK_SET_RATE_PARENT |		\
 			    CLK_IS_BASIC,			\
 		.typeflags = CLK_DIVIDER_ONE_BASED |		\
 			     CLK_DIVIDER_ALLOW_ZERO,		\
@@ -340,25 +354,25 @@
 
 static struct pm_clock_node generic_mux_div_nodes[] = {
 	GENERIC_MUX,
-	GENERIC_DIV(1),
+	GENERIC_DIV1,
 };
 
 static struct pm_clock_node generic_mux_div_gate_nodes[] = {
 	GENERIC_MUX,
-	GENERIC_DIV(1),
+	GENERIC_DIV1,
 	GENERIC_GATE,
 };
 
 static struct pm_clock_node generic_mux_div_unused_gate_nodes[] = {
 	GENERIC_MUX,
-	GENERIC_DIV(1),
+	GENERIC_DIV1,
 	IGNORE_UNUSED_GATE,
 };
 
 static struct pm_clock_node generic_mux_div_div_gate_nodes[] = {
 	GENERIC_MUX,
-	GENERIC_DIV(1),
-	GENERIC_DIV(2),
+	GENERIC_DIV1,
+	GENERIC_DIV2,
 	GENERIC_GATE,
 };
 
@@ -410,8 +424,8 @@
 
 static struct pm_clock_node usb_nodes[] = {
 	GENERIC_MUX,
-	GENERIC_DIV(1),
-	GENERIC_DIV(2),
+	GENERIC_DIV1,
+	GENERIC_DIV2,
 	{
 		.type = TYPE_GATE,
 		.offset = USB_GATE_SHIFT,
@@ -2435,7 +2449,8 @@
 enum pm_ret_status pm_api_clock_get_name(unsigned int clock_id, char *name)
 {
 	if (clock_id == CLK_MAX)
-		memcpy(name, END_OF_CLK, CLK_NAME_LEN);
+		memcpy(name, END_OF_CLK, sizeof(END_OF_CLK) > CLK_NAME_LEN ?
+					 CLK_NAME_LEN : sizeof(END_OF_CLK));
 	else if (!pm_clock_valid(clock_id))
 		memset(name, 0, CLK_NAME_LEN);
 	else if (clock_id < CLK_MAX_OUTPUT_CLK)
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c
index 60e80d9..9da904e 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -575,7 +575,7 @@
  */
 static enum pm_ret_status pm_ioctl_set_boot_health_status(unsigned int value)
 {
-	return pm_mmio_write(PM_BOOT_HEALTH_STATUS_REG,
+	return pm_mmio_write(PMU_GLOBAL_GEN_STORAGE4,
 			     PM_BOOT_HEALTH_STATUS_MASK, value);
 }