Merge changes from topic "zynqmp-update-pinctrl-api" into integration

* changes:
  zynqmp: pm: Reimplement pinctrl get/set config parameter EEMI API calls
  zynqmp: pm: Reimplement pinctrl set/get function EEMI API
  zynqmp: pm: Implement pinctrl request/release EEMI API
  zynqmp: pm: Update return type in query functions
diff --git a/Makefile b/Makefile
index f950eb8..2d5a5bb 100644
--- a/Makefile
+++ b/Makefile
@@ -888,6 +888,7 @@
         CTX_INCLUDE_EL2_REGS \
         CTX_INCLUDE_NEVE_REGS \
         DEBUG \
+        DISABLE_MTPMU \
         DYN_DISABLE_AUTH \
         EL3_EXCEPTION_HANDLING \
         ENABLE_AMU \
@@ -977,6 +978,7 @@
         CTX_INCLUDE_EL2_REGS \
         CTX_INCLUDE_NEVE_REGS \
         DECRYPTION_SUPPORT_${DECRYPTION_SUPPORT} \
+        DISABLE_MTPMU \
         ENABLE_AMU \
         ENABLE_ASSERTIONS \
         ENABLE_BTI \
diff --git a/bl1/bl1.mk b/bl1/bl1.mk
index b839990..d11b4ab 100644
--- a/bl1/bl1.mk
+++ b/bl1/bl1.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -16,6 +16,10 @@
 				plat/common/${ARCH}/platform_up_stack.S \
 				${MBEDTLS_SOURCES}
 
+ifeq (${DISABLE_MTPMU},1)
+BL1_SOURCES		+=	lib/extensions/mtpmu/${ARCH}/mtpmu.S
+endif
+
 ifeq (${ARCH},aarch64)
 BL1_SOURCES		+=	lib/cpus/aarch64/dsu_helpers.S		\
 				lib/el3_runtime/aarch64/context.S
diff --git a/bl2/bl2.mk b/bl2/bl2.mk
index 6dc0f18..735e7e0 100644
--- a/bl2/bl2.mk
+++ b/bl2/bl2.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -25,6 +25,10 @@
 				lib/cpus/${ARCH}/cpu_helpers.S		\
 				lib/cpus/errata_report.c
 
+ifeq (${DISABLE_MTPMU},1)
+BL2_SOURCES		+=	lib/extensions/mtpmu/${ARCH}/mtpmu.S
+endif
+
 ifeq (${ARCH},aarch64)
 BL2_SOURCES		+=	lib/cpus/aarch64/dsu_helpers.S
 endif
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
index cd6549b..e299fe1 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -40,6 +40,9 @@
 				${SPMD_SOURCES}					\
 				${SPM_SOURCES}
 
+ifeq (${DISABLE_MTPMU},1)
+BL31_SOURCES		+=	lib/extensions/mtpmu/aarch64/mtpmu.S
+endif
 
 ifeq (${ENABLE_PMF}, 1)
 BL31_SOURCES		+=	lib/pmf/pmf_main.c
diff --git a/bl32/sp_min/sp_min.mk b/bl32/sp_min/sp_min.mk
index 6233299..afd7ae1 100644
--- a/bl32/sp_min/sp_min.mk
+++ b/bl32/sp_min/sp_min.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -19,6 +19,10 @@
 				services/std_svc/std_svc_setup.c	\
 				${PSCI_LIB_SOURCES}
 
+ifeq (${DISABLE_MTPMU},1)
+BL32_SOURCES		+=	lib/extensions/mtpmu/aarch32/mtpmu.S
+endif
+
 ifeq (${ENABLE_PMF}, 1)
 BL32_SOURCES		+=	lib/pmf/pmf_main.c
 endif
diff --git a/docs/design/cpu-specific-build-macros.rst b/docs/design/cpu-specific-build-macros.rst
index e901e0c..d859cc5 100644
--- a/docs/design/cpu-specific-build-macros.rst
+++ b/docs/design/cpu-specific-build-macros.rst
@@ -249,6 +249,9 @@
 -  ``ERRATA_A76_1868343``: This applies errata 1868343 workaround to Cortex-A76
    CPU. This needs to be enabled only for revision <= r4p0 of the CPU.
 
+-  ``ERRATA_A76_1946160``: This applies errata 1946160 workaround to Cortex-A76
+   CPU. This needs to be enabled only for revisions r3p0 - r4p1 of the CPU.
+
 For Cortex-A77, the following errata build flags are defined :
 
 -  ``ERRATA_A77_1508412``: This applies errata 1508412 workaround to Cortex-A77
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index d4eb6a7..16de410 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -191,6 +191,11 @@
    of the binary image. If set to 1, then only the ELF image is built.
    0 is the default.
 
+-  ``DISABLE_MTPMU``: Boolean option to disable FEAT_MTPMU if implemented
+   (Armv8.6 onwards). Its default value is 0 to keep consistency with platforms
+   that do not implement FEAT_MTPMU. For more information on FEAT_MTPMU,
+   check the latest Arm ARM.
+
 -  ``DYN_DISABLE_AUTH``: Provides the capability to dynamically disable Trusted
    Board Boot authentication at runtime. This option is meant to be enabled only
    for development platforms. ``TRUSTED_BOARD_BOOT`` flag must be set if this
diff --git a/docs/plat/arm/arm-build-options.rst b/docs/plat/arm/arm-build-options.rst
index 2e50068..a1d2313 100644
--- a/docs/plat/arm/arm-build-options.rst
+++ b/docs/plat/arm/arm-build-options.rst
@@ -94,6 +94,10 @@
 -  ``ARM_SPMC_MANIFEST_DTS`` : path to an alternate manifest file used as the
    SPMC Core manifest. Valid when ``SPD=spmd`` is selected.
 
+-  ``OPTEE_SP_FW_CONFIG``: DTC build flag to include OP-TEE as SP in tb_fw_config
+   device tree. This flag is defined only when ``ARM_SPMC_MANIFEST_DTS`` manifest
+   file name contains pattern optee_sp.
+
 For a better understanding of these options, the Arm development platform memory
 map is explained in the :ref:`Firmware Design`.
 
diff --git a/fdts/tc0.dts b/fdts/tc0.dts
index 763c813..5438474 100644
--- a/fdts/tc0.dts
+++ b/fdts/tc0.dts
@@ -109,6 +109,17 @@
 		reg = <0x0 0x80000000 0x0 0x7d000000>;
 	};
 
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		optee@0xfce00000 {
+			reg = <0x00000000 0xfce00000 0 0x00200000>;
+			no-map;
+		};
+	};
+
 	psci {
 		compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
 		method = "smc";
@@ -370,4 +381,17 @@
 			};
 		};
 	};
+
+	ffa {
+		compatible = "arm,ffa";
+		conduit = "smc";
+		mem_share_buffer = "tx";
+	};
+
+	firmware {
+		optee {
+		      compatible = "linaro,optee-tz";
+		      method = "ffa";
+		};
+	};
 };
diff --git a/include/arch/aarch32/arch.h b/include/arch/aarch32/arch.h
index db8938f..c30073b 100644
--- a/include/arch/aarch32/arch.h
+++ b/include/arch/aarch32/arch.h
@@ -102,6 +102,11 @@
 /* CSSELR definitions */
 #define LEVEL_SHIFT		U(1)
 
+/* ID_DFR1_EL1 definitions */
+#define ID_DFR1_MTPMU_SHIFT	U(0)
+#define ID_DFR1_MTPMU_MASK	U(0xf)
+#define ID_DFR1_MTPMU_SUPPORTED	U(1)
+
 /* ID_MMFR4 definitions */
 #define ID_MMFR4_CNP_SHIFT	U(12)
 #define ID_MMFR4_CNP_LENGTH	U(4)
@@ -126,6 +131,9 @@
 #define ID_PFR1_GENTIMER_MASK	U(0xf)
 #define ID_PFR1_GIC_SHIFT	U(28)
 #define ID_PFR1_GIC_MASK	U(0xf)
+#define ID_PFR1_SEC_SHIFT	U(4)
+#define ID_PFR1_SEC_MASK	U(0xf)
+#define ID_PFR1_ELx_ENABLED	U(1)
 
 /* SCTLR definitions */
 #define SCTLR_RES1_DEF		((U(1) << 23) | (U(1) << 22) | (U(1) << 4) | \
@@ -164,6 +172,7 @@
 #define SDCR_SCCD_BIT		(U(1) << 23)
 #define SDCR_SPME_BIT		(U(1) << 17)
 #define SDCR_RESET_VAL		U(0x0)
+#define SDCR_MTPME_BIT		(U(1) << 28)
 
 /* HSCTLR definitions */
 #define HSCTLR_RES1	((U(1) << 29) | (U(1) << 28) | (U(1) << 23) | \
@@ -244,6 +253,7 @@
 #define VTTBR_BADDR_SHIFT	U(0)
 
 /* HDCR definitions */
+#define HDCR_MTPME_BIT		(U(1) << 28)
 #define HDCR_HLP_BIT		(U(1) << 26)
 #define HDCR_HPME_BIT		(U(1) << 7)
 #define HDCR_RESET_VAL		U(0x0)
@@ -503,6 +513,7 @@
 #define CTR		p15, 0, c0, c0, 1
 #define CNTFRQ		p15, 0, c14, c0, 0
 #define ID_MMFR4	p15, 0, c0, c2, 6
+#define ID_DFR1		p15, 0, c0, c3, 5
 #define ID_PFR0		p15, 0, c0, c1, 0
 #define ID_PFR1		p15, 0, c0, c1, 1
 #define MAIR0		p15, 0, c10, c2, 0
diff --git a/include/arch/aarch32/el3_common_macros.S b/include/arch/aarch32/el3_common_macros.S
index 4fd746d..580dd95 100644
--- a/include/arch/aarch32/el3_common_macros.S
+++ b/include/arch/aarch32/el3_common_macros.S
@@ -242,6 +242,10 @@
 	cps	#MODE32_mon
 	isb
 
+#if DISABLE_MTPMU
+	bl	mtpmu_disable
+#endif
+
 	.if \_warm_boot_mailbox
 		/* -------------------------------------------------------------
 		 * This code will be executed for both warm and cold resets.
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 6dcdacf..09e598a 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -188,6 +188,11 @@
 #define ID_AA64DFR0_PMS_SHIFT	U(32)
 #define ID_AA64DFR0_PMS_MASK	ULL(0xf)
 
+/* ID_AA64DFR0_EL1.MTPMU definitions (for ARMv8.6+) */
+#define ID_AA64DFR0_MTPMU_SHIFT		U(48)
+#define ID_AA64DFR0_MTPMU_MASK		ULL(0xf)
+#define ID_AA64DFR0_MTPMU_SUPPORTED	ULL(1)
+
 /* ID_AA64ISAR1_EL1 definitions */
 #define ID_AA64ISAR1_EL1	S3_0_C0_C6_1
 #define ID_AA64ISAR1_GPI_SHIFT	U(28)
@@ -421,6 +426,7 @@
 #define SCR_RESET_VAL		SCR_RES1_BITS
 
 /* MDCR_EL3 definitions */
+#define MDCR_MTPME_BIT		(ULL(1) << 28)
 #define MDCR_SCCD_BIT		(ULL(1) << 23)
 #define MDCR_SPME_BIT		(ULL(1) << 17)
 #define MDCR_SDD_BIT		(ULL(1) << 16)
@@ -436,6 +442,7 @@
 #define MDCR_EL3_RESET_VAL	ULL(0x0)
 
 /* MDCR_EL2 definitions */
+#define MDCR_EL2_MTPME		(U(1) << 28)
 #define MDCR_EL2_HLP		(U(1) << 26)
 #define MDCR_EL2_HCCD		(U(1) << 23)
 #define MDCR_EL2_TTRF		(U(1) << 19)
diff --git a/include/arch/aarch64/el3_common_macros.S b/include/arch/aarch64/el3_common_macros.S
index 6f4143c..f759983 100644
--- a/include/arch/aarch64/el3_common_macros.S
+++ b/include/arch/aarch64/el3_common_macros.S
@@ -277,6 +277,10 @@
 		isb
 	.endif /* _init_sctlr */
 
+#if DISABLE_MTPMU
+		bl	mtpmu_disable
+#endif
+
 	.if \_warm_boot_mailbox
 		/* -------------------------------------------------------------
 		 * This code will be executed for both warm and cold resets.
diff --git a/include/drivers/allwinner/axp.h b/include/drivers/allwinner/axp.h
index 9c0035f..222820b 100644
--- a/include/drivers/allwinner/axp.h
+++ b/include/drivers/allwinner/axp.h
@@ -9,6 +9,10 @@
 
 #include <stdint.h>
 
+#define AXP20X_MODE_REG 0x3e
+#define AXP20X_MODE_I2C 0x00
+#define AXP20X_MODE_RSB 0x7c
+
 #define NA 0xff
 
 enum {
diff --git a/include/plat/arm/common/fconf_arm_sp_getter.h b/include/plat/arm/common/fconf_arm_sp_getter.h
index c6315be..aa628df 100644
--- a/include/plat/arm/common/fconf_arm_sp_getter.h
+++ b/include/plat/arm/common/fconf_arm_sp_getter.h
@@ -13,7 +13,7 @@
 /* arm_sp getter */
 #define arm__sp_getter(prop)	arm_sp.prop
 
-#define ARM_SP_MAX_SIZE		U(0x80000)
+#define ARM_SP_MAX_SIZE		U(0xb0000)
 #define ARM_SP_OWNER_NAME_LEN	U(8)
 
 struct arm_sp_t {
diff --git a/lib/cpus/aarch64/cortex_a76.S b/lib/cpus/aarch64/cortex_a76.S
index 2c99cdc..4f7f4bb 100644
--- a/lib/cpus/aarch64/cortex_a76.S
+++ b/lib/cpus/aarch64/cortex_a76.S
@@ -430,6 +430,61 @@
 	b	cpu_rev_var_ls
 endfunc check_errata_1868343
 
+/* --------------------------------------------------
+ * Errata Workaround for A76 Erratum 1946160.
+ * This applies to revisions r3p0 - r4p1 of A76.
+ * It also exists in r0p0 - r2p0 but there is no fix
+ * in those revisions.
+ * Inputs:
+ * x0: variant[4:7] and revision[0:3] of current cpu.
+ * Shall clobber: x0-x17
+ * --------------------------------------------------
+ */
+func errata_a76_1946160_wa
+	/* Compare x0 against revisions r3p0 - r4p1 */
+	mov	x17, x30
+	bl	check_errata_1946160
+	cbz	x0, 1f
+
+	mov	x0, #3
+	msr	S3_6_C15_C8_0, x0
+	ldr	x0, =0x10E3900002
+	msr	S3_6_C15_C8_2, x0
+	ldr	x0, =0x10FFF00083
+	msr	S3_6_C15_C8_3, x0
+	ldr	x0, =0x2001003FF
+	msr	S3_6_C15_C8_1, x0
+
+	mov	x0, #4
+	msr	S3_6_C15_C8_0, x0
+	ldr	x0, =0x10E3800082
+	msr	S3_6_C15_C8_2, x0
+	ldr	x0, =0x10FFF00083
+	msr	S3_6_C15_C8_3, x0
+	ldr	x0, =0x2001003FF
+	msr	S3_6_C15_C8_1, x0
+
+	mov	x0, #5
+	msr	S3_6_C15_C8_0, x0
+	ldr	x0, =0x10E3800200
+	msr	S3_6_C15_C8_2, x0
+	ldr	x0, =0x10FFF003E0
+	msr	S3_6_C15_C8_3, x0
+	ldr	x0, =0x2001003FF
+	msr	S3_6_C15_C8_1, x0
+
+	isb
+1:
+	ret	x17
+endfunc errata_a76_1946160_wa
+
+func check_errata_1946160
+	/* Applies to revisions r3p0 - r4p1. */
+	mov	x1, #0x30
+	mov	x2, #0x41
+	b	cpu_rev_var_range
+endfunc check_errata_1946160
+
 func check_errata_cve_2018_3639
 #if WORKAROUND_CVE_2018_3639
 	mov	x0, #ERRATA_APPLIES
@@ -509,6 +564,11 @@
 	bl	errata_a76_1791580_wa
 #endif
 
+#if ERRATA_A76_1946160
+	mov	x0, x18
+	bl	errata_a76_1946160_wa
+#endif
+
 #if WORKAROUND_CVE_2018_3639
 	/* If the PE implements SSBS, we don't need the dynamic workaround */
 	mrs	x0, id_aa64pfr1_el1
@@ -592,6 +652,7 @@
 	report_errata ERRATA_A76_1791580, cortex_a76, 1791580
 	report_errata ERRATA_A76_1165522, cortex_a76, 1165522
 	report_errata ERRATA_A76_1868343, cortex_a76, 1868343
+	report_errata ERRATA_A76_1946160, cortex_a76, 1946160
 	report_errata WORKAROUND_CVE_2018_3639, cortex_a76, cve_2018_3639
 	report_errata ERRATA_DSU_798953, cortex_a76, dsu_798953
 	report_errata ERRATA_DSU_936184, cortex_a76, dsu_936184
diff --git a/lib/cpus/cpu-ops.mk b/lib/cpus/cpu-ops.mk
index 084e6e7..da0157f 100644
--- a/lib/cpus/cpu-ops.mk
+++ b/lib/cpus/cpu-ops.mk
@@ -278,6 +278,10 @@
 # only to revision <= r4p0 of the Cortex A76 cpu.
 ERRATA_A76_1868343	?=0
 
+# Flag to apply erratum 1946160 workaround during reset. This erratum applies
+# only to revisions r3p0 - r4p1 of the Cortex A76 cpu.
+ERRATA_A76_1946160	?=0
+
 # Flag to apply erratum 1508412 workaround during reset. This erratum applies
 # only to revision <= r1p0 of the Cortex A77 cpu.
 ERRATA_A77_1508412	?=0
@@ -555,6 +559,10 @@
 $(eval $(call assert_boolean,ERRATA_A76_1868343))
 $(eval $(call add_define,ERRATA_A76_1868343))
 
+# Process ERRATA_A76_1946160 flag
+$(eval $(call assert_boolean,ERRATA_A76_1946160))
+$(eval $(call add_define,ERRATA_A76_1946160))
+
 # Process ERRATA_A77_1508412 flag
 $(eval $(call assert_boolean,ERRATA_A77_1508412))
 $(eval $(call add_define,ERRATA_A77_1508412))
diff --git a/lib/extensions/mtpmu/aarch32/mtpmu.S b/lib/extensions/mtpmu/aarch32/mtpmu.S
new file mode 100644
index 0000000..834cee3
--- /dev/null
+++ b/lib/extensions/mtpmu/aarch32/mtpmu.S
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+	.global	mtpmu_disable
+
+/* -------------------------------------------------------------
+ * The functions in this file are called at entrypoint, before
+ * the CPU has decided whether this is a cold or a warm boot.
+ * Therefore there are no stack yet to rely on for a C function
+ * call.
+ * -------------------------------------------------------------
+ */
+
+/*
+ * bool mtpmu_supported(void)
+ *
+ * Return a boolean indicating whether FEAT_MTPMU is supported or not.
+ *
+ * Trash registers: r0.
+ */
+func mtpmu_supported
+	ldcopr	r0, ID_DFR1
+	and	r0, r0, #(ID_DFR1_MTPMU_MASK >> ID_DFR1_MTPMU_SHIFT)
+	cmp	r0, #ID_DFR1_MTPMU_SUPPORTED
+	mov	r0, #0
+	addeq	r0, r0, #1
+	bx	lr
+endfunc mtpmu_supported
+
+/*
+ * bool el_implemented(unsigned int el)
+ *
+ * Return a boolean indicating if the specified EL (2 or 3) is implemented.
+ *
+ * Trash registers: r0
+ */
+func el_implemented
+	cmp	r0, #3
+	ldcopr	r0, ID_PFR1
+	lsreq	r0, r0, #ID_PFR1_SEC_SHIFT
+	lsrne	r0, r0, #ID_PFR1_VIRTEXT_SHIFT
+	/*
+	 * ID_PFR1_VIRTEXT_MASK is the same as ID_PFR1_SEC_MASK
+	 * so use any one of them
+	 */
+	and	r0, r0, #ID_PFR1_VIRTEXT_MASK
+	cmp	r0, #ID_PFR1_ELx_ENABLED
+	mov	r0, #0
+	addeq	r0, r0, #1
+	bx	lr
+endfunc el_implemented
+
+/*
+ * void mtpmu_disable(void)
+ *
+ * Disable mtpmu feature if supported.
+ *
+ * Trash register: r0, r1, r2
+ */
+func mtpmu_disable
+	mov	r2, lr
+	bl	mtpmu_supported
+	cmp	r0, #0
+	bxeq	r2	/* FEAT_MTPMU not supported */
+
+	/* FEAT_MTMPU Supported */
+	mov	r0, #3
+	bl	el_implemented
+	cmp	r0, #0
+	beq	1f
+
+	/* EL3 implemented */
+	ldcopr	r0, SDCR
+	ldr	r1, =SDCR_MTPME_BIT
+	bic	r0, r0, r1
+	stcopr	r0, SDCR
+
+	/*
+	 * If EL3 is implemented, HDCR.MTPME is implemented as Res0 and
+	 * FEAT_MTPMU is controlled only from EL3, so no need to perform
+	 * any operations for EL2.
+	 */
+	isb
+	bx	r2
+1:
+	/* EL3 not implemented */
+	mov	r0, #2
+	bl	el_implemented
+	cmp	r0, #0
+	bxeq	r2	/* No EL2 or EL3 implemented */
+
+	/* EL2 implemented */
+	ldcopr	r0, HDCR
+	ldr	r1, =HDCR_MTPME_BIT
+	orr	r0, r0, r1
+	stcopr	r0, HDCR
+	isb
+	bx	r2
+endfunc mtpmu_disable
diff --git a/lib/extensions/mtpmu/aarch64/mtpmu.S b/lib/extensions/mtpmu/aarch64/mtpmu.S
new file mode 100644
index 0000000..0a1d57b
--- /dev/null
+++ b/lib/extensions/mtpmu/aarch64/mtpmu.S
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+
+	.global	mtpmu_disable
+
+/* -------------------------------------------------------------
+ * The functions in this file are called at entrypoint, before
+ * the CPU has decided whether this is a cold or a warm boot.
+ * Therefore there are no stack yet to rely on for a C function
+ * call.
+ * -------------------------------------------------------------
+ */
+
+/*
+ * bool mtpmu_supported(void)
+ *
+ * Return a boolean indicating whether FEAT_MTPMU is supported or not.
+ *
+ * Trash registers: x0, x1
+ */
+func mtpmu_supported
+	mrs	x0, id_aa64dfr0_el1
+	mov_imm	x1, ID_AA64DFR0_MTPMU_MASK
+	and	x0, x1, x0, LSR #ID_AA64DFR0_MTPMU_SHIFT
+	cmp	x0, ID_AA64DFR0_MTPMU_SUPPORTED
+	cset	x0, eq
+	ret
+endfunc mtpmu_supported
+
+/*
+ * bool el_implemented(unsigned int el_shift)
+ *
+ * Return a boolean indicating if the specified EL is implemented.
+ * The EL is represented as the bitmask shift on id_aa64pfr0_el1 register.
+ *
+ * Trash registers: x0, x1
+ */
+func el_implemented
+	mrs	x1, id_aa64pfr0_el1
+	lsr	x1, x1, x0
+	cmp	x1, #ID_AA64PFR0_ELX_MASK
+	cset	x0, eq
+	ret
+endfunc el_implemented
+
+/*
+ * void mtpmu_disable(void)
+ *
+ * Disable mtpmu feature if supported.
+ *
+ * Trash register: x0, x1, x30
+ */
+func mtpmu_disable
+	mov	x10, x30
+	bl	mtpmu_supported
+	cbz	x0, exit_disable
+
+	/* FEAT_MTMPU Supported */
+	mov_imm	x0, ID_AA64PFR0_EL3_SHIFT
+	bl	el_implemented
+	cbz	x0, 1f
+
+	/* EL3 implemented */
+	mrs	x0, mdcr_el3
+	mov_imm x1, MDCR_MTPME_BIT
+	bic	x0, x0, x1
+	msr	mdcr_el3, x0
+
+	/*
+	 * If EL3 is implemented, MDCR_EL2.MTPME is implemented as Res0 and
+	 * FEAT_MTPMU is controlled only from EL3, so no need to perform
+	 * any operations for EL2.
+	 */
+	isb
+exit_disable:
+	ret	x10
+1:
+	/* EL3 not implemented */
+	mov_imm	x0, ID_AA64PFR0_EL2_SHIFT
+	bl	el_implemented
+	cbz	x0, exit_disable
+
+	/* EL2 implemented */
+	mrs	x0, mdcr_el2
+	mov_imm x1, MDCR_EL2_MTPME
+	bic	x0, x0, x1
+	msr	mdcr_el2, x0
+	isb
+	ret	x10
+endfunc mtpmu_disable
diff --git a/lib/psci/psci_private.h b/lib/psci/psci_private.h
index e2dcfa8..72bd6bd 100644
--- a/lib/psci/psci_private.h
+++ b/lib/psci/psci_private.h
@@ -42,6 +42,11 @@
 			define_psci_cap(PSCI_SYSTEM_RESET2_AARCH64) |	\
 			define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64))
 
+/* Internally PSCI uses a uint16_t for various cpu indexes so
+ * define a limit to number of CPUs that can be initialised.
+ */
+#define PSCI_MAX_CPUS_INDEX	0xFFFFU
+
 /*
  * Helper functions to get/set the fields of PSCI per-cpu data.
  */
@@ -134,7 +139,7 @@
 	unsigned char level;
 
 	/* For indexing the psci_lock array*/
-	unsigned char lock_index;
+	uint16_t lock_index;
 } non_cpu_pd_node_t;
 
 typedef struct cpu_pwr_domain_node {
@@ -239,7 +244,7 @@
 #endif /* HW_ASSISTED_COHERENCY */
 
 static inline void psci_lock_init(non_cpu_pd_node_t *non_cpu_pd_node,
-				  unsigned char idx)
+				  uint16_t idx)
 {
 	non_cpu_pd_node[idx].lock_index = idx;
 }
diff --git a/lib/psci/psci_setup.c b/lib/psci/psci_setup.c
index d1ec998..9c37d63 100644
--- a/lib/psci/psci_setup.c
+++ b/lib/psci/psci_setup.c
@@ -17,6 +17,12 @@
 
 #include "psci_private.h"
 
+/*
+ * Check that PLATFORM_CORE_COUNT fits into the number of cores
+ * that can be represented by PSCI_MAX_CPUS_INDEX.
+ */
+CASSERT(PLATFORM_CORE_COUNT <= (PSCI_MAX_CPUS_INDEX + 1U), assert_psci_cores_overflow);
+
 /*******************************************************************************
  * Per cpu non-secure contexts used to program the architectural state prior
  * return to the normal world.
@@ -34,11 +40,13 @@
  * Function which initializes the 'psci_non_cpu_pd_nodes' or the
  * 'psci_cpu_pd_nodes' corresponding to the power level.
  ******************************************************************************/
-static void __init psci_init_pwr_domain_node(unsigned char node_idx,
+static void __init psci_init_pwr_domain_node(uint16_t node_idx,
 					unsigned int parent_idx,
 					unsigned char level)
 {
 	if (level > PSCI_CPU_PWR_LVL) {
+		assert(node_idx < PSCI_NUM_NON_CPU_PWR_DOMAINS);
+
 		psci_non_cpu_pd_nodes[node_idx].level = level;
 		psci_lock_init(psci_non_cpu_pd_nodes, node_idx);
 		psci_non_cpu_pd_nodes[node_idx].parent_node = parent_idx;
@@ -47,6 +55,8 @@
 	} else {
 		psci_cpu_data_t *svc_cpu_data;
 
+		assert(node_idx < PLATFORM_CORE_COUNT);
+
 		psci_cpu_pd_nodes[node_idx].parent_node = parent_idx;
 
 		/* Initialize with an invalid mpidr */
@@ -144,7 +154,7 @@
 
 			for (j = node_index;
 				j < (node_index + num_children); j++)
-				psci_init_pwr_domain_node((unsigned char)j,
+				psci_init_pwr_domain_node((uint16_t)j,
 						  parent_node_index - 1U,
 						  (unsigned char)level);
 
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 9e5fe85..5217a85 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -82,6 +82,10 @@
 # Disable the generation of the binary image (ELF only).
 DISABLE_BIN_GENERATION		:= 0
 
+# Disable MTPMU if FEAT_MTPMU is supported. Default is 0 to keep backwards
+# compatibility.
+DISABLE_MTPMU			:= 0
+
 # Enable capability to disable authentication dynamically. Only meant for
 # development platforms.
 DYN_DISABLE_AUTH		:= 0
diff --git a/plat/allwinner/common/allwinner-common.mk b/plat/allwinner/common/allwinner-common.mk
index 997aaa6..901d888 100644
--- a/plat/allwinner/common/allwinner-common.mk
+++ b/plat/allwinner/common/allwinner-common.mk
@@ -48,6 +48,10 @@
 ERRATA_A53_835769		:=	1
 ERRATA_A53_843419		:=	1
 ERRATA_A53_855873		:=	1
+ERRATA_A53_1530924		:=	1
+
+# The traditional U-Boot load address is 160MB into DRAM.
+PRELOADED_BL33_BASE		?=	0x4a000000
 
 # The reset vector can be changed for each CPU.
 PROGRAMMABLE_RESET_ADDRESS	:=	1
diff --git a/plat/allwinner/common/include/platform_def.h b/plat/allwinner/common/include/platform_def.h
index 975cc48..93720ff 100644
--- a/plat/allwinner/common/include/platform_def.h
+++ b/plat/allwinner/common/include/platform_def.h
@@ -25,9 +25,6 @@
 #define BL31_NOBITS_BASE		(SUNXI_SRAM_A1_BASE + 0x1000)
 #define BL31_NOBITS_LIMIT		(SUNXI_SRAM_A1_BASE + SUNXI_SRAM_A1_SIZE)
 
-/* The traditional U-Boot load address is 160MB into DRAM, so at 0x4a000000 */
-#define PLAT_SUNXI_NS_IMAGE_OFFSET	(SUNXI_DRAM_BASE + (160U << 20))
-
 /* How much memory to reserve as secure for BL32, if configured */
 #define SUNXI_DRAM_SEC_SIZE		(32U << 20)
 
diff --git a/plat/allwinner/common/sunxi_bl31_setup.c b/plat/allwinner/common/sunxi_bl31_setup.c
index e836a34..9c8eaa4 100644
--- a/plat/allwinner/common/sunxi_bl31_setup.c
+++ b/plat/allwinner/common/sunxi_bl31_setup.c
@@ -57,7 +57,7 @@
 	for (i = 0; i < 2048 / sizeof(uint64_t); i++) {
 		uint32_t *dtb_base;
 
-		if (u_boot_base[i] != PLAT_SUNXI_NS_IMAGE_OFFSET)
+		if (u_boot_base[i] != PRELOADED_BL33_BASE)
 			continue;
 
 		/* Does the suspected U-Boot size look anyhow reasonable? */
@@ -96,7 +96,7 @@
 	 * Tell BL31 where the non-trusted software image
 	 * is located and the entry state information
 	 */
-	bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+	bl33_image_ep_info.pc = PRELOADED_BL33_BASE;
 	bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
 					  DISABLE_ALL_EXCEPTIONS);
 	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
diff --git a/plat/allwinner/common/sunxi_common.c b/plat/allwinner/common/sunxi_common.c
index 0ca18ad..5b536a0 100644
--- a/plat/allwinner/common/sunxi_common.c
+++ b/plat/allwinner/common/sunxi_common.c
@@ -27,7 +27,7 @@
 			MT_DEVICE | MT_RW | MT_SECURE | MT_EXECUTE_NEVER),
 	MAP_REGION(SUNXI_DRAM_BASE, SUNXI_DRAM_VIRT_BASE, SUNXI_DRAM_SEC_SIZE,
 		   MT_RW_DATA | MT_SECURE),
-	MAP_REGION(PLAT_SUNXI_NS_IMAGE_OFFSET,
+	MAP_REGION(PRELOADED_BL33_BASE,
 		   SUNXI_DRAM_VIRT_BASE + SUNXI_DRAM_SEC_SIZE,
 		   SUNXI_DRAM_MAP_SIZE,
 		   MT_RO_DATA | MT_NS),
@@ -39,15 +39,6 @@
 	return SUNXI_OSC24M_CLK_IN_HZ;
 }
 
-uintptr_t plat_get_ns_image_entrypoint(void)
-{
-#ifdef PRELOADED_BL33_BASE
-	return PRELOADED_BL33_BASE;
-#else
-	return PLAT_SUNXI_NS_IMAGE_OFFSET;
-#endif
-}
-
 void sunxi_configure_mmu_el3(int flags)
 {
 	mmap_add_region(BL_CODE_BASE, BL_CODE_BASE,
@@ -125,11 +116,9 @@
 		device_bit = BIT(6);
 		break;
 	case SUNXI_SOC_H6:
-		if (use_rsb)
-			return -ENODEV;
-		pin_func = 0x33;
+		pin_func = use_rsb ? 0x22 : 0x33;
 		device_bit = BIT(16);
-		reset_offset = 0x19c;
+		reset_offset = use_rsb ? 0x1bc : 0x19c;
 		break;
 	case SUNXI_SOC_A64:
 		pin_func = use_rsb ? 0x22 : 0x33;
@@ -157,7 +146,7 @@
 	if (socid != SUNXI_SOC_H6)
 		mmio_setbits_32(SUNXI_R_PRCM_BASE + 0x28, device_bit);
 	else
-		mmio_setbits_32(SUNXI_R_PRCM_BASE + 0x19c, device_bit | BIT(0));
+		mmio_setbits_32(SUNXI_R_PRCM_BASE + reset_offset, BIT(0));
 
 	/* assert, then de-assert reset of I2C/RSB controller */
 	mmio_clrbits_32(SUNXI_R_PRCM_BASE + reset_offset, device_bit);
diff --git a/plat/allwinner/common/sunxi_security.c b/plat/allwinner/common/sunxi_security.c
index 92c83b0..98b91c3 100644
--- a/plat/allwinner/common/sunxi_security.c
+++ b/plat/allwinner/common/sunxi_security.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,16 +7,11 @@
 #include <common/debug.h>
 #include <lib/mmio.h>
 
+#include <sunxi_ccu.h>
 #include <sunxi_mmap.h>
 #include <sunxi_private.h>
+#include <sunxi_spc.h>
 
-#ifdef SUNXI_SPC_BASE
-#define SPC_DECPORT_STA_REG(p)	(SUNXI_SPC_BASE + ((p) * 0x0c) + 0x4)
-#define SPC_DECPORT_SET_REG(p)	(SUNXI_SPC_BASE + ((p) * 0x0c) + 0x8)
-#define SPC_DECPORT_CLR_REG(p)	(SUNXI_SPC_BASE + ((p) * 0x0c) + 0xc)
-#endif
-
-#define R_PRCM_SEC_SWITCH_REG	0x1d0
 #define DMA_SEC_REG		0x20
 
 /*
@@ -27,20 +22,18 @@
  */
 void sunxi_security_setup(void)
 {
-#ifdef SUNXI_SPC_BASE
 	int i;
 
 	INFO("Configuring SPC Controller\n");
 	/* SPC setup: set all devices to non-secure */
-	for (i = 0; i < 6; i++)
-		mmio_write_32(SPC_DECPORT_SET_REG(i), 0xff);
-#endif
+	for (i = 0; i < SUNXI_SPC_NUM_PORTS; i++)
+		mmio_write_32(SUNXI_SPC_DECPORT_SET_REG(i), 0xffffffff);
 
 	/* set MBUS clocks, bus clocks (AXI/AHB/APB) and PLLs to non-secure */
 	mmio_write_32(SUNXI_CCU_SEC_SWITCH_REG, 0x7);
 
 	/* Set R_PRCM bus clocks to non-secure */
-	mmio_write_32(SUNXI_R_PRCM_BASE + R_PRCM_SEC_SWITCH_REG, 0x1);
+	mmio_write_32(SUNXI_R_PRCM_SEC_SWITCH_REG, 0x1);
 
 	/* Set all DMA channels (16 max.) to non-secure */
 	mmio_write_32(SUNXI_DMA_BASE + DMA_SEC_REG, 0xffff);
diff --git a/plat/allwinner/sun50i_a64/include/sunxi_ccu.h b/plat/allwinner/sun50i_a64/include/sunxi_ccu.h
new file mode 100644
index 0000000..2a24886
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/include/sunxi_ccu.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_CCU_H
+#define SUNXI_CCU_H
+
+#define SUNXI_CCU_SEC_SWITCH_REG	(SUNXI_CCU_BASE + 0x02f0)
+
+#define SUNXI_R_PRCM_SEC_SWITCH_REG	(SUNXI_R_PRCM_BASE + 0x01d0)
+
+#endif /* SUNXI_CCU_H */
diff --git a/plat/allwinner/sun50i_a64/include/sunxi_mmap.h b/plat/allwinner/sun50i_a64/include/sunxi_mmap.h
index 9d2542f..6c847d3 100644
--- a/plat/allwinner/sun50i_a64/include/sunxi_mmap.h
+++ b/plat/allwinner/sun50i_a64/include/sunxi_mmap.h
@@ -36,7 +36,6 @@
 #define SUNXI_MSGBOX_BASE		0x01c17000
 #define SUNXI_SPINLOCK_BASE		0x01c18000
 #define SUNXI_CCU_BASE			0x01c20000
-#define SUNXI_CCU_SEC_SWITCH_REG	(SUNXI_CCU_BASE + 0x2f0)
 #define SUNXI_PIO_BASE			0x01c20800
 #define SUNXI_TIMER_BASE		0x01c20c00
 #define SUNXI_WDOG_BASE			0x01c20ca0
diff --git a/plat/allwinner/sun50i_a64/include/sunxi_spc.h b/plat/allwinner/sun50i_a64/include/sunxi_spc.h
new file mode 100644
index 0000000..5ba7e18
--- /dev/null
+++ b/plat/allwinner/sun50i_a64/include/sunxi_spc.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_SPC_H
+#define SUNXI_SPC_H
+
+#define SUNXI_SPC_NUM_PORTS		6
+
+#define SUNXI_SPC_DECPORT_STA_REG(p)	(SUNXI_SPC_BASE + 0x0004 + 0x0c * (p))
+#define SUNXI_SPC_DECPORT_SET_REG(p)	(SUNXI_SPC_BASE + 0x0008 + 0x0c * (p))
+#define SUNXI_SPC_DECPORT_CLR_REG(p)	(SUNXI_SPC_BASE + 0x000c + 0x0c * (p))
+
+#endif /* SUNXI_SPC_H */
diff --git a/plat/allwinner/sun50i_a64/sunxi_power.c b/plat/allwinner/sun50i_a64/sunxi_power.c
index 5b7d76a..80a69c3 100644
--- a/plat/allwinner/sun50i_a64/sunxi_power.c
+++ b/plat/allwinner/sun50i_a64/sunxi_power.c
@@ -92,24 +92,16 @@
 	if (ret)
 		return ret;
 
-	/* Start with 400 KHz to issue the I2C->RSB switch command. */
-	ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 400000);
-	if (ret)
-		return ret;
-
-	/*
-	 * Initiate an I2C transaction to write 0x7c into register 0x3e,
-	 * switching the PMIC to RSB mode.
-	 */
-	ret = rsb_set_device_mode(0x7c3e00);
-	if (ret)
-		return ret;
-
-	/* Now in RSB mode, switch to the recommended 3 MHz. */
+	/* Switch to the recommended 3 MHz bus clock. */
 	ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
 	if (ret)
 		return ret;
 
+	/* Initiate an I2C transaction to switch the PMIC to RSB mode. */
+	ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8);
+	if (ret)
+		return ret;
+
 	/* Associate the 8-bit runtime address with the 12-bit bus address. */
 	ret = rsb_assign_runtime_address(AXP803_HW_ADDR,
 					 AXP803_RT_ADDR);
@@ -156,6 +148,11 @@
 		pmic = AXP803_RSB;
 		axp_setup_regulators(fdt);
 
+		/* Switch the PMIC back to I2C mode. */
+		ret = axp_write(AXP20X_MODE_REG, AXP20X_MODE_I2C);
+		if (ret)
+			return ret;
+
 		break;
 	default:
 		return -ENODEV;
diff --git a/plat/allwinner/sun50i_h6/include/sunxi_ccu.h b/plat/allwinner/sun50i_h6/include/sunxi_ccu.h
new file mode 100644
index 0000000..85fbb90
--- /dev/null
+++ b/plat/allwinner/sun50i_h6/include/sunxi_ccu.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_CCU_H
+#define SUNXI_CCU_H
+
+#define SUNXI_CCU_SEC_SWITCH_REG	(SUNXI_CCU_BASE + 0x0f00)
+
+#define SUNXI_R_PRCM_SEC_SWITCH_REG	(SUNXI_R_PRCM_BASE + 0x0290)
+
+#endif /* SUNXI_CCU_H */
diff --git a/plat/allwinner/sun50i_h6/include/sunxi_mmap.h b/plat/allwinner/sun50i_h6/include/sunxi_mmap.h
index 702db77..2d7b098 100644
--- a/plat/allwinner/sun50i_h6/include/sunxi_mmap.h
+++ b/plat/allwinner/sun50i_h6/include/sunxi_mmap.h
@@ -30,8 +30,8 @@
 #define SUNXI_DMA_BASE			0x03002000
 #define SUNXI_MSGBOX_BASE		0x03003000
 #define SUNXI_CCU_BASE			0x03001000
-#define SUNXI_CCU_SEC_SWITCH_REG	(SUNXI_CCU_BASE + 0xf00)
 #define SUNXI_PIO_BASE			0x0300b000
+#define SUNXI_SPC_BASE			0x03008000
 #define SUNXI_TIMER_BASE		0x03009000
 #define SUNXI_WDOG_BASE			0x030090a0
 #define SUNXI_THS_BASE			0x05070400
@@ -55,6 +55,7 @@
 #define SUNXI_R_TWD_BASE		0x07020800
 #define SUNXI_R_CPUCFG_BASE		0x07000400
 #define SUNXI_R_I2C_BASE		0x07081400
+#define SUNXI_R_RSB_BASE		0x07083000
 #define SUNXI_R_UART_BASE		0x07080000
 #define SUNXI_R_PIO_BASE		0x07022000
 
diff --git a/plat/allwinner/sun50i_h6/include/sunxi_spc.h b/plat/allwinner/sun50i_h6/include/sunxi_spc.h
new file mode 100644
index 0000000..0f5965b
--- /dev/null
+++ b/plat/allwinner/sun50i_h6/include/sunxi_spc.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SUNXI_SPC_H
+#define SUNXI_SPC_H
+
+#define SUNXI_SPC_NUM_PORTS		14
+
+#define SUNXI_SPC_DECPORT_STA_REG(p)	(SUNXI_SPC_BASE + 0x0000 + 0x10 * (p))
+#define SUNXI_SPC_DECPORT_SET_REG(p)	(SUNXI_SPC_BASE + 0x0004 + 0x10 * (p))
+#define SUNXI_SPC_DECPORT_CLR_REG(p)	(SUNXI_SPC_BASE + 0x0008 + 0x10 * (p))
+
+#endif /* SUNXI_SPC_H */
diff --git a/plat/allwinner/sun50i_h6/platform.mk b/plat/allwinner/sun50i_h6/platform.mk
index 4ecc57c..1c98919 100644
--- a/plat/allwinner/sun50i_h6/platform.mk
+++ b/plat/allwinner/sun50i_h6/platform.mk
@@ -8,4 +8,4 @@
 include plat/allwinner/common/allwinner-common.mk
 
 BL31_SOURCES		+=	drivers/allwinner/axp/axp805.c		\
-				drivers/mentor/i2c/mi2cv.c
+				drivers/allwinner/sunxi_rsb.c
diff --git a/plat/allwinner/sun50i_h6/sunxi_power.c b/plat/allwinner/sun50i_h6/sunxi_power.c
index 443015b..a7865a5 100644
--- a/plat/allwinner/sun50i_h6/sunxi_power.c
+++ b/plat/allwinner/sun50i_h6/sunxi_power.c
@@ -6,20 +6,17 @@
  */
 
 #include <errno.h>
-#include <string.h>
 
-#include <arch_helpers.h>
 #include <common/debug.h>
 #include <drivers/allwinner/axp.h>
-#include <drivers/delay_timer.h>
-#include <drivers/mentor/mi2cv.h>
-#include <lib/mmio.h>
+#include <drivers/allwinner/sunxi_rsb.h>
 
 #include <sunxi_def.h>
 #include <sunxi_mmap.h>
 #include <sunxi_private.h>
 
-#define AXP805_ADDR	0x36
+#define AXP805_HW_ADDR	0x745
+#define AXP805_RT_ADDR	0x3a
 
 static enum pmic_type {
 	UNKNOWN,
@@ -28,67 +25,67 @@
 
 int axp_read(uint8_t reg)
 {
-	uint8_t val;
-	int ret;
-
-	ret = i2c_write(AXP805_ADDR, 0, 0, &reg, 1);
-	if (ret == 0)
-		ret = i2c_read(AXP805_ADDR, 0, 0, &val, 1);
-	if (ret) {
-		ERROR("PMIC: Cannot read AXP805 register %02x\n", reg);
-		return ret;
-	}
-
-	return val;
+	return rsb_read(AXP805_RT_ADDR, reg);
 }
 
 int axp_write(uint8_t reg, uint8_t val)
 {
-	int ret;
-
-	ret = i2c_write(AXP805_ADDR, reg, 1, &val, 1);
-	if (ret)
-		ERROR("PMIC: Cannot write AXP805 register %02x\n", reg);
-
-	return ret;
+	return rsb_write(AXP805_RT_ADDR, reg, val);
 }
 
-static int axp805_probe(void)
+static int rsb_init(void)
 {
 	int ret;
 
-	/* Switch the AXP805 to master/single-PMIC mode. */
-	ret = axp_write(0xff, 0x0);
+	ret = rsb_init_controller();
 	if (ret)
 		return ret;
 
-	ret = axp_check_id();
+	/* Switch to the recommended 3 MHz bus clock. */
+	ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
 	if (ret)
 		return ret;
 
-	return 0;
+	/* Initiate an I2C transaction to switch the PMIC to RSB mode. */
+	ret = rsb_set_device_mode(AXP20X_MODE_RSB << 16 | AXP20X_MODE_REG << 8);
+	if (ret)
+		return ret;
+
+	/* Associate the 8-bit runtime address with the 12-bit bus address. */
+	ret = rsb_assign_runtime_address(AXP805_HW_ADDR, AXP805_RT_ADDR);
+	if (ret)
+		return ret;
+
+	return axp_check_id();
 }
 
 int sunxi_pmic_setup(uint16_t socid, const void *fdt)
 {
 	int ret;
 
-	INFO("PMIC: Probing AXP805 on I2C\n");
+	INFO("PMIC: Probing AXP805 on RSB\n");
 
-	ret = sunxi_init_platform_r_twi(SUNXI_SOC_H6, false);
+	ret = sunxi_init_platform_r_twi(socid, true);
 	if (ret)
 		return ret;
 
-	/* initialise mi2cv driver */
-	i2c_init((void *)SUNXI_R_I2C_BASE);
+	ret = rsb_init();
+	if (ret)
+		return ret;
 
-	ret = axp805_probe();
+	/* Switch the AXP805 to master/single-PMIC mode. */
+	ret = axp_write(0xff, 0x0);
 	if (ret)
 		return ret;
 
 	pmic = AXP805;
 	axp_setup_regulators(fdt);
 
+	/* Switch the PMIC back to I2C mode. */
+	ret = axp_write(AXP20X_MODE_REG, AXP20X_MODE_I2C);
+	if (ret)
+		return ret;
+
 	return 0;
 }
 
@@ -96,10 +93,9 @@
 {
 	switch (pmic) {
 	case AXP805:
-		/* Re-initialise after rich OS might have used it. */
-		sunxi_init_platform_r_twi(SUNXI_SOC_H6, false);
-		/* initialise mi2cv driver */
-		i2c_init((void *)SUNXI_R_I2C_BASE);
+		/* (Re-)init RSB in case the rich OS has disabled it. */
+		sunxi_init_platform_r_twi(SUNXI_SOC_H6, true);
+		rsb_init();
 		axp_power_off();
 		break;
 	default:
diff --git a/plat/arm/board/rdn2/include/platform_def.h b/plat/arm/board/rdn2/include/platform_def.h
index ebfbf66..5561f8c 100644
--- a/plat/arm/board/rdn2/include/platform_def.h
+++ b/plat/arm/board/rdn2/include/platform_def.h
@@ -60,6 +60,6 @@
 /* GIC related constants */
 #define PLAT_ARM_GICD_BASE		UL(0x30000000)
 #define PLAT_ARM_GICC_BASE		UL(0x2C000000)
-#define PLAT_ARM_GICR_BASE		UL(0x30140000)
+#define PLAT_ARM_GICR_BASE		UL(0x301C0000)
 
 #endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/tc0/fdts/tc0_spmc_optee_sp_manifest.dts b/plat/arm/board/tc0/fdts/tc0_spmc_optee_sp_manifest.dts
new file mode 100644
index 0000000..a58b911
--- /dev/null
+++ b/plat/arm/board/tc0/fdts/tc0_spmc_optee_sp_manifest.dts
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2020, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+/dts-v1/;
+
+#define	AFF	00
+
+#include "fvp-defs.dtsi"
+#undef POST
+#define	POST \
+	};
+
+/ {
+	compatible = "arm,ffa-core-manifest-1.0";
+	#address-cells = <2>;
+	#size-cells = <1>;
+
+	attribute {
+		spmc_id = <0x8000>;
+		maj_ver = <0x1>;
+		min_ver = <0x0>;
+		exec_state = <0x0>;
+		load_address = <0x0 0xfd000000>;
+		entrypoint = <0x0 0xfd000000>;
+		binary_size = <0x80000>;
+	};
+
+	/*
+	 * temporary: This entry is added based on v2.4 hafnium and will be
+	 * removed when rebased to upstream master.
+	 */
+	chosen {
+	       linux,initrd-start = <0>;
+	       linux,initrd-end = <0>;
+	};
+
+	hypervisor {
+		compatible = "hafnium,hafnium";
+		vm1 {
+			is_ffa_partition;
+			debug_name = "op-tee";
+			load_address = <0xfd280000>;
+		};
+	};
+
+	cpus {
+		#address-cells = <0x2>;
+		#size-cells = <0x0>;
+
+		CPU_0
+
+		/*
+		 * SPMC (Hafnium) requires secondary core nodes are declared
+		 * in descending order.
+		 */
+		CPU_3
+		CPU_2
+		CPU_1
+	};
+
+	/*
+	 * temporary: This device-memory region is added based on v2.4 hafnium
+	 * and will be removed when rebased to upstream master. As first
+	 * Secure Partition no longer maps device memory.
+	 */
+	device-memory@21000000 {
+		device_type = "device-memory";
+		reg = <0x0 0x21000000 0x5f000000>;
+	};
+
+	/* 32MB of TC0_TZC_DRAM1_BASE */
+	memory@fd000000 {
+		device_type = "memory";
+		reg = <0x0 0xfd000000 0x2000000>;
+	};
+};
diff --git a/plat/arm/board/tc0/fdts/tc0_tb_fw_config.dts b/plat/arm/board/tc0/fdts/tc0_tb_fw_config.dts
index 3df94bf..de5f95d 100644
--- a/plat/arm/board/tc0/fdts/tc0_tb_fw_config.dts
+++ b/plat/arm/board/tc0/fdts/tc0_tb_fw_config.dts
@@ -27,6 +27,12 @@
 
 	secure-partitions {
 		compatible = "arm,sp";
+#if OPTEE_SP_FW_CONFIG
+		op-tee {
+		       uuid = <0x486178e0 0xe7f811e3 0xbc5e0002 0xa5d5c51b>;
+		       load-address = <0xfd280000>;
+		};
+#else
 		cactus-primary {
 			uuid = <0xb4b5671e 0x4a904fe1 0xb81ffb13 0xdae1dacb>;
 			load-address = <0xfe000000>;
@@ -43,5 +49,6 @@
 			uuid = <0x79b55c73 0x1d8c44b9 0x859361e1 0x770ad8d2>;
 			load-address = <0xfe200000>;
 		};
+#endif
 	};
 };
diff --git a/plat/arm/board/tc0/include/platform_def.h b/plat/arm/board/tc0/include/platform_def.h
index 72a035f..2ff2699 100644
--- a/plat/arm/board/tc0/include/platform_def.h
+++ b/plat/arm/board/tc0/include/platform_def.h
@@ -112,7 +112,7 @@
  * little space for growth.
  */
 #if TRUSTED_BOARD_BOOT
-# define PLAT_ARM_MAX_BL2_SIZE		0x1E000
+# define PLAT_ARM_MAX_BL2_SIZE		0x20000
 #else
 # define PLAT_ARM_MAX_BL2_SIZE		0x14000
 #endif
diff --git a/plat/arm/board/tc0/platform.mk b/plat/arm/board/tc0/platform.mk
index 5d2cc38..6cc5f46 100644
--- a/plat/arm/board/tc0/platform.mk
+++ b/plat/arm/board/tc0/platform.mk
@@ -86,8 +86,12 @@
 $(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config,${TB_FW_CONFIG}))
 
 ifeq (${SPD},spmd)
-FDT_SOURCES		+=	${TC0_BASE}/fdts/${PLAT}_spmc_manifest.dts
-TC0_TOS_FW_CONFIG	:=	${BUILD_PLAT}/fdts/${PLAT}_spmc_manifest.dtb
+ifeq ($(ARM_SPMC_MANIFEST_DTS),)
+ARM_SPMC_MANIFEST_DTS	:=	${TC0_BASE}/fdts/${PLAT}_spmc_manifest.dts
+endif
+
+FDT_SOURCES		+=	${ARM_SPMC_MANIFEST_DTS}
+TC0_TOS_FW_CONFIG	:=	${BUILD_PLAT}/fdts/$(notdir $(basename ${ARM_SPMC_MANIFEST_DTS})).dtb
 
 # Add the TOS_FW_CONFIG to FIP and specify the same to certtool
 $(eval $(call TOOL_ADD_PAYLOAD,${TC0_TOS_FW_CONFIG},--tos-fw-config,${TC0_TOS_FW_CONFIG}))
diff --git a/plat/arm/board/tc0/tc0_plat.c b/plat/arm/board/tc0/tc0_plat.c
index e12ad56..b5698c0 100644
--- a/plat/arm/board/tc0/tc0_plat.c
+++ b/plat/arm/board/tc0/tc0_plat.c
@@ -51,6 +51,10 @@
 #if TRUSTED_BOARD_BOOT && !BL2_AT_EL3
 	ARM_MAP_BL1_RW,
 #endif
+#ifdef SPD_opteed
+	ARM_MAP_OPTEE_CORE_MEM,
+	ARM_OPTEE_PAGEABLE_LOAD_MEM,
+#endif
 	{0}
 };
 #endif
diff --git a/plat/mediatek/mt8192/bl31_plat_setup.c b/plat/mediatek/mt8192/bl31_plat_setup.c
index 32e124f..9de4a2e 100644
--- a/plat/mediatek/mt8192/bl31_plat_setup.c
+++ b/plat/mediatek/mt8192/bl31_plat_setup.c
@@ -16,6 +16,7 @@
 #include <lib/coreboot.h>
 
 /* Platform Includes */
+#include <emi_mpu/emi_mpu.h>
 #include <gpio/mtgpio.h>
 #include <mt_gic_v3.h>
 #include <mt_timer.h>
@@ -89,6 +90,9 @@
 		ERROR("Failed to set default dcm on!!\n");
 	}
 
+	/* MPU Init */
+	emi_mpu_init();
+
 	/* Initialize the GIC driver, CPU and distributor interfaces */
 	mt_gic_driver_init();
 	mt_gic_init();
diff --git a/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.c b/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.c
new file mode 100644
index 0000000..d5d7e2e
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <emi_mpu.h>
+#include <lib/mmio.h>
+
+/*
+ * emi_mpu_set_region_protection: protect a region.
+ * @start: start address of the region
+ * @end: end address of the region
+ * @access_permission: EMI MPU access permission
+ * Return 0 for success, otherwise negative status code.
+ */
+static int _emi_mpu_set_protection(
+	unsigned long start, unsigned long end,
+	unsigned int apc)
+{
+	unsigned int dgroup;
+	unsigned int region;
+
+	region = (start >> 24) & 0xFF;
+	start &= 0x00FFFFFF;
+	dgroup = (end >> 24) & 0xFF;
+	end &= 0x00FFFFFF;
+
+	if  ((region >= EMI_MPU_REGION_NUM) || (dgroup > EMI_MPU_DGROUP_NUM)) {
+		WARN("Region:%u or dgroup:%u is wrong!\n", region, dgroup);
+		return -1;
+	}
+
+	apc &= 0x80FFFFFF;
+
+	if ((start >= DRAM_OFFSET) && (end >= start)) {
+		start -= DRAM_OFFSET;
+		end -= DRAM_OFFSET;
+	} else {
+		WARN("start:0x%lx or end:0x%lx address is wrong!\n",
+		     start, end);
+		return -2;
+	}
+
+	mmio_write_32(EMI_MPU_SA(region), start);
+	mmio_write_32(EMI_MPU_EA(region), end);
+	mmio_write_32(EMI_MPU_APC(region, dgroup), apc);
+
+	return 0;
+}
+
+void dump_emi_mpu_regions(void)
+{
+	unsigned long apc[EMI_MPU_DGROUP_NUM], sa, ea;
+
+	int region, i;
+
+	/* Only dump 8 regions(max: EMI_MPU_REGION_NUM --> 32) */
+	for (region = 0; region < 8; ++region) {
+		for (i = 0; i < EMI_MPU_DGROUP_NUM; ++i)
+			apc[i] = mmio_read_32(EMI_MPU_APC(region, i));
+		sa = mmio_read_32(EMI_MPU_SA(region));
+		ea = mmio_read_32(EMI_MPU_EA(region));
+
+		WARN("region %d:\n", region);
+		WARN("\tsa:0x%lx, ea:0x%lx, apc0: 0x%lx apc1: 0x%lx\n",
+		     sa, ea, apc[0], apc[1]);
+	}
+}
+
+int emi_mpu_set_protection(struct emi_region_info_t *region_info)
+{
+	unsigned long start, end;
+	int i;
+
+	if (region_info->region >= EMI_MPU_REGION_NUM)
+		return -1;
+
+	start = (unsigned long)(region_info->start >> EMI_MPU_ALIGN_BITS) |
+		(region_info->region << 24);
+
+	for (i = EMI_MPU_DGROUP_NUM - 1; i >= 0; i--) {
+		end = (unsigned long)(region_info->end >> EMI_MPU_ALIGN_BITS) |
+			(i << 24);
+		_emi_mpu_set_protection(start, end, region_info->apc[i]);
+	}
+
+	return 0;
+}
+
+void emi_mpu_init(void)
+{
+	/* Set permission */
+	struct emi_region_info_t region_info;
+
+	/* PCE-e protect address(TODO) */
+	region_info.start = 0x80000000ULL;
+	region_info.end = 0x83FF0000ULL;
+	region_info.region = 1;
+	SET_ACCESS_PERMISSION(region_info.apc, 1,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, FORBIDDEN, FORBIDDEN,
+			      FORBIDDEN, FORBIDDEN, NO_PROT,
+			      NO_PROT /*FORBIDDEN*/);
+	emi_mpu_set_protection(&region_info);
+
+	/* Forbidden All */
+	region_info.start = 0x40000000ULL;	/* dram base addr */
+	region_info.end = 0x1FFFF0000ULL;
+	region_info.region = 2;
+	SET_ACCESS_PERMISSION(region_info.apc, 1,
+			      NO_PROT, NO_PROT, NO_PROT, NO_PROT,
+			      NO_PROT, NO_PROT, NO_PROT, NO_PROT,
+			      NO_PROT, NO_PROT, NO_PROT, NO_PROT,
+			      NO_PROT, FORBIDDEN, NO_PROT, NO_PROT);
+	emi_mpu_set_protection(&region_info);
+
+	dump_emi_mpu_regions();
+}
+
diff --git a/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.h b/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.h
new file mode 100644
index 0000000..0b15431
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/emi_mpu/emi_mpu.h
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EMI_MPU_H
+#define EMI_MPU_H
+
+#include <platform_def.h>
+
+#define EMI_MPUP		(EMI_BASE + 0x01D8)
+#define EMI_MPUQ		(EMI_BASE + 0x01E0)
+#define EMI_MPUR		(EMI_BASE + 0x01E8)
+#define EMI_MPUS		(EMI_BASE + 0x01F0)
+#define EMI_MPUT		(EMI_BASE + 0x01F8)
+#define EMI_MPUY		(EMI_BASE + 0x0220)
+#define EMI_MPU_CTRL		(EMI_MPU_BASE + 0x0000)
+#define EMI_MPUD0_ST		(EMI_BASE + 0x0160)
+#define EMI_MPUD1_ST		(EMI_BASE + 0x0164)
+#define EMI_MPUD2_ST		(EMI_BASE + 0x0168)
+#define EMI_MPUD3_ST		(EMI_BASE + 0x016C)
+#define EMI_MPUD0_ST2		(EMI_BASE + 0x0200)
+#define EMI_MPUD1_ST2		(EMI_BASE + 0x0204)
+#define EMI_MPUD2_ST2		(EMI_BASE + 0x0208)
+#define EMI_MPUD3_ST2		(EMI_BASE + 0x020C)
+
+#define EMI_PHY_OFFSET		(0x40000000UL)
+
+#define NO_PROT 		(0)
+#define SEC_RW			(1)
+#define SEC_RW_NSEC_R		(2)
+#define SEC_RW_NSEC_W		(3)
+#define SEC_R_NSEC_R		(4)
+#define FORBIDDEN		(5)
+#define SEC_R_NSEC_RW		(6)
+
+#define SECURE_OS_MPU_REGION_ID	(0)
+#define ATF_MPU_REGION_ID	(1)
+
+#define EMI_MPU_SA0		(EMI_MPU_BASE + 0x100)
+#define EMI_MPU_EA0		(EMI_MPU_BASE + 0x200)
+#define EMI_MPU_SA(region)	(EMI_MPU_SA0 + (region) * 4)
+#define EMI_MPU_EA(region)	(EMI_MPU_EA0 + (region) * 4)
+
+#define EMI_MPU_APC0			(EMI_MPU_BASE + 0x300)
+#define EMI_MPU_APC(region, dgroup)	(EMI_MPU_APC0 + (region) * 4 + \
+					(dgroup) * 0x100)
+
+#define EMI_MPU_CTRL_D0		(EMI_MPU_BASE + 0x800)
+#define EMI_MPU_CTRL_D(domain)	(EMI_MPU_CTRL_D0 + domain * 4)
+#define EMI_RG_MASK_D0		(EMI_MPU_BASE + 0x900)
+#define EMI_RG_MASK_D(domain)	(EMI_RG_MASK_D0 + domain * 4)
+
+#define EMI_MPU_DOMAIN_NUM	16
+#define EMI_MPU_REGION_NUM	32
+#define EMI_MPU_ALIGN_BITS	16
+#define DRAM_OFFSET		(0x40000000 >> EMI_MPU_ALIGN_BITS)
+
+#define EMI_MPU_DGROUP_NUM	(EMI_MPU_DOMAIN_NUM / 8)
+
+#if (EMI_MPU_DGROUP_NUM == 1)
+#define SET_ACCESS_PERMISSION(apc_ary, lock, d7, d6, d5, d4, d3, d2, d1, d0) \
+do { \
+	apc_ary[0] = 0; \
+	apc_ary[0] = \
+		(((unsigned int)    d7) << 21) | (((unsigned int)  d6) << 18) \
+		| (((unsigned int)  d5) << 15) | (((unsigned int)  d4) << 12) \
+		| (((unsigned int)  d3) <<  9) | (((unsigned int)  d2) <<  6) \
+		| (((unsigned int)  d1) <<  3) | ((unsigned int)   d0) \
+		| (((unsigned int) lock) << 31); \
+} while (0)
+#elif (EMI_MPU_DGROUP_NUM == 2)
+#define SET_ACCESS_PERMISSION(apc_ary, lock, d15, d14, d13, d12, d11, d10, \
+			      d9, d8, d7, d6, d5, d4, d3, d2, d1, d0) \
+do { \
+	apc_ary[1] = \
+		(((unsigned int)   d15) << 21) | (((unsigned int) d14) << 18) \
+		| (((unsigned int) d13) << 15) | (((unsigned int) d12) << 12) \
+		| (((unsigned int) d11) <<  9) | (((unsigned int) d10) <<  6) \
+		| (((unsigned int)  d9) <<  3) |  ((unsigned int)  d8); \
+	apc_ary[0] = \
+		(((unsigned int)    d7) << 21) | (((unsigned int)  d6) << 18) \
+		| (((unsigned int)  d5) << 15) | (((unsigned int)  d4) << 12) \
+		| (((unsigned int)  d3) <<  9) | (((unsigned int)  d2) <<  6) \
+		| (((unsigned int)  d1) <<  3) |  ((unsigned int)  d0) \
+		| (((unsigned int) lock) << 31); \
+} while (0)
+#endif
+
+struct emi_region_info_t {
+	unsigned long long	start;
+	unsigned long long	end;
+	unsigned int		region;
+	unsigned long		apc[EMI_MPU_DGROUP_NUM];
+};
+
+void emi_mpu_init(void);
+int emi_mpu_set_protection(struct emi_region_info_t *region_info);
+void dump_emi_mpu_regions(void);
+
+#endif  /* __EMI_MPU_H */
diff --git a/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_main.c b/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_main.c
index 053d210..f1d8493 100644
--- a/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_main.c
+++ b/plat/mediatek/mt8192/drivers/ptp3/mtk_ptp3_main.c
@@ -39,15 +39,15 @@
 {
 	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]);
-		}
+	/* Apply ptp3_cfg1 for core 0 to 7 */
+	if (core < NR_PTP3_CFG1_CPU) {
+		/* update ptp3_cfg1 */
+		ptp3_write(
+			ptp3_cfg1[core][PTP3_CFG_ADDR],
+			ptp3_cfg1[core][PTP3_CFG_VALUE]);
 	}
 
+	/* Apply ptp3_cfg2 for core 4 to 7 */
 	if (core >= PTP3_CFG2_CPU_START_ID) {
 		_core = core - PTP3_CFG2_CPU_START_ID;
 
@@ -59,6 +59,7 @@
 		}
 	}
 
+	/* Apply ptp3_cfg3 for core 4 to 7 */
 	if (core >= PTP3_CFG3_CPU_START_ID) {
 		_core = core - PTP3_CFG3_CPU_START_ID;
 
@@ -73,13 +74,11 @@
 
 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);
-		}
+	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/rtc/rtc.c b/plat/mediatek/mt8192/drivers/rtc/rtc.c
new file mode 100644
index 0000000..124bc8f
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/rtc/rtc.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <rtc.h>
+
+
+static void RTC_Config_Interface(uint32_t addr, uint16_t data,
+			    uint16_t mask, uint16_t shift)
+{
+	uint16_t pmic_reg;
+
+	pmic_reg = RTC_Read(addr);
+
+	pmic_reg &= ~(mask << shift);
+	pmic_reg |= (data << shift);
+
+	RTC_Write(addr, pmic_reg);
+}
+
+static int32_t rtc_disable_2sec_reboot(void)
+{
+	uint16_t reboot;
+
+	reboot = (RTC_Read(RTC_AL_SEC) & ~RTC_BBPU_2SEC_EN) &
+		 ~RTC_BBPU_AUTO_PDN_SEL;
+	RTC_Write(RTC_AL_SEC, reboot);
+
+	return RTC_Write_Trigger();
+}
+
+static int32_t rtc_enable_k_eosc(void)
+{
+	uint16_t alm_dow, alm_sec;
+	int16_t ret;
+
+	/* Turning on eosc cali mode clock */
+	RTC_Config_Interface(PMIC_RG_SCK_TOP_CKPDN_CON0_CLR, 1,
+			PMIC_RG_RTC_EOSC32_CK_PDN_MASK,
+			PMIC_RG_RTC_EOSC32_CK_PDN_SHIFT);
+
+	alm_sec = RTC_Read(RTC_AL_SEC) & (~RTC_LPD_OPT_MASK);
+	RTC_Write(RTC_AL_SEC, alm_sec);
+	ret = RTC_Write_Trigger();
+	if (ret == 0) {
+		return 0;
+	}
+
+	RTC_Write(RTC_CON, RTC_LPD_EN);
+	ret = RTC_Write_Trigger();
+	if (ret == 0) {
+		return 0;
+	}
+
+	RTC_Write(RTC_CON, RTC_LPD_RST);
+	ret = RTC_Write_Trigger();
+	if (ret == 0) {
+		return 0;
+	}
+
+	RTC_Write(RTC_CON, RTC_LPD_EN);
+	ret = RTC_Write_Trigger();
+	if (ret == 0) {
+		return 0;
+	}
+
+	RTC_Write(RTC_POWERKEY1, RTC_POWERKEY1_KEY);
+	RTC_Write(RTC_POWERKEY2, RTC_POWERKEY2_KEY);
+	ret = RTC_Write_Trigger();
+	if (ret == 0) {
+		return 0;
+	}
+
+	/* set RTC EOSC calibration period = 8sec */
+	alm_dow = (RTC_Read(RTC_AL_DOW) & (~RTC_RG_EOSC_CALI_TD_MASK)) |
+		  RTC_RG_EOSC_CALI_TD_8SEC;
+	RTC_Write(RTC_AL_DOW, alm_dow);
+	ret = RTC_Write_Trigger();
+	if (ret == 0) {
+		return 0;
+	}
+
+	RTC_Write(RTC_BBPU,
+		  RTC_Read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD);
+	ret = RTC_Write_Trigger();
+	if (ret == 0) {
+		return 0;
+	}
+
+	/* Enable K EOSC mode :use solution1 of eosc cali to fix mt6359p 32K*/
+	RTC_Write(RTC_AL_YEA, (((RTC_Read(RTC_AL_YEA) | RTC_K_EOSC_RSV_0)
+				& (~RTC_K_EOSC_RSV_1)) | (RTC_K_EOSC_RSV_2)));
+	ret = RTC_Write_Trigger();
+	if (ret == 0) {
+		return 0;
+	}
+
+	INFO("[RTC] RTC_enable_k_eosc\n");
+
+	return 1;
+}
+
+void rtc_power_off_sequence(void)
+{
+	uint16_t bbpu;
+	int16_t ret;
+
+	ret = rtc_disable_2sec_reboot();
+	if (ret == 0) {
+		return;
+	}
+
+	ret = rtc_enable_k_eosc();
+	if (ret == 0) {
+		return;
+	}
+
+	bbpu = RTC_BBPU_KEY | RTC_BBPU_PWREN;
+
+	if (Writeif_unlock() != 0) {
+		RTC_Write(RTC_BBPU,
+			  bbpu | RTC_BBPU_RESET_ALARM | RTC_BBPU_RESET_SPAR);
+		RTC_Write(RTC_AL_MASK, RTC_AL_MASK_DOW);
+		ret = RTC_Write_Trigger();
+		if (ret == 0) {
+			return;
+		}
+		mdelay(1);
+
+		bbpu = RTC_Read(RTC_BBPU);
+
+		if (((bbpu & RTC_BBPU_RESET_ALARM) > 0) ||
+		    ((bbpu & RTC_BBPU_RESET_SPAR) > 0)) {
+			INFO("[RTC] timeout\n");
+		}
+
+		bbpu = RTC_Read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD;
+		RTC_Write(RTC_BBPU, bbpu);
+		ret = RTC_Write_Trigger();
+		if (ret == 0) {
+			return;
+		}
+	}
+}
diff --git a/plat/mediatek/mt8192/drivers/rtc/rtc.h b/plat/mediatek/mt8192/drivers/rtc/rtc.h
new file mode 100644
index 0000000..419bfe4
--- /dev/null
+++ b/plat/mediatek/mt8192/drivers/rtc/rtc.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2020, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RTC_H
+#define RTC_H
+
+/* RTC registers */
+enum {
+	RTC_BBPU = 0x0588,
+	RTC_IRQ_STA = 0x058A,
+	RTC_IRQ_EN = 0x058C,
+	RTC_CII_EN = 0x058E
+};
+
+enum {
+	RTC_AL_SEC = 0x05A0,
+	RTC_AL_MIN = 0x05A2,
+	RTC_AL_HOU = 0x05A4,
+	RTC_AL_DOM = 0x05A6,
+	RTC_AL_DOW = 0x05A8,
+	RTC_AL_MTH = 0x05AA,
+	RTC_AL_YEA = 0x05AC,
+	RTC_AL_MASK = 0x0590
+};
+
+enum {
+	RTC_OSC32CON = 0x05AE,
+	RTC_CON = 0x05C4,
+	RTC_WRTGR = 0x05C2
+};
+
+enum {
+	RTC_POWERKEY1 = 0x05B0,
+	RTC_POWERKEY2 = 0x05B2
+};
+
+enum {
+	RTC_POWERKEY1_KEY	= 0xA357,
+	RTC_POWERKEY2_KEY	= 0x67D2
+};
+
+enum {
+	RTC_PDN1 = 0x05B4,
+	RTC_PDN2 = 0x05B6,
+	RTC_SPAR0 = 0x05B8,
+	RTC_SPAR1 = 0x05BA,
+	RTC_PROT = 0x05BC,
+	RTC_DIFF = 0x05BE,
+	RTC_CALI = 0x05C0
+};
+
+enum {
+	RTC_OSC32CON_UNLOCK1 = 0x1A57,
+	RTC_OSC32CON_UNLOCK2 = 0x2B68
+};
+
+enum {
+	RTC_LPD_EN = 0x0406,
+	RTC_LPD_RST = 0x040E
+};
+
+enum {
+	RTC_LPD_OPT_XOSC_AND_EOSC_LPD	= 0U << 13,
+	RTC_LPD_OPT_EOSC_LPD		= 1U << 13,
+	RTC_LPD_OPT_XOSC_LPD		= 2U << 13,
+	RTC_LPD_OPT_F32K_CK_ALIVE	= 3U << 13,
+};
+
+#define RTC_LPD_OPT_MASK	(3U << 13)
+
+enum {
+	RTC_PROT_UNLOCK1 = 0x586A,
+	RTC_PROT_UNLOCK2 = 0x9136
+};
+
+enum {
+	RTC_BBPU_PWREN	= 1U << 0,
+	RTC_BBPU_SPAR_SW	= 1U << 1,
+	RTC_BBPU_RESET_SPAR	= 1U << 2,
+	RTC_BBPU_RESET_ALARM	= 1U << 3,
+	RTC_BBPU_CLRPKY	= 1U << 4,
+	RTC_BBPU_RELOAD	= 1U << 5,
+	RTC_BBPU_CBUSY	= 1U << 6
+};
+
+enum {
+	RTC_AL_MASK_SEC = 1U << 0,
+	RTC_AL_MASK_MIN = 1U << 1,
+	RTC_AL_MASK_HOU = 1U << 2,
+	RTC_AL_MASK_DOM = 1U << 3,
+	RTC_AL_MASK_DOW = 1U << 4,
+	RTC_AL_MASK_MTH = 1U << 5,
+	RTC_AL_MASK_YEA = 1U << 6
+};
+
+enum {
+	RTC_BBPU_AUTO_PDN_SEL = 1U << 6,
+	RTC_BBPU_2SEC_CK_SEL = 1U << 7,
+	RTC_BBPU_2SEC_EN = 1U << 8,
+	RTC_BBPU_2SEC_MODE = 0x3 << 9,
+	RTC_BBPU_2SEC_STAT_CLEAR = 1U << 11,
+	RTC_BBPU_2SEC_STAT_STA = 1U << 12
+};
+
+enum {
+	RTC_BBPU_KEY	= 0x43 << 8
+};
+
+enum {
+	RTC_EMBCK_SRC_SEL	= 1 << 8,
+	RTC_EMBCK_SEL_MODE	= 3 << 6,
+	RTC_XOSC32_ENB		= 1 << 5,
+	RTC_REG_XOSC32_ENB	= 1 << 15
+};
+
+enum {
+	RTC_K_EOSC_RSV_0	= 1 << 8,
+	RTC_K_EOSC_RSV_1	= 1 << 9,
+	RTC_K_EOSC_RSV_2	= 1 << 10
+};
+
+enum {
+	RTC_RG_EOSC_CALI_TD_1SEC	= 3 << 5,
+	RTC_RG_EOSC_CALI_TD_2SEC	= 4 << 5,
+	RTC_RG_EOSC_CALI_TD_4SEC	= 5 << 5,
+	RTC_RG_EOSC_CALI_TD_8SEC	= 6 << 5,
+	RTC_RG_EOSC_CALI_TD_16SEC	= 7 << 5,
+	RTC_RG_EOSC_CALI_TD_MASK	= 7 << 5
+};
+
+/* PMIC TOP Register Definition */
+enum {
+	PMIC_RG_TOP_CON = 0x0020,
+	PMIC_RG_TOP_CKPDN_CON1 = 0x0112,
+	PMIC_RG_TOP_CKPDN_CON1_SET = 0x0114,
+	PMIC_RG_TOP_CKPDN_CON1_CLR = 0x0116,
+	PMIC_RG_TOP_CKSEL_CON0 = 0x0118,
+	PMIC_RG_TOP_CKSEL_CON0_SET = 0x011A,
+	PMIC_RG_TOP_CKSEL_CON0_CLR = 0x011C
+};
+
+/* PMIC SCK Register Definition */
+enum {
+	PMIC_RG_SCK_TOP_CKPDN_CON0 = 0x0514,
+	PMIC_RG_SCK_TOP_CKPDN_CON0_SET = 0x0516,
+	PMIC_RG_SCK_TOP_CKPDN_CON0_CLR = 0x0518,
+	PMIC_RG_EOSC_CALI_CON0 = 0x53A
+};
+
+enum {
+	PMIC_EOSC_CALI_START_ADDR = 0x53A
+};
+
+enum {
+	PMIC_EOSC_CALI_START_MASK = 0x1,
+	PMIC_EOSC_CALI_START_SHIFT = 0
+};
+
+/* PMIC DCXO Register Definition */
+enum {
+	PMIC_RG_DCXO_CW00 = 0x0788,
+	PMIC_RG_DCXO_CW02 = 0x0790,
+	PMIC_RG_DCXO_CW08 = 0x079C,
+	PMIC_RG_DCXO_CW09 = 0x079E,
+	PMIC_RG_DCXO_CW09_CLR = 0x07A2,
+	PMIC_RG_DCXO_CW10 = 0x07A4,
+	PMIC_RG_DCXO_CW12 = 0x07A8,
+	PMIC_RG_DCXO_CW13 = 0x07AA,
+	PMIC_RG_DCXO_CW15 = 0x07AE,
+	PMIC_RG_DCXO_CW19 = 0x07B6,
+};
+
+enum {
+	PMIC_RG_SRCLKEN_IN0_HW_MODE_MASK = 0x1,
+	PMIC_RG_SRCLKEN_IN0_HW_MODE_SHIFT = 1,
+	PMIC_RG_SRCLKEN_IN1_HW_MODE_MASK = 0x1,
+	PMIC_RG_SRCLKEN_IN1_HW_MODE_SHIFT = 3,
+	PMIC_RG_RTC_EOSC32_CK_PDN_MASK = 0x1,
+	PMIC_RG_RTC_EOSC32_CK_PDN_SHIFT = 2,
+	PMIC_RG_EOSC_CALI_TD_MASK = 0x7,
+	PMIC_RG_EOSC_CALI_TD_SHIFT = 5,
+	PMIC_RG_XO_EN32K_MAN_MASK = 0x1,
+	PMIC_RG_XO_EN32K_MAN_SHIFT = 0
+};
+
+/* external API */
+uint16_t RTC_Read(uint32_t addr);
+void RTC_Write(uint32_t addr, uint16_t data);
+int32_t rtc_busy_wait(void);
+int32_t RTC_Write_Trigger(void);
+int32_t Writeif_unlock(void);
+void rtc_power_off_sequence(void);
+
+#endif /* RTC_H */
diff --git a/plat/mediatek/mt8192/include/platform_def.h b/plat/mediatek/mt8192/include/platform_def.h
index 51cf361..3e44414 100644
--- a/plat/mediatek/mt8192/include/platform_def.h
+++ b/plat/mediatek/mt8192/include/platform_def.h
@@ -30,6 +30,8 @@
 #define GPIO_BASE        (IO_PHYS + 0x00005000)
 #define SPM_BASE         (IO_PHYS + 0x00006000)
 #define PMIC_WRAP_BASE   (IO_PHYS + 0x00026000)
+#define EMI_BASE         (IO_PHYS + 0x00219000)
+#define EMI_MPU_BASE     (IO_PHYS + 0x00226000)
 #define IOCFG_RM_BASE    (IO_PHYS + 0x01C20000)
 #define IOCFG_BM_BASE    (IO_PHYS + 0x01D10000)
 #define IOCFG_BL_BASE    (IO_PHYS + 0x01D30000)
diff --git a/plat/mediatek/mt8192/plat_pm.c b/plat/mediatek/mt8192/plat_pm.c
index 3ea27b6..6a74c02 100644
--- a/plat/mediatek/mt8192/plat_pm.c
+++ b/plat/mediatek/mt8192/plat_pm.c
@@ -21,6 +21,7 @@
 #include <plat_params.h>
 #include <plat_pm.h>
 #include <pmic.h>
+#include <rtc.h>
 
 /*
  * Cluster state request:
@@ -297,10 +298,6 @@
 	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 {
@@ -345,6 +342,7 @@
 {
 	INFO("MTK System Off\n");
 
+	rtc_power_off_sequence();
 	pmic_power_off();
 
 	wfi();
diff --git a/plat/mediatek/mt8192/platform.mk b/plat/mediatek/mt8192/platform.mk
index 191895a..a5e7ee2 100644
--- a/plat/mediatek/mt8192/platform.mk
+++ b/plat/mediatek/mt8192/platform.mk
@@ -11,10 +11,12 @@
                  -I${MTK_PLAT_SOC}/include/                       \
                  -I${MTK_PLAT_SOC}/drivers/                       \
                  -I${MTK_PLAT_SOC}/drivers/dcm                    \
+                 -I${MTK_PLAT_SOC}/drivers/emi_mpu/               \
                  -I${MTK_PLAT_SOC}/drivers/gpio/                  \
                  -I${MTK_PLAT_SOC}/drivers/mcdi/                  \
                  -I${MTK_PLAT_SOC}/drivers/pmic/                  \
                  -I${MTK_PLAT_SOC}/drivers/ptp3/                  \
+                 -I${MTK_PLAT_SOC}/drivers/rtc/                   \
                  -I${MTK_PLAT_SOC}/drivers/spmc/                  \
                  -I${MTK_PLAT_SOC}/drivers/timer/                 \
                  -I${MTK_PLAT_SOC}/drivers/uart/
@@ -38,6 +40,7 @@
                    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/rtc/rtc_common.c           \
                    ${MTK_PLAT}/common/drivers/uart/uart.c                \
                    ${MTK_PLAT}/common/mtk_plat_common.c                  \
                    ${MTK_PLAT}/common/mtk_sip_svc.c                      \
@@ -46,6 +49,7 @@
                    ${MTK_PLAT_SOC}/aarch64/plat_helpers.S                \
                    ${MTK_PLAT_SOC}/bl31_plat_setup.c                     \
                    ${MTK_PLAT_SOC}/drivers/pmic/pmic.c                   \
+                   ${MTK_PLAT_SOC}/drivers/rtc/rtc.c                     \
                    ${MTK_PLAT_SOC}/plat_pm.c                             \
                    ${MTK_PLAT_SOC}/plat_topology.c                       \
                    ${MTK_PLAT_SOC}/plat_mt_gic.c                         \
@@ -53,6 +57,7 @@
                    ${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/emi_mpu/emi_mpu.c             \
                    ${MTK_PLAT_SOC}/drivers/gpio/mtgpio.c                 \
                    ${MTK_PLAT_SOC}/drivers/mcdi/mt_cpu_pm.c              \
                    ${MTK_PLAT_SOC}/drivers/mcdi/mt_cpu_pm_cpc.c          \