Merge "Plat AXG: Fix PLAT_MAX_PWR_LVL value" into integration
diff --git a/docs/about/maintainers.rst b/docs/about/maintainers.rst
index f500938..91a5621 100644
--- a/docs/about/maintainers.rst
+++ b/docs/about/maintainers.rst
@@ -516,8 +516,8 @@
 
 Texas Instruments platform port
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-:M: Andrew F. Davis <afd@ti.com>
-:G: `glneo`_
+:M: Nishanth Menon <nm@ti.com>
+:G: `nmenon`_
 :F: docs/plat/ti-k3.rst
 :F: plat/ti/
 
@@ -651,5 +651,6 @@
 .. _john-powell-arm: https://github.com/john-powell-arm
 .. _raghuncstate: https://github.com/raghuncstate
 .. _CJKay: https://github.com/cjkay
+.. _nmenon: https://github.com/nmenon
 
 .. _Project Maintenance Process: https://developer.trustedfirmware.org/w/collaboration/project-maintenance-process/
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/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/drivers/marvell/uart/a3700_console.S b/drivers/marvell/uart/a3700_console.S
index d184a2d..dc374ee 100644
--- a/drivers/marvell/uart/a3700_console.S
+++ b/drivers/marvell/uart/a3700_console.S
@@ -232,6 +232,11 @@
 	 * ---------------------------------------------
 	 */
 func console_a3700_core_flush
+	/* Wait for the TX FIFO to be empty */
+1:	ldr	w1, [x0, #UART_STATUS_REG]
+	and	w1, w1, #UARTLSR_TXFIFOEMPTY
+	cmp	w1, #UARTLSR_TXFIFOEMPTY
+	b.ne	1b
 	ret
 endfunc console_a3700_core_flush
 
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/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/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/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,21 +92,13 @@
 	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);
+	/* Switch to the recommended 3 MHz bus clock. */
+	ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
 	if (ret)
 		return ret;
 
-	/* Now in RSB mode, switch to the recommended 3 MHz. */
-	ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000);
+	/* 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;
 
@@ -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/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          \
diff --git a/plat/ti/k3/board/generic/board.mk b/plat/ti/k3/board/generic/board.mk
index a342214..ef74cd6 100644
--- a/plat/ti/k3/board/generic/board.mk
+++ b/plat/ti/k3/board/generic/board.mk
@@ -13,5 +13,12 @@
 K3_HW_CONFIG_BASE ?= 0x82000000
 $(eval $(call add_define,K3_HW_CONFIG_BASE))
 
+# Define sec_proxy usage as the full prioritized communication scheme
+K3_SEC_PROXY_LITE	:=	0
+$(eval $(call add_define,K3_SEC_PROXY_LITE))
+
+# System coherency is managed in hardware
+USE_COHERENT_MEM	:=	1
+
 PLAT_INCLUDES		+=	\
 				-Iplat/ti/k3/board/generic/include	\
diff --git a/plat/ti/k3/board/lite/board.mk b/plat/ti/k3/board/lite/board.mk
new file mode 100644
index 0000000..76246be
--- /dev/null
+++ b/plat/ti/k3/board/lite/board.mk
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+BL32_BASE ?= 0x9e800000
+$(eval $(call add_define,BL32_BASE))
+
+PRELOADED_BL33_BASE ?= 0x80080000
+$(eval $(call add_define,PRELOADED_BL33_BASE))
+
+K3_HW_CONFIG_BASE ?= 0x82000000
+$(eval $(call add_define,K3_HW_CONFIG_BASE))
+
+# Define sec_proxy usage as the lite version
+K3_SEC_PROXY_LITE	:=	1
+$(eval $(call add_define,K3_SEC_PROXY_LITE))
+
+# We dont have system level coherency capability
+USE_COHERENT_MEM	:=	0
+
+PLAT_INCLUDES	+=			\
+	-Iplat/ti/k3/board/lite/include	\
diff --git a/plat/ti/k3/board/lite/include/board_def.h b/plat/ti/k3/board/lite/include/board_def.h
new file mode 100644
index 0000000..7c7ea62
--- /dev/null
+++ b/plat/ti/k3/board/lite/include/board_def.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef BOARD_DEF_H
+#define BOARD_DEF_H
+
+#include <lib/utils_def.h>
+
+/* The ports must be in order and contiguous */
+#define K3_CLUSTER0_CORE_COUNT		U(4)
+#define K3_CLUSTER1_CORE_COUNT		U(0)
+#define K3_CLUSTER2_CORE_COUNT		U(0)
+#define K3_CLUSTER3_CORE_COUNT		U(0)
+
+/*
+ * This RAM will be used for the bootloader including code, bss, and stacks.
+ * It may need to be increased if BL31 grows in size.
+ * Current computation assumes data structures necessary for GIC and ARM for
+ * a single cluster of 4 processor.
+ */
+#define SEC_SRAM_BASE			0x70000000 /* Base of SRAM */
+#define SEC_SRAM_SIZE			0x0001a000 /* 104k */
+
+#define PLAT_MAX_OFF_STATE		U(2)
+#define PLAT_MAX_RET_STATE		U(1)
+
+#define PLAT_PROC_START_ID		32
+#define PLAT_PROC_DEVICE_START_ID	135
+#define PLAT_CLUSTER_DEVICE_START_ID	134
+
+#endif /* BOARD_DEF_H */
diff --git a/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c
index ee1eecf..a0bfdee 100644
--- a/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c
+++ b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c
@@ -97,11 +97,16 @@
 		.data_end_offset = 0x3C,
 	},
 	.threads = {
+#if !K3_SEC_PROXY_LITE
 		SP_THREAD(SP_NOTIFY),
 		SP_THREAD(SP_RESPONSE),
 		SP_THREAD(SP_HIGH_PRIORITY),
 		SP_THREAD(SP_LOW_PRIORITY),
 		SP_THREAD(SP_NOTIFY_RESP),
+#else
+		SP_THREAD(SP_RESPONSE),
+		SP_THREAD(SP_HIGH_PRIORITY),
+#endif /* K3_SEC_PROXY_LITE */
 	},
 };
 
@@ -261,9 +266,14 @@
 	/*
 	 * 'data_reg' indicates next register to write. If we did not already
 	 * write on tx complete reg(last reg), we must do so for transmit
+	 * In addition, we also need to make sure all intermediate data
+	 * registers(if any required), are reset to 0 for TISCI backward
+	 * compatibility to be maintained.
 	 */
-	if (data_reg <= spm.desc.data_end_offset)
-		mmio_write_32(spt->data + spm.desc.data_end_offset, 0);
+	while (data_reg <= spm.desc.data_end_offset) {
+		mmio_write_32(spt->data + data_reg, 0);
+		data_reg += sizeof(uint32_t);
+	}
 
 	VERBOSE("Message successfully sent on thread %s\n", spt->name);
 
diff --git a/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h
index 6c4f5df..f4b0b4b 100644
--- a/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h
+++ b/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h
@@ -16,13 +16,28 @@
  * enum k3_sec_proxy_chan_id - Secure Proxy thread IDs
  *
  * These the available IDs used in k3_sec_proxy_{send,recv}()
+ * There are two schemes we use:
+ * * if K3_SEC_PROXY_LITE = 1, we just have two threads to talk
+ * * if K3_SEC_PROXY_LITE = 0, we have the full fledged
+ *   communication scheme available.
  */
 enum k3_sec_proxy_chan_id {
+#if !K3_SEC_PROXY_LITE
 	SP_NOTIFY = 0,
 	SP_RESPONSE,
 	SP_HIGH_PRIORITY,
 	SP_LOW_PRIORITY,
 	SP_NOTIFY_RESP,
+#else
+	SP_RESPONSE = 8,
+	/*
+	 * Note: TISCI documentation indicates "low priority", but in reality
+	 * with a single thread, there is no low or high priority.. This usage
+	 * is more appropriate for TF-A since we can reduce the churn as a
+	 * result.
+	 */
+	SP_HIGH_PRIORITY,
+#endif /* K3_SEC_PROXY_LITE */
 };
 
 /**
diff --git a/plat/ti/k3/common/drivers/ti_sci/ti_sci.c b/plat/ti/k3/common/drivers/ti_sci/ti_sci.c
index e390efe..2c3313c 100644
--- a/plat/ti/k3/common/drivers/ti_sci/ti_sci.c
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci.c
@@ -1163,6 +1163,7 @@
 		ERROR("Message alloc failed (%d)\n", ret);
 		return ret;
 	}
+	req.domain = TI_SCI_DOMAIN_FULL_SOC_RESET;
 
 	ret = ti_sci_do_xfer(&xfer);
 	if (ret) {
diff --git a/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h b/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h
index 2d23f9a..310bf45 100644
--- a/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h
+++ b/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h
@@ -95,12 +95,15 @@
 /**
  * struct ti_sci_msg_req_reboot - Reboot the SoC
  * @hdr:	Generic Header
+ * @domain:	Domain to be reset, 0 for full SoC reboot
  *
  * Request type is TI_SCI_MSG_SYS_RESET, responded with a generic
  * ACK/NACK message.
  */
 struct ti_sci_msg_req_reboot {
 	struct ti_sci_msg_hdr hdr;
+#define TI_SCI_DOMAIN_FULL_SOC_RESET	0x0
+	uint8_t domain;
 } __packed;
 
 /**
diff --git a/plat/ti/k3/common/k3_bl31_setup.c b/plat/ti/k3/common/k3_bl31_setup.c
index 8bd7362..ac4e60e 100644
--- a/plat/ti/k3/common/k3_bl31_setup.c
+++ b/plat/ti/k3/common/k3_bl31_setup.c
@@ -13,6 +13,7 @@
 #include <arch_helpers.h>
 #include <common/bl_common.h>
 #include <common/debug.h>
+#include <lib/mmio.h>
 #include <lib/xlat_tables/xlat_tables_v2.h>
 
 #include <k3_console.h>
@@ -23,6 +24,7 @@
 const mmap_region_t plat_k3_mmap[] = {
 	MAP_REGION_FLAT(K3_USART_BASE,       K3_USART_SIZE,       MT_DEVICE | MT_RW | MT_SECURE),
 	MAP_REGION_FLAT(K3_GIC_BASE,         K3_GIC_SIZE,         MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(K3_GTC_BASE,         K3_GTC_SIZE,         MT_DEVICE | MT_RW | MT_SECURE),
 	MAP_REGION_FLAT(SEC_PROXY_RT_BASE,   SEC_PROXY_RT_SIZE,   MT_DEVICE | MT_RW | MT_SECURE),
 	MAP_REGION_FLAT(SEC_PROXY_SCFG_BASE, SEC_PROXY_SCFG_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
 	MAP_REGION_FLAT(SEC_PROXY_DATA_BASE, SEC_PROXY_DATA_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
@@ -127,6 +129,38 @@
 
 unsigned int plat_get_syscnt_freq2(void)
 {
+	uint32_t gtc_freq;
+	uint32_t gtc_ctrl;
+
+	/* Lets try and provide basic diagnostics - cost is low */
+	gtc_ctrl = mmio_read_32(K3_GTC_BASE + K3_GTC_CNTCR_OFFSET);
+	/* Did the bootloader fail to enable timer and OS guys are confused? */
+	if ((gtc_ctrl & K3_GTC_CNTCR_EN_MASK) == 0U) {
+		ERROR("GTC is disabled! Timekeeping broken. Fix Bootloader\n");
+	}
+	/*
+	 * If debug will not pause time, we will have issues like
+	 * drivers timing out while debugging, in cases of OS like Linux,
+	 * RCU stall errors, which can be hard to differentiate vs real issues.
+	 */
+	if ((gtc_ctrl & K3_GTC_CNTCR_HDBG_MASK) == 0U) {
+		WARN("GTC: Debug access doesn't stop time. Fix Bootloader\n");
+	}
+
+	gtc_freq = mmio_read_32(K3_GTC_BASE + K3_GTC_CNTFID0_OFFSET);
+	/* Many older bootloaders may have missed programming FID0 register */
+	if (gtc_freq != 0U) {
+		return gtc_freq;
+	}
+
+	/*
+	 * We could have just warned about this, but this can have serious
+	 * hard to debug side effects if we are NOT sure what the actual
+	 * frequency is. Lets make sure people don't miss this.
+	 */
+	ERROR("GTC_CNTFID0 is 0! Assuming %d Hz. Fix Bootloader\n",
+	      SYS_COUNTER_FREQ_IN_TICKS);
+
 	return SYS_COUNTER_FREQ_IN_TICKS;
 }
 
diff --git a/plat/ti/k3/common/plat_common.mk b/plat/ti/k3/common/plat_common.mk
index c00262b..ab7366b 100644
--- a/plat/ti/k3/common/plat_common.mk
+++ b/plat/ti/k3/common/plat_common.mk
@@ -11,9 +11,8 @@
 # We can choose where a core starts executing
 PROGRAMMABLE_RESET_ADDRESS:=	1
 
-# System coherency is managed in hardware
+# ARM coherency is managed in hardware
 WARMBOOT_ENABLE_DCACHE_EARLY :=	1
-USE_COHERENT_MEM	:=	1
 
 # A53 erratum for SoC. (enable them all)
 ERRATA_A53_826319	:=	1
@@ -21,9 +20,11 @@
 ERRATA_A53_836870	:=	1
 ERRATA_A53_843419	:=	1
 ERRATA_A53_855873	:=	1
+ERRATA_A53_1530924	:=	1
 
 # A72 Erratum for SoC
 ERRATA_A72_859971	:=	1
+ERRATA_A72_1319367	:=	1
 
 CRASH_REPORTING		:= 1
 HANDLE_EA_EL3_FIRST	:= 1
diff --git a/plat/ti/k3/include/platform_def.h b/plat/ti/k3/include/platform_def.h
index 98db626..f12fb0b 100644
--- a/plat/ti/k3/include/platform_def.h
+++ b/plat/ti/k3/include/platform_def.h
@@ -150,15 +150,33 @@
 	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
 			GIC_INTR_CFG_EDGE)
 
+
+#define K3_GTC_BASE		0x00A90000
+/* We just need 20 byte offset, but simpler to just remap the 64K page in */
+#define K3_GTC_SIZE		0x10000
+#define K3_GTC_CNTCR_OFFSET	0x00
+#define K3_GTC_CNTCR_EN_MASK	0x01
+#define K3_GTC_CNTCR_HDBG_MASK	0x02
+#define K3_GTC_CNTFID0_OFFSET	0x20
+
 #define K3_GIC_BASE	0x01800000
 #define K3_GIC_SIZE	0x200000
 
+#if !K3_SEC_PROXY_LITE
 #define SEC_PROXY_DATA_BASE	0x32C00000
 #define SEC_PROXY_DATA_SIZE	0x80000
 #define SEC_PROXY_SCFG_BASE	0x32800000
 #define SEC_PROXY_SCFG_SIZE	0x80000
 #define SEC_PROXY_RT_BASE	0x32400000
 #define SEC_PROXY_RT_SIZE	0x80000
+#else
+#define SEC_PROXY_DATA_BASE	0x4D000000
+#define SEC_PROXY_DATA_SIZE	0x80000
+#define SEC_PROXY_SCFG_BASE	0x4A400000
+#define SEC_PROXY_SCFG_SIZE	0x80000
+#define SEC_PROXY_RT_BASE	0x4A600000
+#define SEC_PROXY_RT_SIZE	0x80000
+#endif /* K3_SEC_PROXY_LITE */
 
 #define SEC_PROXY_TIMEOUT_US		1000000
 #define SEC_PROXY_MAX_MESSAGE_SIZE	56
diff --git a/plat/xilinx/zynqmp/include/zynqmp_def.h b/plat/xilinx/zynqmp/include/zynqmp_def.h
index 4614395..b492210 100644
--- a/plat/xilinx/zynqmp/include/zynqmp_def.h
+++ b/plat/xilinx/zynqmp/include/zynqmp_def.h
@@ -350,4 +350,10 @@
 #define  AFIFM6_WRCTRL		U(13)
 #define  FABRIC_WIDTH		U(3)
 
+/* CSUDMA Module Base Address*/
+#define CSUDMA_BASE		0xFFC80000
+
+/* RSA-CORE Module Base Address*/
+#define RSA_CORE_BASE		0xFFCE0000
+
 #endif /* ZYNQMP_DEF_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
index f2dfbb1..0cc517e 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
@@ -2446,7 +2446,7 @@
  *
  * @return	Returns success. In case of error, name data is 0.
  */
-enum pm_ret_status pm_api_clock_get_name(unsigned int clock_id, char *name)
+void pm_api_clock_get_name(unsigned int clock_id, char *name)
 {
 	if (clock_id == CLK_MAX)
 		memcpy(name, END_OF_CLK, sizeof(END_OF_CLK) > CLK_NAME_LEN ?
@@ -2458,8 +2458,6 @@
 	else
 		memcpy(name, ext_clocks[clock_id - CLK_MAX_OUTPUT_CLK].name,
 		       CLK_NAME_LEN);
-
-	return PM_RET_SUCCESS;
 }
 
 /**
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.h b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
index 301ed24..5efd63f 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
@@ -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
  */
@@ -294,7 +294,7 @@
 struct pm_pll *pm_clock_get_pll_by_related_clk(enum clock_id clock_id);
 uint8_t pm_clock_has_div(unsigned int clock_id, enum pm_clock_div_id div_id);
 
-enum pm_ret_status pm_api_clock_get_name(unsigned int clock_id, char *name);
+void pm_api_clock_get_name(unsigned int clock_id, char *name);
 enum pm_ret_status pm_api_clock_get_num_clocks(unsigned int *nclocks);
 enum pm_ret_status pm_api_clock_get_topology(unsigned int clock_id,
 					     unsigned int index,
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c
index 4b8dfb6..9a6b497 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c
@@ -19,39 +19,6 @@
 #include "pm_common.h"
 #include "pm_ipi.h"
 
-#define PINCTRL_FUNCTION_MASK			U(0xFE)
-#define PINCTRL_VOLTAGE_STATUS_MASK		U(0x01)
-#define NFUNCS_PER_PIN				U(13)
-#define PINCTRL_NUM_MIOS			U(78)
-#define MAX_PIN_PER_REG				U(26)
-#define PINCTRL_BANK_ADDR_STEP			U(28)
-
-#define PINCTRL_DRVSTRN0_REG_OFFSET		U(0)
-#define PINCTRL_DRVSTRN1_REG_OFFSET		U(4)
-#define PINCTRL_SCHCMOS_REG_OFFSET		U(8)
-#define PINCTRL_PULLCTRL_REG_OFFSET		U(12)
-#define PINCTRL_PULLSTAT_REG_OFFSET		U(16)
-#define PINCTRL_SLEWCTRL_REG_OFFSET		U(20)
-#define PINCTRL_VOLTAGE_STAT_REG_OFFSET		U(24)
-
-#define IOU_SLCR_BANK1_CTRL5			U(0XFF180164)
-
-#define PINCTRL_CFG_ADDR_OFFSET(addr, reg, miopin)			\
-	((addr) + 4 * PINCTRL_NUM_MIOS + PINCTRL_BANK_ADDR_STEP *	\
-	((miopin) / MAX_PIN_PER_REG) + (reg))
-
-#define PINCTRL_PIN_OFFSET(_miopin) \
-	((_miopin) - (MAX_PIN_PER_REG * ((_miopin) / MAX_PIN_PER_REG)))
-
-#define PINCTRL_REGVAL_TO_PIN_CONFIG(_pin, _val)			\
-	(((_val) >> PINCTRL_PIN_OFFSET(_pin)) & 0x1)
-
-static uint8_t pm_pinctrl_mux[NFUNCS_PER_PIN] = {
-	0x02, 0x04, 0x08, 0x10, 0x18,
-	0x00, 0x20, 0x40, 0x60, 0x80,
-	0xA0, 0xC0, 0xE0
-};
-
 struct pinctrl_function {
 	char name[FUNCTION_NAME_LEN];
 	uint16_t (*groups)[];
@@ -2604,18 +2571,13 @@
  *
  * This function is used by master to get name of function specified
  * by given function ID.
- *
- * @return	Returns success. In case of error, name data is 0.
  */
-enum pm_ret_status pm_api_pinctrl_get_function_name(unsigned int fid,
-						    char *name)
+void pm_api_pinctrl_get_function_name(unsigned int fid, char *name)
 {
 	if (fid >= MAX_FUNCTION)
 		memcpy(name, END_OF_FUNCTION, FUNCTION_NAME_LEN);
 	else
 		memcpy(name, pinctrl_functions[fid].name, FUNCTION_NAME_LEN);
-
-	return PM_RET_SUCCESS;
 }
 
 /**
@@ -2709,333 +2671,6 @@
 		groups[i] = grps[index + i];
 		if (groups[i] == (uint16_t)END_OF_GROUPS)
 			break;
-	}
-
-	return PM_RET_SUCCESS;
-}
-
-/**
- * pm_api_pinctrl_get_function() - Read function id set for the given pin
- * @pin		Pin number
- * @nid		Node ID of function currently set for given pin
- *
- * This function provides the function currently set for the given pin.
- *
- * @return	Returns status, either success or error+reason
- */
-enum pm_ret_status pm_api_pinctrl_get_function(unsigned int pin,
-					       unsigned int *id)
-{
-	unsigned int i = 0, j = 0;
-	enum pm_ret_status ret = PM_RET_SUCCESS;
-	unsigned int ctrlreg, val, gid;
-	uint16_t *grps;
-
-	ctrlreg = IOU_SLCR_BASEADDR + 4U * pin;
-	ret = pm_mmio_read(ctrlreg, &val);
-	if (ret != PM_RET_SUCCESS)
-		return ret;
-
-	val &= PINCTRL_FUNCTION_MASK;
-
-	for (i = 0; i < NFUNCS_PER_PIN; i++)
-		if (val == pm_pinctrl_mux[i])
-			break;
-
-	if (i == NFUNCS_PER_PIN)
-		return PM_RET_ERROR_NOTSUPPORTED;
-
-	gid = *(*zynqmp_pin_groups[pin].groups + i);
-
-	for (i = 0; i < MAX_FUNCTION; i++) {
-		grps = *pinctrl_functions[i].groups;
-		if (grps == NULL)
-			continue;
-		if (val != pinctrl_functions[i].regval)
-			continue;
-
-		for (j = 0; grps[j] != (uint16_t)END_OF_GROUPS; j++) {
-			if (gid == grps[j]) {
-				*id = i;
-				goto done;
-			}
-		}
-	}
-	if (i == MAX_FUNCTION)
-		ret = PM_RET_ERROR_ARGS;
-done:
-	return ret;
-}
-
-/**
- * pm_api_pinctrl_set_function() - Set function id set for the given pin
- * @pin		Pin number
- * @nid		Node ID of function to set for given pin
- *
- * This function provides the function currently set for the given pin.
- *
- * @return	Returns status, either success or error+reason
- */
-enum pm_ret_status pm_api_pinctrl_set_function(unsigned int pin,
-					       unsigned int fid)
-{
-	int i, j;
-	unsigned int ctrlreg, val;
-	uint16_t *pgrps, *fgrps;
-
-	ctrlreg = IOU_SLCR_BASEADDR + 4U * pin;
-	val = pinctrl_functions[fid].regval;
-
-	for (i = 0; i < NFUNCS_PER_PIN; i++)
-		if (val == pm_pinctrl_mux[i])
-			break;
-
-	if (i == NFUNCS_PER_PIN)
-		return PM_RET_ERROR_NOTSUPPORTED;
-
-	pgrps = *zynqmp_pin_groups[pin].groups;
-	if (!pgrps)
-		return PM_RET_ERROR_NOTSUPPORTED;
-
-	fgrps = *pinctrl_functions[fid].groups;
-	if (!fgrps)
-		return PM_RET_ERROR_NOTSUPPORTED;
-
-	for (i = 0; fgrps[i] != (uint16_t)END_OF_GROUPS; i++)
-		for (j = 0; pgrps[j] != (uint16_t)END_OF_GROUPS; j++)
-			if (fgrps[i] == pgrps[j])
-				goto match;
-
-	return PM_RET_ERROR_NOTSUPPORTED;
-
-match:
-	return pm_mmio_write(ctrlreg, PINCTRL_FUNCTION_MASK, val);
-}
-
-/**
- * pm_api_pinctrl_set_config() - Set configuration parameter for given pin
- * @pin: Pin for which configuration is to be set
- * @param: Configuration parameter to be set
- * @value: Value to be set for configuration parameter
- *
- * This function sets value of requested configuration parameter for given pin.
- *
- * @return	Returns status, either success or error+reason
- */
-enum pm_ret_status pm_api_pinctrl_set_config(unsigned int pin,
-					     unsigned int param,
-					     unsigned int value)
-{
-	enum pm_ret_status ret;
-	unsigned int ctrlreg, mask, val, offset;
-
-	if (param >= PINCTRL_CONFIG_MAX)
-		return PM_RET_ERROR_NOTSUPPORTED;
-
-	if (pin >=  PINCTRL_NUM_MIOS)
-		return PM_RET_ERROR_ARGS;
-
-	mask = 1 << PINCTRL_PIN_OFFSET(pin);
-
-	switch (param) {
-	case PINCTRL_CONFIG_SLEW_RATE:
-		if (value != PINCTRL_SLEW_RATE_FAST &&
-		    value != PINCTRL_SLEW_RATE_SLOW)
-			return PM_RET_ERROR_ARGS;
-
-		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
-					      PINCTRL_SLEWCTRL_REG_OFFSET,
-					      pin);
-		val = value << PINCTRL_PIN_OFFSET(pin);
-		ret = pm_mmio_write(ctrlreg, mask, val);
-		break;
-	case PINCTRL_CONFIG_BIAS_STATUS:
-		if (value != PINCTRL_BIAS_ENABLE &&
-		    value != PINCTRL_BIAS_DISABLE)
-			return PM_RET_ERROR_ARGS;
-
-		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
-					      PINCTRL_PULLSTAT_REG_OFFSET,
-					      pin);
-
-		offset = PINCTRL_PIN_OFFSET(pin);
-		if (ctrlreg == IOU_SLCR_BANK1_CTRL5)
-			offset = (offset < 12U) ?
-					(offset + 14U) : (offset - 12U);
-
-		val = value << offset;
-		mask = 1 << offset;
-		ret = pm_mmio_write(ctrlreg, mask, val);
-		break;
-	case PINCTRL_CONFIG_PULL_CTRL:
-
-		if (value != PINCTRL_BIAS_PULL_DOWN &&
-		    value != PINCTRL_BIAS_PULL_UP)
-			return PM_RET_ERROR_ARGS;
-
-		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
-					      PINCTRL_PULLSTAT_REG_OFFSET,
-					      pin);
-
-		offset = PINCTRL_PIN_OFFSET(pin);
-		if (ctrlreg == IOU_SLCR_BANK1_CTRL5)
-			offset = (offset < 12U) ?
-					(offset + 14U) : (offset - 12U);
-
-		val = PINCTRL_BIAS_ENABLE << offset;
-		ret = pm_mmio_write(ctrlreg, 1 << offset, val);
-		if (ret != PM_RET_SUCCESS)
-			return ret;
-
-		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
-					      PINCTRL_PULLCTRL_REG_OFFSET,
-					      pin);
-		val = value << PINCTRL_PIN_OFFSET(pin);
-		ret = pm_mmio_write(ctrlreg, mask, val);
-		break;
-	case PINCTRL_CONFIG_SCHMITT_CMOS:
-		if (value != PINCTRL_INPUT_TYPE_CMOS &&
-		    value != PINCTRL_INPUT_TYPE_SCHMITT)
-			return PM_RET_ERROR_ARGS;
-
-		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
-					      PINCTRL_SCHCMOS_REG_OFFSET,
-					      pin);
-
-		val = value << PINCTRL_PIN_OFFSET(pin);
-		ret = pm_mmio_write(ctrlreg, mask, val);
-		break;
-	case PINCTRL_CONFIG_DRIVE_STRENGTH:
-		if (value > PINCTRL_DRIVE_STRENGTH_12MA)
-			return PM_RET_ERROR_ARGS;
-
-		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
-					      PINCTRL_DRVSTRN0_REG_OFFSET,
-					      pin);
-		val = (value >> 1) << PINCTRL_PIN_OFFSET(pin);
-		ret = pm_mmio_write(ctrlreg, mask, val);
-		if (ret)
-			return ret;
-
-		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
-					      PINCTRL_DRVSTRN1_REG_OFFSET,
-					      pin);
-		val = (value & 0x01U) << PINCTRL_PIN_OFFSET(pin);
-		ret = pm_mmio_write(ctrlreg, mask, val);
-		break;
-	default:
-		ERROR("Invalid parameter %u\n", param);
-		ret = PM_RET_ERROR_NOTSUPPORTED;
-		break;
-	}
-
-	return ret;
-}
-
-/**
- * pm_api_pinctrl_get_config() - Get configuration parameter value for given pin
- * @pin: Pin for which configuration is to be read
- * @param: Configuration parameter to be read
- * @value: buffer to store value of configuration parameter
- *
- * This function reads value of requested configuration parameter for given pin.
- *
- * @return	Returns status, either success or error+reason
- */
-enum pm_ret_status pm_api_pinctrl_get_config(unsigned int pin,
-					     unsigned int param,
-					     unsigned int *value)
-{
-	enum pm_ret_status ret;
-	unsigned int ctrlreg, val;
-
-	if (param >= PINCTRL_CONFIG_MAX)
-		return PM_RET_ERROR_NOTSUPPORTED;
-
-	if (pin >=  PINCTRL_NUM_MIOS)
-		return PM_RET_ERROR_ARGS;
-
-	switch (param) {
-	case PINCTRL_CONFIG_SLEW_RATE:
-		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
-					      PINCTRL_SLEWCTRL_REG_OFFSET,
-					      pin);
-
-		ret = pm_mmio_read(ctrlreg, &val);
-		if (ret != PM_RET_SUCCESS)
-			return ret;
-
-		*value = PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val);
-		break;
-	case PINCTRL_CONFIG_BIAS_STATUS:
-		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
-					      PINCTRL_PULLSTAT_REG_OFFSET,
-					      pin);
-
-		ret = pm_mmio_read(ctrlreg, &val);
-		if (ret)
-			return ret;
-
-		if (ctrlreg == IOU_SLCR_BANK1_CTRL5)
-			val = ((val & 0x3FFF) << 12) | ((val >> 14) & 0xFFF);
-
-		*value = PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val);
-		break;
-	case PINCTRL_CONFIG_PULL_CTRL:
-
-		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
-					      PINCTRL_PULLCTRL_REG_OFFSET,
-					      pin);
-
-		ret = pm_mmio_read(ctrlreg, &val);
-		if (ret)
-			return ret;
-
-		*value = PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val);
-		break;
-	case PINCTRL_CONFIG_SCHMITT_CMOS:
-		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
-					      PINCTRL_SCHCMOS_REG_OFFSET,
-					      pin);
-
-		ret = pm_mmio_read(ctrlreg, &val);
-		if (ret)
-			return ret;
-
-		*value = PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val);
-		break;
-	case PINCTRL_CONFIG_DRIVE_STRENGTH:
-		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
-					      PINCTRL_DRVSTRN0_REG_OFFSET,
-					      pin);
-		ret = pm_mmio_read(ctrlreg, &val);
-		if (ret)
-			return ret;
-
-		*value = PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val) << 1;
-
-		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
-					      PINCTRL_DRVSTRN1_REG_OFFSET,
-					      pin);
-		ret = pm_mmio_read(ctrlreg, &val);
-		if (ret)
-			return ret;
-
-		*value |= PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val);
-		break;
-	case PINCTRL_CONFIG_VOLTAGE_STATUS:
-		ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR,
-					      PINCTRL_VOLTAGE_STAT_REG_OFFSET,
-					      pin);
-
-		ret = pm_mmio_read(ctrlreg, &val);
-		if (ret)
-			return ret;
-
-		*value = val & PINCTRL_VOLTAGE_STATUS_MASK;
-		break;
-	default:
-		return PM_RET_ERROR_NOTSUPPORTED;
 	}
 
 	return PM_RET_SUCCESS;
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h
index 9923c00..2b8fca3 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h
@@ -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
  */
@@ -709,18 +709,7 @@
 #define	PINCTRL_DRIVE_STRENGTH_8MA 2U
 #define	PINCTRL_DRIVE_STRENGTH_12MA 3U
 
-enum pm_ret_status pm_api_pinctrl_set_function(unsigned int pin,
-					       unsigned int fid);
-enum pm_ret_status pm_api_pinctrl_get_function(unsigned int pin,
-					       unsigned int *id);
-enum pm_ret_status pm_api_pinctrl_set_config(unsigned int pin,
-					     unsigned int param,
-					     unsigned int value);
-enum pm_ret_status pm_api_pinctrl_get_config(unsigned int pin,
-					     unsigned int param,
-					     unsigned int *value);
-enum pm_ret_status pm_api_pinctrl_get_function_name(unsigned int fid,
-						    char *name);
+void pm_api_pinctrl_get_function_name(unsigned int fid, char *name);
 enum pm_ret_status pm_api_pinctrl_get_function_groups(unsigned int fid,
 						      unsigned int index,
 						      uint16_t *groups);
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
index cd9d597..9a53408 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
@@ -65,6 +65,10 @@
 	PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4);		\
 }
 
+#define EM_PACK_PAYLOAD1(pl, arg0) {	\
+	pl[0] = (uint16_t)(0xE) << 16 | (uint16_t)arg0;	\
+}
+
 /**
  * pm_self_suspend() - PM call for processor to suspend itself
  * @nid		Node id of the processor or subsystem
@@ -655,7 +659,11 @@
  */
 enum pm_ret_status pm_pinctrl_request(unsigned int pin)
 {
-	return PM_RET_SUCCESS;
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD2(payload, PM_PINCTRL_REQUEST, pin);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
 }
 
 /**
@@ -668,37 +676,44 @@
  */
 enum pm_ret_status pm_pinctrl_release(unsigned int pin)
 {
-	return PM_RET_SUCCESS;
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD2(payload, PM_PINCTRL_RELEASE, pin);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
 }
 
 /**
  * pm_pinctrl_get_function() - Read function id set for the given pin
  * @pin		Pin number
- * @nid		Node ID of function currently set for given pin
+ * @fid		ID of function currently set for given pin
  *
  * This function provides the function currently set for the given pin.
  *
  * @return	Returns status, either success or error+reason
  */
-enum pm_ret_status pm_pinctrl_get_function(unsigned int pin,
-					   enum pm_node_id *nid)
+enum pm_ret_status pm_pinctrl_get_function(unsigned int pin, unsigned int *fid)
 {
-	return pm_api_pinctrl_get_function(pin, nid);
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	PM_PACK_PAYLOAD2(payload, PM_PINCTRL_GET_FUNCTION, pin);
+	return pm_ipi_send_sync(primary_proc, payload, fid, 1);
 }
 
 /**
  * pm_pinctrl_set_function() - Set function id set for the given pin
  * @pin		Pin number
- * @nid		Node ID of function to set for given pin
- *
- * This function provides the function currently set for the given pin.
+ * @fid		ID of function to set for given pin
  *
  * @return	Returns status, either success or error+reason
  */
-enum pm_ret_status pm_pinctrl_set_function(unsigned int pin,
-					   enum pm_node_id nid)
+enum pm_ret_status pm_pinctrl_set_function(unsigned int pin, unsigned int fid)
 {
-	return pm_api_pinctrl_set_function(pin, (unsigned int)nid);
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD3(payload, PM_PINCTRL_SET_FUNCTION, pin, fid);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
 }
 
 /**
@@ -715,24 +730,30 @@
 					 unsigned int param,
 					 unsigned int *value)
 {
-	return pm_api_pinctrl_get_config(pin, param, value);
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	PM_PACK_PAYLOAD3(payload, PM_PINCTRL_CONFIG_PARAM_GET, pin, param);
+	return pm_ipi_send_sync(primary_proc, payload, value, 1);
 }
 
 /**
- * pm_pinctrl_set_config() - Read value of requested config param for given pin
+ * pm_pinctrl_set_config() - Set value of requested config param for given pin
  * @pin		Pin number
  * @param	Parameter to set
  * @value	Parameter value to set
  *
- * This function provides the configuration parameter value for the given pin.
- *
  * @return	Returns status, either success or error+reason
  */
 enum pm_ret_status pm_pinctrl_set_config(unsigned int pin,
 					 unsigned int param,
 					 unsigned int value)
 {
-	return pm_api_pinctrl_set_config(pin, param, value);
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD4(payload, PM_PINCTRL_CONFIG_PARAM_SET, pin, param,
+			 value);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
 }
 
 /**
@@ -793,12 +814,10 @@
  *
  * This function is used by master to get nmae of clock specified
  * by given clock ID.
- *
- * @return	Returns status, either success or error+reason
  */
-static enum pm_ret_status pm_clock_get_name(unsigned int clock_id, char *name)
+static void pm_clock_get_name(unsigned int clock_id, char *name)
 {
-	return pm_api_clock_get_name(clock_id, name);
+	pm_api_clock_get_name(clock_id, name);
 }
 
 /**
@@ -1235,13 +1254,10 @@
  *
  * This function is used by master to get name of function specified
  * by given function Id
- *
- * Return: Returns status, either success or error+reason.
  */
-static enum pm_ret_status pm_pinctrl_get_function_name(unsigned int fid,
-						       char *name)
+static void pm_pinctrl_get_function_name(unsigned int fid, char *name)
 {
-	return pm_api_pinctrl_get_function_name(fid, name);
+	pm_api_pinctrl_get_function_name(fid, name);
 }
 
 /**
@@ -1301,78 +1317,58 @@
  * @data	Returned output data
  *
  * This function returns requested data.
- *
- * @return	Returns status, either success or error+reason
  */
-enum pm_ret_status pm_query_data(enum pm_query_id qid,
-				 unsigned int arg1,
-				 unsigned int arg2,
-				 unsigned int arg3,
-				 unsigned int *data)
+void pm_query_data(enum pm_query_id qid, unsigned int arg1, unsigned int arg2,
+		   unsigned int arg3, unsigned int *data)
 {
-	enum pm_ret_status ret;
-
 	switch (qid) {
 	case PM_QID_CLOCK_GET_NAME:
-		ret = pm_clock_get_name(arg1, (char *)data);
+		pm_clock_get_name(arg1, (char *)data);
 		break;
 	case PM_QID_CLOCK_GET_TOPOLOGY:
-		ret = pm_clock_get_topology(arg1, arg2, &data[1]);
-		data[0] = (unsigned int)ret;
+		data[0] = pm_clock_get_topology(arg1, arg2, &data[1]);
 		break;
 	case PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS:
-		ret = pm_clock_get_fixedfactor_params(arg1, &data[1], &data[2]);
-		data[0] = (unsigned int)ret;
+		data[0] = pm_clock_get_fixedfactor_params(arg1, &data[1],
+							  &data[2]);
 		break;
 	case PM_QID_CLOCK_GET_PARENTS:
-		ret = pm_clock_get_parents(arg1, arg2, &data[1]);
-		data[0] = (unsigned int)ret;
+		data[0] = pm_clock_get_parents(arg1, arg2, &data[1]);
 		break;
 	case PM_QID_CLOCK_GET_ATTRIBUTES:
-		ret = pm_clock_get_attributes(arg1, &data[1]);
-		data[0] = (unsigned int)ret;
+		data[0] = pm_clock_get_attributes(arg1, &data[1]);
 		break;
 	case PM_QID_PINCTRL_GET_NUM_PINS:
-		ret = pm_pinctrl_get_num_pins(&data[1]);
-		data[0] = (unsigned int)ret;
+		data[0] = pm_pinctrl_get_num_pins(&data[1]);
 		break;
 	case PM_QID_PINCTRL_GET_NUM_FUNCTIONS:
-		ret = pm_pinctrl_get_num_functions(&data[1]);
-		data[0] = (unsigned int)ret;
+		data[0] = pm_pinctrl_get_num_functions(&data[1]);
 		break;
 	case PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS:
-		ret = pm_pinctrl_get_num_function_groups(arg1, &data[1]);
-		data[0] = (unsigned int)ret;
+		data[0] = pm_pinctrl_get_num_function_groups(arg1, &data[1]);
 		break;
 	case PM_QID_PINCTRL_GET_FUNCTION_NAME:
-		ret = pm_pinctrl_get_function_name(arg1, (char *)data);
+		pm_pinctrl_get_function_name(arg1, (char *)data);
 		break;
 	case PM_QID_PINCTRL_GET_FUNCTION_GROUPS:
-		ret = pm_pinctrl_get_function_groups(arg1, arg2,
-						     (uint16_t *)&data[1]);
-		data[0] = (unsigned int)ret;
+		data[0] = pm_pinctrl_get_function_groups(arg1, arg2,
+							 (uint16_t *)&data[1]);
 		break;
 	case PM_QID_PINCTRL_GET_PIN_GROUPS:
-		ret = pm_pinctrl_get_pin_groups(arg1, arg2,
-						(uint16_t *)&data[1]);
-		data[0] = (unsigned int)ret;
+		data[0] = pm_pinctrl_get_pin_groups(arg1, arg2,
+						    (uint16_t *)&data[1]);
 		break;
 	case PM_QID_CLOCK_GET_NUM_CLOCKS:
-		ret = pm_clock_get_num_clocks(&data[1]);
-		data[0] = (unsigned int)ret;
+		data[0] = pm_clock_get_num_clocks(&data[1]);
 		break;
 
 	case PM_QID_CLOCK_GET_MAX_DIVISOR:
-		ret = pm_clock_get_max_divisor(arg1, arg2, &data[1]);
-		data[0] = (unsigned int)ret;
+		data[0] = pm_clock_get_max_divisor(arg1, arg2, &data[1]);
 		break;
 	default:
-		ret = PM_RET_ERROR_ARGS;
+		data[0] = PM_RET_ERROR_ARGS;
 		WARN("Unimplemented query service call: 0x%x\n", qid);
-		break;
 	}
-
-	return ret;
 }
 
 enum pm_ret_status pm_sha_hash(uint32_t address_high,
@@ -1554,3 +1550,101 @@
 	PM_PACK_PAYLOAD2(payload, PM_PLL_GET_MODE, nid);
 	return pm_ipi_send_sync(primary_proc, payload, mode, 1);
 }
+
+/**
+ * pm_register_access() -  PM API for register read/write access data
+ *
+ * @register_access_id	Register_access_id which says register read/write
+ *
+ * @address		Address of the register to be accessed
+ *
+ * @mask		Mask value to be used while writing value
+ *
+ * @value		Value to be written to register
+ *
+ * @out			Returned output data
+ *
+ * This function returns requested data.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_register_access(unsigned int register_access_id,
+				      unsigned int address,
+				      unsigned int mask,
+				      unsigned int value,
+				      unsigned int *out)
+{
+	enum pm_ret_status ret;
+
+	if (((ZYNQMP_CSU_BASEADDR & address) != ZYNQMP_CSU_BASEADDR) &&
+			((CSUDMA_BASE & address) != CSUDMA_BASE) &&
+			((RSA_CORE_BASE & address) != RSA_CORE_BASE) &&
+			((PMU_GLOBAL_BASE & address) != PMU_GLOBAL_BASE))
+		return PM_RET_ERROR_ACCESS;
+
+	switch (register_access_id) {
+	case CONFIG_REG_WRITE:
+		ret = pm_mmio_write(address, mask, value);
+		break;
+	case CONFIG_REG_READ:
+		ret = pm_mmio_read(address, out);
+		break;
+	default:
+		ret = PM_RET_ERROR_ARGS;
+		WARN("Unimplemented register_access call\n\r");
+	}
+	return ret;
+}
+
+/**
+ * pm_efuse_access() - To program or read efuse bits.
+ *
+ * This function provides access to the xilskey library to program/read
+ * efuse bits.
+ *
+ * address_low: lower 32-bit Linear memory space address
+ * address_high: higher 32-bit Linear memory space address
+ *
+ * value: Returned output value
+ *
+ * @return  Returns status, either success or error+reason
+ *
+ */
+enum pm_ret_status pm_efuse_access(uint32_t address_high,
+				   uint32_t address_low,
+				   uint32_t *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD3(payload, PM_EFUSE_ACCESS, address_high, address_low);
+
+	return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+enum pm_ret_status em_set_action(unsigned int *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	EM_PACK_PAYLOAD1(payload, EM_SET_ACTION);
+	return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+enum pm_ret_status em_remove_action(unsigned int *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	EM_PACK_PAYLOAD1(payload, EM_REMOVE_ACTION);
+	return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+enum pm_ret_status em_send_errors(unsigned int *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	EM_PACK_PAYLOAD1(payload, EM_SEND_ERRORS);
+	return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
index ff66d3f..b0c2652 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
@@ -28,6 +28,11 @@
 	PM_QID_CLOCK_GET_MAX_DIVISOR,
 };
 
+enum pm_register_access_id {
+	CONFIG_REG_WRITE,
+	CONFIG_REG_READ,
+};
+
 /**********************************************************
  * System-level API function declarations
  **********************************************************/
@@ -151,11 +156,8 @@
 				      unsigned int parent_id);
 enum pm_ret_status pm_clock_getparent(unsigned int clock_id,
 				      unsigned int *parent_id);
-enum pm_ret_status pm_query_data(enum pm_query_id qid,
-				 unsigned int arg1,
-				 unsigned int arg2,
-				 unsigned int arg3,
-				 unsigned int *data);
+void pm_query_data(enum pm_query_id qid, unsigned int arg1, unsigned int arg2,
+		   unsigned int arg3, unsigned int *data);
 enum pm_ret_status pm_sha_hash(uint32_t address_high,
 				    uint32_t address_low,
 				    uint32_t size,
@@ -178,6 +180,11 @@
 enum pm_ret_status pm_aes_engine(uint32_t address_high,
 				 uint32_t address_low,
 				 uint32_t  *value);
+enum pm_ret_status pm_register_access(unsigned int register_access_id,
+				      unsigned int address,
+				      unsigned int mask,
+				      unsigned int value,
+				      unsigned int *out);
 
 enum pm_ret_status pm_pll_set_parameter(enum pm_node_id nid,
 				enum pm_pll_param param_id,
@@ -189,5 +196,10 @@
 
 enum pm_ret_status pm_pll_set_mode(enum pm_node_id nid, enum pm_pll_mode mode);
 enum pm_ret_status pm_pll_get_mode(enum pm_node_id nid, enum pm_pll_mode *mode);
+enum pm_ret_status pm_efuse_access(uint32_t address_high,
+				   uint32_t address_low, uint32_t *value);
+enum pm_ret_status em_set_action(unsigned int *value);
+enum pm_ret_status em_remove_action(unsigned int *value);
+enum pm_ret_status em_send_errors(unsigned int *value);
 
 #endif /* PM_API_SYS_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_defs.h b/plat/xilinx/zynqmp/pm_service/pm_defs.h
index 4776d42..ee31c92 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_defs.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_defs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -33,6 +33,7 @@
 #define PM_STATE_CPU_IDLE		0x0U
 #define PM_STATE_SUSPEND_TO_RAM		0xFU
 
+#define EM_FUNID_NUM_MASK    0xF0000U
 /*********************************************************************
  * Enum definitions
  ********************************************************************/
@@ -97,6 +98,9 @@
 	PM_PLL_GET_PARAMETER,
 	PM_PLL_SET_MODE,
 	PM_PLL_GET_MODE,
+	/* PM Register Access API */
+	PM_REGISTER_ACCESS,
+	PM_EFUSE_ACCESS,
 	PM_API_MAX
 };
 
@@ -320,4 +324,13 @@
 	PM_CLOCK_DIV1_ID,
 };
 
+/**
+ * EM API IDs
+ */
+enum em_api_id {
+	EM_SET_ACTION = 1,
+	EM_REMOVE_ACTION,
+	EM_SEND_ERRORS,
+};
+
 #endif /* PM_DEFS_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
index 3f4f069..a4bc1ac 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
@@ -474,8 +474,8 @@
 	{
 		uint32_t data[4] = { 0 };
 
-		ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2],
-				    pm_arg[3], data);
+		pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2],
+			      pm_arg[3], data);
 		SMC_RET2(handle, (uint64_t)data[0]  | ((uint64_t)data[1] << 32),
 			 (uint64_t)data[2] | ((uint64_t)data[3] << 32));
 	}
@@ -606,8 +606,78 @@
 		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)mode << 32));
 	}
 
+	case PM_REGISTER_ACCESS:
+	{
+		uint32_t value;
+
+		ret = pm_register_access(pm_arg[0], pm_arg[1], pm_arg[2],
+					 pm_arg[3], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_EFUSE_ACCESS:
+	{
+		uint32_t value;
+
+		ret = pm_efuse_access(pm_arg[0], pm_arg[1], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
 	default:
 		WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
 		SMC_RET1(handle, SMC_UNK);
 	}
 }
+
+/**
+ * em_smc_handler() - SMC handler for EM-API calls coming from EL1/EL2.
+ * @smc_fid - Function Identifier
+ * @x1 - x4 - Arguments
+ * @cookie  - Unused
+ * @handler - Pointer to caller's context structure
+ *
+ * @return  - Unused
+ *
+ * Determines that smc_fid is valid and supported EM SMC Function ID from the
+ * list of em_api_ids, otherwise completes the request with
+ * the unknown SMC Function ID
+ *
+ * The SMC calls for EM service are forwarded from SIP Service SMC handler
+ * function with rt_svc_handle signature
+ */
+uint64_t em_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+			uint64_t x4, void *cookie, void *handle, uint64_t flags)
+{
+	enum pm_ret_status ret;
+
+	switch (smc_fid & FUNCID_NUM_MASK) {
+	/* EM API Functions */
+	case EM_SET_ACTION:
+	{
+		uint32_t value;
+
+		ret = em_set_action(&value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case EM_REMOVE_ACTION:
+	{
+		uint32_t value;
+
+		ret = em_remove_action(&value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case EM_SEND_ERRORS:
+	{
+		uint32_t value;
+
+		ret = em_send_errors(&value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	default:
+		WARN("Unimplemented EM Service Call: 0x%x\n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.h b/plat/xilinx/zynqmp/pm_service/pm_svc_main.h
index 0968f64..abadd40 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.h
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,4 +14,7 @@
 			uint64_t x4, void *cookie, void *handle,
 			uint64_t flags);
 
+uint64_t em_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+			uint64_t x4, void *cookie, void *handle,
+			uint64_t flags);
 #endif /* PM_SVC_MAIN_H */
diff --git a/plat/xilinx/zynqmp/sip_svc_setup.c b/plat/xilinx/zynqmp/sip_svc_setup.c
index 9b18274..4c29da2 100644
--- a/plat/xilinx/zynqmp/sip_svc_setup.c
+++ b/plat/xilinx/zynqmp/sip_svc_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2018, 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,9 @@
 #define PM_FID_MASK	0xf000u
 #define PM_FID_VALUE	0u
 #define IPI_FID_VALUE	0x1000u
+#define EM_FID_MASK     0xf0000u
+#define EM_FID_VALUE    0xE0000u
+#define is_em_fid(_fid) (((_fid) & EM_FID_MASK) == EM_FID_VALUE)
 #define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE)
 #define is_ipi_fid(_fid) (((_fid) & PM_FID_MASK) == IPI_FID_VALUE)
 
@@ -61,8 +64,12 @@
 			      void *handle,
 			      u_register_t flags)
 {
+	/* Let EM SMC handler deal with EM-related requests */
+	if (is_em_fid(smc_fid)) {
+		return em_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+					flags);
+	} else if (is_pm_fid(smc_fid)) {
 	/* Let PM SMC handler deal with PM-related requests */
-	if (is_pm_fid(smc_fid)) {
 		return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
 				      flags);
 	}