Merge "fix(stm32mp1_clk): fix MCU/AXI parent clock" into integration
diff --git a/Makefile b/Makefile
index 59d14ba..ec6f885 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -129,6 +129,23 @@
         $(error Unknown BRANCH_PROTECTION value ${BRANCH_PROTECTION})
 endif
 
+# FEAT_RME
+ifeq (${ENABLE_RME},1)
+# RME doesn't support PIE
+ifneq (${ENABLE_PIE},0)
+        $(error ENABLE_RME does not support PIE)
+endif
+# RME requires AARCH64
+ifneq (${ARCH},aarch64)
+        $(error ENABLE_RME requires AArch64)
+endif
+# RME requires el2 context to be saved for now.
+CTX_INCLUDE_EL2_REGS := 1
+CTX_INCLUDE_AARCH32_REGS := 0
+ARM_ARCH_MAJOR := 8
+ARM_ARCH_MINOR := 6
+endif
+
 # USE_SPINLOCK_CAS requires AArch64 build
 ifeq (${USE_SPINLOCK_CAS},1)
 ifneq (${ARCH},aarch64)
@@ -559,6 +576,18 @@
 endif
 
 ################################################################################
+# Include rmmd Makefile if RME is enabled
+################################################################################
+
+ifneq (${ENABLE_RME},0)
+ifneq (${ARCH},aarch64)
+	$(error ENABLE_RME requires AArch64)
+endif
+include services/std_svc/rmmd/rmmd.mk
+$(warning "RME is an experimental feature")
+endif
+
+################################################################################
 # Include the platform specific Makefile after the SPD Makefile (the platform
 # makefile may use all previous definitions in this file)
 ################################################################################
@@ -776,10 +805,16 @@
 # Process platform overrideable behaviour
 ################################################################################
 
+ifdef BL1_SOURCES
+NEED_BL1 := yes
+endif
+
-# Using BL2 implies that a BL33 image also needs to be supplied for the FIP and
-# Certificate generation tools. This flag can be overridden by the platform.
 ifdef BL2_SOURCES
-        ifdef EL3_PAYLOAD_BASE
+	NEED_BL2 := yes
+
+	# Using BL2 implies that a BL33 image also needs to be supplied for the FIP and
+	# Certificate generation tools. This flag can be overridden by the platform.
+	ifdef EL3_PAYLOAD_BASE
                 # If booting an EL3 payload there is no need for a BL33 image
                 # in the FIP file.
                 NEED_BL33		:=	no
@@ -794,6 +829,10 @@
         endif
 endif
 
+ifdef BL2U_SOURCES
+NEED_BL2U := yes
+endif
+
 # If SCP_BL2 is given, we always want FIP to include it.
 ifdef SCP_BL2
         NEED_SCP_BL2		:=	yes
@@ -831,6 +870,10 @@
 FIP_ARGS += --align ${FIP_ALIGN}
 endif
 
+ifdef FDT_SOURCES
+NEED_FDT := yes
+endif
+
 ################################################################################
 # Include libraries' Makefile that are used in all BL
 ################################################################################
@@ -874,30 +917,22 @@
 ################################################################################
 # Include BL specific makefiles
 ################################################################################
-ifdef BL1_SOURCES
-NEED_BL1 := yes
+
+ifeq (${NEED_BL1},yes)
 include bl1/bl1.mk
 endif
 
-ifdef BL2_SOURCES
-NEED_BL2 := yes
+ifeq (${NEED_BL2},yes)
 include bl2/bl2.mk
 endif
 
-ifdef BL2U_SOURCES
-NEED_BL2U := yes
+ifeq (${NEED_BL2U},yes)
 include bl2u/bl2u.mk
 endif
 
 ifeq (${NEED_BL31},yes)
-ifdef BL31_SOURCES
 include bl31/bl31.mk
 endif
-endif
-
-ifdef FDT_SOURCES
-NEED_FDT := yes
-endif
 
 ################################################################################
 # Build options checks
@@ -926,6 +961,7 @@
         ENABLE_PIE \
         ENABLE_PMF \
         ENABLE_PSCI_STAT \
+        ENABLE_RME \
         ENABLE_RUNTIME_INSTRUMENTATION \
         ENABLE_SPE_FOR_LOWER_ELS \
         ENABLE_SVE_FOR_NS \
@@ -1028,6 +1064,7 @@
         ENABLE_PIE \
         ENABLE_PMF \
         ENABLE_PSCI_STAT \
+        ENABLE_RME \
         ENABLE_RUNTIME_INSTRUMENTATION \
         ENABLE_SPE_FOR_LOWER_ELS \
         ENABLE_SVE_FOR_NS \
@@ -1148,7 +1185,7 @@
 
 # Expand build macros for the different images
 ifeq (${NEED_BL1},yes)
-$(eval $(call MAKE_BL,1))
+$(eval $(call MAKE_BL,bl1))
 endif
 
 ifeq (${NEED_BL2},yes)
@@ -1157,7 +1194,7 @@
 endif
 
 $(if ${BL2}, $(eval $(call TOOL_ADD_IMG,bl2,--${FIP_BL2_ARGS})),\
-	$(eval $(call MAKE_BL,2,${FIP_BL2_ARGS})))
+	$(eval $(call MAKE_BL,bl2,${FIP_BL2_ARGS})))
 endif
 
 ifeq (${NEED_SCP_BL2},yes)
@@ -1170,10 +1207,10 @@
 BL31_SOURCES := $(sort ${BL31_SOURCES})
 ifneq (${DECRYPTION_SUPPORT},none)
 $(if ${BL31}, $(eval $(call TOOL_ADD_IMG,bl31,--soc-fw,,$(ENCRYPT_BL31))),\
-	$(eval $(call MAKE_BL,31,soc-fw,,$(ENCRYPT_BL31))))
+	$(eval $(call MAKE_BL,bl31,soc-fw,,$(ENCRYPT_BL31))))
 else
 $(if ${BL31}, $(eval $(call TOOL_ADD_IMG,bl31,--soc-fw)),\
-	$(eval $(call MAKE_BL,31,soc-fw)))
+	$(eval $(call MAKE_BL,bl31,soc-fw)))
 endif
 endif
 
@@ -1186,14 +1223,25 @@
 BUILD_BL32 := $(if $(BL32),,$(if $(BL32_SOURCES),1))
 
 ifneq (${DECRYPTION_SUPPORT},none)
-$(if ${BUILD_BL32}, $(eval $(call MAKE_BL,32,tos-fw,,$(ENCRYPT_BL32))),\
+$(if ${BUILD_BL32}, $(eval $(call MAKE_BL,bl32,tos-fw,,$(ENCRYPT_BL32))),\
 	$(eval $(call TOOL_ADD_IMG,bl32,--tos-fw,,$(ENCRYPT_BL32))))
 else
-$(if ${BUILD_BL32}, $(eval $(call MAKE_BL,32,tos-fw)),\
+$(if ${BUILD_BL32}, $(eval $(call MAKE_BL,bl32,tos-fw)),\
 	$(eval $(call TOOL_ADD_IMG,bl32,--tos-fw)))
 endif
 endif
 
+# If RMM image is needed but RMM is not defined, Test Realm Payload (TRP)
+# needs to be built from RMM_SOURCES.
+ifeq (${NEED_RMM},yes)
+# Sort RMM source files to remove duplicates
+RMM_SOURCES := $(sort ${RMM_SOURCES})
+BUILD_RMM := $(if $(RMM),,$(if $(RMM_SOURCES),1))
+
+$(if ${BUILD_RMM}, $(eval $(call MAKE_BL,rmm,rmm-fw)),\
+         $(eval $(call TOOL_ADD_IMG,rmm,--rmm-fw)))
+endif
+
 # Add the BL33 image if required by the platform
 ifeq (${NEED_BL33},yes)
 $(eval $(call TOOL_ADD_IMG,bl33,--nt-fw))
@@ -1201,7 +1249,7 @@
 
 ifeq (${NEED_BL2U},yes)
 $(if ${BL2U}, $(eval $(call TOOL_ADD_IMG,bl2u,--ap-fwu-cfg,FWU_)),\
-	$(eval $(call MAKE_BL,2u,ap-fwu-cfg,FWU_)))
+	$(eval $(call MAKE_BL,bl2u,ap-fwu-cfg,FWU_)))
 endif
 
 # Expand build macros for the different images
diff --git a/bl1/aarch64/bl1_context_mgmt.c b/bl1/aarch64/bl1_context_mgmt.c
index 2a8d58e..b9a7e5b 100644
--- a/bl1/aarch64/bl1_context_mgmt.c
+++ b/bl1/aarch64/bl1_context_mgmt.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -16,6 +16,7 @@
 
 /* Following contains the cpu context pointers. */
 static void *bl1_cpu_context_ptr[2];
+entry_point_info_t *bl2_ep_info;
 
 
 void *cm_get_context(uint32_t security_state)
@@ -30,6 +31,40 @@
 	bl1_cpu_context_ptr[security_state] = context;
 }
 
+#if ENABLE_RME
+/*******************************************************************************
+ * This function prepares the entry point information to run BL2 in Root world,
+ * i.e. EL3, for the case when FEAT_RME is enabled.
+ ******************************************************************************/
+void bl1_prepare_next_image(unsigned int image_id)
+{
+	image_desc_t *bl2_desc;
+
+	assert(image_id == BL2_IMAGE_ID);
+
+	/* Get the image descriptor. */
+	bl2_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
+	assert(bl2_desc != NULL);
+
+	/* Get the entry point info. */
+	bl2_ep_info = &bl2_desc->ep_info;
+
+	bl2_ep_info->spsr = (uint32_t)SPSR_64(MODE_EL3, MODE_SP_ELX,
+						DISABLE_ALL_EXCEPTIONS);
+
+	/*
+	 * Flush cache since bl2_ep_info is accessed after MMU is disabled
+	 * before jumping to BL2.
+	 */
+	flush_dcache_range((uintptr_t)bl2_ep_info, sizeof(entry_point_info_t));
+
+	/* Indicate that image is in execution state. */
+	bl2_desc->state = IMAGE_STATE_EXECUTED;
+
+	/* Print debug info and flush the console before running BL2. */
+	print_entry_point_info(bl2_ep_info);
+}
+#else
 /*******************************************************************************
  * This function prepares the context for Secure/Normal world images.
  * Normal world images are transitioned to EL2(if supported) else EL1.
@@ -93,3 +128,4 @@
 
 	print_entry_point_info(next_bl_ep);
 }
+#endif /* ENABLE_RME */
diff --git a/bl1/aarch64/bl1_entrypoint.S b/bl1/aarch64/bl1_entrypoint.S
index 00f2718..f61c060 100644
--- a/bl1/aarch64/bl1_entrypoint.S
+++ b/bl1/aarch64/bl1_entrypoint.S
@@ -1,13 +1,15 @@
 /*
- * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <arch.h>
+#include <common/bl_common.h>
 #include <el3_common_macros.S>
 
 	.globl	bl1_entrypoint
+	.globl	bl1_run_bl2_in_root
 
 
 	/* -----------------------------------------------------
@@ -66,5 +68,41 @@
 	 * Do the transition to next boot image.
 	 * --------------------------------------------------
 	 */
+#if ENABLE_RME
+	b	bl1_run_bl2_in_root
+#else
 	b	el3_exit
+#endif
 endfunc bl1_entrypoint
+
+	/* -----------------------------------------------------
+	 * void bl1_run_bl2_in_root();
+	 * This function runs BL2 in root/EL3 when RME is enabled.
+	 * -----------------------------------------------------
+	 */
+
+func bl1_run_bl2_in_root
+	/* read bl2_ep_info */
+	adrp	x20, bl2_ep_info
+	add	x20, x20, :lo12:bl2_ep_info
+	ldr	x20, [x20]
+
+	/* ---------------------------------------------
+	 * MMU needs to be disabled because BL2 executes
+	 * in EL3. It will initialize the address space
+	 * according to its own requirements.
+	 * ---------------------------------------------
+	 */
+	bl	disable_mmu_icache_el3
+	tlbi	alle3
+
+	ldp	x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET]
+	msr	elr_el3, x0
+	msr	spsr_el3, x1
+
+	ldp	x6, x7, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x30)]
+	ldp	x4, x5, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x20)]
+	ldp	x2, x3, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x10)]
+	ldp	x0, x1, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x0)]
+	exception_return
+endfunc bl1_run_bl2_in_root
diff --git a/bl1/bl1.mk b/bl1/bl1.mk
index 8f44151..9f63fd5 100644
--- a/bl1/bl1.mk
+++ b/bl1/bl1.mk
@@ -4,14 +4,12 @@
 # SPDX-License-Identifier: BSD-3-Clause
 #
 
-ifneq (${PLAT},fvp_r)
 BL1_SOURCES		+=	bl1/${ARCH}/bl1_arch_setup.c		\
 				bl1/${ARCH}/bl1_context_mgmt.c		\
 				bl1/${ARCH}/bl1_entrypoint.S		\
 				bl1/${ARCH}/bl1_exceptions.S		\
-				bl1/bl1_main.c
-endif
-BL1_SOURCES		+=	lib/cpus/${ARCH}/cpu_helpers.S		\
+				bl1/bl1_main.c				\
+				lib/cpus/${ARCH}/cpu_helpers.S		\
 				lib/cpus/errata_report.c		\
 				lib/el3_runtime/${ARCH}/context_mgmt.c	\
 				plat/common/plat_bl1_common.c		\
diff --git a/bl1/bl1_main.c b/bl1/bl1_main.c
index fd60232..663ec64 100644
--- a/bl1/bl1_main.c
+++ b/bl1/bl1_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -126,6 +126,9 @@
 	auth_mod_init();
 #endif /* TRUSTED_BOARD_BOOT */
 
+	/* Initialize the measured boot */
+	bl1_plat_mboot_init();
+
 	/* Perform platform setup in BL1. */
 	bl1_platform_setup();
 
@@ -147,6 +150,9 @@
 	else
 		NOTICE("BL1-FWU: *******FWU Process Started*******\n");
 
+	/* Teardown the measured boot driver */
+	bl1_plat_mboot_finish();
+
 	bl1_prepare_next_image(image_id);
 
 	console_flush();
diff --git a/bl1/bl1_private.h b/bl1/bl1_private.h
index 2cfeeea..e119ba7 100644
--- a/bl1/bl1_private.h
+++ b/bl1/bl1_private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,6 +11,8 @@
 
 #include <common/bl_common.h>
 
+extern entry_point_info_t *bl2_ep_info;
+
 /******************************************
  * Function prototypes
  *****************************************/
@@ -18,6 +20,7 @@
 void bl1_arch_next_el_setup(void);
 
 void bl1_prepare_next_image(unsigned int image_id);
+void bl1_run_bl2_in_root(void);
 
 u_register_t bl1_fwu_smc_handler(unsigned int smc_fid,
 		u_register_t x1,
diff --git a/bl2/aarch32/bl2_el3_entrypoint.S b/bl2/aarch32/bl2_el3_entrypoint.S
index 7e85551..40154aa 100644
--- a/bl2/aarch32/bl2_el3_entrypoint.S
+++ b/bl2/aarch32/bl2_el3_entrypoint.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,7 +10,6 @@
 #include <el3_common_macros.S>
 
 	.globl	bl2_entrypoint
-	.globl	bl2_run_next_image
 
 
 func bl2_entrypoint
@@ -56,37 +55,3 @@
 	no_ret	plat_panic_handler
 
 endfunc bl2_entrypoint
-
-func bl2_run_next_image
-	mov	r8,r0
-
-	/*
-	 * MMU needs to be disabled because both BL2 and BL32 execute
-	 * in PL1, and therefore share the same address space.
-	 * BL32 will initialize the address space according to its
-	 * own requirement.
-	 */
-	bl	disable_mmu_icache_secure
-	stcopr	r0, TLBIALL
-	dsb	sy
-	isb
-	mov	r0, r8
-	bl	bl2_el3_plat_prepare_exit
-
-	/*
-	 * Extract PC and SPSR based on struct `entry_point_info_t`
-	 * and load it in LR and SPSR registers respectively.
-	 */
-	ldr	lr, [r8, #ENTRY_POINT_INFO_PC_OFFSET]
-	ldr	r1, [r8, #(ENTRY_POINT_INFO_PC_OFFSET + 4)]
-	msr	spsr_xc, r1
-
-	/* Some BL32 stages expect lr_svc to provide the BL33 entry address */
-	cps	#MODE32_svc
-	ldr	lr, [r8, #ENTRY_POINT_INFO_LR_SVC_OFFSET]
-	cps	#MODE32_mon
-
-	add	r8, r8, #ENTRY_POINT_INFO_ARGS_OFFSET
-	ldm	r8, {r0, r1, r2, r3}
-	exception_return
-endfunc bl2_run_next_image
diff --git a/bl2/aarch32/bl2_run_next_image.S b/bl2/aarch32/bl2_run_next_image.S
new file mode 100644
index 0000000..0b3554e
--- /dev/null
+++ b/bl2/aarch32/bl2_run_next_image.S
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+	.globl	bl2_run_next_image
+
+
+func bl2_run_next_image
+	mov	r8,r0
+
+	/*
+	 * MMU needs to be disabled because both BL2 and BL32 execute
+	 * in PL1, and therefore share the same address space.
+	 * BL32 will initialize the address space according to its
+	 * own requirement.
+	 */
+	bl	disable_mmu_icache_secure
+	stcopr	r0, TLBIALL
+	dsb	sy
+	isb
+	mov	r0, r8
+	bl	bl2_el3_plat_prepare_exit
+
+	/*
+	 * Extract PC and SPSR based on struct `entry_point_info_t`
+	 * and load it in LR and SPSR registers respectively.
+	 */
+	ldr	lr, [r8, #ENTRY_POINT_INFO_PC_OFFSET]
+	ldr	r1, [r8, #(ENTRY_POINT_INFO_PC_OFFSET + 4)]
+	msr	spsr_xc, r1
+
+	/* Some BL32 stages expect lr_svc to provide the BL33 entry address */
+	cps	#MODE32_svc
+	ldr	lr, [r8, #ENTRY_POINT_INFO_LR_SVC_OFFSET]
+	cps	#MODE32_mon
+
+	add	r8, r8, #ENTRY_POINT_INFO_ARGS_OFFSET
+	ldm	r8, {r0, r1, r2, r3}
+	exception_return
+endfunc bl2_run_next_image
diff --git a/bl2/aarch64/bl2_el3_entrypoint.S b/bl2/aarch64/bl2_el3_entrypoint.S
index 4eab39c..45bac7d 100644
--- a/bl2/aarch64/bl2_el3_entrypoint.S
+++ b/bl2/aarch64/bl2_el3_entrypoint.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -12,8 +12,6 @@
 #include <el3_common_macros.S>
 
 	.globl	bl2_entrypoint
-	.globl	bl2_el3_run_image
-	.globl	bl2_run_next_image
 
 #if BL2_IN_XIP_MEM
 #define FIXUP_SIZE	0
@@ -72,36 +70,3 @@
 	 */
 	no_ret	plat_panic_handler
 endfunc bl2_entrypoint
-
-func bl2_run_next_image
-	mov	x20,x0
-	/* ---------------------------------------------
-	 * MMU needs to be disabled because both BL2 and BL31 execute
-	 * in EL3, and therefore share the same address space.
-	 * BL31 will initialize the address space according to its
-	 * own requirement.
-	 * ---------------------------------------------
-	 */
-	bl	disable_mmu_icache_el3
-	tlbi	alle3
-	bl	bl2_el3_plat_prepare_exit
-
-#if ENABLE_PAUTH
-	/* ---------------------------------------------
-	 * Disable pointer authentication before jumping
-	 * to next boot image.
-	 * ---------------------------------------------
-	 */
-	bl	pauth_disable_el3
-#endif /* ENABLE_PAUTH */
-
-	ldp	x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET]
-	msr	elr_el3, x0
-	msr	spsr_el3, x1
-
-	ldp	x6, x7, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x30)]
-	ldp	x4, x5, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x20)]
-	ldp	x2, x3, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x10)]
-	ldp	x0, x1, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x0)]
-	exception_return
-endfunc bl2_run_next_image
diff --git a/bl2/aarch64/bl2_rme_entrypoint.S b/bl2/aarch64/bl2_rme_entrypoint.S
new file mode 100644
index 0000000..076e326
--- /dev/null
+++ b/bl2/aarch64/bl2_rme_entrypoint.S
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+#include <el3_common_macros.S>
+
+	.globl	bl2_entrypoint
+
+
+func bl2_entrypoint
+	/* Save arguments x0-x3 from previous Boot loader */
+	mov	x20, x0
+	mov	x21, x1
+	mov	x22, x2
+	mov	x23, x3
+
+	el3_entrypoint_common                                   \
+		_init_sctlr=0                                   \
+		_warm_boot_mailbox=0                            \
+		_secondary_cold_boot=0                          \
+		_init_memory=0                                  \
+		_init_c_runtime=1                               \
+		_exception_vectors=bl2_el3_exceptions           \
+		_pie_fixup_size=0
+
+	/* ---------------------------------------------
+	 * Restore parameters of boot rom
+	 * ---------------------------------------------
+	 */
+	mov	x0, x20
+	mov	x1, x21
+	mov	x2, x22
+	mov	x3, x23
+
+	/* ---------------------------------------------
+	 * Perform BL2 setup
+	 * ---------------------------------------------
+	 */
+	bl	bl2_setup
+
+#if ENABLE_PAUTH
+	/* ---------------------------------------------
+	 * Program APIAKey_EL1 and enable pointer authentication.
+	 * ---------------------------------------------
+	 */
+	bl	pauth_init_enable_el3
+#endif /* ENABLE_PAUTH */
+
+	/* ---------------------------------------------
+	 * Jump to main function.
+	 * ---------------------------------------------
+	 */
+	bl	bl2_main
+
+	/* ---------------------------------------------
+	 * Should never reach this point.
+	 * ---------------------------------------------
+	 */
+	no_ret	plat_panic_handler
+endfunc bl2_entrypoint
diff --git a/bl2/aarch64/bl2_run_next_image.S b/bl2/aarch64/bl2_run_next_image.S
new file mode 100644
index 0000000..f0a8be8
--- /dev/null
+++ b/bl2/aarch64/bl2_run_next_image.S
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <common/bl_common.h>
+
+	.globl	bl2_run_next_image
+
+
+func bl2_run_next_image
+	mov	x20,x0
+	/* ---------------------------------------------
+	 * MMU needs to be disabled because both BL2 and BL31 execute
+	 * in EL3, and therefore share the same address space.
+	 * BL31 will initialize the address space according to its
+	 * own requirement.
+	 * ---------------------------------------------
+	 */
+	bl	disable_mmu_icache_el3
+	tlbi	alle3
+	bl	bl2_el3_plat_prepare_exit
+
+#if ENABLE_PAUTH
+	/* ---------------------------------------------
+	 * Disable pointer authentication before jumping
+	 * to next boot image.
+	 * ---------------------------------------------
+	 */
+	bl	pauth_disable_el3
+#endif /* ENABLE_PAUTH */
+
+	ldp	x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET]
+	msr	elr_el3, x0
+	msr	spsr_el3, x1
+
+	ldp	x6, x7, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x30)]
+	ldp	x4, x5, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x20)]
+	ldp	x2, x3, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x10)]
+	ldp	x0, x1, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x0)]
+	exception_return
+endfunc bl2_run_next_image
diff --git a/bl2/bl2.ld.S b/bl2/bl2.ld.S
index 37849c3..d332ec0 100644
--- a/bl2/bl2.ld.S
+++ b/bl2/bl2.ld.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -25,7 +25,11 @@
 #if SEPARATE_CODE_AND_RODATA
     .text . : {
         __TEXT_START__ = .;
+#if ENABLE_RME
+        *bl2_rme_entrypoint.o(.text*)
+#else /* ENABLE_RME */
         *bl2_entrypoint.o(.text*)
+#endif /* ENABLE_RME */
         *(SORT_BY_ALIGNMENT(.text*))
         *(.vectors)
         . = ALIGN(PAGE_SIZE);
diff --git a/bl2/bl2.mk b/bl2/bl2.mk
index 735e7e0..7a973e5 100644
--- a/bl2/bl2.mk
+++ b/bl2/bl2.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -15,13 +15,26 @@
 BL2_SOURCES		+=	common/aarch64/early_exceptions.S
 endif
 
-ifeq (${BL2_AT_EL3},0)
+ifeq (${ENABLE_RME},1)
+# Using RME, run BL2 at EL3
+include lib/gpt_rme/gpt_rme.mk
+
+BL2_SOURCES		+=      bl2/${ARCH}/bl2_rme_entrypoint.S	\
+				bl2/${ARCH}/bl2_el3_exceptions.S	\
+				bl2/${ARCH}/bl2_run_next_image.S	\
+				${GPT_LIB_SRCS}
+BL2_LINKERFILE		:=	bl2/bl2.ld.S
+
+else ifeq (${BL2_AT_EL3},0)
+# Normal operation, no RME, no BL2 at EL3
 BL2_SOURCES		+=	bl2/${ARCH}/bl2_entrypoint.S
 BL2_LINKERFILE		:=	bl2/bl2.ld.S
 
 else
+# BL2 at EL3, no RME
 BL2_SOURCES		+=	bl2/${ARCH}/bl2_el3_entrypoint.S	\
 				bl2/${ARCH}/bl2_el3_exceptions.S	\
+				bl2/${ARCH}/bl2_run_next_image.S        \
 				lib/cpus/${ARCH}/cpu_helpers.S		\
 				lib/cpus/errata_report.c
 
diff --git a/bl2/bl2_main.c b/bl2/bl2_main.c
index d2de135..90fe39b 100644
--- a/bl2/bl2_main.c
+++ b/bl2/bl2_main.c
@@ -15,9 +15,6 @@
 #include <drivers/auth/auth_mod.h>
 #include <drivers/console.h>
 #include <drivers/fwu/fwu.h>
-#if MEASURED_BOOT
-#include <drivers/measured_boot/measured_boot.h>
-#endif
 #include <lib/extensions/pauth.h>
 #include <plat/common/platform.h>
 
@@ -29,18 +26,18 @@
 #define NEXT_IMAGE	"BL32"
 #endif
 
-#if !BL2_AT_EL3
+#if BL2_AT_EL3
 /*******************************************************************************
- * Setup function for BL2.
+ * Setup function for BL2 when BL2_AT_EL3=1
  ******************************************************************************/
-void bl2_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
-	       u_register_t arg3)
+void bl2_el3_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
+		   u_register_t arg3)
 {
 	/* Perform early platform-specific setup */
-	bl2_early_platform_setup2(arg0, arg1, arg2, arg3);
+	bl2_el3_early_platform_setup(arg0, arg1, arg2, arg3);
 
 	/* Perform late platform-specific setup */
-	bl2_plat_arch_setup();
+	bl2_el3_plat_arch_setup();
 
 #if CTX_INCLUDE_PAUTH_REGS
 	/*
@@ -50,19 +47,18 @@
 	assert(is_armv8_3_pauth_present());
 #endif /* CTX_INCLUDE_PAUTH_REGS */
 }
-
-#else /* if BL2_AT_EL3 */
+#else /* BL2_AT_EL3 */
 /*******************************************************************************
- * Setup function for BL2 when BL2_AT_EL3=1.
+ * Setup function for BL2 when BL2_AT_EL3=0
  ******************************************************************************/
-void bl2_el3_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
-		   u_register_t arg3)
+void bl2_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
+	       u_register_t arg3)
 {
 	/* Perform early platform-specific setup */
-	bl2_el3_early_platform_setup(arg0, arg1, arg2, arg3);
+	bl2_early_platform_setup2(arg0, arg1, arg2, arg3);
 
 	/* Perform late platform-specific setup */
-	bl2_el3_plat_arch_setup();
+	bl2_plat_arch_setup();
 
 #if CTX_INCLUDE_PAUTH_REGS
 	/*
@@ -96,26 +92,21 @@
 #if TRUSTED_BOARD_BOOT
 	/* Initialize authentication module */
 	auth_mod_init();
-
-#if MEASURED_BOOT
-	/* Initialize measured boot module */
-	measured_boot_init();
-
-#endif /* MEASURED_BOOT */
 #endif /* TRUSTED_BOARD_BOOT */
 
+	/* Initialize the Measured Boot backend */
+	bl2_plat_mboot_init();
+
 	/* Initialize boot source */
 	bl2_plat_preload_setup();
 
 	/* Load the subsequent bootloader images. */
 	next_bl_ep_info = bl2_load_images();
 
-#if MEASURED_BOOT
-	/* Finalize measured boot */
-	measured_boot_finish();
-#endif /* MEASURED_BOOT */
+	/* Teardown the Measured Boot backend */
+	bl2_plat_mboot_finish();
 
-#if !BL2_AT_EL3
+#if !BL2_AT_EL3 && !ENABLE_RME
 #ifndef __aarch64__
 	/*
 	 * For AArch32 state BL1 and BL2 share the MMU setup.
@@ -140,7 +131,7 @@
 	 * be passed to next BL image as an argument.
 	 */
 	smc(BL1_SMC_RUN_IMAGE, (unsigned long)next_bl_ep_info, 0, 0, 0, 0, 0, 0);
-#else /* if BL2_AT_EL3 */
+#else /* if BL2_AT_EL3 || ENABLE_RME */
 	NOTICE("BL2: Booting " NEXT_IMAGE "\n");
 	print_entry_point_info(next_bl_ep_info);
 	console_flush();
@@ -153,5 +144,5 @@
 #endif /* ENABLE_PAUTH */
 
 	bl2_run_next_image(next_bl_ep_info);
-#endif /* BL2_AT_EL3 */
+#endif /* BL2_AT_EL3 && ENABLE_RME */
 }
diff --git a/bl31/aarch64/bl31_entrypoint.S b/bl31/aarch64/bl31_entrypoint.S
index 2d672dd..ed05864 100644
--- a/bl31/aarch64/bl31_entrypoint.S
+++ b/bl31/aarch64/bl31_entrypoint.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -195,6 +195,19 @@
 #endif
 	bl	bl31_plat_enable_mmu
 
+#if ENABLE_RME
+	/*
+	 * At warm boot GPT data structures have already been initialized in RAM
+	 * but the sysregs for this CPU need to be initialized. Note that the GPT
+	 * accesses are controlled attributes in GPCCR and do not depend on the
+	 * SCR_EL3.C bit.
+	 */
+	bl	gpt_enable
+	cbz	x0, 1f
+	no_ret plat_panic_handler
+1:
+#endif
+
 #if ENABLE_PAUTH
 	/* --------------------------------------------------------------------
 	 * Program APIAKey_EL1 and enable pointer authentication
diff --git a/bl31/aarch64/runtime_exceptions.S b/bl31/aarch64/runtime_exceptions.S
index 51eb2bd..0d0a12d 100644
--- a/bl31/aarch64/runtime_exceptions.S
+++ b/bl31/aarch64/runtime_exceptions.S
@@ -500,6 +500,21 @@
 	stp	x16, x17, [x6, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
 	str	x18, [x6, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
 
+	/* Clear flag register */
+	mov	x7, xzr
+
+#if ENABLE_RME
+	/* Copy SCR_EL3.NSE bit to the flag to indicate caller's security */
+	ubfx	x7, x18, #SCR_NSE_SHIFT, 1
+
+	/*
+	 * Shift copied SCR_EL3.NSE bit by 5 to create space for
+	 * SCR_EL3.NS bit. Bit 5 of the flag correspondes to
+	 * the SCR_EL3.NSE bit.
+	 */
+	lsl	x7, x7, #5
+#endif /* ENABLE_RME */
+
 	/* Copy SCR_EL3.NS bit to the flag to indicate caller's security */
 	bfi	x7, x18, #0, #1
 
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
index 7819141..106d410 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -111,6 +111,13 @@
 BL31_SOURCES		+=	services/std_svc/pci_svc.c
 endif
 
+ifeq (${ENABLE_RME},1)
+include lib/gpt_rme/gpt_rme.mk
+
+BL31_SOURCES		+=	${GPT_LIB_SRCS}					\
+				${RMMD_SOURCES}
+endif
+
 BL31_LINKERFILE		:=	bl31/bl31.ld.S
 
 # Flag used to indicate if Crash reporting via console should be included
diff --git a/bl31/bl31_context_mgmt.c b/bl31/bl31_context_mgmt.c
index 9175ee3..34f69ad 100644
--- a/bl31/bl31_context_mgmt.c
+++ b/bl31/bl31_context_mgmt.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -19,9 +19,9 @@
  ******************************************************************************/
 void *cm_get_context(uint32_t security_state)
 {
-	assert(security_state <= NON_SECURE);
+	assert(sec_state_is_valid(security_state));
 
-	return get_cpu_data(cpu_context[security_state]);
+	return get_cpu_data(cpu_context[get_cpu_context_index(security_state)]);
 }
 
 /*******************************************************************************
@@ -30,9 +30,10 @@
  ******************************************************************************/
 void cm_set_context(void *context, uint32_t security_state)
 {
-	assert(security_state <= NON_SECURE);
+	assert(sec_state_is_valid(security_state));
 
-	set_cpu_data(cpu_context[security_state], context);
+	set_cpu_data(cpu_context[get_cpu_context_index(security_state)],
+			context);
 }
 
 /*******************************************************************************
@@ -46,7 +47,8 @@
 {
 	assert(sec_state_is_valid(security_state));
 
-	return get_cpu_data_by_index(cpu_idx, cpu_context[security_state]);
+	return get_cpu_data_by_index(cpu_idx,
+			cpu_context[get_cpu_context_index(security_state)]);
 }
 
 /*******************************************************************************
@@ -58,5 +60,7 @@
 {
 	assert(sec_state_is_valid(security_state));
 
-	set_cpu_data_by_index(cpu_idx, cpu_context[security_state], context);
+	set_cpu_data_by_index(cpu_idx,
+			cpu_context[get_cpu_context_index(security_state)],
+			context);
 }
diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c
index f272af5..9ac10e2 100644
--- a/bl31/bl31_main.c
+++ b/bl31/bl31_main.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -35,6 +35,13 @@
  ******************************************************************************/
 static int32_t (*bl32_init)(void);
 
+/*****************************************************************************
+ * Function used to initialise RMM if RME is enabled
+ *****************************************************************************/
+#if ENABLE_RME
+static int32_t (*rmm_init)(void);
+#endif
+
 /*******************************************************************************
  * Variable to indicate whether next image to execute after BL31 is BL33
  * (non-secure & default) or BL32 (secure).
@@ -139,12 +146,15 @@
 
 	/*
 	 * All the cold boot actions on the primary cpu are done. We now need to
-	 * decide which is the next image (BL32 or BL33) and how to execute it.
+	 * decide which is the next image and how to execute it.
 	 * If the SPD runtime service is present, it would want to pass control
 	 * to BL32 first in S-EL1. In that case, SPD would have registered a
 	 * function to initialize bl32 where it takes responsibility of entering
-	 * S-EL1 and returning control back to bl31_main. Once this is done we
-	 * can prepare entry into BL33 as normal.
+	 * S-EL1 and returning control back to bl31_main. Similarly, if RME is
+	 * enabled and a function is registered to initialize RMM, control is
+	 * transferred to RMM in R-EL2. After RMM initialization, control is
+	 * returned back to bl31_main. Once this is done we can prepare entry
+	 * into BL33 as normal.
 	 */
 
 	/*
@@ -155,9 +165,27 @@
 
 		int32_t rc = (*bl32_init)();
 
-		if (rc == 0)
+		if (rc == 0) {
 			WARN("BL31: BL32 initialization failed\n");
+		}
+	}
+
+	/*
+	 * If RME is enabled and init hook is registered, initialize RMM
+	 * in R-EL2.
+	 */
+#if ENABLE_RME
+	if (rmm_init != NULL) {
+		INFO("BL31: Initializing RMM\n");
+
+		int32_t rc = (*rmm_init)();
+
+		if (rc == 0) {
+			WARN("BL31: RMM initialization failed\n");
+		}
 	}
+#endif
+
 	/*
 	 * We are ready to enter the next EL. Prepare entry into the image
 	 * corresponding to the desired security state after the next ERET.
@@ -236,3 +264,14 @@
 {
 	bl32_init = func;
 }
+
+#if ENABLE_RME
+/*******************************************************************************
+ * This function initializes the pointer to RMM init function. This is expected
+ * to be called by the RMMD after it finishes all its initialization
+ ******************************************************************************/
+void bl31_register_rmm_init(int32_t (*func)(void))
+{
+	rmm_init = func;
+}
+#endif
diff --git a/common/bl_common.c b/common/bl_common.c
index a7e2816..eb2352a 100644
--- a/common/bl_common.c
+++ b/common/bl_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -202,12 +202,26 @@
 		return -EAUTH;
 	}
 
-	/*
-	 * Flush the image to main memory so that it can be executed later by
-	 * any CPU, regardless of cache and MMU state. This is only needed for
-	 * child images, not for the parents (certificates).
-	 */
 	if (is_parent_image == 0) {
+		/*
+		 * Measure the image.
+		 * We do not measure its parents because these only play a role
+		 * in authentication, which is orthogonal to measured boot.
+		 *
+		 * TODO: Change this code if we change our minds about measuring
+		 * certificates.
+		 */
+		rc = plat_mboot_measure_image(image_id, image_data);
+		if (rc != 0) {
+			return rc;
+		}
+
+		/*
+		 * Flush the image to main memory so that it can be executed
+		 * later by any CPU, regardless of cache and MMU state. This
+		 * is only needed for child images, not for the parents
+		 * (certificates).
+		 */
 		flush_dcache_range(image_data->image_base,
 				   image_data->image_size);
 	}
diff --git a/docs/about/maintainers.rst b/docs/about/maintainers.rst
index 1bd4666..7db81fc 100644
--- a/docs/about/maintainers.rst
+++ b/docs/about/maintainers.rst
@@ -109,6 +109,16 @@
 :|G|: `john-powell-arm`_
 :|F|: bl31/ehf.c
 
+Realm Management Extension (RME)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+:|M|: Bipin Ravi <bipin.ravi@arm.com>
+:|G|: `bipinravi-arm`_
+:|M|: Mark Dykes <mark.dykes@arm.com>
+:|G|: `mardyk01`_
+:|M|: John Powell <John.Powell@arm.com>
+:|G|: `john-powell-arm`_
+:|M|: Zelalem Aweke <Zelalem.Aweke@arm.com>
+:|G|: `zelalem-aweke`_
 
 Drivers, Libraries and Framework Code
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/about/release-information.rst b/docs/about/release-information.rst
index 3e8dd91..b65571d 100644
--- a/docs/about/release-information.rst
+++ b/docs/about/release-information.rst
@@ -46,7 +46,7 @@
 +-----------------+---------------------------+------------------------------+
 | v2.5            | 3rd week of May '21       | 5th week of Apr '21          |
 +-----------------+---------------------------+------------------------------+
-| v2.6            | 4th week of Oct '21       | 1st week of Oct '21          |
+| v2.6            | 4th week of Nov '21       | 2nd week of Nov '21          |
 +-----------------+---------------------------+------------------------------+
 
 Removal of Deprecated Interfaces
diff --git a/docs/components/index.rst b/docs/components/index.rst
index 2409f96..f349d8d 100644
--- a/docs/components/index.rst
+++ b/docs/components/index.rst
@@ -22,3 +22,4 @@
    ffa-manifest-binding
    xlat-tables-lib-v2-design
    cot-binding
+   realm-management-extension
diff --git a/docs/components/measured_boot/event_log.rst b/docs/components/measured_boot/event_log.rst
index 5347dcc..0881248 100644
--- a/docs/components/measured_boot/event_log.rst
+++ b/docs/components/measured_boot/event_log.rst
@@ -9,7 +9,7 @@
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Measured Boot driver expects a *tpm_event_log* node with the following field
-in 'nt_fw_config' and 'tsp_fw_config' DTS files:
+in 'tb_fw_config', 'nt_fw_config' and 'tsp_fw_config' DTS files:
 
 - compatible [mandatory]
    - value type: <string>
diff --git a/docs/components/realm-management-extension.rst b/docs/components/realm-management-extension.rst
new file mode 100644
index 0000000..5c580f3
--- /dev/null
+++ b/docs/components/realm-management-extension.rst
@@ -0,0 +1,194 @@
+
+Realm Management Extension (RME)
+====================================
+
+FEAT_RME (or RME for short) is an Armv9-A extension and is one component of the
+`Arm Confidential Compute Architecture (Arm CCA)`_. TF-A supports RME starting
+from version 2.6. This document provides instructions on how to build and run
+TF-A with RME.
+
+Building and running TF-A with RME
+------------------------------------
+
+This section describes how you can build and run TF-A with RME enabled.
+We assume you have all the :ref:`Prerequisites` to build TF-A.
+
+To enable RME, you need to set the ENABLE_RME build flag when building
+TF-A. Currently, this feature is only supported for the FVP platform.
+
+The following instructions show you how to build and run TF-A with RME
+for two scenarios: TF-A with TF-A Tests, and four-world execution with
+Hafnium and TF-A Tests. The instructions assume you have already obtained
+TF-A. You can use the following command to clone TF-A.
+
+.. code:: shell
+
+ git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+
+To run the tests, you need an FVP model. You can download a model that supports
+RME from the `Arm Architecture Models website`_. Please select the
+*Base RevC AEM FVP* model. After extracting the downloaded file, you should be able to
+find the *FVP_Base_RevC-2xAEMvA* binary. The instructions below have been tested
+with model version 11.15 revision 18.
+
+.. note::
+
+ ENABLE_RME build option is currently experimental.
+
+Building TF-A with TF-A Tests
+********************************************
+Use the following instructions to build TF-A with `TF-A Tests`_ as the
+non-secure payload (BL33).
+
+**1. Obtain and build TF-A Tests**
+
+.. code:: shell
+
+ git clone https://git.trustedfirmware.org/TF-A/tf-a-tests.git
+ cd tf-a-tests
+ make CROSS_COMPILE=aarch64-none-elf- PLAT=fvp DEBUG=1
+
+This produces a TF-A Tests binary (*tftf.bin*) in the *build/fvp/debug* directory.
+
+**2. Build TF-A**
+
+.. code:: shell
+
+ cd trusted-firmware-a
+ make CROSS_COMPILE=aarch64-none-elf- \
+ PLAT=fvp \
+ ENABLE_RME=1 \
+ FVP_HW_CONFIG_DTS=fdts/fvp-base-gicv3-psci-1t.dts \
+ DEBUG=1 \
+ BL33=<path/to/tftf.bin> \
+ all fip
+
+This produces *bl1.bin* and *fip.bin* binaries in the *build/fvp/debug* directory.
+The above command also builds a Test Realm Payload (TRP), which is a small test
+payload that implements Realm Monitor Management (RMM) functionalities and runs
+in the realm world (R-EL2). The TRP binary is packaged in *fip.bin*.
+
+Four-world execution with Hafnium and TF-A Tests
+****************************************************
+Four-world execution involves software components at each security state: root,
+secure, realm and non-secure. This section describes how to build TF-A
+with four-world support. We use TF-A as the root firmware, `Hafnium`_ as the
+secure component, TRP as the realm-world firmware and TF-A Tests as the
+non-secure payload.
+
+Before building TF-A, you first need to build the other software components.
+You can find instructions on how to get and build TF-A Tests above.
+
+**1. Obtain and build Hafnium**
+
+.. code:: shell
+
+ git clone --recurse-submodules https://git.trustedfirmware.org/hafnium/hafnium.git
+ cd hafnium
+ make PROJECT=reference
+
+The Hafnium binary should be located at
+*out/reference/secure_aem_v8a_fvp_clang/hafnium.bin*
+
+**2. Build TF-A**
+
+Build TF-A with RME as well as SPM enabled.
+
+.. code:: shell
+
+ make CROSS_COMPILE=aarch64-none-elf- \
+ PLAT=fvp \
+ ENABLE_RME=1 \
+ FVP_HW_CONFIG_DTS=fdts/fvp-base-gicv3-psci-1t.dts \
+ SPD=spmd \
+ SPMD_SPM_AT_SEL2=1 \
+ BRANCH_PROTECTION=1 \
+ CTX_INCLUDE_PAUTH_REGS=1 \
+ DEBUG=1 \
+ SP_LAYOUT_FILE=<path/to/tf-a-tests>/build/fvp/debug/sp_layout.json> \
+ BL32=<path/to/hafnium.bin> \
+ BL33=<path/to/tftf.bin> \
+ all fip
+
+Running the tests
+*********************
+Use the following command to run the tests on FVP. TF-A Tests should boot
+and run the default tests including RME tests.
+
+.. code:: shell
+
+ FVP_Base_RevC-2xAEMvA \
+ -C bp.flashloader0.fname=<path/to/fip.bin> \
+ -C bp.secureflashloader.fname=<path/to/bl1.bin> \
+ -C bp.refcounter.non_arch_start_at_default=1 \
+ -C bp.refcounter.use_real_time=0 \
+ -C bp.ve_sysregs.exit_on_shutdown=1 \
+ -C cache_state_modelled=1 \
+ -C cluster0.NUM_CORES=4 \
+ -C cluster0.PA_SIZE=48 \
+ -C cluster0.ecv_support_level=2 \
+ -C cluster0.gicv3.cpuintf-mmap-access-level=2 \
+ -C cluster0.gicv3.without-DS-support=1 \
+ -C cluster0.gicv4.mask-virtual-interrupt=1 \
+ -C cluster0.has_arm_v8-6=1 \
+ -C cluster0.has_branch_target_exception=1 \
+ -C cluster0.has_rme=1 \
+ -C cluster0.has_rndr=1 \
+ -C cluster0.has_amu=1 \
+ -C cluster0.has_v8_7_pmu_extension=2 \
+ -C cluster0.max_32bit_el=-1 \
+ -C cluster0.restriction_on_speculative_execution=2 \
+ -C cluster0.restriction_on_speculative_execution_aarch32=2 \
+ -C cluster1.NUM_CORES=4 \
+ -C cluster1.PA_SIZE=48 \
+ -C cluster1.ecv_support_level=2 \
+ -C cluster1.gicv3.cpuintf-mmap-access-level=2 \
+ -C cluster1.gicv3.without-DS-support=1 \
+ -C cluster1.gicv4.mask-virtual-interrupt=1 \
+ -C cluster1.has_arm_v8-6=1 \
+ -C cluster1.has_branch_target_exception=1 \
+ -C cluster1.has_rme=1 \
+ -C cluster1.has_rndr=1 \
+ -C cluster1.has_amu=1 \
+ -C cluster1.has_v8_7_pmu_extension=2 \
+ -C cluster1.max_32bit_el=-1 \
+ -C cluster1.restriction_on_speculative_execution=2 \
+ -C cluster1.restriction_on_speculative_execution_aarch32=2 \
+ -C pci.pci_smmuv3.mmu.SMMU_AIDR=2 \
+ -C pci.pci_smmuv3.mmu.SMMU_IDR0=0x0046123B \
+ -C pci.pci_smmuv3.mmu.SMMU_IDR1=0x00600002 \
+ -C pci.pci_smmuv3.mmu.SMMU_IDR3=0x1714 \
+ -C pci.pci_smmuv3.mmu.SMMU_IDR5=0xFFFF0475 \
+ -C pci.pci_smmuv3.mmu.SMMU_S_IDR1=0xA0000002 \
+ -C pci.pci_smmuv3.mmu.SMMU_S_IDR2=0 \
+ -C pci.pci_smmuv3.mmu.SMMU_S_IDR3=0 \
+ -C bp.pl011_uart0.out_file=uart0.log \
+ -C bp.pl011_uart1.out_file=uart1.log \
+ -C bp.pl011_uart2.out_file=uart2.log \
+ -C pctl.startup=0.0.0.0 \
+ -Q 1000 \
+ "$@"
+
+The bottom of the output from *uart0* should look something like the following.
+
+.. code-block:: shell
+
+ ...
+
+ > Test suite 'FF-A Interrupt'
+                                                                Passed
+ > Test suite 'SMMUv3 tests'
+                                                                Passed
+ > Test suite 'PMU Leakage'
+                                                                Passed
+ > Test suite 'DebugFS'
+                                                                Passed
+ > Test suite 'Realm payload tests'
+                                                                Passed
+ ...
+
+
+.. _Arm Confidential Compute Architecture (Arm CCA): https://www.arm.com/why-arm/architecture/security-features/arm-confidential-compute-architecture
+.. _Arm Architecture Models website: https://developer.arm.com/tools-and-software/simulation-models/fixed-virtual-platforms/arm-ecosystem-models
+.. _TF-A Tests: https://trustedfirmware-a-tests.readthedocs.io/en/latest
+.. _Hafnium: https://www.trustedfirmware.org/projects/hafnium
diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst
index 7fe6ccd..1259881 100644
--- a/docs/getting_started/build-options.rst
+++ b/docs/getting_started/build-options.rst
@@ -271,6 +271,10 @@
    be enabled. If ``ENABLE_PMF`` is set, the residency statistics are tracked in
    software.
 
+- ``ENABLE_RME``: Boolean option to enable support for the ARMv9 Realm
+   Management Extension. Default value is 0. This is currently an experimental
+   feature.
+
 -  ``ENABLE_RUNTIME_INSTRUMENTATION``: Boolean option to enable runtime
    instrumentation which injects timestamp collection points into TF-A to
    allow runtime performance to be measured. Currently, only PSCI is
diff --git a/docs/getting_started/porting-guide.rst b/docs/getting_started/porting-guide.rst
index 54754fe..6569a47 100644
--- a/docs/getting_started/porting-guide.rst
+++ b/docs/getting_started/porting-guide.rst
@@ -1199,6 +1199,25 @@
 the SMCCC function specified in the argument; otherwise returns
 SMC_ARCH_CALL_NOT_SUPPORTED.
 
+Function : plat_mboot_measure_image()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : unsigned int, image_info_t *
+    Return   : void
+
+When the MEASURED_BOOT flag is enabled:
+
+-  This function measures the given image and records its measurement using
+   the measured boot backend driver.
+-  On the Arm FVP port, this function measures the given image using its
+   passed id and information and then records that measurement in the
+   Event Log buffer.
+-  This function must return 0 on success, a negative error code otherwise.
+
+When the MEASURED_BOOT flag is disabled, this function doesn't do anything.
+
 Modifications specific to a Boot Loader stage
 ---------------------------------------------
 
@@ -1450,6 +1469,42 @@
 The default implementation of this function asserts therefore platforms must
 override it when using the FWU feature.
 
+Function : bl1_plat_mboot_init() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+When the MEASURED_BOOT flag is enabled:
+
+-  This function is used to initialize the backend driver(s) of measured boot.
+-  On the Arm FVP port, this function is used to initialize the Event Log
+   backend driver, and also to write header information in the Event Log buffer.
+
+When the MEASURED_BOOT flag is disabled, this function doesn't do anything.
+
+Function : bl1_plat_mboot_finish() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+When the MEASURED_BOOT flag is enabled:
+
+-  This function is used to finalize the measured boot backend driver(s),
+   and also, set the information for the next bootloader component to
+   extend the measurement if needed.
+-  On the Arm FVP port, this function is used to pass the base address of
+   the Event Log buffer and its size to BL2 via tb_fw_config to extend the
+   Event Log buffer with the measurement of various images loaded by BL2.
+   It results in panic on error.
+
+When the MEASURED_BOOT flag is disabled, this function doesn't do anything.
+
 Boot Loader Stage 2 (BL2)
 -------------------------
 
@@ -1738,6 +1793,42 @@
 This function returns 0 on success, a negative error code otherwise.
 This function is included if SCP_BL2U_BASE is defined.
 
+Function : bl2_plat_mboot_init() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+When the MEASURED_BOOT flag is enabled:
+
+-  This function is used to initialize the backend driver(s) of measured boot.
+-  On the Arm FVP port, this function is used to initialize the Event Log
+   backend driver with the Event Log buffer information (base address and
+   size) received from BL1. It results in panic on error.
+
+When the MEASURED_BOOT flag is disabled, this function doesn't do anything.
+
+Function : bl2_plat_mboot_finish() [optional]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+::
+
+    Argument : void
+    Return   : void
+
+When the MEASURED_BOOT flag is enabled:
+
+-  This function is used to finalize the measured boot backend driver(s),
+   and also, set the information for the next bootloader component to extend
+   the measurement if needed.
+-  On the Arm FVP port, this function is used to pass the Event Log buffer
+   information (base address and size) to non-secure(BL33) and trusted OS(BL32)
+   via nt_fw and tos_fw config respectively. It results in panic on error.
+
+When the MEASURED_BOOT flag is disabled, this function doesn't do anything.
+
 Boot Loader Stage 3-1 (BL31)
 ----------------------------
 
diff --git a/docs/plat/marvell/armada/build.rst b/docs/plat/marvell/armada/build.rst
index b125144..6872f56 100644
--- a/docs/plat/marvell/armada/build.rst
+++ b/docs/plat/marvell/armada/build.rst
@@ -58,6 +58,7 @@
             - a3700        - A3720 DB, EspressoBin and Turris MOX
             - a70x0
             - a70x0_amc    - AMC board
+            - a70x0_mochabin - Globalscale MOCHAbin
             - a80x0
             - a80x0_mcbin  - MacchiatoBin
             - a80x0_puzzle - IEI Puzzle-M801
@@ -150,6 +151,16 @@
         Specify path to the MSS fimware image binary which will run on Cortex-M3 coprocessor.
         It is available in Marvell binaries-marvell git repository. Required when ``MSS_SUPPORT=1``.
 
+Globalscale MOCHAbin specific build options:
+
+- DDR_TOPOLOGY
+
+        The DDR topology map index/name, default is 0.
+
+        Supported Options:
+            -    0 - DDR4 1CS 2GB
+            -    1 - DDR4 1CS 4GB
+            -    2 - DDR4 2CS 8GB
 
 Armada37x0 specific build options:
 
diff --git a/drivers/marvell/comphy/phy-comphy-3700.c b/drivers/marvell/comphy/phy-comphy-3700.c
index 0ad14a8..a3e414c 100644
--- a/drivers/marvell/comphy/phy-comphy-3700.c
+++ b/drivers/marvell/comphy/phy-comphy-3700.c
@@ -815,6 +815,12 @@
 
 	debug_enter();
 
+	/* Configure phy selector for PCIe */
+	ret = mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode);
+	if (ret) {
+		return ret;
+	}
+
 	/* 1. Enable max PLL. */
 	reg_set16(LANE_CFG1_ADDR(PCIE) + COMPHY_SD_ADDR,
 		  USE_MAX_PLL_RATE_EN, USE_MAX_PLL_RATE_EN);
diff --git a/drivers/measured_boot/event_log.c b/drivers/measured_boot/event_log.c
deleted file mode 100644
index 0157b03..0000000
--- a/drivers/measured_boot/event_log.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-#include <arch_helpers.h>
-
-#include <common/bl_common.h>
-#include <common/debug.h>
-#include <drivers/auth/crypto_mod.h>
-#include <drivers/measured_boot/event_log.h>
-#include <mbedtls/md.h>
-
-#include <plat/common/platform.h>
-
-/* Event Log data */
-static uint8_t event_log[EVENT_LOG_SIZE];
-
-/* End of Event Log */
-#define	EVENT_LOG_END	((uintptr_t)event_log + sizeof(event_log) - 1U)
-
-CASSERT(sizeof(event_log) >= LOG_MIN_SIZE, assert_event_log_size);
-
-/* Pointer in event_log[] */
-static uint8_t *log_ptr = event_log;
-
-/* Pointer to measured_boot_data_t */
-const static measured_boot_data_t *plat_data_ptr;
-
-static uintptr_t tos_fw_config_base;
-static uintptr_t nt_fw_config_base;
-
-/* TCG_EfiSpecIdEvent */
-static const id_event_headers_t id_event_header = {
-	.header = {
-		.pcr_index = PCR_0,
-		.event_type = EV_NO_ACTION,
-		.digest = {0},
-		.event_size = (uint32_t)(sizeof(id_event_struct_t) +
-				(sizeof(id_event_algorithm_size_t) *
-				HASH_ALG_COUNT))
-	},
-
-	.struct_header = {
-		.signature = TCG_ID_EVENT_SIGNATURE_03,
-		.platform_class = PLATFORM_CLASS_CLIENT,
-		.spec_version_minor = TCG_SPEC_VERSION_MINOR_TPM2,
-		.spec_version_major = TCG_SPEC_VERSION_MAJOR_TPM2,
-		.spec_errata = TCG_SPEC_ERRATA_TPM2,
-		.uintn_size = (uint8_t)(sizeof(unsigned int) /
-					sizeof(uint32_t)),
-		.number_of_algorithms = HASH_ALG_COUNT
-	}
-};
-
-static const event2_header_t locality_event_header = {
-	/*
-	 * All EV_NO_ACTION events SHALL set
-	 * TCG_PCR_EVENT2.pcrIndex = 0, unless otherwise specified
-	 */
-	.pcr_index = PCR_0,
-
-	/*
-	 * All EV_NO_ACTION events SHALL set
-	 * TCG_PCR_EVENT2.eventType = 03h
-	 */
-	.event_type = EV_NO_ACTION,
-
-	/*
-	 * All EV_NO_ACTION events SHALL set TCG_PCR_EVENT2.digests to all
-	 * 0x00's for each allocated Hash algorithm
-	 */
-	.digests = {
-		.count = HASH_ALG_COUNT
-	}
-};
-
-/*
- * Add TCG_PCR_EVENT2 event
- *
- * @param[in] hash	Pointer to hash data of TCG_DIGEST_SIZE bytes
- * @param[in] image_ptr	Pointer to image_data_t structure
- *
- * There must be room for storing this new event into the event log buffer.
- */
-static void add_event2(const uint8_t *hash, const image_data_t *image_ptr)
-{
-	void *ptr = log_ptr;
-	uint32_t name_len;
-
-	assert(image_ptr != NULL);
-	assert(image_ptr->name != NULL);
-
-	name_len = (uint32_t)strlen(image_ptr->name) + 1U;
-
-	/* Check for space in Event Log buffer */
-	assert(((uintptr_t)ptr + (uint32_t)EVENT2_HDR_SIZE + name_len) <=
-	       EVENT_LOG_END);
-
-	/*
-	 * As per TCG specifications, firmware components that are measured
-	 * into PCR[0] must be logged in the event log using the event type
-	 * EV_POST_CODE.
-	 */
-	/* TCG_PCR_EVENT2.PCRIndex */
-	((event2_header_t *)ptr)->pcr_index = image_ptr->pcr;
-
-	/* TCG_PCR_EVENT2.EventType */
-	((event2_header_t *)ptr)->event_type = EV_POST_CODE;
-
-	/* TCG_PCR_EVENT2.Digests.Count */
-	ptr = (uint8_t *)ptr + offsetof(event2_header_t, digests);
-	((tpml_digest_values *)ptr)->count = HASH_ALG_COUNT;
-
-	/* TCG_PCR_EVENT2.Digests[] */
-	ptr = (uint8_t *)((uintptr_t)ptr +
-			offsetof(tpml_digest_values, digests));
-
-	/* TCG_PCR_EVENT2.Digests[].AlgorithmId */
-	((tpmt_ha *)ptr)->algorithm_id = TPM_ALG_ID;
-
-	/* TCG_PCR_EVENT2.Digests[].Digest[] */
-	ptr = (uint8_t *)((uintptr_t)ptr + offsetof(tpmt_ha, digest));
-
-	if (hash == NULL) {
-		/* Get BL2 hash from DTB */
-		bl2_plat_get_hash(ptr);
-	} else {
-		/* Copy digest */
-		(void)memcpy(ptr, (const void *)hash, TCG_DIGEST_SIZE);
-	}
-
-	/* TCG_PCR_EVENT2.EventSize */
-	ptr = (uint8_t *)((uintptr_t)ptr + TCG_DIGEST_SIZE);
-	((event2_data_t *)ptr)->event_size = name_len;
-
-	/* Copy event data to TCG_PCR_EVENT2.Event */
-	(void)memcpy((void *)(((event2_data_t *)ptr)->event),
-			(const void *)image_ptr->name, name_len);
-
-	/* End of event data */
-	log_ptr = (uint8_t *)((uintptr_t)ptr +
-			offsetof(event2_data_t, event) + name_len);
-}
-
-/*
- * Init Event Log
- *
- * Initialises Event Log by writing Specification ID and
- * Startup Locality events.
- */
-void event_log_init(void)
-{
-	const char locality_signature[] = TCG_STARTUP_LOCALITY_SIGNATURE;
-	void *ptr = event_log;
-
-	/* Get pointer to platform's measured_boot_data_t structure */
-	plat_data_ptr = plat_get_measured_boot_data();
-
-	/*
-	 * Add Specification ID Event first
-	 *
-	 * Copy TCG_EfiSpecIDEventStruct structure header
-	 */
-	(void)memcpy(ptr, (const void *)&id_event_header,
-			sizeof(id_event_header));
-	ptr = (uint8_t *)((uintptr_t)ptr + sizeof(id_event_header));
-
-	/* TCG_EfiSpecIdEventAlgorithmSize structure */
-	((id_event_algorithm_size_t *)ptr)->algorithm_id = TPM_ALG_ID;
-	((id_event_algorithm_size_t *)ptr)->digest_size = TCG_DIGEST_SIZE;
-	ptr = (uint8_t *)((uintptr_t)ptr + sizeof(id_event_algorithm_size_t));
-
-	/*
-	 * TCG_EfiSpecIDEventStruct.vendorInfoSize
-	 * No vendor data
-	 */
-	((id_event_struct_data_t *)ptr)->vendor_info_size = 0;
-	ptr = (uint8_t *)((uintptr_t)ptr +
-			offsetof(id_event_struct_data_t, vendor_info));
-
-	/*
-	 * The Startup Locality event should be placed in the log before
-	 * any event which extends PCR[0].
-	 *
-	 * Ref. TCG PC Client Platform Firmware Profile 9.4.5.3
-	 */
-
-	/* Copy Startup Locality Event Header */
-	(void)memcpy(ptr, (const void *)&locality_event_header,
-			sizeof(locality_event_header));
-	ptr = (uint8_t *)((uintptr_t)ptr + sizeof(locality_event_header));
-
-	/* TCG_PCR_EVENT2.Digests[].AlgorithmId */
-	((tpmt_ha *)ptr)->algorithm_id = TPM_ALG_ID;
-
-	/* TCG_PCR_EVENT2.Digests[].Digest[] */
-	(void)memset(&((tpmt_ha *)ptr)->digest, 0, TPM_ALG_ID);
-	ptr = (uint8_t *)((uintptr_t)ptr +
-			offsetof(tpmt_ha, digest) + TCG_DIGEST_SIZE);
-
-	/* TCG_PCR_EVENT2.EventSize */
-	((event2_data_t *)ptr)->event_size =
-		(uint32_t)sizeof(startup_locality_event_t);
-	ptr = (uint8_t *)((uintptr_t)ptr + offsetof(event2_data_t, event));
-
-	/* TCG_EfiStartupLocalityEvent.Signature */
-	(void)memcpy(ptr, (const void *)locality_signature,
-		sizeof(TCG_STARTUP_LOCALITY_SIGNATURE));
-
-	/*
-	 * TCG_EfiStartupLocalityEvent.StartupLocality = 0:
-	 * the platform's boot firmware
-	 */
-	((startup_locality_event_t *)ptr)->startup_locality = 0U;
-	ptr = (uint8_t *)((uintptr_t)ptr + sizeof(startup_locality_event_t));
-
-	log_ptr = (uint8_t *)ptr;
-
-	/* Add BL2 event */
-	add_event2(NULL, plat_data_ptr->images_data);
-}
-
-/*
- * Calculate and write hash of image, configuration data, etc.
- * to Event Log.
- *
- * @param[in] data_base		Address of data
- * @param[in] data_size		Size of data
- * @param[in] data_id		Data ID
- * @return:
- *	0 = success
- *    < 0 = error
- */
-int tpm_record_measurement(uintptr_t data_base, uint32_t data_size,
-			   uint32_t data_id)
-{
-	const image_data_t *data_ptr = plat_data_ptr->images_data;
-	unsigned char hash_data[MBEDTLS_MD_MAX_SIZE];
-	int rc;
-
-	/* Get the metadata associated with this image. */
-	while ((data_ptr->id != INVALID_ID) && (data_ptr->id != data_id)) {
-		data_ptr++;
-	}
-	assert(data_ptr->id != INVALID_ID);
-
-	if (data_id == TOS_FW_CONFIG_ID) {
-		tos_fw_config_base = data_base;
-	} else if (data_id == NT_FW_CONFIG_ID) {
-		nt_fw_config_base = data_base;
-	} else {
-		/* No action */
-	}
-
-	/* Calculate hash */
-	rc = crypto_mod_calc_hash((unsigned int)MBEDTLS_MD_ID,
-				(void *)data_base, data_size, hash_data);
-	if (rc != 0) {
-		return rc;
-	}
-
-	add_event2(hash_data, data_ptr);
-	return 0;
-}
-
-/*
- * Finalise Event Log
- *
- * @param[out] log_addr	Pointer to return Event Log address
- * @param[out] log_size	Pointer to return Event Log size
- * @return:
- *	0 = success
- *    < 0 = error code
- */
-int event_log_finalise(uint8_t **log_addr, size_t *log_size)
-{
-	/* Event Log size */
-	size_t num_bytes = (uintptr_t)log_ptr - (uintptr_t)event_log;
-	int rc;
-
-	assert(log_addr != NULL);
-	assert(log_size != NULL);
-
-	if (nt_fw_config_base == 0UL) {
-		ERROR("%s(): %s_FW_CONFIG not loaded\n", __func__, "NT");
-		return -ENOENT;
-	}
-
-	/*
-	 * Set Event Log data in NT_FW_CONFIG and
-	 * get Event Log address in Non-Secure memory
-	 */
-	if (plat_data_ptr->set_nt_fw_info != NULL) {
-
-		/* Event Log address in Non-Secure memory */
-		uintptr_t ns_log_addr;
-
-		rc = plat_data_ptr->set_nt_fw_info(
-				nt_fw_config_base,
-#ifdef SPD_opteed
-				(uintptr_t)event_log,
-#endif
-				num_bytes, &ns_log_addr);
-		if (rc != 0) {
-			ERROR("%s(): Unable to update %s_FW_CONFIG\n",
-						__func__, "NT");
-			return rc;
-		}
-
-		/* Copy Event Log to Non-secure memory */
-		(void)memcpy((void *)ns_log_addr, (const void *)event_log,
-				num_bytes);
-
-		/* Ensure that the Event Log is visible in Non-secure memory */
-		flush_dcache_range(ns_log_addr, num_bytes);
-
-		/* Return Event Log address in Non-Secure memory */
-		*log_addr = (uint8_t *)ns_log_addr;
-
-	} else {
-		INFO("%s(): set_%s_fw_info not set\n", __func__, "nt");
-
-		/* Return Event Log address in Secure memory */
-		*log_addr = event_log;
-	}
-
-	if (tos_fw_config_base != 0UL) {
-		if (plat_data_ptr->set_tos_fw_info != NULL) {
-
-			/* Set Event Log data in TOS_FW_CONFIG */
-			rc = plat_data_ptr->set_tos_fw_info(
-						tos_fw_config_base,
-						(uintptr_t)event_log,
-						num_bytes);
-			if (rc != 0) {
-				ERROR("%s(): Unable to update %s_FW_CONFIG\n",
-						__func__, "TOS");
-				return rc;
-			}
-		} else {
-			INFO("%s(): set_%s_fw_info not set\n", __func__, "tos");
-		}
-	} else {
-		INFO("%s(): %s_FW_CONFIG not loaded\n", __func__, "TOS");
-	}
-
-	/* Ensure that the Event Log is visible in Secure memory */
-	flush_dcache_range((uintptr_t)event_log, num_bytes);
-
-	/* Return Event Log size */
-	*log_size = num_bytes;
-
-	return 0;
-}
diff --git a/drivers/measured_boot/event_log/event_log.c b/drivers/measured_boot/event_log/event_log.c
new file mode 100644
index 0000000..1755dd9
--- /dev/null
+++ b/drivers/measured_boot/event_log/event_log.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <arch_helpers.h>
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/auth/crypto_mod.h>
+#include <drivers/measured_boot/event_log/event_log.h>
+#include <mbedtls/md.h>
+
+#include <plat/common/platform.h>
+
+/* Running Event Log Pointer */
+static uint8_t *log_ptr;
+
+/* Pointer to the first byte past end of the Event Log buffer */
+static uintptr_t log_end;
+
+/* Pointer to event_log_metadata_t */
+static const event_log_metadata_t *plat_metadata_ptr;
+
+/* TCG_EfiSpecIdEvent */
+static const id_event_headers_t id_event_header = {
+	.header = {
+		.pcr_index = PCR_0,
+		.event_type = EV_NO_ACTION,
+		.digest = {0},
+		.event_size = (uint32_t)(sizeof(id_event_struct_t) +
+				(sizeof(id_event_algorithm_size_t) *
+				HASH_ALG_COUNT))
+	},
+
+	.struct_header = {
+		.signature = TCG_ID_EVENT_SIGNATURE_03,
+		.platform_class = PLATFORM_CLASS_CLIENT,
+		.spec_version_minor = TCG_SPEC_VERSION_MINOR_TPM2,
+		.spec_version_major = TCG_SPEC_VERSION_MAJOR_TPM2,
+		.spec_errata = TCG_SPEC_ERRATA_TPM2,
+		.uintn_size = (uint8_t)(sizeof(unsigned int) /
+					sizeof(uint32_t)),
+		.number_of_algorithms = HASH_ALG_COUNT
+	}
+};
+
+static const event2_header_t locality_event_header = {
+	/*
+	 * All EV_NO_ACTION events SHALL set
+	 * TCG_PCR_EVENT2.pcrIndex = 0, unless otherwise specified
+	 */
+	.pcr_index = PCR_0,
+
+	/*
+	 * All EV_NO_ACTION events SHALL set
+	 * TCG_PCR_EVENT2.eventType = 03h
+	 */
+	.event_type = EV_NO_ACTION,
+
+	/*
+	 * All EV_NO_ACTION events SHALL set TCG_PCR_EVENT2.digests to all
+	 * 0x00's for each allocated Hash algorithm
+	 */
+	.digests = {
+		.count = HASH_ALG_COUNT
+	}
+};
+
+/*
+ * Record a measurement as a TCG_PCR_EVENT2 event
+ *
+ * @param[in] hash		Pointer to hash data of TCG_DIGEST_SIZE bytes
+ * @param[in] metadata_ptr	Pointer to event_log_metadata_t structure
+ *
+ * There must be room for storing this new event into the event log buffer.
+ */
+static void event_log_record(const uint8_t *hash,
+			     const event_log_metadata_t *metadata_ptr)
+{
+	void *ptr = log_ptr;
+	uint32_t name_len;
+
+	assert(hash != NULL);
+	assert(metadata_ptr != NULL);
+	assert(metadata_ptr->name != NULL);
+	/* event_log_init() must have been called prior to this. */
+	assert(log_ptr != NULL);
+
+	name_len = (uint32_t)strlen(metadata_ptr->name) + 1U;
+
+	/* Check for space in Event Log buffer */
+	assert(((uintptr_t)ptr + (uint32_t)EVENT2_HDR_SIZE + name_len) <
+	       log_end);
+
+	/*
+	 * As per TCG specifications, firmware components that are measured
+	 * into PCR[0] must be logged in the event log using the event type
+	 * EV_POST_CODE.
+	 */
+	/* TCG_PCR_EVENT2.PCRIndex */
+	((event2_header_t *)ptr)->pcr_index = metadata_ptr->pcr;
+
+	/* TCG_PCR_EVENT2.EventType */
+	((event2_header_t *)ptr)->event_type = EV_POST_CODE;
+
+	/* TCG_PCR_EVENT2.Digests.Count */
+	ptr = (uint8_t *)ptr + offsetof(event2_header_t, digests);
+	((tpml_digest_values *)ptr)->count = HASH_ALG_COUNT;
+
+	/* TCG_PCR_EVENT2.Digests[] */
+	ptr = (uint8_t *)((uintptr_t)ptr +
+			offsetof(tpml_digest_values, digests));
+
+	/* TCG_PCR_EVENT2.Digests[].AlgorithmId */
+	((tpmt_ha *)ptr)->algorithm_id = TPM_ALG_ID;
+
+	/* TCG_PCR_EVENT2.Digests[].Digest[] */
+	ptr = (uint8_t *)((uintptr_t)ptr + offsetof(tpmt_ha, digest));
+
+	/* Copy digest */
+	(void)memcpy(ptr, (const void *)hash, TCG_DIGEST_SIZE);
+
+	/* TCG_PCR_EVENT2.EventSize */
+	ptr = (uint8_t *)((uintptr_t)ptr + TCG_DIGEST_SIZE);
+	((event2_data_t *)ptr)->event_size = name_len;
+
+	/* Copy event data to TCG_PCR_EVENT2.Event */
+	(void)memcpy((void *)(((event2_data_t *)ptr)->event),
+			(const void *)metadata_ptr->name, name_len);
+
+	/* End of event data */
+	log_ptr = (uint8_t *)((uintptr_t)ptr +
+			offsetof(event2_data_t, event) + name_len);
+}
+
+/*
+ * Initialise Event Log global variables, used during the recording
+ * of various payload measurements into the Event Log buffer
+ *
+ * @param[in] event_log_start		Base address of Event Log buffer
+ * @param[in] event_log_finish		End address of Event Log buffer,
+ * 					it is a first byte past end of the
+ * 					buffer
+ */
+void event_log_init(uint8_t *event_log_start, uint8_t *event_log_finish)
+{
+	assert(event_log_start != NULL);
+	assert(event_log_finish > event_log_start);
+
+	log_ptr = event_log_start;
+	log_end = (uintptr_t)event_log_finish;
+
+	/* Get pointer to platform's event_log_metadata_t structure */
+	plat_metadata_ptr = plat_event_log_get_metadata();
+	assert(plat_metadata_ptr != NULL);
+}
+
+/*
+ * Initialises Event Log by writing Specification ID and
+ * Startup Locality events
+ */
+void event_log_write_header(void)
+{
+	const char locality_signature[] = TCG_STARTUP_LOCALITY_SIGNATURE;
+	void *ptr = log_ptr;
+
+	/* event_log_init() must have been called prior to this. */
+	assert(log_ptr != NULL);
+
+	/*
+	 * Add Specification ID Event first
+	 *
+	 * Copy TCG_EfiSpecIDEventStruct structure header
+	 */
+	(void)memcpy(ptr, (const void *)&id_event_header,
+			sizeof(id_event_header));
+	ptr = (uint8_t *)((uintptr_t)ptr + sizeof(id_event_header));
+
+	/* TCG_EfiSpecIdEventAlgorithmSize structure */
+	((id_event_algorithm_size_t *)ptr)->algorithm_id = TPM_ALG_ID;
+	((id_event_algorithm_size_t *)ptr)->digest_size = TCG_DIGEST_SIZE;
+	ptr = (uint8_t *)((uintptr_t)ptr + sizeof(id_event_algorithm_size_t));
+
+	/*
+	 * TCG_EfiSpecIDEventStruct.vendorInfoSize
+	 * No vendor data
+	 */
+	((id_event_struct_data_t *)ptr)->vendor_info_size = 0;
+	ptr = (uint8_t *)((uintptr_t)ptr +
+			offsetof(id_event_struct_data_t, vendor_info));
+
+	/*
+	 * The Startup Locality event should be placed in the log before
+	 * any event which extends PCR[0].
+	 *
+	 * Ref. TCG PC Client Platform Firmware Profile 9.4.5.3
+	 */
+
+	/* Copy Startup Locality Event Header */
+	(void)memcpy(ptr, (const void *)&locality_event_header,
+			sizeof(locality_event_header));
+	ptr = (uint8_t *)((uintptr_t)ptr + sizeof(locality_event_header));
+
+	/* TCG_PCR_EVENT2.Digests[].AlgorithmId */
+	((tpmt_ha *)ptr)->algorithm_id = TPM_ALG_ID;
+
+	/* TCG_PCR_EVENT2.Digests[].Digest[] */
+	(void)memset(&((tpmt_ha *)ptr)->digest, 0, TPM_ALG_ID);
+	ptr = (uint8_t *)((uintptr_t)ptr +
+			offsetof(tpmt_ha, digest) + TCG_DIGEST_SIZE);
+
+	/* TCG_PCR_EVENT2.EventSize */
+	((event2_data_t *)ptr)->event_size =
+		(uint32_t)sizeof(startup_locality_event_t);
+	ptr = (uint8_t *)((uintptr_t)ptr + offsetof(event2_data_t, event));
+
+	/* TCG_EfiStartupLocalityEvent.Signature */
+	(void)memcpy(ptr, (const void *)locality_signature,
+		sizeof(TCG_STARTUP_LOCALITY_SIGNATURE));
+
+	/*
+	 * TCG_EfiStartupLocalityEvent.StartupLocality = 0:
+	 * the platform's boot firmware
+	 */
+	((startup_locality_event_t *)ptr)->startup_locality = 0U;
+	log_ptr = (uint8_t *)((uintptr_t)ptr + sizeof(startup_locality_event_t));
+}
+
+/*
+ * Calculate and write hash of image, configuration data, etc.
+ * to Event Log.
+ *
+ * @param[in] data_base		Address of data
+ * @param[in] data_size		Size of data
+ * @param[in] data_id		Data ID
+ * @return:
+ *	0 = success
+ *    < 0 = error
+ */
+int event_log_measure_and_record(uintptr_t data_base, uint32_t data_size,
+				 uint32_t data_id)
+{
+	unsigned char hash_data[MBEDTLS_MD_MAX_SIZE];
+	int rc;
+	const event_log_metadata_t *metadata_ptr = plat_metadata_ptr;
+
+	/* Get the metadata associated with this image. */
+	while ((metadata_ptr->id != INVALID_ID) &&
+		(metadata_ptr->id != data_id)) {
+		metadata_ptr++;
+	}
+	assert(metadata_ptr->id != INVALID_ID);
+
+	/* Calculate hash */
+	rc = crypto_mod_calc_hash((unsigned int)MBEDTLS_MD_ID,
+				(void *)data_base, data_size, hash_data);
+	if (rc != 0) {
+		return rc;
+	}
+
+	event_log_record(hash_data, metadata_ptr);
+
+	return 0;
+}
+
+/*
+ * Get current Event Log buffer size i.e. used space of Event Log buffer
+ *
+ * @param[in]  event_log_start		Base Pointer to Event Log buffer
+ *
+ * @return: current Size of Event Log buffer
+ */
+size_t event_log_get_cur_size(uint8_t *event_log_start)
+{
+	assert(event_log_start != NULL);
+	assert(log_ptr >= event_log_start);
+
+	return (size_t)((uintptr_t)log_ptr - (uintptr_t)event_log_start);
+}
diff --git a/drivers/measured_boot/measured_boot.mk b/drivers/measured_boot/event_log/event_log.mk
similarity index 63%
rename from drivers/measured_boot/measured_boot.mk
rename to drivers/measured_boot/event_log/event_log.mk
index 497fdba..37e5e29 100644
--- a/drivers/measured_boot/measured_boot.mk
+++ b/drivers/measured_boot/event_log/event_log.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2020, Arm Limited. All rights reserved.
+# Copyright (c) 2020-2021, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -7,7 +7,8 @@
 # Default log level to dump the event log (LOG_LEVEL_INFO)
 EVENT_LOG_LEVEL         ?= 40
 
-# TPM hash algorithm
+# TPM hash algorithm.
+# SHA-256 (or stronger) is required for all devices that are TPM 2.0 compliant.
 TPM_HASH_ALG			:=	sha256
 
 ifeq (${TPM_HASH_ALG}, sha512)
@@ -24,8 +25,6 @@
     TCG_DIGEST_SIZE		:=	32U
 endif
 
-# Event Log length in bytes
-EVENT_LOG_SIZE			:= 1024
 
 # Set definitions for mbed TLS library and Measured Boot driver
 $(eval $(call add_defines,\
@@ -33,20 +32,19 @@
         MBEDTLS_MD_ID \
         TPM_ALG_ID \
         TCG_DIGEST_SIZE \
-        EVENT_LOG_SIZE \
         EVENT_LOG_LEVEL \
 )))
 
 ifeq (${HASH_ALG}, sha256)
-ifneq (${TPM_HASH_ALG}, sha256)
-$(eval $(call add_define,MBEDTLS_SHA512_C))
-endif
+    ifneq (${TPM_HASH_ALG}, sha256)
+        $(eval $(call add_define,MBEDTLS_SHA512_C))
+    endif
 endif
 
-MEASURED_BOOT_SRC_DIR	:= drivers/measured_boot/
+MEASURED_BOOT_SRC_DIR	:= drivers/measured_boot/event_log/
 
-MEASURED_BOOT_SOURCES	:= ${MEASURED_BOOT_SRC_DIR}measured_boot.c	\
-    			   ${MEASURED_BOOT_SRC_DIR}event_log.c		\
-    			   ${MEASURED_BOOT_SRC_DIR}event_print.c
+MEASURED_BOOT_SOURCES	:= ${MEASURED_BOOT_SRC_DIR}event_log.c		\
+			   ${MEASURED_BOOT_SRC_DIR}event_print.c
 
 BL2_SOURCES		+= ${MEASURED_BOOT_SOURCES}
+BL1_SOURCES             += ${MEASURED_BOOT_SOURCES}
diff --git a/drivers/measured_boot/event_print.c b/drivers/measured_boot/event_log/event_print.c
similarity index 98%
rename from drivers/measured_boot/event_print.c
rename to drivers/measured_boot/event_log/event_print.c
index 84ed4b1..e2ba174 100644
--- a/drivers/measured_boot/event_print.c
+++ b/drivers/measured_boot/event_log/event_print.c
@@ -8,7 +8,7 @@
 #include <string.h>
 
 #include <common/debug.h>
-#include <drivers/measured_boot/event_log.h>
+#include <drivers/measured_boot/event_log/event_log.h>
 
 #if LOG_LEVEL >= EVENT_LOG_LEVEL
 
diff --git a/drivers/measured_boot/measured_boot.c b/drivers/measured_boot/measured_boot.c
deleted file mode 100644
index 37fddfb..0000000
--- a/drivers/measured_boot/measured_boot.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <assert.h>
-
-#include <common/debug.h>
-#include <drivers/measured_boot/measured_boot.h>
-
-/*
- * Init Measured Boot driver
- *
- * Initialises Event Log.
- */
-void measured_boot_init(void)
-{
-	event_log_init();
-}
-
-/*
- * Finish Measured Boot driver
- *
- * Finalises Event Log and dumps the records to the debug console.
- */
-void measured_boot_finish(void)
-{
-	uint8_t *log_addr;
-	size_t log_size;
-	int rc;
-
-	rc = event_log_finalise(&log_addr, &log_size);
-	if (rc != 0) {
-		panic();
-	}
-
-	dump_event_log(log_addr, log_size);
-}
diff --git a/fdts/fvp-base-gicv3-psci-common.dtsi b/fdts/fvp-base-gicv3-psci-common.dtsi
index b6753de..3cb613f 100644
--- a/fdts/fvp-base-gicv3-psci-common.dtsi
+++ b/fdts/fvp-base-gicv3-psci-common.dtsi
@@ -24,7 +24,11 @@
 	#address-cells = <2>;
 	#size-cells = <2>;
 
-	chosen { };
+#if (ENABLE_RME == 1)
+	chosen { bootargs = "mem=1G console=ttyAMA0 earlycon=pl011,0x1c090000 root=/dev/vda ip=on";};
+#else
+	chosen {};
+#endif
 
 	aliases {
 		serial0 = &v2m_serial0;
@@ -135,8 +139,13 @@
 
 	memory@80000000 {
 		device_type = "memory";
+#if (ENABLE_RME == 1)
+		reg = <0x00000000 0x80000000 0 0x7C000000>,
+		      <0x00000008 0x80000000 0 0x80000000>;
+#else
 		reg = <0x00000000 0x80000000 0 0x7F000000>,
 		      <0x00000008 0x80000000 0 0x80000000>;
+#endif
 	};
 
 	gic: interrupt-controller@2f000000 {
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index 1b3ae02..74bc8cb 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -182,6 +182,11 @@
 #define ID_AA64PFR0_CSV2_SHIFT	U(56)
 #define ID_AA64PFR0_CSV2_MASK	ULL(0xf)
 #define ID_AA64PFR0_CSV2_LENGTH	U(4)
+#define ID_AA64PFR0_FEAT_RME_SHIFT		U(52)
+#define ID_AA64PFR0_FEAT_RME_MASK		ULL(0xf)
+#define ID_AA64PFR0_FEAT_RME_LENGTH		U(4)
+#define ID_AA64PFR0_FEAT_RME_NOT_SUPPORTED	U(0)
+#define ID_AA64PFR0_FEAT_RME_V1			U(1)
 
 /* Exception level handling */
 #define EL_IMPL_NONE		ULL(0)
@@ -432,6 +437,9 @@
 
 /* SCR definitions */
 #define SCR_RES1_BITS		((U(1) << 4) | (U(1) << 5))
+#define SCR_NSE_SHIFT		U(62)
+#define SCR_NSE_BIT		(ULL(1) << SCR_NSE_SHIFT)
+#define SCR_GPF_BIT		(UL(1) << 48)
 #define SCR_TWEDEL_SHIFT	U(30)
 #define SCR_TWEDEL_MASK		ULL(0xf)
 #define SCR_HXEn_BIT            (UL(1) << 38)
@@ -440,6 +448,7 @@
 #define SCR_ECVEN_BIT		(UL(1) << 28)
 #define SCR_FGTEN_BIT		(UL(1) << 27)
 #define SCR_ATA_BIT		(UL(1) << 26)
+#define SCR_EnSCXT_BIT		(UL(1) << 25)
 #define SCR_FIEN_BIT		(UL(1) << 21)
 #define SCR_EEL2_BIT		(UL(1) << 18)
 #define SCR_API_BIT		(UL(1) << 17)
@@ -576,6 +585,10 @@
 #define CPTR_EL2_TZ_BIT		(U(1) << 8)
 #define CPTR_EL2_RESET_VAL	CPTR_EL2_RES1
 
+/* VTCR_EL2 definitions */
+#define VTCR_RESET_VAL         U(0x0)
+#define VTCR_EL2_MSA           (U(1) << 31)
+
 /* CPSR/SPSR definitions */
 #define DAIF_FIQ_BIT		(U(1) << 0)
 #define DAIF_IRQ_BIT		(U(1) << 1)
@@ -601,6 +614,7 @@
 #define SPSR_M_MASK		U(0x1)
 #define SPSR_M_AARCH64		U(0x0)
 #define SPSR_M_AARCH32		U(0x1)
+#define SPSR_M_EL2H		U(0x9)
 
 #define SPSR_EL_SHIFT		U(2)
 #define SPSR_EL_WIDTH		U(2)
@@ -1093,6 +1107,12 @@
 #define AMEVCNTVOFF1F_EL2	S3_4_C13_C11_7
 
 /*******************************************************************************
+ * Realm management extension register definitions
+ ******************************************************************************/
+#define GPCCR_EL3			S3_6_C2_C1_6
+#define GPTBR_EL3			S3_6_C2_C1_4
+
+/*******************************************************************************
  * RAS system registers
  ******************************************************************************/
 #define DISR_EL1		S3_0_C12_C1_1
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
index 3ff67e5..46cd1c9 100644
--- a/include/arch/aarch64/arch_features.h
+++ b/include/arch/aarch64/arch_features.h
@@ -123,4 +123,15 @@
 		ID_AA64MMFR1_EL1_HCX_MASK) == ID_AA64MMFR1_EL1_HCX_SUPPORTED);
 }
 
+static inline unsigned int get_armv9_2_feat_rme_support(void)
+{
+	/*
+	 * Return the RME version, zero if not supported.  This function can be
+	 * used as both an integer value for the RME version or compared to zero
+	 * to detect RME presence.
+	 */
+	return (unsigned int)(read_id_aa64pfr0_el1() >>
+		ID_AA64PFR0_FEAT_RME_SHIFT) & ID_AA64PFR0_FEAT_RME_MASK;
+}
+
 #endif /* ARCH_FEATURES_H */
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index 72b87c8..cae05dc 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -442,6 +442,8 @@
 DEFINE_SYSREG_READ_FUNC(cntpct_el0)
 DEFINE_SYSREG_RW_FUNCS(cnthctl_el2)
 
+DEFINE_SYSREG_RW_FUNCS(vtcr_el2)
+
 #define get_cntp_ctl_enable(x)  (((x) >> CNTP_CTL_ENABLE_SHIFT) & \
 					CNTP_CTL_ENABLE_MASK)
 #define get_cntp_ctl_imask(x)   (((x) >> CNTP_CTL_IMASK_SHIFT) & \
@@ -540,6 +542,10 @@
 /* DynamIQ Shared Unit power management */
 DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpwrdn_el1, CLUSTERPWRDN_EL1)
 
+/* Armv9.2 RME Registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(gptbr_el3, GPTBR_EL3)
+DEFINE_RENAME_SYSREG_RW_FUNCS(gpccr_el3, GPCCR_EL3)
+
 #define IS_IN_EL(x) \
 	(GET_EL(read_CurrentEl()) == MODE_EL##x)
 
@@ -583,7 +589,28 @@
 	}
 }
 
+/*
+ * TLBIPAALLOS instruction
+ * (TLB Inivalidate GPT Information by PA,
+ * All Entries, Outer Shareable)
+ */
+static inline void tlbipaallos(void)
+{
+	__asm__("SYS #6,c8,c1,#4");
+}
+
+/*
+ * Invalidate cached copies of GPT entries
+ * from TLBs by physical address
+ *
+ * @pa: the starting address for the range
+ *      of invalidation
+ * @size: size of the range of invalidation
+ */
+void gpt_tlbi_by_pa(uint64_t pa, size_t size);
+
+
-/* Previously defined accesor functions with incomplete register names  */
+/* Previously defined accessor functions with incomplete register names  */
 
 #define read_current_el()	read_CurrentEl()
 
diff --git a/include/arch/aarch64/el3_common_macros.S b/include/arch/aarch64/el3_common_macros.S
index d496584..7d6a963 100644
--- a/include/arch/aarch64/el3_common_macros.S
+++ b/include/arch/aarch64/el3_common_macros.S
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -88,6 +88,13 @@
 	 */
 	orr	x0, x0, #(SCR_API_BIT | SCR_APK_BIT)
 #endif
+#if ENABLE_RME
+	/*
+	 * TODO: Settting the EEL2 bit to allow EL3 access to secure only registers
+	 * in context management. This will need to be refactored.
+	 */
+	orr	x0, x0, #SCR_EEL2_BIT
+#endif
 	msr	scr_el3, x0
 
 	/* ---------------------------------------------------------------------
@@ -365,6 +372,7 @@
 	msr	vbar_el3, x0
 	isb
 
+#if !(defined(IMAGE_BL2) && ENABLE_RME)
 	/* ---------------------------------------------------------------------
 	 * It is a cold boot.
 	 * Perform any processor specific actions upon reset e.g. cache, TLB
@@ -372,6 +380,7 @@
 	 * ---------------------------------------------------------------------
 	 */
 	bl	reset_handler
+#endif
 
 	el3_arch_init_common
 
@@ -414,7 +423,8 @@
 	 * ---------------------------------------------------------------------
 	 */
 	.if \_init_c_runtime
-#if defined(IMAGE_BL31) || (defined(IMAGE_BL2) && BL2_AT_EL3 && BL2_INV_DCACHE)
+#if defined(IMAGE_BL31) || (defined(IMAGE_BL2) && \
+	((BL2_AT_EL3 && BL2_INV_DCACHE) || ENABLE_RME))
 		/* -------------------------------------------------------------
 		 * Invalidate the RW memory used by the BL31 image. This
 		 * includes the data and NOBITS sections. This is done to
diff --git a/include/bl31/bl31.h b/include/bl31/bl31.h
index 3deb0a5..1d58ef9 100644
--- a/include/bl31/bl31.h
+++ b/include/bl31/bl31.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -19,6 +19,7 @@
 uint32_t bl31_get_next_image_type(void);
 void bl31_prepare_next_image_entry(void);
 void bl31_register_bl32_init(int32_t (*func)(void));
+void bl31_register_rmm_init(int32_t (*func)(void));
 void bl31_warm_entrypoint(void);
 void bl31_main(void);
 void bl31_lib_init(void);
diff --git a/include/common/bl_common.h b/include/common/bl_common.h
index e33840c..8cb4990 100644
--- a/include/common/bl_common.h
+++ b/include/common/bl_common.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -126,6 +126,8 @@
 IMPORT_SYM(uintptr_t, __BL31_END__,		BL31_END);
 #elif defined(IMAGE_BL32)
 IMPORT_SYM(uintptr_t, __BL32_END__,		BL32_END);
+#elif defined(IMAGE_RMM)
+IMPORT_SYM(uintptr_t, __RMM_END__,		RMM_END);
 #endif /* IMAGE_BLX */
 
 /* The following symbols are only exported from the BL2 at EL3 linker script. */
diff --git a/include/common/ep_info.h b/include/common/ep_info.h
index 4bfa1fa..771572c 100644
--- a/include/common/ep_info.h
+++ b/include/common/ep_info.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -18,14 +18,21 @@
 
 #define SECURE		EP_SECURE
 #define NON_SECURE	EP_NON_SECURE
+#define REALM		EP_REALM
+#if ENABLE_RME
+#define sec_state_is_valid(s)	(((s) == SECURE) ||	\
+				((s) == NON_SECURE) ||	\
+				((s) == REALM))
+#else
 #define sec_state_is_valid(s) (((s) == SECURE) || ((s) == NON_SECURE))
+#endif
 
 #define PARAM_EP_SECURITY_MASK	EP_SECURITY_MASK
 
 #define NON_EXECUTABLE	EP_NON_EXECUTABLE
 #define EXECUTABLE	EP_EXECUTABLE
 
-/* Secure or Non-secure image */
+/* Get/set security state of an image */
 #define GET_SECURITY_STATE(x) ((x) & EP_SECURITY_MASK)
 #define SET_SECURITY_STATE(x, security) \
 			((x) = ((x) & ~EP_SECURITY_MASK) | (security))
diff --git a/include/drivers/measured_boot/event_log.h b/include/drivers/measured_boot/event_log.h
deleted file mode 100644
index efde117..0000000
--- a/include/drivers/measured_boot/event_log.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef EVENT_LOG_H
-#define EVENT_LOG_H
-
-#include <stdint.h>
-
-#include <common/debug.h>
-#include <drivers/measured_boot/tcg.h>
-
-/*
- * Set Event Log debug level to one of:
- *
- * LOG_LEVEL_ERROR
- * LOG_LEVEL_INFO
- * LOG_LEVEL_WARNING
- * LOG_LEVEL_VERBOSE
- */
-#if EVENT_LOG_LEVEL   == LOG_LEVEL_ERROR
-#define	LOG_EVENT	ERROR
-#elif EVENT_LOG_LEVEL == LOG_LEVEL_NOTICE
-#define	LOG_EVENT	NOTICE
-#elif EVENT_LOG_LEVEL == LOG_LEVEL_WARNING
-#define	LOG_EVENT	WARN
-#elif EVENT_LOG_LEVEL == LOG_LEVEL_INFO
-#define	LOG_EVENT	INFO
-#elif EVENT_LOG_LEVEL == LOG_LEVEL_VERBOSE
-#define	LOG_EVENT	VERBOSE
-#else
-#error "Not supported EVENT_LOG_LEVEL"
-#endif
-
-/* Number of hashing algorithms supported */
-#define HASH_ALG_COUNT	1U
-
-#define	INVALID_ID	MAX_NUMBER_IDS
-
-#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
-
-#define BL2_STRING			"BL_2"
-#define BL31_STRING			"BL_31"
-#define BL32_STRING			"BL_32"
-#define	BL32_EXTRA1_IMAGE_STRING	"BL32_EXTRA1_IMAGE"
-#define	BL32_EXTRA2_IMAGE_STRING	"BL32_EXTRA2_IMAGE"
-#define BL33_STRING			"BL_33"
-#define GPT_IMAGE_STRING		"GPT"
-#define HW_CONFIG_STRING		"HW_CONFIG"
-#define NT_FW_CONFIG_STRING		"NT_FW_CONFIG"
-#define SCP_BL2_IMAGE_STRING		"SCP_BL2_IMAGE"
-#define SOC_FW_CONFIG_STRING		"SOC_FW_CONFIG"
-#define STM32_IMAGE_STRING		"STM32"
-#define	TOS_FW_CONFIG_STRING		"TOS_FW_CONFIG"
-
-typedef struct {
-	unsigned int id;
-	const char *name;
-	unsigned int pcr;
-} image_data_t;
-
-typedef struct {
-	const image_data_t *images_data;
-	int (*set_nt_fw_info)(uintptr_t config_base,
-#ifdef SPD_opteed
-				uintptr_t log_addr,
-#endif
-				size_t log_size, uintptr_t *ns_log_addr);
-	int (*set_tos_fw_info)(uintptr_t config_base, uintptr_t log_addr,
-				size_t log_size);
-} measured_boot_data_t;
-
-#define	ID_EVENT_SIZE	(sizeof(id_event_headers_t) + \
-			(sizeof(id_event_algorithm_size_t) * HASH_ALG_COUNT) + \
-			sizeof(id_event_struct_data_t))
-
-#define	LOC_EVENT_SIZE	(sizeof(event2_header_t) + \
-			sizeof(tpmt_ha) + TCG_DIGEST_SIZE + \
-			sizeof(event2_data_t) + \
-			sizeof(startup_locality_event_t))
-
-#define	LOG_MIN_SIZE	(ID_EVENT_SIZE + LOC_EVENT_SIZE)
-
-#define EVENT2_HDR_SIZE	(sizeof(event2_header_t) + \
-			sizeof(tpmt_ha) + TCG_DIGEST_SIZE + \
-			sizeof(event2_data_t))
-
-/* Functions' declarations */
-void event_log_init(void);
-int event_log_finalise(uint8_t **log_addr, size_t *log_size);
-void dump_event_log(uint8_t *log_addr, size_t log_size);
-const measured_boot_data_t *plat_get_measured_boot_data(void);
-int tpm_record_measurement(uintptr_t data_base, uint32_t data_size,
-			   uint32_t data_id);
-#endif /* EVENT_LOG_H */
diff --git a/include/drivers/measured_boot/event_log/event_log.h b/include/drivers/measured_boot/event_log/event_log.h
new file mode 100644
index 0000000..c6eb29c
--- /dev/null
+++ b/include/drivers/measured_boot/event_log/event_log.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef EVENT_LOG_H
+#define EVENT_LOG_H
+
+#include <stdint.h>
+
+#include <common/debug.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/measured_boot/event_log/tcg.h>
+
+/*
+ * Set Event Log debug level to one of:
+ *
+ * LOG_LEVEL_ERROR
+ * LOG_LEVEL_INFO
+ * LOG_LEVEL_WARNING
+ * LOG_LEVEL_VERBOSE
+ */
+#if EVENT_LOG_LEVEL   == LOG_LEVEL_ERROR
+#define	LOG_EVENT	ERROR
+#elif EVENT_LOG_LEVEL == LOG_LEVEL_NOTICE
+#define	LOG_EVENT	NOTICE
+#elif EVENT_LOG_LEVEL == LOG_LEVEL_WARNING
+#define	LOG_EVENT	WARN
+#elif EVENT_LOG_LEVEL == LOG_LEVEL_INFO
+#define	LOG_EVENT	INFO
+#elif EVENT_LOG_LEVEL == LOG_LEVEL_VERBOSE
+#define	LOG_EVENT	VERBOSE
+#else
+#error "Not supported EVENT_LOG_LEVEL"
+#endif
+
+/* Number of hashing algorithms supported */
+#define HASH_ALG_COUNT	1U
+
+#define	INVALID_ID	MAX_NUMBER_IDS
+
+#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
+
+/*
+ * Each event log entry has some metadata (i.e. a string) that identifies
+ * what is measured.These macros define these strings.
+ * Note that these strings follow the standardization recommendations
+ * defined in the Arm Server Base Security Guide (a.k.a. SBSG, Arm DEN 0086),
+ * where applicable. They should not be changed in the code.
+ * Where the SBSG does not make recommendations, we are free to choose any
+ * naming convention.
+ * The key thing is to choose meaningful strings so that when the TPM event
+ * log is used in attestation, the different components can be identified.
+ */
+#define EVLOG_BL2_STRING		"BL_2"
+#define EVLOG_BL31_STRING		"SECURE_RT_EL3"
+#if defined(SPD_opteed)
+#define EVLOG_BL32_STRING		"SECURE_RT_EL1_OPTEE"
+#elif defined(SPD_tspd)
+#define EVLOG_BL32_STRING		"SECURE_RT_EL1_TSPD"
+#elif defined(SPD_tlkd)
+#define EVLOG_BL32_STRING		"SECURE_RT_EL1_TLKD"
+#elif defined(SPD_trusty)
+#define EVLOG_BL32_STRING		"SECURE_RT_EL1_TRUSTY"
+#else
+#define EVLOG_BL32_STRING		"SECURE_RT_EL1_UNKNOWN"
+#endif
+#define	EVLOG_BL32_EXTRA1_STRING	"SECURE_RT_EL1_OPTEE_EXTRA1"
+#define	EVLOG_BL32_EXTRA2_STRING	"SECURE_RT_EL1_OPTEE_EXTRA2"
+#define EVLOG_BL33_STRING		"BL_33"
+#define EVLOG_FW_CONFIG_STRING		"FW_CONFIG"
+#define EVLOG_HW_CONFIG_STRING		"HW_CONFIG"
+#define EVLOG_NT_FW_CONFIG_STRING	"NT_FW_CONFIG"
+#define EVLOG_SCP_BL2_STRING		"SYS_CTRL_2"
+#define EVLOG_SOC_FW_CONFIG_STRING	"SOC_FW_CONFIG"
+#define EVLOG_STM32_STRING		"STM32"
+#define EVLOG_TB_FW_CONFIG_STRING	"TB_FW_CONFIG"
+#define	EVLOG_TOS_FW_CONFIG_STRING	"TOS_FW_CONFIG"
+
+typedef struct {
+	unsigned int id;
+	const char *name;
+	unsigned int pcr;
+} event_log_metadata_t;
+
+#define	ID_EVENT_SIZE	(sizeof(id_event_headers_t) + \
+			(sizeof(id_event_algorithm_size_t) * HASH_ALG_COUNT) + \
+			sizeof(id_event_struct_data_t))
+
+#define	LOC_EVENT_SIZE	(sizeof(event2_header_t) + \
+			sizeof(tpmt_ha) + TCG_DIGEST_SIZE + \
+			sizeof(event2_data_t) + \
+			sizeof(startup_locality_event_t))
+
+#define	LOG_MIN_SIZE	(ID_EVENT_SIZE + LOC_EVENT_SIZE)
+
+#define EVENT2_HDR_SIZE	(sizeof(event2_header_t) + \
+			sizeof(tpmt_ha) + TCG_DIGEST_SIZE + \
+			sizeof(event2_data_t))
+
+/* Functions' declarations */
+void event_log_init(uint8_t *event_log_start, uint8_t *event_log_finish);
+void event_log_write_header(void);
+void dump_event_log(uint8_t *log_addr, size_t log_size);
+const event_log_metadata_t *plat_event_log_get_metadata(void);
+int event_log_measure_and_record(uintptr_t data_base, uint32_t data_size,
+				 uint32_t data_id);
+size_t event_log_get_cur_size(uint8_t *event_log_start);
+
+#endif /* EVENT_LOG_H */
diff --git a/include/drivers/measured_boot/tcg.h b/include/drivers/measured_boot/event_log/tcg.h
similarity index 100%
rename from include/drivers/measured_boot/tcg.h
rename to include/drivers/measured_boot/event_log/tcg.h
diff --git a/include/drivers/measured_boot/measured_boot.h b/include/drivers/measured_boot/measured_boot.h
deleted file mode 100644
index 05be4a9..0000000
--- a/include/drivers/measured_boot/measured_boot.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (c) 2020-2021, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#ifndef MEASURED_BOOT_H
-#define MEASURED_BOOT_H
-
-#include <stdint.h>
-
-#include <drivers/measured_boot/event_log.h>
-
-/* Functions' declarations */
-void measured_boot_init(void);
-void measured_boot_finish(void);
-
-#endif /* MEASURED_BOOT_H */
diff --git a/include/drivers/nxp/flexspi/flash_info.h b/include/drivers/nxp/flexspi/flash_info.h
index 94c9f02..d0ffc86 100644
--- a/include/drivers/nxp/flexspi/flash_info.h
+++ b/include/drivers/nxp/flexspi/flash_info.h
@@ -12,6 +12,7 @@
 
 #define SZ_16M_BYTES			0x1000000U
 
+/* Start of "if defined(CONFIG_MT25QU512A)" */
 #if defined(CONFIG_MT25QU512A)
 #define F_SECTOR_64K			0x10000U
 #define F_PAGE_256			0x100U
@@ -22,6 +23,9 @@
 #define F_SECTOR_ERASE_SZ		F_SECTOR_4K
 #endif
 
+/* End of "if defined(CONFIG_MT25QU512A)" */
+
+/* Start of "if defined(CONFIG_MX25U25645G)" */
 #elif defined(CONFIG_MX25U25645G)
 #define F_SECTOR_64K			0x10000U
 #define F_PAGE_256			0x100U
@@ -32,6 +36,9 @@
 #define F_SECTOR_ERASE_SZ		F_SECTOR_4K
 #endif
 
+/* End of "if defined(CONFIG_MX25U25645G)" */
+
+/* Start of "if defined(CONFIG_MX25U51245G)" */
 #elif defined(CONFIG_MX25U51245G)
 #define F_SECTOR_64K			0x10000U
 #define F_PAGE_256			0x100U
@@ -42,6 +49,9 @@
 #define F_SECTOR_ERASE_SZ		F_SECTOR_4K
 #endif
 
+/* End of "if defined(CONFIG_MX25U51245G)" */
+
+/* Start of "if defined(CONFIG_MT35XU512A)" */
 #elif defined(CONFIG_MT35XU512A)
 #define F_SECTOR_128K			0x20000U
 #define F_SECTOR_32K			0x8000U
@@ -52,7 +62,18 @@
 #ifdef CONFIG_FSPI_4K_ERASE
 #define F_SECTOR_ERASE_SZ		F_SECTOR_4K
 #endif
+/* If Warm boot is enabled for the platform,
+ * count of arm instruction N-OP(s) to mark
+ * the completion of write operation to flash;
+ * varies from one flash to other.
+ */
+#ifdef NXP_WARM_BOOT
+#define FLASH_WR_COMP_WAIT_BY_NOP_COUNT	0x20000
+#endif
 
+/* End of "if defined(CONFIG_MT35XU512A)" */
+
+/* Start of #elif defined(CONFIG_MT35XU02G) */
 #elif defined(CONFIG_MT35XU02G)
 #define F_SECTOR_128K			0x20000U
 #define F_PAGE_256			0x100U
@@ -63,9 +84,6 @@
 #define F_SECTOR_ERASE_SZ		F_SECTOR_4K
 #endif
 
-#ifdef NXP_WARM_BOOT
-#define FLASH_WR_COMP_WAIT_BY_NOP_COUNT	0x20000
-#endif
+#endif /* End of #elif defined(CONFIG_MT35XU02G) */
 
-#endif
 #endif /* FLASH_INFO_H */
diff --git a/include/export/common/ep_info_exp.h b/include/export/common/ep_info_exp.h
index 9d2969f..a5bd10a 100644
--- a/include/export/common/ep_info_exp.h
+++ b/include/export/common/ep_info_exp.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -24,11 +24,23 @@
 #define ENTRY_POINT_INFO_ARGS_OFFSET	U(0x14)
 #endif
 
-/* Security state of the image. */
-#define EP_SECURITY_MASK	UL(0x1)
+/*
+ * Security state of the image. Bit 0 and
+ * bit 5 are used to determine the security
+ * state of the image as follows:
+ *
+ * ---------------------------------
+ *  Bit 5 | Bit 0 | Security state
+ * ---------------------------------
+ *   0        0      EP_SECURE
+ *   0        1      EP_NON_SECURE
+ *   1        1      EP_REALM
+ */
+#define EP_SECURITY_MASK	UL(0x21)
 #define EP_SECURITY_SHIFT	UL(0)
 #define EP_SECURE		UL(0x0)
 #define EP_NON_SECURE		UL(0x1)
+#define EP_REALM		UL(0x21)
 
 /* Endianness of the image. */
 #define EP_EE_MASK		U(0x2)
diff --git a/include/export/common/tbbr/tbbr_img_def_exp.h b/include/export/common/tbbr/tbbr_img_def_exp.h
index 2623c75..98544c0 100644
--- a/include/export/common/tbbr/tbbr_img_def_exp.h
+++ b/include/export/common/tbbr/tbbr_img_def_exp.h
@@ -101,7 +101,10 @@
  */
 #define BKUP_FWU_METADATA_IMAGE_ID	U(33)
 
+/* Realm Monitor Manager (RMM) */
+#define RMM_IMAGE_ID			U(34)
+
 /* Max Images */
-#define MAX_IMAGE_IDS			U(34)
+#define MAX_IMAGE_IDS			U(35)
 
 #endif /* ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_TBBR_TBBR_IMG_DEF_EXP_H */
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
index c3f4117..698e208 100644
--- a/include/lib/el3_runtime/aarch64/context.h
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -405,13 +405,12 @@
 					 = (uint64_t) (val))
 
 /*
- * Top-level context structure which is used by EL3 firmware to
- * preserve the state of a core at EL1 in one of the two security
- * states and save enough EL3 meta data to be able to return to that
- * EL and security state. The context management library will be used
- * to ensure that SP_EL3 always points to an instance of this
- * structure at exception entry and exit. Each instance will
- * correspond to either the secure or the non-secure state.
+ * Top-level context structure which is used by EL3 firmware to preserve
+ * the state of a core at the next lower EL in a given security state and
+ * save enough EL3 meta data to be able to return to that EL and security
+ * state. The context management library will be used to ensure that
+ * SP_EL3 always points to an instance of this structure at exception
+ * entry and exit.
  */
 typedef struct cpu_context {
 	gp_regs_t gpregs_ctx;
diff --git a/include/lib/el3_runtime/cpu_data.h b/include/lib/el3_runtime/cpu_data.h
index 3d57a5c..2c7b619 100644
--- a/include/lib/el3_runtime/cpu_data.h
+++ b/include/lib/el3_runtime/cpu_data.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -19,16 +19,25 @@
 /* 8-bytes aligned size of psci_cpu_data structure */
 #define PSCI_CPU_DATA_SIZE_ALIGNED	((PSCI_CPU_DATA_SIZE + 7) & ~7)
 
+#if ENABLE_RME
+/* Size of cpu_context array */
+#define CPU_DATA_CONTEXT_NUM		3
 /* Offset of cpu_ops_ptr, size 8 bytes */
+#define CPU_DATA_CPU_OPS_PTR		0x18
+#else /* ENABLE_RME */
+#define CPU_DATA_CONTEXT_NUM		2
 #define CPU_DATA_CPU_OPS_PTR		0x10
+#endif /* ENABLE_RME */
 
 #if ENABLE_PAUTH
 /* 8-bytes aligned offset of apiakey[2], size 16 bytes */
-#define	CPU_DATA_APIAKEY_OFFSET		(0x18 + PSCI_CPU_DATA_SIZE_ALIGNED)
-#define CPU_DATA_CRASH_BUF_OFFSET	(CPU_DATA_APIAKEY_OFFSET + 0x10)
-#else
-#define CPU_DATA_CRASH_BUF_OFFSET	(0x18 + PSCI_CPU_DATA_SIZE_ALIGNED)
-#endif	/* ENABLE_PAUTH */
+#define	CPU_DATA_APIAKEY_OFFSET		(0x8 + PSCI_CPU_DATA_SIZE_ALIGNED \
+					     + CPU_DATA_CPU_OPS_PTR)
+#define CPU_DATA_CRASH_BUF_OFFSET	(0x10 + CPU_DATA_APIAKEY_OFFSET)
+#else /* ENABLE_PAUTH */
+#define CPU_DATA_CRASH_BUF_OFFSET	(0x8 + PSCI_CPU_DATA_SIZE_ALIGNED \
+					     + CPU_DATA_CPU_OPS_PTR)
+#endif /* ENABLE_PAUTH */
 
 /* need enough space in crash buffer to save 8 registers */
 #define CPU_DATA_CRASH_BUF_SIZE		64
@@ -65,11 +74,14 @@
 
 #ifndef __ASSEMBLER__
 
+#include <assert.h>
+#include <stdint.h>
+
 #include <arch_helpers.h>
 #include <lib/cassert.h>
 #include <lib/psci/psci.h>
+
 #include <platform_def.h>
-#include <stdint.h>
 
 /* Offsets for the cpu_data structure */
 #define CPU_DATA_PSCI_LOCK_OFFSET	__builtin_offsetof\
@@ -80,27 +92,34 @@
 		(cpu_data_t, platform_cpu_data)
 #endif
 
+typedef enum context_pas {
+	CPU_CONTEXT_SECURE = 0,
+	CPU_CONTEXT_NS,
+#if ENABLE_RME
+	CPU_CONTEXT_REALM,
+#endif
+	CPU_CONTEXT_NUM
+} context_pas_t;
+
 /*******************************************************************************
  * Function & variable prototypes
  ******************************************************************************/
 
 /*******************************************************************************
  * Cache of frequently used per-cpu data:
- *   Pointers to non-secure and secure security state contexts
+ *   Pointers to non-secure, realm, and secure security state contexts
  *   Address of the crash stack
  * It is aligned to the cache line boundary to allow efficient concurrent
  * manipulation of these pointers on different cpus
  *
- * TODO: Add other commonly used variables to this (tf_issues#90)
- *
  * The data structure and the _cpu_data accessors should not be used directly
  * by components that have per-cpu members. The member access macros should be
  * used for this.
  ******************************************************************************/
 typedef struct cpu_data {
 #ifdef __aarch64__
-	void *cpu_context[2];
-#endif
+	void *cpu_context[CPU_DATA_CONTEXT_NUM];
+#endif /* __aarch64__ */
 	uintptr_t cpu_ops_ptr;
 	struct psci_cpu_data psci_svc_cpu_data;
 #if ENABLE_PAUTH
@@ -122,6 +141,11 @@
 
 extern cpu_data_t percpu_data[PLATFORM_CORE_COUNT];
 
+#ifdef __aarch64__
+CASSERT(CPU_DATA_CONTEXT_NUM == CPU_CONTEXT_NUM,
+		assert_cpu_data_context_num_mismatch);
+#endif
+
 #if ENABLE_PAUTH
 CASSERT(CPU_DATA_APIAKEY_OFFSET == __builtin_offsetof
 	(cpu_data_t, apiakey),
@@ -160,6 +184,31 @@
 struct cpu_data *_cpu_data(void);
 #endif
 
+/*
+ * Returns the index of the cpu_context array for the given security state.
+ * All accesses to cpu_context should be through this helper to make sure
+ * an access is not out-of-bounds. The function assumes security_state is
+ * valid.
+ */
+static inline context_pas_t get_cpu_context_index(uint32_t security_state)
+{
+	if (security_state == SECURE) {
+		return CPU_CONTEXT_SECURE;
+	} else {
+#if ENABLE_RME
+		if (security_state == NON_SECURE) {
+			return CPU_CONTEXT_NS;
+		} else {
+			assert(security_state == REALM);
+			return CPU_CONTEXT_REALM;
+		}
+#else
+		assert(security_state == NON_SECURE);
+		return CPU_CONTEXT_NS;
+#endif
+	}
+}
+
 /**************************************************************************
  * APIs for initialising and accessing per-cpu data
  *************************************************************************/
diff --git a/include/lib/fconf/fconf_tbbr_getter.h b/include/lib/fconf/fconf_tbbr_getter.h
index 6066af6..db98b68 100644
--- a/include/lib/fconf/fconf_tbbr_getter.h
+++ b/include/lib/fconf/fconf_tbbr_getter.h
@@ -23,9 +23,6 @@
 	uint32_t disable_auth;
 	void *mbedtls_heap_addr;
 	size_t mbedtls_heap_size;
-#if MEASURED_BOOT
-	uint8_t bl2_hash_data[TCG_DIGEST_SIZE];
-#endif
 };
 
 extern struct tbbr_dyn_config_t tbbr_dyn_config;
diff --git a/include/lib/gpt_rme/gpt_rme.h b/include/lib/gpt_rme/gpt_rme.h
new file mode 100644
index 0000000..379b915
--- /dev/null
+++ b/include/lib/gpt_rme/gpt_rme.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPT_RME_H
+#define GPT_RME_H
+
+#include <stdint.h>
+
+#include <arch.h>
+
+/******************************************************************************/
+/* GPT helper macros and definitions                                          */
+/******************************************************************************/
+
+/*
+ * Structure for specifying a mapping range and it's properties. This should not
+ * be manually initialized, using the MAP_GPT_REGION_x macros is recommended as
+ * to avoid potential incompatibilities in the future.
+ */
+typedef struct pas_region {
+	uintptr_t	base_pa;	/* Base address for PAS. */
+	size_t		size;		/* Size of the PAS. */
+	unsigned int	attrs;		/* PAS GPI and entry type. */
+} pas_region_t;
+
+/* GPT GPI definitions */
+#define GPT_GPI_NO_ACCESS		U(0x0)
+#define GPT_GPI_SECURE			U(0x8)
+#define GPT_GPI_NS			U(0x9)
+#define GPT_GPI_ROOT			U(0xA)
+#define GPT_GPI_REALM			U(0xB)
+#define GPT_GPI_ANY			U(0xF)
+#define GPT_GPI_VAL_MASK		UL(0xF)
+
+/* PAS attribute GPI definitions. */
+#define GPT_PAS_ATTR_GPI_SHIFT		U(0)
+#define GPT_PAS_ATTR_GPI_MASK		U(0xF)
+#define GPT_PAS_ATTR_GPI(_attrs)	(((_attrs)			\
+					>> GPT_PAS_ATTR_GPI_SHIFT)	\
+					& GPT_PAS_ATTR_GPI_MASK)
+
+/* PAS attribute mapping type definitions */
+#define GPT_PAS_ATTR_MAP_TYPE_BLOCK	U(0x0)
+#define GPT_PAS_ATTR_MAP_TYPE_GRANULE	U(0x1)
+#define GPT_PAS_ATTR_MAP_TYPE_SHIFT	U(4)
+#define GPT_PAS_ATTR_MAP_TYPE_MASK	U(0x1)
+#define GPT_PAS_ATTR_MAP_TYPE(_attrs)	(((_attrs)			\
+					>> GPT_PAS_ATTR_MAP_TYPE_SHIFT)	\
+					& GPT_PAS_ATTR_MAP_TYPE_MASK)
+
+/*
+ * Macro to initialize the attributes field in the pas_region_t structure.
+ * [31:5] Reserved
+ * [4]    Mapping type (GPT_PAS_ATTR_MAP_TYPE_x definitions)
+ * [3:0]  PAS GPI type (GPT_GPI_x definitions)
+ */
+#define GPT_PAS_ATTR(_type, _gpi)					\
+	((((_type) & GPT_PAS_ATTR_MAP_TYPE_MASK)			\
+	  << GPT_PAS_ATTR_MAP_TYPE_SHIFT) |				\
+	(((_gpi) & GPT_PAS_ATTR_GPI_MASK)				\
+	 << GPT_PAS_ATTR_GPI_SHIFT))
+
+/*
+ * Macro to create a GPT entry for this PAS range as a block descriptor. If this
+ * region does not fit the requirements for a block descriptor then GPT
+ * initialization will fail.
+ */
+#define GPT_MAP_REGION_BLOCK(_pa, _sz, _gpi)				\
+	{								\
+		.base_pa = (_pa),					\
+		.size = (_sz),						\
+		.attrs = GPT_PAS_ATTR(GPT_PAS_ATTR_MAP_TYPE_BLOCK, (_gpi)), \
+	}
+
+/*
+ * Macro to create a GPT entry for this PAS range as a table descriptor. If this
+ * region does not fit the requirements for a table descriptor then GPT
+ * initialization will fail.
+ */
+#define GPT_MAP_REGION_GRANULE(_pa, _sz, _gpi)				\
+	{								\
+		.base_pa = (_pa),					\
+		.size = (_sz),						\
+		.attrs = GPT_PAS_ATTR(GPT_PAS_ATTR_MAP_TYPE_GRANULE, (_gpi)), \
+	}
+
+/******************************************************************************/
+/* GPT register field definitions                                             */
+/******************************************************************************/
+
+/*
+ * Least significant address bits protected by each entry in level 0 GPT. This
+ * field is read-only.
+ */
+#define GPCCR_L0GPTSZ_SHIFT	U(20)
+#define GPCCR_L0GPTSZ_MASK	U(0xF)
+
+typedef enum {
+	GPCCR_L0GPTSZ_30BITS	= U(0x0),
+	GPCCR_L0GPTSZ_34BITS	= U(0x4),
+	GPCCR_L0GPTSZ_36BITS	= U(0x6),
+	GPCCR_L0GPTSZ_39BITS	= U(0x9)
+} gpccr_l0gptsz_e;
+
+/* Granule protection check priority bit definitions */
+#define GPCCR_GPCP_SHIFT	U(17)
+#define GPCCR_GPCP_BIT		(ULL(1) << GPCCR_EL3_GPCP_SHIFT)
+
+/* Granule protection check bit definitions */
+#define GPCCR_GPC_SHIFT		U(16)
+#define GPCCR_GPC_BIT		(ULL(1) << GPCCR_GPC_SHIFT)
+
+/* Physical granule size bit definitions */
+#define GPCCR_PGS_SHIFT		U(14)
+#define GPCCR_PGS_MASK		U(0x3)
+#define SET_GPCCR_PGS(x)	(((x) & GPCCR_PGS_MASK) << GPCCR_PGS_SHIFT)
+
+typedef enum {
+	GPCCR_PGS_4K		= U(0x0),
+	GPCCR_PGS_64K		= U(0x1),
+	GPCCR_PGS_16K		= U(0x2)
+} gpccr_pgs_e;
+
+/* GPT fetch shareability attribute bit definitions */
+#define GPCCR_SH_SHIFT		U(12)
+#define GPCCR_SH_MASK		U(0x3)
+#define SET_GPCCR_SH(x)		(((x) & GPCCR_SH_MASK) << GPCCR_SH_SHIFT)
+
+typedef enum {
+	GPCCR_SH_NS		= U(0x0),
+	GPCCR_SH_OS		= U(0x2),
+	GPCCR_SH_IS		= U(0x3)
+} gpccr_sh_e;
+
+/* GPT fetch outer cacheability attribute bit definitions */
+#define GPCCR_ORGN_SHIFT	U(10)
+#define GPCCR_ORGN_MASK		U(0x3)
+#define SET_GPCCR_ORGN(x)	(((x) & GPCCR_ORGN_MASK) << GPCCR_ORGN_SHIFT)
+
+typedef enum {
+	GPCCR_ORGN_NC		= U(0x0),
+	GPCCR_ORGN_WB_RA_WA	= U(0x1),
+	GPCCR_ORGN_WT_RA_NWA	= U(0x2),
+	GPCCR_ORGN_WB_RA_NWA	= U(0x3)
+} gpccr_orgn_e;
+
+/* GPT fetch inner cacheability attribute bit definitions */
+#define GPCCR_IRGN_SHIFT	U(8)
+#define GPCCR_IRGN_MASK		U(0x3)
+#define SET_GPCCR_IRGN(x)	(((x) & GPCCR_IRGN_MASK) << GPCCR_IRGN_SHIFT)
+
+typedef enum {
+	GPCCR_IRGN_NC		= U(0x0),
+	GPCCR_IRGN_WB_RA_WA	= U(0x1),
+	GPCCR_IRGN_WT_RA_NWA	= U(0x2),
+	GPCCR_IRGN_WB_RA_NWA	= U(0x3)
+} gpccr_irgn_e;
+
+/* Protected physical address size bit definitions */
+#define GPCCR_PPS_SHIFT		U(0)
+#define GPCCR_PPS_MASK		U(0x7)
+#define SET_GPCCR_PPS(x)	(((x) & GPCCR_PPS_MASK) << GPCCR_PPS_SHIFT)
+
+typedef enum {
+	GPCCR_PPS_4GB		= U(0x0),
+	GPCCR_PPS_64GB		= U(0x1),
+	GPCCR_PPS_1TB		= U(0x2),
+	GPCCR_PPS_4TB		= U(0x3),
+	GPCCR_PPS_16TB		= U(0x4),
+	GPCCR_PPS_256TB		= U(0x5),
+	GPCCR_PPS_4PB		= U(0x6)
+} gpccr_pps_e;
+
+/* Base Address for the GPT bit definitions */
+#define GPTBR_BADDR_SHIFT	U(0)
+#define GPTBR_BADDR_VAL_SHIFT	U(12)
+#define GPTBR_BADDR_MASK	ULL(0xffffffffff)
+
+/******************************************************************************/
+/* GPT public APIs                                                            */
+/******************************************************************************/
+
+/*
+ * Public API that initializes the entire protected space to GPT_GPI_ANY using
+ * the L0 tables (block descriptors).  Ideally, this function is invoked prior
+ * to DDR discovery and initialization.  The MMU must be initialized before
+ * calling this function.
+ *
+ * Parameters
+ *   pps		PPS value to use for table generation
+ *   l0_mem_base	Base address of L0 tables in memory.
+ *   l0_mem_size	Total size of memory available for L0 tables.
+ *
+ * Return
+ *   Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_init_l0_tables(gpccr_pps_e pps,
+		       uintptr_t l0_mem_base,
+		       size_t l0_mem_size);
+
+/*
+ * Public API that carves out PAS regions from the L0 tables and builds any L1
+ * tables that are needed.  This function ideally is run after DDR discovery and
+ * initialization.  The L0 tables must have already been initialized to GPI_ANY
+ * when this function is called.
+ *
+ * Parameters
+ *   pgs		PGS value to use for table generation.
+ *   l1_mem_base	Base address of memory used for L1 tables.
+ *   l1_mem_size	Total size of memory available for L1 tables.
+ *   *pas_regions	Pointer to PAS regions structure array.
+ *   pas_count		Total number of PAS regions.
+ *
+ * Return
+ *   Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_init_pas_l1_tables(gpccr_pgs_e pgs,
+			   uintptr_t l1_mem_base,
+			   size_t l1_mem_size,
+			   pas_region_t *pas_regions,
+			   unsigned int pas_count);
+
+/*
+ * Public API to initialize the runtime gpt_config structure based on the values
+ * present in the GPTBR_EL3 and GPCCR_EL3 registers. GPT initialization
+ * typically happens in a bootloader stage prior to setting up the EL3 runtime
+ * environment for the granule transition service so this function detects the
+ * initialization from a previous stage. Granule protection checks must be
+ * enabled already or this function will return an error.
+ *
+ * Return
+ *   Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_runtime_init(void);
+
+/*
+ * Public API to enable granule protection checks once the tables have all been
+ * initialized.  This function is called at first initialization and then again
+ * later during warm boots of CPU cores.
+ *
+ * Return
+ *   Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_enable(void);
+
+/*
+ * Public API to disable granule protection checks.
+ */
+void gpt_disable(void);
+
+/*
+ * This function is the core of the granule transition service. When a granule
+ * transition request occurs it is routed to this function where the request is
+ * validated then fulfilled if possible.
+ *
+ * TODO: implement support for transitioning multiple granules at once.
+ *
+ * Parameters
+ *   base: Base address of the region to transition, must be aligned to granule
+ *         size.
+ *   size: Size of region to transition, must be aligned to granule size.
+ *   src_sec_state: Security state of the caller.
+ *   target_pas: Target PAS of the specified memory region.
+ *
+ * Return
+ *    Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_transition_pas(uint64_t base,
+		       size_t size,
+		       unsigned int src_sec_state,
+		       unsigned int target_pas);
+
+#endif /* GPT_RME_H */
diff --git a/include/lib/smccc.h b/include/lib/smccc.h
index deaeb1d..1a39f24 100644
--- a/include/lib/smccc.h
+++ b/include/lib/smccc.h
@@ -108,9 +108,24 @@
 #define SMC_ARCH_CALL_NOT_REQUIRED	-2
 #define SMC_ARCH_CALL_INVAL_PARAM	-3
 
-/* Various flags passed to SMC handlers */
+/*
+ * Various flags passed to SMC handlers
+ *
+ * Bit 5 and bit 0 of the flag are used to
+ * determine the source security state as
+ * follows:
+ * ---------------------------------
+ *  Bit 5 | Bit 0 | Security state
+ * ---------------------------------
+ *   0        0      SMC_FROM_SECURE
+ *   0        1      SMC_FROM_NON_SECURE
+ *   1        1      SMC_FROM_REALM
+ */
+
 #define SMC_FROM_SECURE		(U(0) << 0)
 #define SMC_FROM_NON_SECURE	(U(1) << 0)
+#define SMC_FROM_REALM		U(0x21)
+#define SMC_FROM_MASK		U(0x21)
 
 #ifndef __ASSEMBLER__
 
@@ -118,8 +133,18 @@
 
 #include <lib/cassert.h>
 
+#if ENABLE_RME
+#define is_caller_non_secure(_f)	(((_f) & SMC_FROM_MASK) \
+					  == SMC_FROM_NON_SECURE)
+#define is_caller_secure(_f)		(((_f) & SMC_FROM_MASK) \
+					  == SMC_FROM_SECURE)
+#define is_caller_realm(_f)		(((_f) & SMC_FROM_MASK) \
+					  == SMC_FROM_REALM)
+#define caller_sec_state(_f)		((_f) & SMC_FROM_MASK)
+#else /* ENABLE_RME */
 #define is_caller_non_secure(_f)	(((_f) & SMC_FROM_NON_SECURE) != U(0))
 #define is_caller_secure(_f)		(!is_caller_non_secure(_f))
+#endif /* ENABLE_RME */
 
 /* The macro below is used to identify a Standard Service SMC call */
 #define is_std_svc_call(_fid)		(GET_SMC_OEN(_fid) == OEN_STD_START)
diff --git a/include/lib/xlat_tables/xlat_tables.h b/include/lib/xlat_tables/xlat_tables.h
index 082bb5e..a156969 100644
--- a/include/lib/xlat_tables/xlat_tables.h
+++ b/include/lib/xlat_tables/xlat_tables.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -72,6 +72,13 @@
 #define MT_CODE			(MT_MEMORY | MT_RO | MT_EXECUTE)
 #define MT_RO_DATA		(MT_MEMORY | MT_RO | MT_EXECUTE_NEVER)
 
+/* Memory type for EL3 regions */
+#if ENABLE_RME
+#error FEAT_RME requires version 2 of the Translation Tables Library
+#else
+#define EL3_PAS			MT_SECURE
+#endif
+
 /*
  * Structure for specifying a single region of memory.
  */
diff --git a/include/lib/xlat_tables/xlat_tables_defs.h b/include/lib/xlat_tables/xlat_tables_defs.h
index 579d8d8..2d0949b 100644
--- a/include/lib/xlat_tables/xlat_tables_defs.h
+++ b/include/lib/xlat_tables/xlat_tables_defs.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -142,6 +142,7 @@
 #define AP_NO_ACCESS_UNPRIVILEGED	(AP1_NO_ACCESS_UNPRIVILEGED << 4)
 #define AP_ONE_VA_RANGE_RES1		(AP1_RES1 << 4)
 #define NS				(U(0x1) << 3)
+#define EL3_S1_NSE			(U(0x1) << 9)
 #define ATTR_NON_CACHEABLE_INDEX	ULL(0x2)
 #define ATTR_DEVICE_INDEX		ULL(0x1)
 #define ATTR_IWBWA_OWBWA_NTR_INDEX	ULL(0x0)
diff --git a/include/lib/xlat_tables/xlat_tables_v2.h b/include/lib/xlat_tables/xlat_tables_v2.h
index 359b983..69ad027 100644
--- a/include/lib/xlat_tables/xlat_tables_v2.h
+++ b/include/lib/xlat_tables/xlat_tables_v2.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -60,17 +60,22 @@
 #define MT_TYPE(_attr)		((_attr) & MT_TYPE_MASK)
 /* Access permissions (RO/RW) */
 #define MT_PERM_SHIFT		U(3)
-/* Security state (SECURE/NS) */
-#define MT_SEC_SHIFT		U(4)
+
+/* Physical address space (SECURE/NS/Root/Realm) */
+#define	MT_PAS_SHIFT		U(4)
+#define MT_PAS_MASK		(U(3) << MT_PAS_SHIFT)
+#define MT_PAS(_attr)		((_attr) & MT_PAS_MASK)
+
 /* Access permissions for instruction execution (EXECUTE/EXECUTE_NEVER) */
-#define MT_EXECUTE_SHIFT	U(5)
+#define MT_EXECUTE_SHIFT	U(6)
 /* In the EL1&0 translation regime, User (EL0) or Privileged (EL1). */
-#define MT_USER_SHIFT		U(6)
+#define MT_USER_SHIFT		U(7)
 
 /* Shareability attribute for the memory region */
-#define MT_SHAREABILITY_SHIFT	U(7)
+#define MT_SHAREABILITY_SHIFT	U(8)
 #define MT_SHAREABILITY_MASK	(U(3) << MT_SHAREABILITY_SHIFT)
 #define MT_SHAREABILITY(_attr)	((_attr) & MT_SHAREABILITY_MASK)
+
 /* All other bits are reserved */
 
 /*
@@ -91,8 +96,10 @@
 #define MT_RO			(U(0) << MT_PERM_SHIFT)
 #define MT_RW			(U(1) << MT_PERM_SHIFT)
 
-#define MT_SECURE		(U(0) << MT_SEC_SHIFT)
-#define MT_NS			(U(1) << MT_SEC_SHIFT)
+#define MT_SECURE		(U(0) << MT_PAS_SHIFT)
+#define MT_NS			(U(1) << MT_PAS_SHIFT)
+#define MT_ROOT			(U(2) << MT_PAS_SHIFT)
+#define MT_REALM		(U(3) << MT_PAS_SHIFT)
 
 /*
  * Access permissions for instruction execution are only relevant for normal
@@ -149,6 +156,13 @@
 #define EL3_REGIME		3
 #define EL_REGIME_INVALID	-1
 
+/* Memory type for EL3 regions. With RME, EL3 is in ROOT PAS */
+#if ENABLE_RME
+#define EL3_PAS			MT_ROOT
+#else
+#define EL3_PAS			MT_SECURE
+#endif /* ENABLE_RME */
+
 /*
  * Declare the translation context type.
  * Its definition is private.
diff --git a/include/plat/arm/common/arm_def.h b/include/plat/arm/common/arm_def.h
index 7cc215f..1993cb4 100644
--- a/include/plat/arm/common/arm_def.h
+++ b/include/plat/arm/common/arm_def.h
@@ -74,38 +74,84 @@
 					 ARM_SHARED_RAM_SIZE)
 
 /*
- * The top 16MB of DRAM1 is configured as secure access only using the TZC
+ * The top 16MB (or 64MB if RME is enabled) of DRAM1 is configured as
+ * follows:
  *   - SCP TZC DRAM: If present, DRAM reserved for SCP use
+ *   - L1 GPT DRAM: Reserved for L1 GPT if RME is enabled
+ *   - REALM DRAM: Reserved for Realm world if RME is enabled
  *   - AP TZC DRAM: The remaining TZC secured DRAM reserved for AP use
+ *
+ *              RME enabled(64MB)                RME not enabled(16MB)
+ *              --------------------             -------------------
+ *              |                  |             |                 |
+ *              |  AP TZC (~28MB)  |             |  AP TZC (~14MB) |
+ *              --------------------             -------------------
+ *              |                  |             |                 |
+ *              |  REALM (32MB)    |             |  EL3 TZC (2MB)  |
+ *              --------------------             -------------------
+ *              |                  |             |                 |
+ *              |  EL3 TZC (3MB)   |             |    SCP TZC      |
+ *              --------------------  0xFFFF_FFFF-------------------
+ *              | L1 GPT + SCP TZC |
+ *              |       (~1MB)     |
+ *  0xFFFF_FFFF --------------------
  */
-#define ARM_TZC_DRAM1_SIZE		UL(0x01000000)
+#if ENABLE_RME
+#define ARM_TZC_DRAM1_SIZE              UL(0x04000000) /* 64MB */
+/*
+ * Define a region within the TZC secured DRAM for use by EL3 runtime
+ * firmware. This region is meant to be NOLOAD and will not be zero
+ * initialized. Data sections with the attribute `arm_el3_tzc_dram` will be
+ * placed here. 3MB region is reserved if RME is enabled, 2MB otherwise.
+ */
+#define ARM_EL3_TZC_DRAM1_SIZE		UL(0x00300000) /* 3MB */
+#define ARM_L1_GPT_SIZE			UL(0x00100000) /* 1MB */
+#define ARM_REALM_SIZE			UL(0x02000000) /* 32MB */
+#else
+#define ARM_TZC_DRAM1_SIZE		UL(0x01000000) /* 16MB */
+#define ARM_EL3_TZC_DRAM1_SIZE		UL(0x00200000) /* 2MB */
+#define ARM_L1_GPT_SIZE			UL(0)
+#define ARM_REALM_SIZE			UL(0)
+#endif /* ENABLE_RME */
 
 #define ARM_SCP_TZC_DRAM1_BASE		(ARM_DRAM1_BASE +		\
-					 ARM_DRAM1_SIZE -		\
-					 ARM_SCP_TZC_DRAM1_SIZE)
+					ARM_DRAM1_SIZE -		\
+					(ARM_SCP_TZC_DRAM1_SIZE +	\
+					ARM_L1_GPT_SIZE))
 #define ARM_SCP_TZC_DRAM1_SIZE		PLAT_ARM_SCP_TZC_DRAM1_SIZE
 #define ARM_SCP_TZC_DRAM1_END		(ARM_SCP_TZC_DRAM1_BASE +	\
-					 ARM_SCP_TZC_DRAM1_SIZE - 1U)
+					ARM_SCP_TZC_DRAM1_SIZE - 1U)
+#if ENABLE_RME
+#define ARM_L1_GPT_ADDR_BASE		(ARM_DRAM1_BASE +		\
+					ARM_DRAM1_SIZE -		\
+					ARM_L1_GPT_SIZE)
+#define ARM_L1_GPT_END			(ARM_L1_GPT_ADDR_BASE +		\
+					ARM_L1_GPT_SIZE - 1U)
 
-/*
- * Define a 2MB region within the TZC secured DRAM for use by EL3 runtime
- * firmware. This region is meant to be NOLOAD and will not be zero
- * initialized. Data sections with the attribute `arm_el3_tzc_dram` will be
- * placed here.
- */
-#define ARM_EL3_TZC_DRAM1_BASE		(ARM_SCP_TZC_DRAM1_BASE - ARM_EL3_TZC_DRAM1_SIZE)
-#define ARM_EL3_TZC_DRAM1_SIZE		UL(0x00200000) /* 2 MB */
+#define ARM_REALM_BASE			(ARM_DRAM1_BASE +		\
+					ARM_DRAM1_SIZE -		\
+					(ARM_SCP_TZC_DRAM1_SIZE +	\
+					ARM_EL3_TZC_DRAM1_SIZE +	\
+					ARM_REALM_SIZE +		\
+					ARM_L1_GPT_SIZE))
+#define ARM_REALM_END                   (ARM_REALM_BASE + ARM_REALM_SIZE - 1U)
+#endif /* ENABLE_RME */
+
+#define ARM_EL3_TZC_DRAM1_BASE		(ARM_SCP_TZC_DRAM1_BASE -	\
+					ARM_EL3_TZC_DRAM1_SIZE)
 #define ARM_EL3_TZC_DRAM1_END		(ARM_EL3_TZC_DRAM1_BASE +	\
 					ARM_EL3_TZC_DRAM1_SIZE - 1U)
 
 #define ARM_AP_TZC_DRAM1_BASE		(ARM_DRAM1_BASE +		\
-					 ARM_DRAM1_SIZE -		\
-					 ARM_TZC_DRAM1_SIZE)
+					ARM_DRAM1_SIZE -		\
+					ARM_TZC_DRAM1_SIZE)
 #define ARM_AP_TZC_DRAM1_SIZE		(ARM_TZC_DRAM1_SIZE -		\
-					 (ARM_SCP_TZC_DRAM1_SIZE +	\
-					 ARM_EL3_TZC_DRAM1_SIZE))
+					(ARM_SCP_TZC_DRAM1_SIZE +	\
+					ARM_EL3_TZC_DRAM1_SIZE +	\
+					ARM_REALM_SIZE +		\
+					ARM_L1_GPT_SIZE))
 #define ARM_AP_TZC_DRAM1_END		(ARM_AP_TZC_DRAM1_BASE +	\
-					 ARM_AP_TZC_DRAM1_SIZE - 1U)
+					ARM_AP_TZC_DRAM1_SIZE - 1U)
 
 /* Define the Access permissions for Secure peripherals to NS_DRAM */
 #if ARM_CRYPTOCELL_INTEG
@@ -206,45 +252,58 @@
 	INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, (grp), \
 			GIC_INTR_CFG_EDGE)
 
-#define ARM_MAP_SHARED_RAM		MAP_REGION_FLAT(		\
-						ARM_SHARED_RAM_BASE,	\
-						ARM_SHARED_RAM_SIZE,	\
-						MT_DEVICE | MT_RW | MT_SECURE)
+#define ARM_MAP_SHARED_RAM	MAP_REGION_FLAT(			\
+					ARM_SHARED_RAM_BASE,		\
+					ARM_SHARED_RAM_SIZE,		\
+					MT_DEVICE | MT_RW | EL3_PAS)
 
-#define ARM_MAP_NS_DRAM1		MAP_REGION_FLAT(		\
-						ARM_NS_DRAM1_BASE,	\
-						ARM_NS_DRAM1_SIZE,	\
-						MT_MEMORY | MT_RW | MT_NS)
+#define ARM_MAP_NS_DRAM1	MAP_REGION_FLAT(			\
+					ARM_NS_DRAM1_BASE,		\
+					ARM_NS_DRAM1_SIZE,		\
+					MT_MEMORY | MT_RW | MT_NS)
 
-#define ARM_MAP_DRAM2			MAP_REGION_FLAT(		\
-						ARM_DRAM2_BASE,		\
-						ARM_DRAM2_SIZE,		\
-						MT_MEMORY | MT_RW | MT_NS)
+#define ARM_MAP_DRAM2		MAP_REGION_FLAT(			\
+					ARM_DRAM2_BASE,			\
+					ARM_DRAM2_SIZE,			\
+					MT_MEMORY | MT_RW | MT_NS)
 
-#define ARM_MAP_TSP_SEC_MEM		MAP_REGION_FLAT(		\
-						TSP_SEC_MEM_BASE,	\
-						TSP_SEC_MEM_SIZE,	\
-						MT_MEMORY | MT_RW | MT_SECURE)
+#define ARM_MAP_TSP_SEC_MEM	MAP_REGION_FLAT(			\
+					TSP_SEC_MEM_BASE,		\
+					TSP_SEC_MEM_SIZE,		\
+					MT_MEMORY | MT_RW | MT_SECURE)
 
 #if ARM_BL31_IN_DRAM
-#define ARM_MAP_BL31_SEC_DRAM		MAP_REGION_FLAT(		\
-						BL31_BASE,		\
-						PLAT_ARM_MAX_BL31_SIZE,	\
-						MT_MEMORY | MT_RW | MT_SECURE)
+#define ARM_MAP_BL31_SEC_DRAM	MAP_REGION_FLAT(			\
+					BL31_BASE,			\
+					PLAT_ARM_MAX_BL31_SIZE,		\
+					MT_MEMORY | MT_RW | MT_SECURE)
 #endif
 
-#define ARM_MAP_EL3_TZC_DRAM		MAP_REGION_FLAT(			\
-						ARM_EL3_TZC_DRAM1_BASE,	\
-						ARM_EL3_TZC_DRAM1_SIZE,	\
-						MT_MEMORY | MT_RW | MT_SECURE)
+#define ARM_MAP_EL3_TZC_DRAM	MAP_REGION_FLAT(			\
+					ARM_EL3_TZC_DRAM1_BASE,		\
+					ARM_EL3_TZC_DRAM1_SIZE,		\
+					MT_MEMORY | MT_RW | EL3_PAS)
 
 #if defined(SPD_spmd)
-#define ARM_MAP_TRUSTED_DRAM		MAP_REGION_FLAT(		    \
-						PLAT_ARM_TRUSTED_DRAM_BASE, \
-						PLAT_ARM_TRUSTED_DRAM_SIZE, \
-						MT_MEMORY | MT_RW | MT_SECURE)
+#define ARM_MAP_TRUSTED_DRAM	MAP_REGION_FLAT(			\
+					PLAT_ARM_TRUSTED_DRAM_BASE,	\
+					PLAT_ARM_TRUSTED_DRAM_SIZE,	\
+					MT_MEMORY | MT_RW | MT_SECURE)
 #endif
 
+#if ENABLE_RME
+#define ARM_MAP_RMM_DRAM	MAP_REGION_FLAT(			\
+					PLAT_ARM_RMM_BASE,		\
+					PLAT_ARM_RMM_SIZE,		\
+					MT_MEMORY | MT_RW | MT_REALM)
+
+
+#define ARM_MAP_GPT_L1_DRAM	MAP_REGION_FLAT(			\
+					ARM_L1_GPT_ADDR_BASE,		\
+					ARM_L1_GPT_SIZE,		\
+					MT_MEMORY | MT_RW | EL3_PAS)
+
+#endif /* ENABLE_RME */
 
 /*
  * Mapping for the BL1 RW region. This mapping is needed by BL2 in order to
@@ -255,7 +314,7 @@
 #define ARM_MAP_BL1_RW		MAP_REGION_FLAT(	\
 					BL1_RW_BASE,	\
 					BL1_RW_LIMIT - BL1_RW_BASE, \
-					MT_MEMORY | MT_RW | MT_SECURE)
+					MT_MEMORY | MT_RW | EL3_PAS)
 
 /*
  * If SEPARATE_CODE_AND_RODATA=1 we define a region for each section
@@ -265,35 +324,35 @@
 #define ARM_MAP_BL_RO			MAP_REGION_FLAT(			\
 						BL_CODE_BASE,			\
 						BL_CODE_END - BL_CODE_BASE,	\
-						MT_CODE | MT_SECURE),		\
+						MT_CODE | EL3_PAS),		\
 					MAP_REGION_FLAT(			\
 						BL_RO_DATA_BASE,		\
 						BL_RO_DATA_END			\
 							- BL_RO_DATA_BASE,	\
-						MT_RO_DATA | MT_SECURE)
+						MT_RO_DATA | EL3_PAS)
 #else
 #define ARM_MAP_BL_RO			MAP_REGION_FLAT(			\
 						BL_CODE_BASE,			\
 						BL_CODE_END - BL_CODE_BASE,	\
-						MT_CODE | MT_SECURE)
+						MT_CODE | EL3_PAS)
 #endif
 #if USE_COHERENT_MEM
 #define ARM_MAP_BL_COHERENT_RAM		MAP_REGION_FLAT(			\
 						BL_COHERENT_RAM_BASE,		\
 						BL_COHERENT_RAM_END		\
 							- BL_COHERENT_RAM_BASE, \
-						MT_DEVICE | MT_RW | MT_SECURE)
+						MT_DEVICE | MT_RW | EL3_PAS)
 #endif
 #if USE_ROMLIB
 #define ARM_MAP_ROMLIB_CODE		MAP_REGION_FLAT(			\
 						ROMLIB_RO_BASE,			\
 						ROMLIB_RO_LIMIT	- ROMLIB_RO_BASE,\
-						MT_CODE | MT_SECURE)
+						MT_CODE | EL3_PAS)
 
 #define ARM_MAP_ROMLIB_DATA		MAP_REGION_FLAT(			\
 						ROMLIB_RW_BASE,			\
 						ROMLIB_RW_END	- ROMLIB_RW_BASE,\
-						MT_MEMORY | MT_RW | MT_SECURE)
+						MT_MEMORY | MT_RW | EL3_PAS)
 #endif
 
 /*
@@ -308,7 +367,15 @@
 #define ARM_MAP_BL_CONFIG_REGION	MAP_REGION_FLAT(ARM_BL_RAM_BASE,	\
 						(ARM_FW_CONFIGS_LIMIT		\
 							- ARM_BL_RAM_BASE),	\
-						MT_MEMORY | MT_RW | MT_SECURE)
+						MT_MEMORY | MT_RW | EL3_PAS)
+/*
+ * Map L0_GPT with read and write permissions
+ */
+#if ENABLE_RME
+#define ARM_MAP_L0_GPT_REGION		MAP_REGION_FLAT(ARM_L0_GPT_ADDR_BASE,	\
+						ARM_L0_GPT_SIZE,		\
+						MT_MEMORY | MT_RW | MT_ROOT)
+#endif
 
 /*
  * The max number of regions like RO(code), coherent and data required by
@@ -409,6 +476,18 @@
  */
 #define ARM_FW_CONFIGS_LIMIT		(ARM_BL_RAM_BASE + (PAGE_SIZE * 2))
 
+#if ENABLE_RME
+/*
+ * Store the L0 GPT on Trusted SRAM next to firmware
+ * configuration memory, 4KB aligned.
+ */
+#define ARM_L0_GPT_SIZE			(PAGE_SIZE)
+#define ARM_L0_GPT_ADDR_BASE		(ARM_FW_CONFIGS_LIMIT)
+#define ARM_L0_GPT_LIMIT		(ARM_L0_GPT_ADDR_BASE + ARM_L0_GPT_SIZE)
+#else
+#define ARM_L0_GPT_SIZE			U(0)
+#endif
+
 /*******************************************************************************
  * BL1 specific defines.
  * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of
@@ -501,6 +580,14 @@
 #endif
 #endif
 
+/******************************************************************************
+ * RMM specific defines
+ *****************************************************************************/
+#if ENABLE_RME
+#define RMM_BASE			(ARM_REALM_BASE)
+#define RMM_LIMIT			(RMM_BASE + ARM_REALM_SIZE)
+#endif
+
 #if !defined(__aarch64__) || JUNO_AARCH32_EL3_RUNTIME
 /*******************************************************************************
  * BL32 specific defines for EL3 runtime in AArch32 mode
diff --git a/include/plat/arm/common/arm_dyn_cfg_helpers.h b/include/plat/arm/common/arm_dyn_cfg_helpers.h
index 34bf07c..ff00fe7 100644
--- a/include/plat/arm/common/arm_dyn_cfg_helpers.h
+++ b/include/plat/arm/common/arm_dyn_cfg_helpers.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -14,8 +14,4 @@
 int arm_set_dtb_mbedtls_heap_info(void *dtb, void *heap_addr,
 	size_t heap_size);
 
-#if MEASURED_BOOT
-int arm_set_bl2_hash_info(void *dtb, void *data);
-#endif
-
 #endif /* ARM_DYN_CFG_HELPERS_H */
diff --git a/include/plat/arm/common/arm_pas_def.h b/include/plat/arm/common/arm_pas_def.h
new file mode 100644
index 0000000..4fee41b
--- /dev/null
+++ b/include/plat/arm/common/arm_pas_def.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef ARM_PAS_DEF_H
+#define ARM_PAS_DEF_H
+
+#include <lib/gpt_rme/gpt_rme.h>
+#include <plat/arm/common/arm_def.h>
+
+/*****************************************************************************
+ * PAS regions used to initialize the Granule Protection Table (GPT)
+ ****************************************************************************/
+
+/*
+ * The PA space is initially mapped in the GPT as follows:
+ *
+ * ============================================================================
+ * Base Addr| Size        |L? GPT|PAS   |Content                 |Comment
+ * ============================================================================
+ * 0GB      | 1GB         |L0 GPT|ANY   |TBROM (EL3 code)        |Fixed mapping
+ *          |             |      |      |TSRAM (EL3 data)        |
+ *          |             |      |      |IO (incl.UARTs & GIC)   |
+ * ----------------------------------------------------------------------------
+ * 1GB      | 1GB         |L0 GPT|ANY   |IO                      |Fixed mapping
+ * ----------------------------------------------------------------------------
+ * 2GB      | 1GB         |L1 GPT|NS    |DRAM (NS Kernel)        |Use T.Descrip
+ * ----------------------------------------------------------------------------
+ * 3GB      |1GB-64MB     |L1 GPT|NS    |DRAM (NS Kernel)        |Use T.Descrip
+ * ----------------------------------------------------------------------------
+ * 4GB-64MB |64MB-32MB    |      |      |                        |
+ *          | -4MB        |L1 GPT|SECURE|DRAM TZC                |Use T.Descrip
+ * ----------------------------------------------------------------------------
+ * 4GB-32MB |             |      |      |                        |
+ * -3MB-1MB |32MB         |L1 GPT|REALM |RMM                     |Use T.Descrip
+ * ----------------------------------------------------------------------------
+ * 4GB-3MB  |             |      |      |                        |
+ * -1MB     |3MB          |L1 GPT|ROOT  |EL3 DRAM data           |Use T.Descrip
+ * ----------------------------------------------------------------------------
+ * 4GB-1MB  |1MB          |L1 GPT|ROOT  |DRAM (L1 GPTs, SCP TZC) |Fixed mapping
+ * ============================================================================
+ *
+ * - 4KB of L0 GPT reside in TSRAM, on top of the CONFIG section.
+ * - ~1MB of L1 GPTs reside at the top of DRAM1 (TZC area).
+ * - The first 1GB region has GPT_GPI_ANY and, therefore, is not protected by
+ *   the GPT.
+ * - The DRAM TZC area is split into three regions: the L1 GPT region and
+ *   3MB of region below that are defined as GPT_GPI_ROOT, 32MB Realm region
+ *   below that is defined as GPT_GPI_REALM and the rest of it is defined as
+ *   GPT_GPI_SECURE.
+ */
+
+/* TODO: This might not be the best way to map the PAS */
+
+/* Device memory 0 to 2GB */
+#define ARM_PAS_1_BASE			(U(0))
+#define ARM_PAS_1_SIZE			((ULL(1)<<31)) /* 2GB */
+
+/* NS memory 2GB to (end - 64MB) */
+#define ARM_PAS_2_BASE			(ARM_PAS_1_BASE + ARM_PAS_1_SIZE)
+#define ARM_PAS_2_SIZE			(ARM_NS_DRAM1_SIZE)
+
+/* Secure TZC region */
+#define ARM_PAS_3_BASE			(ARM_AP_TZC_DRAM1_BASE)
+#define ARM_PAS_3_SIZE			(ARM_AP_TZC_DRAM1_SIZE)
+
+#define ARM_PAS_GPI_ANY			MAP_GPT_REGION(ARM_PAS_1_BASE, \
+						       ARM_PAS_1_SIZE, \
+						       GPT_GPI_ANY)
+#define	ARM_PAS_KERNEL			GPT_MAP_REGION_GRANULE(ARM_PAS_2_BASE, \
+							       ARM_PAS_2_SIZE, \
+							       GPT_GPI_NS)
+
+#define ARM_PAS_SECURE			GPT_MAP_REGION_GRANULE(ARM_PAS_3_BASE, \
+							       ARM_PAS_3_SIZE, \
+							       GPT_GPI_SECURE)
+
+#define ARM_PAS_REALM			GPT_MAP_REGION_GRANULE(ARM_REALM_BASE, \
+							       ARM_REALM_SIZE, \
+							       GPT_GPI_REALM)
+
+#define ARM_PAS_EL3_DRAM		GPT_MAP_REGION_GRANULE(ARM_EL3_TZC_DRAM1_BASE, \
+							       ARM_EL3_TZC_DRAM1_SIZE, \
+							       GPT_GPI_ROOT)
+
+#define	ARM_PAS_GPTS			GPT_MAP_REGION_GRANULE(ARM_L1_GPT_ADDR_BASE, \
+							       ARM_L1_GPT_SIZE, \
+							       GPT_GPI_ROOT)
+
+/* GPT Configuration options */
+#define PLATFORM_L0GPTSZ		GPCCR_L0GPTSZ_30BITS
+
+#endif /* ARM_PAS_DEF_H */
diff --git a/include/plat/arm/common/plat_arm.h b/include/plat/arm/common/plat_arm.h
index 0a19d8b..9618700 100644
--- a/include/plat/arm/common/plat_arm.h
+++ b/include/plat/arm/common/plat_arm.h
@@ -41,7 +41,7 @@
  ******************************************************************************/
 #if SPM_MM
 #define ARM_TZC_REGIONS_DEF						\
-	{ARM_AP_TZC_DRAM1_BASE, ARM_EL3_TZC_DRAM1_END,			\
+	{ARM_AP_TZC_DRAM1_BASE, ARM_EL3_TZC_DRAM1_END + ARM_L1_GPT_SIZE,\
 		TZC_REGION_S_RDWR, 0},					\
 	{ARM_NS_DRAM1_BASE, ARM_NS_DRAM1_END, ARM_TZC_NS_DRAM_S_ACCESS, \
 		PLAT_ARM_TZC_NS_DEV_ACCESS}, 				\
@@ -51,9 +51,20 @@
 		PLAT_SP_IMAGE_NS_BUF_SIZE) - 1, TZC_REGION_S_NONE,	\
 		PLAT_ARM_TZC_NS_DEV_ACCESS}
 
+#elif ENABLE_RME
+#define ARM_TZC_REGIONS_DEF						    \
+	{ARM_AP_TZC_DRAM1_BASE, ARM_AP_TZC_DRAM1_END, TZC_REGION_S_RDWR, 0},\
+	{ARM_EL3_TZC_DRAM1_BASE, ARM_L1_GPT_END, TZC_REGION_S_RDWR, 0},	    \
+	{ARM_NS_DRAM1_BASE, ARM_NS_DRAM1_END, ARM_TZC_NS_DRAM_S_ACCESS,	    \
+		PLAT_ARM_TZC_NS_DEV_ACCESS},				    \
+	{ARM_REALM_BASE, ARM_REALM_END, ARM_TZC_NS_DRAM_S_ACCESS,	    \
+		PLAT_ARM_TZC_NS_DEV_ACCESS},				    \
+	{ARM_DRAM2_BASE, ARM_DRAM2_END, ARM_TZC_NS_DRAM_S_ACCESS,	    \
+		PLAT_ARM_TZC_NS_DEV_ACCESS}
+
 #else
 #define ARM_TZC_REGIONS_DEF						\
-	{ARM_AP_TZC_DRAM1_BASE, ARM_EL3_TZC_DRAM1_END,			\
+	{ARM_AP_TZC_DRAM1_BASE, ARM_EL3_TZC_DRAM1_END + ARM_L1_GPT_SIZE,\
 		TZC_REGION_S_RDWR, 0},					\
 	{ARM_NS_DRAM1_BASE, ARM_NS_DRAM1_END, ARM_TZC_NS_DRAM_S_ACCESS, \
 		PLAT_ARM_TZC_NS_DEV_ACCESS},	 			\
@@ -239,12 +250,8 @@
 int arm_get_mbedtls_heap(void **heap_addr, size_t *heap_size);
 
 #if MEASURED_BOOT
-/* Measured boot related functions */
-void arm_bl1_set_bl2_hash(const image_desc_t *image_desc);
-void arm_bl2_get_hash(void *data);
-int arm_set_tos_fw_info(uintptr_t config_base, uintptr_t log_addr,
-			size_t log_size);
-int arm_set_nt_fw_info(uintptr_t config_base,
+int arm_set_tos_fw_info(uintptr_t log_addr, size_t log_size);
+int arm_set_nt_fw_info(
 /*
  * Currently OP-TEE does not support reading DTBs from Secure memory
  * and this option should be removed when feature is supported.
@@ -253,6 +260,8 @@
 			uintptr_t log_addr,
 #endif
 			size_t log_size, uintptr_t *ns_log_addr);
+int arm_set_tb_fw_info(uintptr_t log_addr, size_t log_size);
+int arm_get_tb_fw_info(uint64_t *log_addr, size_t *log_size);
 #endif /* MEASURED_BOOT */
 
 /*
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index 434835e..3fa63f5 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -122,6 +122,16 @@
 void bl2_plat_preload_setup(void);
 int plat_try_next_boot_source(void);
 
+#if MEASURED_BOOT
+int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data);
+#else
+static inline int plat_mboot_measure_image(unsigned int image_id __unused,
+					   image_info_t *image_data __unused)
+{
+	return 0;
+}
+#endif /* MEASURED_BOOT */
+
 /*******************************************************************************
  * Mandatory BL1 functions
  ******************************************************************************/
@@ -182,12 +192,16 @@
 int bl1_plat_handle_post_image_load(unsigned int image_id);
 
 #if MEASURED_BOOT
-/*
- * Calculates and writes BL2 hash data to the platform's defined location.
- * For ARM platforms the data are written to TB_FW_CONFIG DTB.
- */
-void bl1_plat_set_bl2_hash(const image_desc_t *image_desc);
-#endif
+void bl1_plat_mboot_init(void);
+void bl1_plat_mboot_finish(void);
+#else
+static inline void bl1_plat_mboot_init(void)
+{
+}
+static inline void bl1_plat_mboot_finish(void)
+{
+}
+#endif /* MEASURED_BOOT */
 
 /*******************************************************************************
  * Mandatory BL2 functions
@@ -208,9 +222,16 @@
  * Optional BL2 functions (may be overridden)
  ******************************************************************************/
 #if MEASURED_BOOT
-/* Read TCG_DIGEST_SIZE bytes of BL2 hash data */
-void bl2_plat_get_hash(void *data);
-#endif
+void bl2_plat_mboot_init(void);
+void bl2_plat_mboot_finish(void);
+#else
+static inline void bl2_plat_mboot_init(void)
+{
+}
+static inline void bl2_plat_mboot_finish(void)
+{
+}
+#endif /* MEASURED_BOOT */
 
 /*******************************************************************************
  * Mandatory BL2 at EL3 functions: Must be implemented if BL2_AT_EL3 image is
diff --git a/include/services/gtsi_svc.h b/include/services/gtsi_svc.h
new file mode 100644
index 0000000..cb942ed
--- /dev/null
+++ b/include/services/gtsi_svc.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GTSI_SVC_H
+#define GTSI_SVC_H
+
+/* GTSI error codes. */
+#define GTSI_SUCCESS			0
+#define GTSI_ERROR_NOT_SUPPORTED	-1
+#define GTSI_ERROR_INVALID_ADDRESS	-2
+#define GTSI_ERROR_INVALID_PAS		-3
+
+/* The macros below are used to identify GTSI calls from the SMC function ID */
+#define GTSI_FNUM_MIN_VALUE	U(0x100)
+#define GTSI_FNUM_MAX_VALUE	U(0x101)
+#define is_gtsi_fid(fid) __extension__ ({		\
+	__typeof__(fid) _fid = (fid);			\
+	((GET_SMC_NUM(_fid) >= GTSI_FNUM_MIN_VALUE) &&	\
+	 (GET_SMC_NUM(_fid) <= GTSI_FNUM_MAX_VALUE)); })
+
+/* Get GTSI fastcall std FID from function number */
+#define GTSI_FID(smc_cc, func_num)			\
+	((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT)	|	\
+	 ((smc_cc) << FUNCID_CC_SHIFT)		|	\
+	 (OEN_STD_START << FUNCID_OEN_SHIFT)	|	\
+	 ((func_num) << FUNCID_NUM_SHIFT))
+
+#define GRAN_TRANS_TO_REALM_FNUM	U(0x100)
+#define GRAN_TRANS_TO_NS_FNUM		U(0x101)
+
+#define SMC_ASC_MARK_REALM	GTSI_FID(SMC_64, GRAN_TRANS_TO_REALM_FNUM)
+#define SMC_ASC_MARK_NONSECURE	GTSI_FID(SMC_64, GRAN_TRANS_TO_NS_FNUM)
+
+#define GRAN_TRANS_RET_BAD_ADDR		-2
+#define GRAN_TRANS_RET_BAD_PAS		-3
+
+#endif /* GTSI_SVC_H */
diff --git a/include/services/rmi_svc.h b/include/services/rmi_svc.h
new file mode 100644
index 0000000..9106f08
--- /dev/null
+++ b/include/services/rmi_svc.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RMI_SVC_H
+#define RMI_SVC_H
+
+#include <lib/smccc.h>
+#include <lib/utils_def.h>
+
+/* RMI error codes. */
+#define RMI_SUCCESS			0
+#define RMI_ERROR_NOT_SUPPORTED		-1
+#define RMI_ERROR_INVALID_ADDRESS	-2
+#define RMI_ERROR_INVALID_PAS		-3
+
+/* The macros below are used to identify RMI calls from the SMC function ID */
+#define RMI_FNUM_MIN_VALUE	U(0x00)
+#define RMI_FNUM_MAX_VALUE	U(0x20)
+#define is_rmi_fid(fid) __extension__ ({		\
+	__typeof__(fid) _fid = (fid);			\
+	((GET_SMC_NUM(_fid) >= RMI_FNUM_MIN_VALUE) &&	\
+	 (GET_SMC_NUM(_fid) <= RMI_FNUM_MAX_VALUE) &&	\
+	 (GET_SMC_TYPE(_fid) == SMC_TYPE_FAST)	   &&	\
+	 (GET_SMC_CC(_fid) == SMC_64)              &&	\
+	 (GET_SMC_OEN(_fid) == OEN_ARM_START)      &&	\
+	 ((_fid & 0x00FE0000) == 0U)); })
+
+/* Get RMI fastcall std FID from function number */
+#define RMI_FID(smc_cc, func_num)			\
+	((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT)	|	\
+	((smc_cc) << FUNCID_CC_SHIFT)		|	\
+	(OEN_ARM_START << FUNCID_OEN_SHIFT)	|	\
+	((func_num) << FUNCID_NUM_SHIFT))
+
+/*
+ * SMC_RMM_INIT_COMPLETE is the only function in the RMI that originates from
+ * the Realm world and is handled by the RMMD. The remaining functions are
+ * always invoked by the Normal world, forwarded by RMMD and handled by the
+ * RMM
+ */
+#define RMI_FNUM_REQ_COMPLETE		U(0x10)
+#define RMI_FNUM_VERSION_REQ		U(0x00)
+
+#define RMI_FNUM_GRAN_NS_REALM		U(0x01)
+#define RMI_FNUM_GRAN_REALM_NS		U(0x10)
+
+/* RMI SMC64 FIDs handled by the RMMD */
+#define RMI_RMM_REQ_COMPLETE		RMI_FID(SMC_64, RMI_FNUM_REQ_COMPLETE)
+#define RMI_RMM_REQ_VERSION		RMI_FID(SMC_64, RMI_FNUM_VERSION_REQ)
+
+#define RMI_RMM_GRANULE_DELEGATE	RMI_FID(SMC_64, RMI_FNUM_GRAN_NS_REALM)
+#define RMI_RMM_GRANULE_UNDELEGATE	RMI_FID(SMC_64, RMI_FNUM_GRAN_REALM_NS)
+
+
+#define RMI_ABI_VERSION_GET_MAJOR(_version) ((_version) >> 16)
+#define RMI_ABI_VERSION_GET_MINOR(_version) ((_version) & 0xFFFF)
+
+/* Reserve a special value for MBZ parameters. */
+#define RMI_PARAM_MBZ			U(0x0)
+
+#endif /* RMI_SVC_H */
diff --git a/include/services/rmmd_svc.h b/include/services/rmmd_svc.h
new file mode 100644
index 0000000..132973b
--- /dev/null
+++ b/include/services/rmmd_svc.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RMMD_SVC_H
+#define RMMD_SVC_H
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+
+int rmmd_setup(void);
+uint64_t rmmd_rmi_handler(uint32_t smc_fid,
+		uint64_t x1,
+		uint64_t x2,
+		uint64_t x3,
+		uint64_t x4,
+		void *cookie,
+		void *handle,
+		uint64_t flags);
+
+uint64_t rmmd_gtsi_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 /* __ASSEMBLER__ */
+
+#endif /* RMMD_SVC_H */
diff --git a/include/services/trp/platform_trp.h b/include/services/trp/platform_trp.h
new file mode 100644
index 0000000..b34da85
--- /dev/null
+++ b/include/services/trp/platform_trp.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_TRP_H
+#define PLATFORM_TRP_H
+
+/*******************************************************************************
+ * Mandatory TRP functions (only if platform contains a TRP)
+ ******************************************************************************/
+void trp_early_platform_setup(void);
+
+#endif /* PLATFORM_TRP_H */
diff --git a/include/tools_share/firmware_image_package.h b/include/tools_share/firmware_image_package.h
index dc65cc6..bd5b14b 100644
--- a/include/tools_share/firmware_image_package.h
+++ b/include/tools_share/firmware_image_package.h
@@ -38,6 +38,8 @@
 	{{0x8e,  0xa8, 0x7b, 0xb1}, {0xcf, 0xa2}, {0x3f, 0x4d}, 0x85, 0xfd, {0xe7, 0xbb, 0xa5, 0x02, 0x20, 0xd9} }
 #define UUID_NON_TRUSTED_FIRMWARE_BL33 \
 	{{0xd6,  0xd0, 0xee, 0xa7}, {0xfc, 0xea}, {0xd5, 0x4b}, 0x97, 0x82, {0x99, 0x34, 0xf2, 0x34, 0xb6, 0xe4} }
+#define UUID_REALM_MONITOR_MGMT_FIRMWARE \
+	{{0x6c,  0x07, 0x62, 0xa6}, {0x12, 0xf2}, {0x4b, 0x56}, 0x92, 0xcb, {0xba, 0x8f, 0x63, 0x36, 0x06, 0xd9} }
 /* Key certificates */
 #define UUID_ROT_KEY_CERT \
 	{{0x86,  0x2d, 0x1d, 0x72}, {0xf8, 0x60}, {0xe4, 0x11}, 0x92, 0x0b, {0x8b, 0xe7, 0x62, 0x16, 0x0f, 0x24} }
diff --git a/lib/aarch64/misc_helpers.S b/lib/aarch64/misc_helpers.S
index b6f6c9d..6e4d1fc 100644
--- a/lib/aarch64/misc_helpers.S
+++ b/lib/aarch64/misc_helpers.S
@@ -15,6 +15,7 @@
 	.globl	zero_normalmem
 	.globl	zeromem
 	.globl	memcpy16
+	.globl	gpt_tlbi_by_pa
 
 	.globl	disable_mmu_el1
 	.globl	disable_mmu_el3
@@ -162,7 +163,8 @@
 	 * Check for M bit (MMU enabled) of the current SCTLR_EL(1|3)
 	 * register value and panic if the MMU is disabled.
 	 */
-#if defined(IMAGE_BL1) || defined(IMAGE_BL31) || (defined(IMAGE_BL2) && BL2_AT_EL3)
+#if defined(IMAGE_BL1) || defined(IMAGE_BL31) || (defined(IMAGE_BL2) && \
+	(BL2_AT_EL3 || ENABLE_RME))
 	mrs	tmp1, sctlr_el3
 #else
 	mrs	tmp1, sctlr_el1
@@ -592,3 +594,20 @@
 	b.lo	1b
 	ret
 endfunc fixup_gdt_reloc
+
+/*
+ * TODO: Currently only supports size of 4KB,
+ * support other sizes as well.
+ */
+func gpt_tlbi_by_pa
+#if ENABLE_ASSERTIONS
+	cmp	x1, #PAGE_SIZE_4KB
+	ASM_ASSERT(eq)
+	tst	x0, #(PAGE_SIZE_MASK)
+	ASM_ASSERT(eq)
+#endif
+	lsr	x0, x0, #FOUR_KB_SHIFT	/* 4KB size encoding is zero */
+	sys	#6, c8, c4, #3, x0 	/* TLBI RPAOS, <Xt> */
+	dsb	sy
+	ret
+endfunc gpt_tlbi_by_pa
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 08022d4..0ec7e7e 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -93,24 +93,41 @@
 	scr_el3 = read_scr();
 	scr_el3 &= ~(SCR_NS_BIT | SCR_RW_BIT | SCR_FIQ_BIT | SCR_IRQ_BIT |
 			SCR_ST_BIT | SCR_HCE_BIT);
+
+#if ENABLE_RME
+	/* When RME support is enabled, clear the NSE bit as well. */
+	scr_el3 &= ~SCR_NSE_BIT;
+#endif /* ENABLE_RME */
+
 	/*
 	 * SCR_NS: Set the security state of the next EL.
 	 */
-	if (security_state != SECURE)
+	if (security_state == NON_SECURE) {
 		scr_el3 |= SCR_NS_BIT;
+	}
+
+#if ENABLE_RME
+	/* Check for realm state if RME support enabled. */
+	if (security_state == REALM) {
+		scr_el3 |= SCR_NS_BIT | SCR_NSE_BIT | SCR_EnSCXT_BIT;
+	}
+#endif /* ENABLE_RME */
+
 	/*
 	 * SCR_EL3.RW: Set the execution state, AArch32 or AArch64, for next
 	 *  Exception level as specified by SPSR.
 	 */
-	if (GET_RW(ep->spsr) == MODE_RW_64)
+	if (GET_RW(ep->spsr) == MODE_RW_64) {
 		scr_el3 |= SCR_RW_BIT;
+	}
 	/*
 	 * SCR_EL3.ST: Traps Secure EL1 accesses to the Counter-timer Physical
 	 *  Secure timer registers to EL3, from AArch64 state only, if specified
 	 *  by the entrypoint attributes.
 	 */
-	if (EP_GET_ST(ep->h.attr) != 0U)
+	if (EP_GET_ST(ep->h.attr) != 0U) {
 		scr_el3 |= SCR_ST_BIT;
+	}
 
 	/*
 	 * If FEAT_HCX is enabled, enable access to HCRX_EL2 by setting
@@ -152,8 +169,9 @@
 	 * If the Secure world wants to use pointer authentication,
 	 * CTX_INCLUDE_PAUTH_REGS must be set to 1.
 	 */
-	if (security_state == NON_SECURE)
+	if (security_state == NON_SECURE) {
 		scr_el3 |= SCR_API_BIT | SCR_APK_BIT;
+	}
 #endif /* !CTX_INCLUDE_PAUTH_REGS */
 
 #if !CTX_INCLUDE_MTE_REGS || ENABLE_ASSERTIONS
@@ -188,8 +206,14 @@
 	/*
 	 * SCR_EL3.IRQ, SCR_EL3.FIQ: Enable the physical FIQ and IRQ routing as
 	 *  indicated by the interrupt routing model for BL31.
+	 *
+	 * TODO: The interrupt routing model code is not updated for REALM
+	 * state. Use the default values of IRQ = FIQ = 0 for REALM security
+	 * state for now.
 	 */
-	scr_el3 |= get_scr_el3_from_routing_model(security_state);
+	if (security_state != REALM) {
+		scr_el3 |= get_scr_el3_from_routing_model(security_state);
+	}
 #endif
 
 	/* Save the initialized value of CPTR_EL3 register */
@@ -256,9 +280,9 @@
 	 *  required by PSCI specification)
 	 */
 	sctlr_elx = (EP_GET_EE(ep->h.attr) != 0U) ? SCTLR_EE_BIT : 0U;
-	if (GET_RW(ep->spsr) == MODE_RW_64)
+	if (GET_RW(ep->spsr) == MODE_RW_64) {
 		sctlr_elx |= SCTLR_EL1_RES1;
-	else {
+	} else {
 		/*
 		 * If the target execution state is AArch32 then the following
 		 * fields need to be set.
@@ -413,7 +437,8 @@
 }
 
 /*******************************************************************************
- * Prepare the CPU system registers for first entry into secure or normal world
+ * Prepare the CPU system registers for first entry into realm, secure, or
+ * normal world.
  *
  * If execution is requested to EL2 or hyp mode, SCTLR_EL2 is initialized
  * If execution is requested to non-secure EL1 or svc mode, and the CPU supports
@@ -497,7 +522,7 @@
 			 * architecturally UNKNOWN on reset and are set to zero
 			 * except for field(s) listed below.
 			 *
-			 * CNTHCTL_EL2.EL1PCEN: Set to one to disable traps to
+			 * CNTHCTL_EL2.EL1PTEN: Set to one to disable traps to
 			 *  Hyp mode of Non-secure EL0 and EL1 accesses to the
 			 *  physical timer registers.
 			 *
@@ -645,10 +670,10 @@
 	u_register_t scr_el3 = read_scr();
 
 	/*
-	 * Always save the non-secure EL2 context, only save the
+	 * Always save the non-secure and realm EL2 context, only save the
 	 * S-EL2 context if S-EL2 is enabled.
 	 */
-	if ((security_state == NON_SECURE) ||
+	if ((security_state != SECURE) ||
 	    ((security_state == SECURE) && ((scr_el3 & SCR_EEL2_BIT) != 0U))) {
 		cpu_context_t *ctx;
 
@@ -667,10 +692,10 @@
 	u_register_t scr_el3 = read_scr();
 
 	/*
-	 * Always restore the non-secure EL2 context, only restore the
+	 * Always restore the non-secure and realm EL2 context, only restore the
 	 * S-EL2 context if S-EL2 is enabled.
 	 */
-	if ((security_state == NON_SECURE) ||
+	if ((security_state != SECURE) ||
 	    ((security_state == SECURE) && ((scr_el3 & SCR_EEL2_BIT) != 0U))) {
 		cpu_context_t *ctx;
 
diff --git a/lib/fconf/fconf_tbbr_getter.c b/lib/fconf/fconf_tbbr_getter.c
index 9a20ced..6f043e6 100644
--- a/lib/fconf/fconf_tbbr_getter.c
+++ b/lib/fconf/fconf_tbbr_getter.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020, ARM Limited. All rights reserved.
+ * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -71,26 +71,13 @@
 	}
 	tbbr_dyn_config.mbedtls_heap_size = val32;
 
-#if MEASURED_BOOT
-	/* Retrieve BL2 hash data details from the DTB */
-	err = fdtw_read_bytes(dtb, node, "bl2_hash_data", TCG_DIGEST_SIZE,
-				&tbbr_dyn_config.bl2_hash_data);
-	if (err < 0) {
-		ERROR("FCONF: Read %s failed for '%s'\n",
-				"bytes", "bl2_hash_data");
-		return err;
-	}
-#endif
 	VERBOSE("%s%s%s %d\n", "FCONF: `tbbr.", "disable_auth",
 		"` cell found with value =", tbbr_dyn_config.disable_auth);
 	VERBOSE("%s%s%s %p\n", "FCONF: `tbbr.", "mbedtls_heap_addr",
 		"` cell found with value =", tbbr_dyn_config.mbedtls_heap_addr);
 	VERBOSE("%s%s%s %zu\n", "FCONF: `tbbr.", "mbedtls_heap_size",
 		"` cell found with value =", tbbr_dyn_config.mbedtls_heap_size);
-#if MEASURED_BOOT
-	VERBOSE("%s%s%s %p\n", "FCONF: `tbbr.", "bl2_hash_data",
-		"` array found at address =", tbbr_dyn_config.bl2_hash_data);
-#endif
+
 	return 0;
 }
 
diff --git a/lib/gpt_rme/gpt_rme.c b/lib/gpt_rme/gpt_rme.c
new file mode 100644
index 0000000..1f90e64
--- /dev/null
+++ b/lib/gpt_rme/gpt_rme.c
@@ -0,0 +1,1112 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdint.h>
+
+#include <arch.h>
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include "gpt_rme_private.h"
+#include <lib/gpt_rme/gpt_rme.h>
+#include <lib/smccc.h>
+#include <lib/spinlock.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#if !ENABLE_RME
+#error "ENABLE_RME must be enabled to use the GPT library."
+#endif
+
+/*
+ * Lookup T from PPS
+ *
+ *   PPS    Size    T
+ *   0b000  4GB     32
+ *   0b001  64GB    36
+ *   0b010  1TB     40
+ *   0b011  4TB     42
+ *   0b100  16TB    44
+ *   0b101  256TB   48
+ *   0b110  4PB     52
+ *
+ * See section 15.1.27 of the RME specification.
+ */
+static const gpt_t_val_e gpt_t_lookup[] = {PPS_4GB_T, PPS_64GB_T,
+					   PPS_1TB_T, PPS_4TB_T,
+					   PPS_16TB_T, PPS_256TB_T,
+					   PPS_4PB_T};
+
+/*
+ * Lookup P from PGS
+ *
+ *   PGS    Size    P
+ *   0b00   4KB     12
+ *   0b10   16KB    14
+ *   0b01   64KB    16
+ *
+ * Note that pgs=0b10 is 16KB and pgs=0b01 is 64KB, this is not a typo.
+ *
+ * See section 15.1.27 of the RME specification.
+ */
+static const gpt_p_val_e gpt_p_lookup[] = {PGS_4KB_P, PGS_64KB_P, PGS_16KB_P};
+
+/*
+ * This structure contains GPT configuration data.
+ */
+typedef struct {
+	uintptr_t plat_gpt_l0_base;
+	gpccr_pps_e pps;
+	gpt_t_val_e t;
+	gpccr_pgs_e pgs;
+	gpt_p_val_e p;
+} gpt_config_t;
+
+static gpt_config_t gpt_config;
+
+/* These variables are used during initialization of the L1 tables. */
+static unsigned int gpt_next_l1_tbl_idx;
+static uintptr_t gpt_l1_tbl;
+
+/*
+ * This function checks to see if a GPI value is valid.
+ *
+ * These are valid GPI values.
+ *   GPT_GPI_NO_ACCESS   U(0x0)
+ *   GPT_GPI_SECURE      U(0x8)
+ *   GPT_GPI_NS          U(0x9)
+ *   GPT_GPI_ROOT        U(0xA)
+ *   GPT_GPI_REALM       U(0xB)
+ *   GPT_GPI_ANY         U(0xF)
+ *
+ * Parameters
+ *   gpi		GPI to check for validity.
+ *
+ * Return
+ *   true for a valid GPI, false for an invalid one.
+ */
+static bool gpt_is_gpi_valid(unsigned int gpi)
+{
+	if ((gpi == GPT_GPI_NO_ACCESS) || (gpi == GPT_GPI_ANY) ||
+	    ((gpi >= GPT_GPI_SECURE) && (gpi <= GPT_GPI_REALM))) {
+		return true;
+	} else {
+		return false;
+	}
+}
+
+/*
+ * This function checks to see if two PAS regions overlap.
+ *
+ * Parameters
+ *   base_1: base address of first PAS
+ *   size_1: size of first PAS
+ *   base_2: base address of second PAS
+ *   size_2: size of second PAS
+ *
+ * Return
+ *   True if PAS regions overlap, false if they do not.
+ */
+static bool gpt_check_pas_overlap(uintptr_t base_1, size_t size_1,
+				  uintptr_t base_2, size_t size_2)
+{
+	if (((base_1 + size_1) > base_2) && ((base_2 + size_2) > base_1)) {
+		return true;
+	} else {
+		return false;
+	}
+}
+
+/*
+ * This helper function checks to see if a PAS region from index 0 to
+ * (pas_idx - 1) occupies the L0 region at index l0_idx in the L0 table.
+ *
+ * Parameters
+ *   l0_idx:      Index of the L0 entry to check
+ *   pas_regions: PAS region array
+ *   pas_idx:     Upper bound of the PAS array index.
+ *
+ * Return
+ *   True if a PAS region occupies the L0 region in question, false if not.
+ */
+static bool gpt_does_previous_pas_exist_here(unsigned int l0_idx,
+					     pas_region_t *pas_regions,
+					     unsigned int pas_idx)
+{
+	/* Iterate over PAS regions up to pas_idx. */
+	for (unsigned int i = 0U; i < pas_idx; i++) {
+		if (gpt_check_pas_overlap((GPT_L0GPTSZ_ACTUAL_SIZE * l0_idx),
+		    GPT_L0GPTSZ_ACTUAL_SIZE,
+		    pas_regions[i].base_pa, pas_regions[i].size)) {
+			return true;
+		}
+	}
+	return false;
+}
+
+/*
+ * This function iterates over all of the PAS regions and checks them to ensure
+ * proper alignment of base and size, that the GPI is valid, and that no regions
+ * overlap. As a part of the overlap checks, this function checks existing L0
+ * mappings against the new PAS regions in the event that gpt_init_pas_l1_tables
+ * is called multiple times to place L1 tables in different areas of memory. It
+ * also counts the number of L1 tables needed and returns it on success.
+ *
+ * Parameters
+ *   *pas_regions	Pointer to array of PAS region structures.
+ *   pas_region_cnt	Total number of PAS regions in the array.
+ *
+ * Return
+ *   Negative Linux error code in the event of a failure, number of L1 regions
+ *   required when successful.
+ */
+static int gpt_validate_pas_mappings(pas_region_t *pas_regions,
+				     unsigned int pas_region_cnt)
+{
+	unsigned int idx;
+	unsigned int l1_cnt = 0U;
+	unsigned int pas_l1_cnt;
+	uint64_t *l0_desc = (uint64_t *)gpt_config.plat_gpt_l0_base;
+
+	assert(pas_regions != NULL);
+	assert(pas_region_cnt != 0U);
+
+	for (idx = 0U; idx < pas_region_cnt; idx++) {
+		/* Check for arithmetic overflow in region. */
+		if ((ULONG_MAX - pas_regions[idx].base_pa) <
+		    pas_regions[idx].size) {
+			ERROR("[GPT] Address overflow in PAS[%u]!\n", idx);
+			return -EOVERFLOW;
+		}
+
+		/* Initial checks for PAS validity. */
+		if (((pas_regions[idx].base_pa + pas_regions[idx].size) >
+		    GPT_PPS_ACTUAL_SIZE(gpt_config.t)) ||
+		    !gpt_is_gpi_valid(GPT_PAS_ATTR_GPI(pas_regions[idx].attrs))) {
+			ERROR("[GPT] PAS[%u] is invalid!\n", idx);
+			return -EFAULT;
+		}
+
+		/*
+		 * Make sure this PAS does not overlap with another one. We
+		 * start from idx + 1 instead of 0 since prior PAS mappings will
+		 * have already checked themselves against this one.
+		 */
+		for (unsigned int i = idx + 1; i < pas_region_cnt; i++) {
+			if (gpt_check_pas_overlap(pas_regions[idx].base_pa,
+			    pas_regions[idx].size,
+			    pas_regions[i].base_pa,
+			    pas_regions[i].size)) {
+				ERROR("[GPT] PAS[%u] overlaps with PAS[%u]\n",
+					i, idx);
+				return -EFAULT;
+			}
+		}
+
+		/*
+		 * Since this function can be called multiple times with
+		 * separate L1 tables we need to check the existing L0 mapping
+		 * to see if this PAS would fall into one that has already been
+		 * initialized.
+		 */
+		for (unsigned int i = GPT_L0_IDX(pas_regions[idx].base_pa);
+		     i <= GPT_L0_IDX(pas_regions[idx].base_pa + pas_regions[idx].size - 1);
+		     i++) {
+			if ((GPT_L0_TYPE(l0_desc[i]) == GPT_L0_TYPE_BLK_DESC) &&
+			    (GPT_L0_BLKD_GPI(l0_desc[i]) == GPT_GPI_ANY)) {
+				/* This descriptor is unused so continue. */
+				continue;
+			}
+
+			/*
+			 * This descriptor has been initialized in a previous
+			 * call to this function so cannot be initialized again.
+			 */
+			ERROR("[GPT] PAS[%u] overlaps with previous L0[%d]!\n",
+			      idx, i);
+			return -EFAULT;
+		}
+
+		/* Check for block mapping (L0) type. */
+		if (GPT_PAS_ATTR_MAP_TYPE(pas_regions[idx].attrs) ==
+		    GPT_PAS_ATTR_MAP_TYPE_BLOCK) {
+			/* Make sure base and size are block-aligned. */
+			if (!GPT_IS_L0_ALIGNED(pas_regions[idx].base_pa) ||
+			    !GPT_IS_L0_ALIGNED(pas_regions[idx].size)) {
+				ERROR("[GPT] PAS[%u] is not block-aligned!\n",
+				      idx);
+				return -EFAULT;
+			}
+
+			continue;
+		}
+
+		/* Check for granule mapping (L1) type. */
+		if (GPT_PAS_ATTR_MAP_TYPE(pas_regions[idx].attrs) ==
+		    GPT_PAS_ATTR_MAP_TYPE_GRANULE) {
+			/* Make sure base and size are granule-aligned. */
+			if (!GPT_IS_L1_ALIGNED(gpt_config.p, pas_regions[idx].base_pa) ||
+			    !GPT_IS_L1_ALIGNED(gpt_config.p, pas_regions[idx].size)) {
+				ERROR("[GPT] PAS[%u] is not granule-aligned!\n",
+				      idx);
+				return -EFAULT;
+			}
+
+			/* Find how many L1 tables this PAS occupies. */
+			pas_l1_cnt = (GPT_L0_IDX(pas_regions[idx].base_pa +
+				     pas_regions[idx].size - 1) -
+				     GPT_L0_IDX(pas_regions[idx].base_pa) + 1);
+
+			/*
+			 * This creates a situation where, if multiple PAS
+			 * regions occupy the same table descriptor, we can get
+			 * an artificially high total L1 table count. The way we
+			 * handle this is by checking each PAS against those
+			 * before it in the array, and if they both occupy the
+			 * same PAS we subtract from pas_l1_cnt and only the
+			 * first PAS in the array gets to count it.
+			 */
+
+			/*
+			 * If L1 count is greater than 1 we know the start and
+			 * end PAs are in different L0 regions so we must check
+			 * both for overlap against other PAS.
+			 */
+			if (pas_l1_cnt > 1) {
+				if (gpt_does_previous_pas_exist_here(
+				    GPT_L0_IDX(pas_regions[idx].base_pa +
+				    pas_regions[idx].size - 1),
+				    pas_regions, idx)) {
+					pas_l1_cnt = pas_l1_cnt - 1;
+				}
+			}
+
+			if (gpt_does_previous_pas_exist_here(
+			    GPT_L0_IDX(pas_regions[idx].base_pa),
+			    pas_regions, idx)) {
+				pas_l1_cnt = pas_l1_cnt - 1;
+			}
+
+			l1_cnt += pas_l1_cnt;
+			continue;
+		}
+
+		/* If execution reaches this point, mapping type is invalid. */
+		ERROR("[GPT] PAS[%u] has invalid mapping type 0x%x.\n", idx,
+		      GPT_PAS_ATTR_MAP_TYPE(pas_regions[idx].attrs));
+		return -EINVAL;
+	}
+
+	return l1_cnt;
+}
+
+/*
+ * This function validates L0 initialization parameters.
+ *
+ * Parameters
+ *   l0_mem_base	Base address of memory used for L0 tables.
+ *   l1_mem_size	Size of memory available for L0 tables.
+ *
+ * Return
+ *   Negative Linux error code in the event of a failure, 0 for success.
+ */
+static int gpt_validate_l0_params(gpccr_pps_e pps, uintptr_t l0_mem_base,
+				  size_t l0_mem_size)
+{
+	size_t l0_alignment;
+
+	/*
+	 * Make sure PPS is valid and then store it since macros need this value
+	 * to work.
+	 */
+	if (pps > GPT_PPS_MAX) {
+		ERROR("[GPT] Invalid PPS: 0x%x\n", pps);
+		return -EINVAL;
+	}
+	gpt_config.pps = pps;
+	gpt_config.t = gpt_t_lookup[pps];
+
+	/* Alignment must be the greater of 4k or l0 table size. */
+	l0_alignment = PAGE_SIZE_4KB;
+	if (l0_alignment < GPT_L0_TABLE_SIZE(gpt_config.t)) {
+		l0_alignment = GPT_L0_TABLE_SIZE(gpt_config.t);
+	}
+
+	/* Check base address. */
+	if ((l0_mem_base == 0U) || ((l0_mem_base & (l0_alignment - 1)) != 0U)) {
+		ERROR("[GPT] Invalid L0 base address: 0x%lx\n", l0_mem_base);
+		return -EFAULT;
+	}
+
+	/* Check size. */
+	if (l0_mem_size < GPT_L0_TABLE_SIZE(gpt_config.t)) {
+		ERROR("[GPT] Inadequate L0 memory: need 0x%lx, have 0x%lx)\n",
+		      GPT_L0_TABLE_SIZE(gpt_config.t),
+		      l0_mem_size);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/*
+ * In the event that L1 tables are needed, this function validates
+ * the L1 table generation parameters.
+ *
+ * Parameters
+ *   l1_mem_base	Base address of memory used for L1 table allocation.
+ *   l1_mem_size	Total size of memory available for L1 tables.
+ *   l1_gpt_cnt		Number of L1 tables needed.
+ *
+ * Return
+ *   Negative Linux error code in the event of a failure, 0 for success.
+ */
+static int gpt_validate_l1_params(uintptr_t l1_mem_base, size_t l1_mem_size,
+				  unsigned int l1_gpt_cnt)
+{
+	size_t l1_gpt_mem_sz;
+
+	/* Check if the granularity is supported */
+	if (!xlat_arch_is_granule_size_supported(
+	    GPT_PGS_ACTUAL_SIZE(gpt_config.p))) {
+		return -EPERM;
+	}
+
+	/* Make sure L1 tables are aligned to their size. */
+	if ((l1_mem_base & (GPT_L1_TABLE_SIZE(gpt_config.p) - 1)) != 0U) {
+		ERROR("[GPT] Unaligned L1 GPT base address: 0x%lx\n",
+		      l1_mem_base);
+		return -EFAULT;
+	}
+
+	/* Get total memory needed for L1 tables. */
+	l1_gpt_mem_sz = l1_gpt_cnt * GPT_L1_TABLE_SIZE(gpt_config.p);
+
+	/* Check for overflow. */
+	if ((l1_gpt_mem_sz / GPT_L1_TABLE_SIZE(gpt_config.p)) != l1_gpt_cnt) {
+		ERROR("[GPT] Overflow calculating L1 memory size.\n");
+		return -ENOMEM;
+	}
+
+	/* Make sure enough space was supplied. */
+	if (l1_mem_size < l1_gpt_mem_sz) {
+		ERROR("[GPT] Inadequate memory for L1 GPTs. ");
+		ERROR("      Expected 0x%lx bytes. Got 0x%lx bytes\n",
+		      l1_gpt_mem_sz, l1_mem_size);
+		return -ENOMEM;
+	}
+
+	VERBOSE("[GPT] Requested 0x%lx bytes for L1 GPTs.\n", l1_gpt_mem_sz);
+	return 0;
+}
+
+/*
+ * This function initializes L0 block descriptors (regions that cannot be
+ * transitioned at the granule level) according to the provided PAS.
+ *
+ * Parameters
+ *   *pas		Pointer to the structure defining the PAS region to
+ *			initialize.
+ */
+static void gpt_generate_l0_blk_desc(pas_region_t *pas)
+{
+	uint64_t gpt_desc;
+	unsigned int end_idx;
+	unsigned int idx;
+	uint64_t *l0_gpt_arr;
+
+	assert(gpt_config.plat_gpt_l0_base != 0U);
+	assert(pas != NULL);
+
+	/*
+	 * Checking of PAS parameters has already been done in
+	 * gpt_validate_pas_mappings so no need to check the same things again.
+	 */
+
+	l0_gpt_arr = (uint64_t *)gpt_config.plat_gpt_l0_base;
+
+	/* Create the GPT Block descriptor for this PAS region */
+	gpt_desc = GPT_L0_BLK_DESC(GPT_PAS_ATTR_GPI(pas->attrs));
+
+	/* Start index of this region in L0 GPTs */
+	idx = pas->base_pa >> GPT_L0_IDX_SHIFT;
+
+	/*
+	 * Determine number of L0 GPT descriptors covered by
+	 * this PAS region and use the count to populate these
+	 * descriptors.
+	 */
+	end_idx = (pas->base_pa + pas->size) >> GPT_L0_IDX_SHIFT;
+
+	/* Generate the needed block descriptors. */
+	for (; idx < end_idx; idx++) {
+		l0_gpt_arr[idx] = gpt_desc;
+		VERBOSE("[GPT] L0 entry (BLOCK) index %u [%p]: GPI = 0x%llx (0x%llx)\n",
+			idx, &l0_gpt_arr[idx],
+			(gpt_desc >> GPT_L0_BLK_DESC_GPI_SHIFT) &
+			GPT_L0_BLK_DESC_GPI_MASK, l0_gpt_arr[idx]);
+	}
+}
+
+/*
+ * Helper function to determine if the end physical address lies in the same L0
+ * region as the current physical address. If true, the end physical address is
+ * returned else, the start address of the next region is returned.
+ *
+ * Parameters
+ *   cur_pa		Physical address of the current PA in the loop through
+ *			the range.
+ *   end_pa		Physical address of the end PA in a PAS range.
+ *
+ * Return
+ *   The PA of the end of the current range.
+ */
+static uintptr_t gpt_get_l1_end_pa(uintptr_t cur_pa, uintptr_t end_pa)
+{
+	uintptr_t cur_idx;
+	uintptr_t end_idx;
+
+	cur_idx = cur_pa >> GPT_L0_IDX_SHIFT;
+	end_idx = end_pa >> GPT_L0_IDX_SHIFT;
+
+	assert(cur_idx <= end_idx);
+
+	if (cur_idx == end_idx) {
+		return end_pa;
+	}
+
+	return (cur_idx + 1U) << GPT_L0_IDX_SHIFT;
+}
+
+/*
+ * Helper function to fill out GPI entries in a single L1 table. This function
+ * fills out entire L1 descriptors at a time to save memory writes.
+ *
+ * Parameters
+ *   gpi		GPI to set this range to
+ *   l1			Pointer to L1 table to fill out
+ *   first		Address of first granule in range.
+ *   last		Address of last granule in range (inclusive).
+ */
+static void gpt_fill_l1_tbl(uint64_t gpi, uint64_t *l1, uintptr_t first,
+			    uintptr_t last)
+{
+	uint64_t gpi_field = GPT_BUILD_L1_DESC(gpi);
+	uint64_t gpi_mask = 0xFFFFFFFFFFFFFFFF;
+
+	assert(first <= last);
+	assert((first & (GPT_PGS_ACTUAL_SIZE(gpt_config.p) - 1)) == 0U);
+	assert((last & (GPT_PGS_ACTUAL_SIZE(gpt_config.p) - 1)) == 0U);
+	assert(GPT_L0_IDX(first) == GPT_L0_IDX(last));
+	assert(l1 != NULL);
+
+	/* Shift the mask if we're starting in the middle of an L1 entry. */
+	gpi_mask = gpi_mask << (GPT_L1_GPI_IDX(gpt_config.p, first) << 2);
+
+	/* Fill out each L1 entry for this region. */
+	for (unsigned int i = GPT_L1_IDX(gpt_config.p, first);
+	     i <= GPT_L1_IDX(gpt_config.p, last); i++) {
+		/* Account for stopping in the middle of an L1 entry. */
+		if (i == GPT_L1_IDX(gpt_config.p, last)) {
+			gpi_mask &= (gpi_mask >> ((15 -
+				    GPT_L1_GPI_IDX(gpt_config.p, last)) << 2));
+		}
+
+		/* Write GPI values. */
+		assert((l1[i] & gpi_mask) ==
+		       (GPT_BUILD_L1_DESC(GPT_GPI_ANY) & gpi_mask));
+		l1[i] = (l1[i] & ~gpi_mask) | (gpi_mask & gpi_field);
+
+		/* Reset mask. */
+		gpi_mask = 0xFFFFFFFFFFFFFFFF;
+	}
+}
+
+/*
+ * This function finds the next available unused L1 table and initializes all
+ * granules descriptor entries to GPI_ANY. This ensures that there are no chunks
+ * of GPI_NO_ACCESS (0b0000) memory floating around in the system in the
+ * event that a PAS region stops midway through an L1 table, thus guaranteeing
+ * that all memory not explicitly assigned is GPI_ANY. This function does not
+ * check for overflow conditions, that should be done by the caller.
+ *
+ * Return
+ *   Pointer to the next available L1 table.
+ */
+static uint64_t *gpt_get_new_l1_tbl(void)
+{
+	/* Retrieve the next L1 table. */
+	uint64_t *l1 = (uint64_t *)((uint64_t)(gpt_l1_tbl) +
+		       (GPT_L1_TABLE_SIZE(gpt_config.p) *
+		       gpt_next_l1_tbl_idx));
+
+	/* Increment L1 counter. */
+	gpt_next_l1_tbl_idx++;
+
+	/* Initialize all GPIs to GPT_GPI_ANY */
+	for (unsigned int i = 0U; i < GPT_L1_ENTRY_COUNT(gpt_config.p); i++) {
+		l1[i] = GPT_BUILD_L1_DESC(GPT_GPI_ANY);
+	}
+
+	return l1;
+}
+
+/*
+ * When L1 tables are needed, this function creates the necessary L0 table
+ * descriptors and fills out the L1 table entries according to the supplied
+ * PAS range.
+ *
+ * Parameters
+ *   *pas		Pointer to the structure defining the PAS region.
+ */
+static void gpt_generate_l0_tbl_desc(pas_region_t *pas)
+{
+	uintptr_t end_pa;
+	uintptr_t cur_pa;
+	uintptr_t last_gran_pa;
+	uint64_t *l0_gpt_base;
+	uint64_t *l1_gpt_arr;
+	unsigned int l0_idx;
+
+	assert(gpt_config.plat_gpt_l0_base != 0U);
+	assert(pas != NULL);
+
+	/*
+	 * Checking of PAS parameters has already been done in
+	 * gpt_validate_pas_mappings so no need to check the same things again.
+	 */
+
+	end_pa = pas->base_pa + pas->size;
+	l0_gpt_base = (uint64_t *)gpt_config.plat_gpt_l0_base;
+
+	/* We start working from the granule at base PA */
+	cur_pa = pas->base_pa;
+
+	/* Iterate over each L0 region in this memory range. */
+	for (l0_idx = GPT_L0_IDX(pas->base_pa);
+	     l0_idx <= GPT_L0_IDX(end_pa - 1U);
+	     l0_idx++) {
+
+		/*
+		 * See if the L0 entry is already a table descriptor or if we
+		 * need to create one.
+		 */
+		if (GPT_L0_TYPE(l0_gpt_base[l0_idx]) == GPT_L0_TYPE_TBL_DESC) {
+			/* Get the L1 array from the L0 entry. */
+			l1_gpt_arr = GPT_L0_TBLD_ADDR(l0_gpt_base[l0_idx]);
+		} else {
+			/* Get a new L1 table from the L1 memory space. */
+			l1_gpt_arr = gpt_get_new_l1_tbl();
+
+			/* Fill out the L0 descriptor and flush it. */
+			l0_gpt_base[l0_idx] = GPT_L0_TBL_DESC(l1_gpt_arr);
+		}
+
+		VERBOSE("[GPT] L0 entry (TABLE) index %u [%p] ==> L1 Addr 0x%llx (0x%llx)\n",
+			l0_idx, &l0_gpt_base[l0_idx],
+			(unsigned long long)(l1_gpt_arr),
+			l0_gpt_base[l0_idx]);
+
+		/*
+		 * Determine the PA of the last granule in this L0 descriptor.
+		 */
+		last_gran_pa = gpt_get_l1_end_pa(cur_pa, end_pa) -
+			       GPT_PGS_ACTUAL_SIZE(gpt_config.p);
+
+		/*
+		 * Fill up L1 GPT entries between these two addresses. This
+		 * function needs the addresses of the first granule and last
+		 * granule in the range.
+		 */
+		gpt_fill_l1_tbl(GPT_PAS_ATTR_GPI(pas->attrs), l1_gpt_arr,
+				cur_pa, last_gran_pa);
+
+		/* Advance cur_pa to first granule in next L0 region. */
+		cur_pa = gpt_get_l1_end_pa(cur_pa, end_pa);
+	}
+}
+
+/*
+ * This function flushes a range of L0 descriptors used by a given PAS region
+ * array. There is a chance that some unmodified L0 descriptors would be flushed
+ * in the case that there are "holes" in an array of PAS regions but overall
+ * this should be faster than individually flushing each modified L0 descriptor
+ * as they are created.
+ *
+ * Parameters
+ *   *pas		Pointer to an array of PAS regions.
+ *   pas_count		Number of entries in the PAS array.
+ */
+static void flush_l0_for_pas_array(pas_region_t *pas, unsigned int pas_count)
+{
+	unsigned int idx;
+	unsigned int start_idx;
+	unsigned int end_idx;
+	uint64_t *l0 = (uint64_t *)gpt_config.plat_gpt_l0_base;
+
+	assert(pas != NULL);
+	assert(pas_count > 0);
+
+	/* Initial start and end values. */
+	start_idx = GPT_L0_IDX(pas[0].base_pa);
+	end_idx = GPT_L0_IDX(pas[0].base_pa + pas[0].size - 1);
+
+	/* Find lowest and highest L0 indices used in this PAS array. */
+	for (idx = 1; idx < pas_count; idx++) {
+		if (GPT_L0_IDX(pas[idx].base_pa) < start_idx) {
+			start_idx = GPT_L0_IDX(pas[idx].base_pa);
+		}
+		if (GPT_L0_IDX(pas[idx].base_pa + pas[idx].size - 1) > end_idx) {
+			end_idx = GPT_L0_IDX(pas[idx].base_pa + pas[idx].size - 1);
+		}
+	}
+
+	/*
+	 * Flush all covered L0 descriptors, add 1 because we need to include
+	 * the end index value.
+	 */
+	flush_dcache_range((uintptr_t)&l0[start_idx],
+			   ((end_idx + 1) - start_idx) * sizeof(uint64_t));
+}
+
+/*
+ * Public API to enable granule protection checks once the tables have all been
+ * initialized. This function is called at first initialization and then again
+ * later during warm boots of CPU cores.
+ *
+ * Return
+ *   Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_enable(void)
+{
+	u_register_t gpccr_el3;
+
+	/*
+	 * Granule tables must be initialised before enabling
+	 * granule protection.
+	 */
+	if (gpt_config.plat_gpt_l0_base == 0U) {
+		ERROR("[GPT] Tables have not been initialized!\n");
+		return -EPERM;
+	}
+
+	/* Invalidate any stale TLB entries */
+	tlbipaallos();
+	dsb();
+
+	/* Write the base address of the L0 tables into GPTBR */
+	write_gptbr_el3(((gpt_config.plat_gpt_l0_base >> GPTBR_BADDR_VAL_SHIFT)
+			>> GPTBR_BADDR_SHIFT) & GPTBR_BADDR_MASK);
+
+	/* GPCCR_EL3.PPS */
+	gpccr_el3 = SET_GPCCR_PPS(gpt_config.pps);
+
+	/* GPCCR_EL3.PGS */
+	gpccr_el3 |= SET_GPCCR_PGS(gpt_config.pgs);
+
+	/* Set shareability attribute to Outher Shareable */
+	gpccr_el3 |= SET_GPCCR_SH(GPCCR_SH_OS);
+
+	/* Outer and Inner cacheability set to Normal memory, WB, RA, WA. */
+	gpccr_el3 |= SET_GPCCR_ORGN(GPCCR_ORGN_WB_RA_WA);
+	gpccr_el3 |= SET_GPCCR_IRGN(GPCCR_IRGN_WB_RA_WA);
+
+	/* Enable GPT */
+	gpccr_el3 |= GPCCR_GPC_BIT;
+
+	/* TODO: Configure GPCCR_EL3_GPCP for Fault control. */
+	write_gpccr_el3(gpccr_el3);
+	tlbipaallos();
+	dsb();
+	isb();
+
+	return 0;
+}
+
+/*
+ * Public API to disable granule protection checks.
+ */
+void gpt_disable(void)
+{
+	u_register_t gpccr_el3 = read_gpccr_el3();
+
+	write_gpccr_el3(gpccr_el3 & ~GPCCR_GPC_BIT);
+	dsbsy();
+	isb();
+}
+
+/*
+ * Public API that initializes the entire protected space to GPT_GPI_ANY using
+ * the L0 tables (block descriptors). Ideally, this function is invoked prior
+ * to DDR discovery and initialization. The MMU must be initialized before
+ * calling this function.
+ *
+ * Parameters
+ *   pps		PPS value to use for table generation
+ *   l0_mem_base	Base address of L0 tables in memory.
+ *   l0_mem_size	Total size of memory available for L0 tables.
+ *
+ * Return
+ *   Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_init_l0_tables(unsigned int pps, uintptr_t l0_mem_base,
+		       size_t l0_mem_size)
+{
+	int ret;
+	uint64_t gpt_desc;
+
+	/* Ensure that MMU and caches are enabled. */
+	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+
+	/* Validate other parameters. */
+	ret = gpt_validate_l0_params(pps, l0_mem_base, l0_mem_size);
+	if (ret < 0) {
+		return ret;
+	}
+
+	/* Create the descriptor to initialize L0 entries with. */
+	gpt_desc = GPT_L0_BLK_DESC(GPT_GPI_ANY);
+
+	/* Iterate through all L0 entries */
+	for (unsigned int i = 0U; i < GPT_L0_REGION_COUNT(gpt_config.t); i++) {
+		((uint64_t *)l0_mem_base)[i] = gpt_desc;
+	}
+
+	/* Flush updated L0 tables to memory. */
+	flush_dcache_range((uintptr_t)l0_mem_base,
+			   (size_t)GPT_L0_TABLE_SIZE(gpt_config.t));
+
+	/* Stash the L0 base address once initial setup is complete. */
+	gpt_config.plat_gpt_l0_base = l0_mem_base;
+
+	return 0;
+}
+
+/*
+ * Public API that carves out PAS regions from the L0 tables and builds any L1
+ * tables that are needed. This function ideally is run after DDR discovery and
+ * initialization. The L0 tables must have already been initialized to GPI_ANY
+ * when this function is called.
+ *
+ * This function can be called multiple times with different L1 memory ranges
+ * and PAS regions if it is desirable to place L1 tables in different locations
+ * in memory. (ex: you have multiple DDR banks and want to place the L1 tables
+ * in the DDR bank that they control)
+ *
+ * Parameters
+ *   pgs		PGS value to use for table generation.
+ *   l1_mem_base	Base address of memory used for L1 tables.
+ *   l1_mem_size	Total size of memory available for L1 tables.
+ *   *pas_regions	Pointer to PAS regions structure array.
+ *   pas_count		Total number of PAS regions.
+ *
+ * Return
+ *   Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_init_pas_l1_tables(gpccr_pgs_e pgs, uintptr_t l1_mem_base,
+			   size_t l1_mem_size, pas_region_t *pas_regions,
+			   unsigned int pas_count)
+{
+	int ret;
+	int l1_gpt_cnt;
+
+	/* Ensure that MMU and caches are enabled. */
+	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+
+	/* PGS is needed for gpt_validate_pas_mappings so check it now. */
+	if (pgs > GPT_PGS_MAX) {
+		ERROR("[GPT] Invalid PGS: 0x%x\n", pgs);
+		return -EINVAL;
+	}
+	gpt_config.pgs = pgs;
+	gpt_config.p = gpt_p_lookup[pgs];
+
+	/* Make sure L0 tables have been initialized. */
+	if (gpt_config.plat_gpt_l0_base == 0U) {
+		ERROR("[GPT] L0 tables must be initialized first!\n");
+		return -EPERM;
+	}
+
+	/* Check if L1 GPTs are required and how many. */
+	l1_gpt_cnt = gpt_validate_pas_mappings(pas_regions, pas_count);
+	if (l1_gpt_cnt < 0) {
+		return l1_gpt_cnt;
+	}
+
+	VERBOSE("[GPT] %u L1 GPTs requested.\n", l1_gpt_cnt);
+
+	/* If L1 tables are needed then validate the L1 parameters. */
+	if (l1_gpt_cnt > 0) {
+		ret = gpt_validate_l1_params(l1_mem_base, l1_mem_size,
+		      l1_gpt_cnt);
+		if (ret < 0) {
+			return ret;
+		}
+
+		/* Set up parameters for L1 table generation. */
+		gpt_l1_tbl = l1_mem_base;
+		gpt_next_l1_tbl_idx = 0U;
+	}
+
+	INFO("[GPT] Boot Configuration\n");
+	INFO("  PPS/T:     0x%x/%u\n", gpt_config.pps, gpt_config.t);
+	INFO("  PGS/P:     0x%x/%u\n", gpt_config.pgs, gpt_config.p);
+	INFO("  L0GPTSZ/S: 0x%x/%u\n", GPT_L0GPTSZ, GPT_S_VAL);
+	INFO("  PAS count: 0x%x\n", pas_count);
+	INFO("  L0 base:   0x%lx\n", gpt_config.plat_gpt_l0_base);
+
+	/* Generate the tables in memory. */
+	for (unsigned int idx = 0U; idx < pas_count; idx++) {
+		INFO("[GPT] PAS[%u]: base 0x%lx, size 0x%lx, GPI 0x%x, type 0x%x\n",
+		     idx, pas_regions[idx].base_pa, pas_regions[idx].size,
+		     GPT_PAS_ATTR_GPI(pas_regions[idx].attrs),
+		     GPT_PAS_ATTR_MAP_TYPE(pas_regions[idx].attrs));
+
+		/* Check if a block or table descriptor is required */
+		if (GPT_PAS_ATTR_MAP_TYPE(pas_regions[idx].attrs) ==
+		    GPT_PAS_ATTR_MAP_TYPE_BLOCK) {
+			gpt_generate_l0_blk_desc(&pas_regions[idx]);
+
+		} else {
+			gpt_generate_l0_tbl_desc(&pas_regions[idx]);
+		}
+	}
+
+	/* Flush modified L0 tables. */
+	flush_l0_for_pas_array(pas_regions, pas_count);
+
+	/* Flush L1 tables if needed. */
+	if (l1_gpt_cnt > 0) {
+		flush_dcache_range(l1_mem_base,
+				   GPT_L1_TABLE_SIZE(gpt_config.p) *
+				   l1_gpt_cnt);
+	}
+
+	/* Make sure that all the entries are written to the memory. */
+	dsbishst();
+
+	return 0;
+}
+
+/*
+ * Public API to initialize the runtime gpt_config structure based on the values
+ * present in the GPTBR_EL3 and GPCCR_EL3 registers. GPT initialization
+ * typically happens in a bootloader stage prior to setting up the EL3 runtime
+ * environment for the granule transition service so this function detects the
+ * initialization from a previous stage. Granule protection checks must be
+ * enabled already or this function will return an error.
+ *
+ * Return
+ *   Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_runtime_init(void)
+{
+	u_register_t reg;
+
+	/* Ensure that MMU and caches are enabled. */
+	assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U);
+
+	/* Ensure GPC are already enabled. */
+	if ((read_gpccr_el3() & GPCCR_GPC_BIT) == 0U) {
+		ERROR("[GPT] Granule protection checks are not enabled!\n");
+		return -EPERM;
+	}
+
+	/*
+	 * Read the L0 table address from GPTBR, we don't need the L1 base
+	 * address since those are included in the L0 tables as needed.
+	 */
+	reg = read_gptbr_el3();
+	gpt_config.plat_gpt_l0_base = ((reg >> GPTBR_BADDR_SHIFT) &
+				      GPTBR_BADDR_MASK) <<
+				      GPTBR_BADDR_VAL_SHIFT;
+
+	/* Read GPCCR to get PGS and PPS values. */
+	reg = read_gpccr_el3();
+	gpt_config.pps = (reg >> GPCCR_PPS_SHIFT) & GPCCR_PPS_MASK;
+	gpt_config.t = gpt_t_lookup[gpt_config.pps];
+	gpt_config.pgs = (reg >> GPCCR_PGS_SHIFT) & GPCCR_PGS_MASK;
+	gpt_config.p = gpt_p_lookup[gpt_config.pgs];
+
+	VERBOSE("[GPT] Runtime Configuration\n");
+	VERBOSE("  PPS/T:     0x%x/%u\n", gpt_config.pps, gpt_config.t);
+	VERBOSE("  PGS/P:     0x%x/%u\n", gpt_config.pgs, gpt_config.p);
+	VERBOSE("  L0GPTSZ/S: 0x%x/%u\n", GPT_L0GPTSZ, GPT_S_VAL);
+	VERBOSE("  L0 base:   0x%lx\n", gpt_config.plat_gpt_l0_base);
+
+	return 0;
+}
+
+/*
+ * The L1 descriptors are protected by a spinlock to ensure that multiple
+ * CPUs do not attempt to change the descriptors at once. In the future it
+ * would be better to have separate spinlocks for each L1 descriptor.
+ */
+static spinlock_t gpt_lock;
+
+/*
+ * Check if caller is allowed to transition a PAS.
+ *
+ * - Secure world caller can only request S <-> NS transitions on a
+ *   granule that is already in either S or NS PAS.
+ *
+ * - Realm world caller can only request R <-> NS transitions on a
+ *   granule that is already in either R or NS PAS.
+ *
+ * Parameters
+ *   src_sec_state	Security state of the caller.
+ *   current_gpi	Current GPI of the granule.
+ *   target_gpi		Requested new GPI for the granule.
+ *
+ * Return
+ *   Negative Linux error code in the event of a failure, 0 for success.
+ */
+static int gpt_check_transition_gpi(unsigned int src_sec_state,
+				    unsigned int current_gpi,
+				    unsigned int target_gpi)
+{
+	unsigned int check_gpi;
+
+	/* Cannot transition a granule to the state it is already in. */
+	if (current_gpi == target_gpi) {
+		return -EINVAL;
+	}
+
+	/* Check security state, only secure and realm can transition. */
+	if (src_sec_state == SMC_FROM_REALM) {
+		check_gpi = GPT_GPI_REALM;
+	} else if (src_sec_state == SMC_FROM_SECURE) {
+		check_gpi = GPT_GPI_SECURE;
+	} else {
+		return -EINVAL;
+	}
+
+	/* Make sure security state is allowed to make the transition. */
+	if ((target_gpi != check_gpi) && (target_gpi != GPT_GPI_NS)) {
+		return -EINVAL;
+	}
+	if ((current_gpi != check_gpi) && (current_gpi != GPT_GPI_NS)) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
+ * This function is the core of the granule transition service. When a granule
+ * transition request occurs it is routed to this function where the request is
+ * validated then fulfilled if possible.
+ *
+ * TODO: implement support for transitioning multiple granules at once.
+ *
+ * Parameters
+ *   base		Base address of the region to transition, must be
+ *			aligned to granule size.
+ *   size		Size of region to transition, must be aligned to granule
+ *			size.
+ *   src_sec_state	Security state of the caller.
+ *   target_pas		Target PAS of the specified memory region.
+ *
+ * Return
+ *    Negative Linux error code in the event of a failure, 0 for success.
+ */
+int gpt_transition_pas(uint64_t base, size_t size, unsigned int src_sec_state,
+	unsigned int target_pas)
+{
+	int idx;
+	unsigned int gpi_shift;
+	unsigned int gpi;
+	uint64_t gpt_l0_desc;
+	uint64_t gpt_l1_desc;
+	uint64_t *gpt_l1_addr;
+	uint64_t *gpt_l0_base;
+
+	/* Ensure that the tables have been set up before taking requests. */
+	assert(gpt_config.plat_gpt_l0_base != 0U);
+
+	/* Check for address range overflow. */
+	if ((ULONG_MAX - base) < size) {
+		VERBOSE("[GPT] Transition request address overflow!\n");
+		VERBOSE("      Base=0x%llx\n", base);
+		VERBOSE("      Size=0x%lx\n", size);
+		return -EINVAL;
+	}
+
+	/* Make sure base and size are valid. */
+	if (((base & (GPT_PGS_ACTUAL_SIZE(gpt_config.p) - 1)) != 0U) ||
+	    ((size & (GPT_PGS_ACTUAL_SIZE(gpt_config.p) - 1)) != 0U) ||
+	    (size == 0U) ||
+	    ((base + size) >= GPT_PPS_ACTUAL_SIZE(gpt_config.t))) {
+		VERBOSE("[GPT] Invalid granule transition address range!\n");
+		VERBOSE("      Base=0x%llx\n", base);
+		VERBOSE("      Size=0x%lx\n", size);
+		return -EINVAL;
+	}
+
+	/* See if this is a single granule transition or a range of granules. */
+	if (size != GPT_PGS_ACTUAL_SIZE(gpt_config.p)) {
+		/*
+		 * TODO: Add support for transitioning multiple granules with a
+		 * single call to this function.
+		 */
+		panic();
+	}
+
+	/* Get the L0 descriptor and make sure it is for a table. */
+	gpt_l0_base = (uint64_t *)gpt_config.plat_gpt_l0_base;
+	gpt_l0_desc = gpt_l0_base[GPT_L0_IDX(base)];
+	if (GPT_L0_TYPE(gpt_l0_desc) != GPT_L0_TYPE_TBL_DESC) {
+		VERBOSE("[GPT] Granule is not covered by a table descriptor!\n");
+		VERBOSE("      Base=0x%llx\n", base);
+		return -EINVAL;
+	}
+
+	/* Get the table index and GPI shift from PA. */
+	gpt_l1_addr = GPT_L0_TBLD_ADDR(gpt_l0_desc);
+	idx = GPT_L1_IDX(gpt_config.p, base);
+	gpi_shift = GPT_L1_GPI_IDX(gpt_config.p, base) << 2;
+
+	/*
+	 * Access to L1 tables is controlled by a global lock to ensure
+	 * that no more than one CPU is allowed to make changes at any
+	 * given time.
+	 */
+	spin_lock(&gpt_lock);
+	gpt_l1_desc = gpt_l1_addr[idx];
+	gpi = (gpt_l1_desc >> gpi_shift) & GPT_L1_GRAN_DESC_GPI_MASK;
+
+	/* Make sure caller state and source/target PAS are allowed. */
+	if (gpt_check_transition_gpi(src_sec_state, gpi, target_pas) < 0) {
+		spin_unlock(&gpt_lock);
+			VERBOSE("[GPT] Invalid caller state and PAS combo!\n");
+		VERBOSE("      Caller: %u, Current GPI: %u, Target GPI: %u\n",
+			src_sec_state, gpi, target_pas);
+		return -EPERM;
+	}
+
+	/* Clear existing GPI encoding and transition granule. */
+	gpt_l1_desc &= ~(GPT_L1_GRAN_DESC_GPI_MASK << gpi_shift);
+	gpt_l1_desc |= ((uint64_t)target_pas << gpi_shift);
+	gpt_l1_addr[idx] = gpt_l1_desc;
+
+	/* Ensure that the write operation happens before the unlock. */
+	dmbishst();
+
+	/* Unlock access to the L1 tables. */
+	spin_unlock(&gpt_lock);
+
+	/* Cache maintenance. */
+	clean_dcache_range((uintptr_t)&gpt_l1_addr[idx],
+			   sizeof(uint64_t));
+	gpt_tlbi_by_pa(base, GPT_PGS_ACTUAL_SIZE(gpt_config.p));
+	dsbishst();
+
+	VERBOSE("[GPT] Granule 0x%llx, GPI 0x%x->0x%x\n", base, gpi,
+		target_pas);
+
+	return 0;
+}
diff --git a/lib/gpt_rme/gpt_rme.mk b/lib/gpt_rme/gpt_rme.mk
new file mode 100644
index 0000000..60176f4
--- /dev/null
+++ b/lib/gpt_rme/gpt_rme.mk
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+GPT_LIB_SRCS	:=	$(addprefix lib/gpt_rme/,        \
+			gpt_rme.c)
diff --git a/lib/gpt_rme/gpt_rme_private.h b/lib/gpt_rme/gpt_rme_private.h
new file mode 100644
index 0000000..5770bf7
--- /dev/null
+++ b/lib/gpt_rme/gpt_rme_private.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef GPT_RME_PRIVATE_H
+#define GPT_RME_PRIVATE_H
+
+#include <arch.h>
+#include <lib/gpt_rme/gpt_rme.h>
+#include <lib/utils_def.h>
+
+/******************************************************************************/
+/* GPT descriptor definitions                                                 */
+/******************************************************************************/
+
+/* GPT level 0 descriptor bit definitions. */
+#define GPT_L0_TYPE_MASK		UL(0xF)
+#define GPT_L0_TYPE_SHIFT		U(0)
+
+/* For now, we don't support contiguous descriptors, only table and block. */
+#define GPT_L0_TYPE_TBL_DESC		UL(0x3)
+#define GPT_L0_TYPE_BLK_DESC		UL(0x1)
+
+#define GPT_L0_TBL_DESC_L1ADDR_MASK	UL(0xFFFFFFFFFF)
+#define GPT_L0_TBL_DESC_L1ADDR_SHIFT	U(12)
+
+#define GPT_L0_BLK_DESC_GPI_MASK	UL(0xF)
+#define GPT_L0_BLK_DESC_GPI_SHIFT	U(4)
+
+/* GPT level 1 descriptor bit definitions */
+#define GPT_L1_GRAN_DESC_GPI_MASK	UL(0xF)
+
+/*
+ * This macro fills out every GPI entry in a granules descriptor to the same
+ * value.
+ */
+#define GPT_BUILD_L1_DESC(_gpi)		(((uint64_t)(_gpi) << 4*0) | \
+					 ((uint64_t)(_gpi) << 4*1) | \
+					 ((uint64_t)(_gpi) << 4*2) | \
+					 ((uint64_t)(_gpi) << 4*3) | \
+					 ((uint64_t)(_gpi) << 4*4) | \
+					 ((uint64_t)(_gpi) << 4*5) | \
+					 ((uint64_t)(_gpi) << 4*6) | \
+					 ((uint64_t)(_gpi) << 4*7) | \
+					 ((uint64_t)(_gpi) << 4*8) | \
+					 ((uint64_t)(_gpi) << 4*9) | \
+					 ((uint64_t)(_gpi) << 4*10) | \
+					 ((uint64_t)(_gpi) << 4*11) | \
+					 ((uint64_t)(_gpi) << 4*12) | \
+					 ((uint64_t)(_gpi) << 4*13) | \
+					 ((uint64_t)(_gpi) << 4*14) | \
+					 ((uint64_t)(_gpi) << 4*15))
+
+/******************************************************************************/
+/* GPT platform configuration                                                 */
+/******************************************************************************/
+
+/* This value comes from GPCCR_EL3 so no externally supplied definition. */
+#define GPT_L0GPTSZ		((unsigned int)((read_gpccr_el3() >> \
+				GPCCR_L0GPTSZ_SHIFT) & GPCCR_L0GPTSZ_MASK))
+
+/* The "S" value is directly related to L0GPTSZ */
+#define GPT_S_VAL		(GPT_L0GPTSZ + 30U)
+
+/*
+ * Map PPS values to T values.
+ *
+ *   PPS    Size    T
+ *   0b000  4GB     32
+ *   0b001  64GB    36
+ *   0b010  1TB     40
+ *   0b011  4TB     42
+ *   0b100  16TB    44
+ *   0b101  256TB   48
+ *   0b110  4PB     52
+ *
+ * See section 15.1.27 of the RME specification.
+ */
+typedef enum {
+	PPS_4GB_T =	32U,
+	PPS_64GB_T =	36U,
+	PPS_1TB_T =	40U,
+	PPS_4TB_T =	42U,
+	PPS_16TB_T =	44U,
+	PPS_256TB_T =	48U,
+	PPS_4PB_T =	52U
+} gpt_t_val_e;
+
+/*
+ * Map PGS values to P values.
+ *
+ *   PGS    Size    P
+ *   0b00   4KB     12
+ *   0b10   16KB    14
+ *   0b01   64KB    16
+ *
+ * Note that pgs=0b10 is 16KB and pgs=0b01 is 64KB, this is not a typo.
+ *
+ * See section 15.1.27 of the RME specification.
+ */
+typedef enum {
+	PGS_4KB_P =	12U,
+	PGS_16KB_P =	14U,
+	PGS_64KB_P =	16U
+} gpt_p_val_e;
+
+/* Max valid value for PGS. */
+#define GPT_PGS_MAX			(2U)
+
+/* Max valid value for PPS. */
+#define GPT_PPS_MAX			(6U)
+
+/******************************************************************************/
+/* L0 address attribute macros                                                */
+/******************************************************************************/
+
+/*
+ * If S is greater than or equal to T then there is a single L0 region covering
+ * the entire protected space so there is no L0 index, so the width (and the
+ * derivative mask value) are both zero.  If we don't specifically handle this
+ * special case we'll get a negative width value which does not make sense and
+ * could cause a lot of problems.
+ */
+#define GPT_L0_IDX_WIDTH(_t)		(((_t) > GPT_S_VAL) ? \
+					((_t) - GPT_S_VAL) : (0U))
+
+/* Bit shift for the L0 index field in a PA. */
+#define GPT_L0_IDX_SHIFT		(GPT_S_VAL)
+
+/* Mask for the L0 index field, must be shifted. */
+#define GPT_L0_IDX_MASK(_t)		(0xFFFFFFFFFFFFFFFFUL >> \
+					(64U - (GPT_L0_IDX_WIDTH(_t))))
+
+/* Total number of L0 regions. */
+#define GPT_L0_REGION_COUNT(_t)		((GPT_L0_IDX_MASK(_t)) + 1U)
+
+/* Total size of each GPT L0 region in bytes. */
+#define GPT_L0_REGION_SIZE		(1UL << (GPT_L0_IDX_SHIFT))
+
+/* Total size in bytes of the whole L0 table. */
+#define GPT_L0_TABLE_SIZE(_t)		((GPT_L0_REGION_COUNT(_t)) << 3U)
+
+/******************************************************************************/
+/* L1 address attribute macros                                                */
+/******************************************************************************/
+
+/* Width of the L1 index field. */
+#define GPT_L1_IDX_WIDTH(_p)		((GPT_S_VAL - 1U) - ((_p) + 3U))
+
+/* Bit shift for the L1 index field. */
+#define GPT_L1_IDX_SHIFT(_p)		((_p) + 4U)
+
+/* Mask for the L1 index field, must be shifted. */
+#define GPT_L1_IDX_MASK(_p)		(0xFFFFFFFFFFFFFFFFUL >> \
+					(64U - (GPT_L1_IDX_WIDTH(_p))))
+
+/* Bit shift for the index of the L1 GPI in a PA. */
+#define GPT_L1_GPI_IDX_SHIFT(_p)	(_p)
+
+/* Mask for the index of the L1 GPI in a PA. */
+#define GPT_L1_GPI_IDX_MASK		(0xF)
+
+/* Total number of entries in each L1 table. */
+#define GPT_L1_ENTRY_COUNT(_p)		((GPT_L1_IDX_MASK(_p)) + 1U)
+
+/* Total size in bytes of each L1 table. */
+#define GPT_L1_TABLE_SIZE(_p)		((GPT_L1_ENTRY_COUNT(_p)) << 3U)
+
+/******************************************************************************/
+/* General helper macros                                                      */
+/******************************************************************************/
+
+/* Protected space actual size in bytes. */
+#define GPT_PPS_ACTUAL_SIZE(_t)	(1UL << (_t))
+
+/* Granule actual size in bytes. */
+#define GPT_PGS_ACTUAL_SIZE(_p)	(1UL << (_p))
+
+/* L0 GPT region size in bytes. */
+#define GPT_L0GPTSZ_ACTUAL_SIZE	(1UL << GPT_S_VAL)
+
+/* Get the index of the L0 entry from a physical address. */
+#define GPT_L0_IDX(_pa)		((_pa) >> GPT_L0_IDX_SHIFT)
+
+/*
+ * This definition is used to determine if a physical address lies on an L0
+ * region boundary.
+ */
+#define GPT_IS_L0_ALIGNED(_pa)	(((_pa) & (GPT_L0_REGION_SIZE - U(1))) == U(0))
+
+/* Get the type field from an L0 descriptor. */
+#define GPT_L0_TYPE(_desc)	(((_desc) >> GPT_L0_TYPE_SHIFT) & \
+				GPT_L0_TYPE_MASK)
+
+/* Create an L0 block descriptor. */
+#define GPT_L0_BLK_DESC(_gpi)	(GPT_L0_TYPE_BLK_DESC | \
+				(((_gpi) & GPT_L0_BLK_DESC_GPI_MASK) << \
+				GPT_L0_BLK_DESC_GPI_SHIFT))
+
+/* Create an L0 table descriptor with an L1 table address. */
+#define GPT_L0_TBL_DESC(_pa)	(GPT_L0_TYPE_TBL_DESC | ((uint64_t)(_pa) & \
+				(GPT_L0_TBL_DESC_L1ADDR_MASK << \
+				GPT_L0_TBL_DESC_L1ADDR_SHIFT)))
+
+/* Get the GPI from an L0 block descriptor. */
+#define GPT_L0_BLKD_GPI(_desc)	(((_desc) >> GPT_L0_BLK_DESC_GPI_SHIFT) & \
+				GPT_L0_BLK_DESC_GPI_MASK)
+
+/* Get the L1 address from an L0 table descriptor. */
+#define GPT_L0_TBLD_ADDR(_desc)	((uint64_t *)(((_desc) & \
+				(GPT_L0_TBL_DESC_L1ADDR_MASK << \
+				GPT_L0_TBL_DESC_L1ADDR_SHIFT))))
+
+/* Get the index into the L1 table from a physical address. */
+#define GPT_L1_IDX(_p, _pa)	(((_pa) >> GPT_L1_IDX_SHIFT(_p)) & \
+				GPT_L1_IDX_MASK(_p))
+
+/* Get the index of the GPI within an L1 table entry from a physical address. */
+#define GPT_L1_GPI_IDX(_p, _pa)	(((_pa) >> GPT_L1_GPI_IDX_SHIFT(_p)) & \
+				GPT_L1_GPI_IDX_MASK)
+
+/* Determine if an address is granule-aligned. */
+#define GPT_IS_L1_ALIGNED(_p, _pa) (((_pa) & (GPT_PGS_ACTUAL_SIZE(_p) - U(1))) \
+				   == U(0))
+
+#endif /* GPT_RME_PRIVATE_H */
diff --git a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
index a95ef07..a1a44af 100644
--- a/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c
@@ -39,6 +39,23 @@
 	return PAGE_SIZE_4KB;
 }
 
+/*
+ * Determine the physical address space encoded in the 'attr' parameter.
+ *
+ * The physical address will fall into one of two spaces; secure or
+ * nonsecure.
+ */
+uint32_t xlat_arch_get_pas(uint32_t attr)
+{
+	uint32_t pas = MT_PAS(attr);
+
+	if (pas == MT_NS) {
+		return LOWER_ATTRS(NS);
+	} else { /* MT_SECURE */
+		return 0U;
+	}
+}
+
 #if ENABLE_ASSERTIONS
 unsigned long long xlat_arch_get_max_supported_pa(void)
 {
diff --git a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
index 3832b07..719110a 100644
--- a/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
+++ b/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -53,6 +53,33 @@
 	}
 }
 
+/*
+ * Determine the physical address space encoded in the 'attr' parameter.
+ *
+ * The physical address will fall into one of four spaces; secure,
+ * nonsecure, root, or realm if RME is enabled, or one of two spaces;
+ * secure and nonsecure otherwise.
+ */
+uint32_t xlat_arch_get_pas(uint32_t attr)
+{
+	uint32_t pas = MT_PAS(attr);
+
+	switch (pas) {
+#if ENABLE_RME
+	/* TTD.NSE = 1 and TTD.NS = 1 for Realm PAS */
+	case MT_REALM:
+		return LOWER_ATTRS(EL3_S1_NSE | NS);
+	/* TTD.NSE = 1 and TTD.NS = 0 for Root PAS */
+	case MT_ROOT:
+		return LOWER_ATTRS(EL3_S1_NSE);
+#endif
+	case MT_NS:
+		return LOWER_ATTRS(NS);
+	default: /* MT_SECURE */
+		return 0U;
+	}
+}
+
 unsigned long long tcr_physical_addr_size_bits(unsigned long long max_addr)
 {
 	/* Physical address can't exceed 48 bits */
diff --git a/lib/xlat_tables_v2/xlat_tables_core.c b/lib/xlat_tables_v2/xlat_tables_core.c
index bb6d184..de57184 100644
--- a/lib/xlat_tables_v2/xlat_tables_core.c
+++ b/lib/xlat_tables_v2/xlat_tables_core.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -125,11 +125,14 @@
 	 * faults aren't managed.
 	 */
 	desc |= LOWER_ATTRS(ACCESS_FLAG);
+
+	/* Determine the physical address space this region belongs to. */
+	desc |= xlat_arch_get_pas(attr);
+
 	/*
-	 * Deduce other fields of the descriptor based on the MT_NS and MT_RW
-	 * memory region attributes.
+	 * Deduce other fields of the descriptor based on the MT_RW memory
+	 * region attributes.
 	 */
-	desc |= ((attr & MT_NS) != 0U) ? LOWER_ATTRS(NS) : 0U;
 	desc |= ((attr & MT_RW) != 0U) ? LOWER_ATTRS(AP_RW) : LOWER_ATTRS(AP_RO);
 
 	/*
diff --git a/lib/xlat_tables_v2/xlat_tables_private.h b/lib/xlat_tables_v2/xlat_tables_private.h
index 863470c..42c9a43 100644
--- a/lib/xlat_tables_v2/xlat_tables_private.h
+++ b/lib/xlat_tables_v2/xlat_tables_private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -40,6 +40,9 @@
 
 extern uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX];
 
+/* Determine the physical address space encoded in the 'attr' parameter. */
+uint32_t xlat_arch_get_pas(uint32_t attr);
+
 /*
  * Return the execute-never mask that will prevent instruction fetch at the
  * given translation regime.
diff --git a/lib/xlat_tables_v2/xlat_tables_utils.c b/lib/xlat_tables_v2/xlat_tables_utils.c
index 9fae7e9..df17386 100644
--- a/lib/xlat_tables_v2/xlat_tables_utils.c
+++ b/lib/xlat_tables_v2/xlat_tables_utils.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -95,7 +95,23 @@
 			  ? "-USER" : "-PRIV");
 	}
 
+#if ENABLE_RME
+	switch (desc & LOWER_ATTRS(EL3_S1_NSE | NS)) {
+	case 0ULL:
+		printf("-S");
+		break;
+	case LOWER_ATTRS(NS):
+		printf("-NS");
+		break;
+	case LOWER_ATTRS(EL3_S1_NSE):
+		printf("-RT");
+		break;
+	default: /* LOWER_ATTRS(EL3_S1_NSE | NS) */
+		printf("-RL");
+	}
+#else
 	printf(((LOWER_ATTRS(NS) & desc) != 0ULL) ? "-NS" : "-S");
+#endif
 
 #ifdef __aarch64__
 	/* Check Guarded Page bit */
diff --git a/make_helpers/build_macros.mk b/make_helpers/build_macros.mk
index 8655028..12aaee6 100644
--- a/make_helpers/build_macros.mk
+++ b/make_helpers/build_macros.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -98,41 +98,41 @@
 endef
 
 # IMG_LINKERFILE defines the linker script corresponding to a BL stage
-#   $(1) = BL stage (1, 2, 2u, 31, 32)
+#   $(1) = BL stage
 define IMG_LINKERFILE
-    ${BUILD_DIR}/bl$(1).ld
+    ${BUILD_DIR}/$(1).ld
 endef
 
 # IMG_MAPFILE defines the output file describing the memory map corresponding
 # to a BL stage
-#   $(1) = BL stage (1, 2, 2u, 31, 32)
+#   $(1) = BL stage
 define IMG_MAPFILE
-    ${BUILD_DIR}/bl$(1).map
+    ${BUILD_DIR}/$(1).map
 endef
 
 # IMG_ELF defines the elf file corresponding to a BL stage
-#   $(1) = BL stage (1, 2, 2u, 31, 32)
+#   $(1) = BL stage
 define IMG_ELF
-    ${BUILD_DIR}/bl$(1).elf
+    ${BUILD_DIR}/$(1).elf
 endef
 
 # IMG_DUMP defines the symbols dump file corresponding to a BL stage
-#   $(1) = BL stage (1, 2, 2u, 31, 32)
+#   $(1) = BL stage
 define IMG_DUMP
-    ${BUILD_DIR}/bl$(1).dump
+    ${BUILD_DIR}/$(1).dump
 endef
 
 # IMG_BIN defines the default image file corresponding to a BL stage
-#   $(1) = BL stage (1, 2, 2u, 31, 32)
+#   $(1) = BL stage
 define IMG_BIN
-    ${BUILD_PLAT}/bl$(1).bin
+    ${BUILD_PLAT}/$(1).bin
 endef
 
 # IMG_ENC_BIN defines the default encrypted image file corresponding to a
 # BL stage
-#   $(1) = BL stage (2, 30, 31, 32, 33)
+#   $(1) = BL stage
 define IMG_ENC_BIN
-    ${BUILD_PLAT}/bl$(1)_enc.bin
+    ${BUILD_PLAT}/$(1)_enc.bin
 endef
 
 # ENCRYPT_FW invokes enctool to encrypt firmware binary
@@ -294,15 +294,15 @@
 # MAKE_C builds a C source file and generates the dependency file
 #   $(1) = output directory
 #   $(2) = source file (%.c)
-#   $(3) = BL stage (1, 2, 2u, 31, 32)
+#   $(3) = BL stage
 define MAKE_C
 
 $(eval OBJ := $(1)/$(patsubst %.c,%.o,$(notdir $(2))))
 $(eval DEP := $(patsubst %.o,%.d,$(OBJ)))
-$(eval BL_CPPFLAGS := $(BL$(call uppercase,$(3))_CPPFLAGS) -DIMAGE_BL$(call uppercase,$(3)))
-$(eval BL_CFLAGS := $(BL$(call uppercase,$(3))_CFLAGS))
+$(eval BL_CPPFLAGS := $($(call uppercase,$(3))_CPPFLAGS) -DIMAGE_$(call uppercase,$(3)))
+$(eval BL_CFLAGS := $($(call uppercase,$(3))_CFLAGS))
 
-$(OBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | bl$(3)_dirs
+$(OBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | $(3)_dirs
 	$$(ECHO) "  CC      $$<"
 	$$(Q)$$(CC) $$(LTO_CFLAGS) $$(TF_CFLAGS) $$(CFLAGS) $(BL_CPPFLAGS) $(BL_CFLAGS) $(MAKE_DEP) -c $$< -o $$@
 
@@ -314,15 +314,15 @@
 # MAKE_S builds an assembly source file and generates the dependency file
 #   $(1) = output directory
 #   $(2) = assembly file (%.S)
-#   $(3) = BL stage (1, 2, 2u, 31, 32)
+#   $(3) = BL stage
 define MAKE_S
 
 $(eval OBJ := $(1)/$(patsubst %.S,%.o,$(notdir $(2))))
 $(eval DEP := $(patsubst %.o,%.d,$(OBJ)))
-$(eval BL_CPPFLAGS := $(BL$(call uppercase,$(3))_CPPFLAGS) -DIMAGE_BL$(call uppercase,$(3)))
-$(eval BL_ASFLAGS := $(BL$(call uppercase,$(3))_ASFLAGS))
+$(eval BL_CPPFLAGS := $($(call uppercase,$(3))_CPPFLAGS) -DIMAGE_$(call uppercase,$(3)))
+$(eval BL_ASFLAGS := $($(call uppercase,$(3))_ASFLAGS))
 
-$(OBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | bl$(3)_dirs
+$(OBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | $(3)_dirs
 	$$(ECHO) "  AS      $$<"
 	$$(Q)$$(AS) $$(ASFLAGS) $(BL_CPPFLAGS) $(BL_ASFLAGS) $(MAKE_DEP) -c $$< -o $$@
 
@@ -334,13 +334,13 @@
 # MAKE_LD generate the linker script using the C preprocessor
 #   $(1) = output linker script
 #   $(2) = input template
-#   $(3) = BL stage (1, 2, 2u, 31, 32)
+#   $(3) = BL stage
 define MAKE_LD
 
 $(eval DEP := $(1).d)
-$(eval BL_CPPFLAGS := $(BL$(call uppercase,$(3))_CPPFLAGS) -DIMAGE_BL$(call uppercase,$(3)))
+$(eval BL_CPPFLAGS := $($(call uppercase,$(3))_CPPFLAGS) -DIMAGE_$(call uppercase,$(3)))
 
-$(1): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | bl$(3)_dirs
+$(1): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | $(3)_dirs
 	$$(ECHO) "  PP      $$<"
 	$$(Q)$$(CPP) $$(CPPFLAGS) $(BL_CPPFLAGS) $(TF_CFLAGS_$(ARCH)) -P -x assembler-with-cpp -D__LINKER__ $(MAKE_DEP) -o $$@ $$<
 
@@ -368,7 +368,7 @@
 # MAKE_OBJS builds both C and assembly source files
 #   $(1) = output directory
 #   $(2) = list of source files (both C and assembly)
-#   $(3) = BL stage (1, 2, 2u, 31, 32)
+#   $(3) = BL stage
 define MAKE_OBJS
         $(eval C_OBJS := $(filter %.c,$(2)))
         $(eval REMAIN := $(filter-out %.c,$(2)))
@@ -445,13 +445,13 @@
 
 # MAKE_BL macro defines the targets and options to build each BL image.
 # Arguments:
-#   $(1) = BL stage (1, 2, 2u, 31, 32)
+#   $(1) = BL stage
 #   $(2) = FIP command line option (if empty, image will not be included in the FIP)
 #   $(3) = FIP prefix (optional) (if FWU_, target is fwu_fip instead of fip)
 #   $(4) = BL encryption flag (optional) (0, 1)
 define MAKE_BL
-        $(eval BUILD_DIR  := ${BUILD_PLAT}/bl$(1))
-        $(eval BL_SOURCES := $(BL$(call uppercase,$(1))_SOURCES))
+        $(eval BUILD_DIR  := ${BUILD_PLAT}/$(1))
+        $(eval BL_SOURCES := $($(call uppercase,$(1))_SOURCES))
         $(eval SOURCES    := $(BL_SOURCES) $(BL_COMMON_SOURCES) $(PLAT_BL_COMMON_SOURCES))
         $(eval OBJS       := $(addprefix $(BUILD_DIR)/,$(call SOURCES_TO_OBJS,$(SOURCES))))
         $(eval LINKERFILE := $(call IMG_LINKERFILE,$(1)))
@@ -460,8 +460,8 @@
         $(eval DUMP       := $(call IMG_DUMP,$(1)))
         $(eval BIN        := $(call IMG_BIN,$(1)))
         $(eval ENC_BIN    := $(call IMG_ENC_BIN,$(1)))
-        $(eval BL_LINKERFILE := $(BL$(call uppercase,$(1))_LINKERFILE))
-        $(eval BL_LIBS    := $(BL$(call uppercase,$(1))_LIBS))
+        $(eval BL_LINKERFILE := $($(call uppercase,$(1))_LINKERFILE))
+        $(eval BL_LIBS    := $($(call uppercase,$(1))_LIBS))
         # We use sort only to get a list of unique object directory names.
         # ordering is not relevant but sort removes duplicates.
         $(eval TEMP_OBJ_DIRS := $(sort $(dir ${OBJS} ${LINKERFILE})))
@@ -475,21 +475,21 @@
 
 $(eval $(foreach objd,${OBJ_DIRS},$(call MAKE_PREREQ_DIR,${objd},${BUILD_DIR})))
 
-.PHONY : bl${1}_dirs
+.PHONY : ${1}_dirs
 
 # We use order-only prerequisites to ensure that directories are created,
 # but do not cause re-builds every time a file is written.
-bl${1}_dirs: | ${OBJ_DIRS}
+${1}_dirs: | ${OBJ_DIRS}
 
 $(eval $(call MAKE_OBJS,$(BUILD_DIR),$(SOURCES),$(1)))
 $(eval $(call MAKE_LD,$(LINKERFILE),$(BL_LINKERFILE),$(1)))
-$(eval BL_LDFLAGS := $(BL$(call uppercase,$(1))_LDFLAGS))
+$(eval BL_LDFLAGS := $($(call uppercase,$(1))_LDFLAGS))
 
 ifeq ($(USE_ROMLIB),1)
 $(ELF): romlib.bin
 endif
 
-$(ELF): $(OBJS) $(LINKERFILE) | bl$(1)_dirs libraries $(BL_LIBS)
+$(ELF): $(OBJS) $(LINKERFILE) | $(1)_dirs libraries $(BL_LIBS)
 	$$(ECHO) "  LD      $$@"
 ifdef MAKE_BUILD_STRINGS
 	$(call MAKE_BUILD_STRINGS, $(BUILD_DIR)/build_message.o)
@@ -499,10 +499,10 @@
 		$$(CC) $$(TF_CFLAGS) $$(CFLAGS) -xc -c - -o $(BUILD_DIR)/build_message.o
 endif
 ifneq ($(findstring armlink,$(notdir $(LD))),)
-	$$(Q)$$(LD) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) $(BL_LDFLAGS) --entry=bl${1}_entrypoint \
+	$$(Q)$$(LD) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) $(BL_LDFLAGS) --entry=${1}_entrypoint \
 		--predefine="-D__LINKER__=$(__LINKER__)" \
 		--predefine="-DTF_CFLAGS=$(TF_CFLAGS)" \
-		--map --list="$(MAPFILE)" --scatter=${PLAT_DIR}/scat/bl${1}.scat \
+		--map --list="$(MAPFILE)" --scatter=${PLAT_DIR}/scat/${1}.scat \
 		$(LDPATHS) $(LIBWRAPPER) $(LDLIBS) $(BL_LIBS) \
 		$(BUILD_DIR)/build_message.o $(OBJS)
 else ifneq ($(findstring gcc,$(notdir $(LD))),)
@@ -531,21 +531,21 @@
 	@echo "Built $$@ successfully"
 	@${ECHO_BLANK_LINE}
 
-.PHONY: bl$(1)
+.PHONY: $(1)
 ifeq ($(DISABLE_BIN_GENERATION),1)
-bl$(1): $(ELF) $(DUMP)
+$(1): $(ELF) $(DUMP)
 else
-bl$(1): $(BIN) $(DUMP)
+$(1): $(BIN) $(DUMP)
 endif
 
-all: bl$(1)
+all: $(1)
 
 ifeq ($(4),1)
 $(call ENCRYPT_FW,$(BIN),$(ENC_BIN))
-$(if $(2),$(call TOOL_ADD_IMG_PAYLOAD,bl$(1),$(BIN),--$(2),$(ENC_BIN),$(3), \
+$(if $(2),$(call TOOL_ADD_IMG_PAYLOAD,$(1),$(BIN),--$(2),$(ENC_BIN),$(3), \
 		$(ENC_BIN)))
 else
-$(if $(2),$(call TOOL_ADD_IMG_PAYLOAD,bl$(1),$(BIN),--$(2),$(BIN),$(3)))
+$(if $(2),$(call TOOL_ADD_IMG_PAYLOAD,$(1),$(BIN),--$(2),$(BIN),$(3)))
 endif
 
 endef
diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk
index 8b350db..819c536 100644
--- a/make_helpers/defaults.mk
+++ b/make_helpers/defaults.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2016-2021, ARM Limited. All rights reserved.
+# Copyright (c) 2016-2021, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -105,6 +105,9 @@
 # Flag to enable PSCI STATs functionality
 ENABLE_PSCI_STAT		:= 0
 
+# Flag to enable Realm Management Extension (FEAT_RME)
+ENABLE_RME			:= 0
+
 # Flag to enable runtime instrumentation using PMF
 ENABLE_RUNTIME_INSTRUMENTATION	:= 0
 
diff --git a/make_helpers/tbbr/tbbr_tools.mk b/make_helpers/tbbr/tbbr_tools.mk
index 293e854..0a280b4 100644
--- a/make_helpers/tbbr/tbbr_tools.mk
+++ b/make_helpers/tbbr/tbbr_tools.mk
@@ -11,6 +11,7 @@
 # Expected environment:
 #
 #   BUILD_PLAT: output directory
+#   NEED_BL2: indicates whether BL2 is needed by the platform
 #   NEED_BL32: indicates whether BL32 is needed by the platform
 #   BL2: image filename (optional). Default is IMG_BIN(2) (see macro IMG_BIN)
 #   SCP_BL2: image filename (optional). Default is IMG_BIN(30)
@@ -67,8 +68,8 @@
 
 
 # Add the BL2 CoT (image cert)
+ifeq (${NEED_BL2},yes)
 ifeq (${BL2_AT_EL3}, 0)
-ifneq (${PLAT},fvp_r)
 $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/tb_fw.crt,--tb-fw-cert))
 endif
 endif
diff --git a/plat/arm/board/arm_fpga/platform.mk b/plat/arm/board/arm_fpga/platform.mk
index 1217425..901fabf 100644
--- a/plat/arm/board/arm_fpga/platform.mk
+++ b/plat/arm/board/arm_fpga/platform.mk
@@ -117,9 +117,9 @@
 				${FPGA_CPU_LIBS}				\
 				${FPGA_GIC_SOURCES}
 
-$(eval $(call MAKE_S,$(BUILD_PLAT),plat/arm/board/arm_fpga/rom_trampoline.S,31))
-$(eval $(call MAKE_S,$(BUILD_PLAT),plat/arm/board/arm_fpga/kernel_trampoline.S,31))
-$(eval $(call MAKE_LD,$(BUILD_PLAT)/build_axf.ld,plat/arm/board/arm_fpga/build_axf.ld.S,31))
+$(eval $(call MAKE_S,$(BUILD_PLAT),plat/arm/board/arm_fpga/rom_trampoline.S,bl31))
+$(eval $(call MAKE_S,$(BUILD_PLAT),plat/arm/board/arm_fpga/kernel_trampoline.S,bl31))
+$(eval $(call MAKE_LD,$(BUILD_PLAT)/build_axf.ld,plat/arm/board/arm_fpga/build_axf.ld.S,bl31))
 
 bl31.axf: bl31 dtbs ${BUILD_PLAT}/rom_trampoline.o ${BUILD_PLAT}/kernel_trampoline.o ${BUILD_PLAT}/build_axf.ld
 	$(ECHO) "  LD      $@"
diff --git a/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts b/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts
index 08d3c32..cf4ef2d 100644
--- a/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts
+++ b/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts
@@ -26,19 +26,6 @@
 		 */
 		mbedtls_heap_addr = <0x0 0x0>;
 		mbedtls_heap_size = <0x0>;
-
-#if MEASURED_BOOT
-		/* BL2 image hash calculated by BL1 */
-		bl2_hash_data = [
-			00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-#if BL2_HASH_SIZE > 32
-			00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-#if BL2_HASH_SIZE > 48
-			00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
-#endif /* > 48 */
-#endif /* > 32 */
-			00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00];
-#endif /* MEASURED_BOOT */
 	};
 
 	/*
@@ -117,6 +104,10 @@
 	#include "cot_descriptors.dtsi"
 #endif
 
+#if MEASURED_BOOT
+	#include "event_log.dtsi"
+#endif
+
 };
 
 #if COT_DESC_IN_DTB
diff --git a/plat/arm/board/fvp/fvp_bl1_measured_boot.c b/plat/arm/board/fvp/fvp_bl1_measured_boot.c
new file mode 100644
index 0000000..47af1f5
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_bl1_measured_boot.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <drivers/measured_boot/event_log/event_log.h>
+#include <plat/arm/common/plat_arm.h>
+
+/* Event Log data */
+static uint8_t event_log[PLAT_ARM_EVENT_LOG_MAX_SIZE];
+
+/* FVP table with platform specific image IDs, names and PCRs */
+const event_log_metadata_t fvp_event_log_metadata[] = {
+	{ FW_CONFIG_ID, EVLOG_FW_CONFIG_STRING, PCR_0 },
+	{ TB_FW_CONFIG_ID, EVLOG_TB_FW_CONFIG_STRING, PCR_0 },
+	{ BL2_IMAGE_ID, EVLOG_BL2_STRING, PCR_0 },
+	{ INVALID_ID, NULL, (unsigned int)(-1) }	/* Terminator */
+};
+
+void bl1_plat_mboot_init(void)
+{
+	event_log_init(event_log, event_log + sizeof(event_log));
+	event_log_write_header();
+}
+
+void bl1_plat_mboot_finish(void)
+{
+	size_t event_log_cur_size;
+
+	event_log_cur_size = event_log_get_cur_size(event_log);
+	int rc = arm_set_tb_fw_info((uintptr_t)event_log,
+				    event_log_cur_size);
+	if (rc != 0) {
+		/*
+		 * It is a fatal error because on FVP platform, BL2 software
+		 * assumes that a valid Event Log buffer exist and it will use
+		 * same Event Log buffer to append image measurements.
+		 */
+		panic();
+	}
+}
diff --git a/plat/arm/board/fvp/fvp_bl1_setup.c b/plat/arm/board/fvp/fvp_bl1_setup.c
index 06ee037..59fc0f3 100644
--- a/plat/arm/board/fvp/fvp_bl1_setup.c
+++ b/plat/arm/board/fvp/fvp_bl1_setup.c
@@ -76,63 +76,6 @@
 		wfi();
 }
 
-#if MEASURED_BOOT
-/*
- * Calculates and writes BL2 hash data to TB_FW_CONFIG DTB.
- */
-void bl1_plat_set_bl2_hash(const image_desc_t *image_desc)
-{
-	arm_bl1_set_bl2_hash(image_desc);
-}
-
-/*
- * Implementation for bl1_plat_handle_post_image_load(). This function
- * populates the default arguments to BL2. The BL2 memory layout structure
- * is allocated and the calculated layout is populated in arg1 to BL2.
- */
-int bl1_plat_handle_post_image_load(unsigned int image_id)
-{
-	meminfo_t *bl2_tzram_layout;
-	meminfo_t *bl1_tzram_layout;
-	image_desc_t *image_desc;
-	entry_point_info_t *ep_info;
-
-	if (image_id != BL2_IMAGE_ID) {
-		return 0;
-	}
-
-	/* Get the image descriptor */
-	image_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
-	assert(image_desc != NULL);
-
-	/* Calculate BL2 hash and set it in TB_FW_CONFIG */
-	bl1_plat_set_bl2_hash(image_desc);
-
-	/* Get the entry point info */
-	ep_info = &image_desc->ep_info;
-
-	/* Find out how much free trusted ram remains after BL1 load */
-	bl1_tzram_layout = bl1_plat_sec_mem_layout();
-
-	/*
-	 * Create a new layout of memory for BL2 as seen by BL1 i.e.
-	 * tell it the amount of total and free memory available.
-	 * This layout is created at the first free address visible
-	 * to BL2. BL2 will read the memory layout before using its
-	 * memory for other purposes.
-	 */
-	bl2_tzram_layout = (meminfo_t *)bl1_tzram_layout->total_base;
-
-	bl1_calc_bl2_mem_layout(bl1_tzram_layout, bl2_tzram_layout);
-
-	ep_info->args.arg1 = (uintptr_t)bl2_tzram_layout;
-
-	VERBOSE("BL1: BL2 memory layout address = %p\n",
-		(void *)bl2_tzram_layout);
-	return 0;
-}
-#endif /* MEASURED_BOOT */
-
 /*******************************************************************************
  * The following function checks if Firmware update is needed by checking error
  * reported in NV flag.
diff --git a/plat/arm/board/fvp/fvp_bl2_measured_boot.c b/plat/arm/board/fvp/fvp_bl2_measured_boot.c
new file mode 100644
index 0000000..5ebfede
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_bl2_measured_boot.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdint.h>
+
+#include <drivers/measured_boot/event_log/event_log.h>
+#include <plat/arm/common/plat_arm.h>
+
+/* Event Log data */
+static uint64_t event_log_base;
+
+/* FVP table with platform specific image IDs, names and PCRs */
+const event_log_metadata_t fvp_event_log_metadata[] = {
+	{ BL31_IMAGE_ID, EVLOG_BL31_STRING, PCR_0 },
+	{ BL32_IMAGE_ID, EVLOG_BL32_STRING, PCR_0 },
+	{ BL32_EXTRA1_IMAGE_ID, EVLOG_BL32_EXTRA1_STRING, PCR_0 },
+	{ BL32_EXTRA2_IMAGE_ID, EVLOG_BL32_EXTRA2_STRING, PCR_0 },
+	{ BL33_IMAGE_ID, EVLOG_BL33_STRING, PCR_0 },
+	{ HW_CONFIG_ID, EVLOG_HW_CONFIG_STRING, PCR_0 },
+	{ NT_FW_CONFIG_ID, EVLOG_NT_FW_CONFIG_STRING, PCR_0 },
+	{ SCP_BL2_IMAGE_ID, EVLOG_SCP_BL2_STRING, PCR_0 },
+	{ SOC_FW_CONFIG_ID, EVLOG_SOC_FW_CONFIG_STRING, PCR_0 },
+	{ TOS_FW_CONFIG_ID, EVLOG_TOS_FW_CONFIG_STRING, PCR_0 },
+	{ INVALID_ID, NULL, (unsigned int)(-1) }	/* Terminator */
+};
+
+void bl2_plat_mboot_init(void)
+{
+	uint8_t *event_log_start;
+	uint8_t *event_log_finish;
+	size_t bl1_event_log_size;
+	int rc;
+
+	rc = arm_get_tb_fw_info(&event_log_base, &bl1_event_log_size);
+	if (rc != 0) {
+		ERROR("%s(): Unable to get Event Log info from TB_FW_CONFIG\n",
+		      __func__);
+		/*
+		 * It is a fatal error because on FVP platform, BL2 software
+		 * assumes that a valid Event Log buffer exist and it will use
+		 * same Event Log buffer to append image measurements.
+		 */
+		panic();
+	}
+
+	/*
+	 * BL1 and BL2 share the same Event Log buffer and that BL2 will
+	 * append its measurements after BL1's
+	 */
+	event_log_start = (uint8_t *)((uintptr_t)event_log_base +
+				      bl1_event_log_size);
+	event_log_finish = (uint8_t *)((uintptr_t)event_log_base +
+				       PLAT_ARM_EVENT_LOG_MAX_SIZE);
+
+	event_log_init((uint8_t *)event_log_start, event_log_finish);
+}
+
+void bl2_plat_mboot_finish(void)
+{
+	int rc;
+
+	/* Event Log address in Non-Secure memory */
+	uintptr_t ns_log_addr;
+
+	/* Event Log filled size */
+	size_t event_log_cur_size;
+
+	event_log_cur_size = event_log_get_cur_size((uint8_t *)event_log_base);
+
+	rc = arm_set_nt_fw_info(
+#ifdef SPD_opteed
+			    (uintptr_t)event_log_base,
+#endif
+			    event_log_cur_size, &ns_log_addr);
+	if (rc != 0) {
+		ERROR("%s(): Unable to update %s_FW_CONFIG\n",
+		      __func__, "NT");
+		/*
+		 * It is a fatal error because on FVP secure world software
+		 * assumes that a valid event log exists and will use it to
+		 * record the measurements into the fTPM.
+		 * Note: In FVP platform, OP-TEE uses nt_fw_config to get the
+		 * secure Event Log buffer address.
+		 */
+		panic();
+	}
+
+	/* Copy Event Log to Non-secure memory */
+	(void)memcpy((void *)ns_log_addr, (const void *)event_log_base,
+		     event_log_cur_size);
+
+	/* Ensure that the Event Log is visible in Non-secure memory */
+	flush_dcache_range(ns_log_addr, event_log_cur_size);
+
+#if defined(SPD_tspd) || defined(SPD_spmd)
+	/* Set Event Log data in TOS_FW_CONFIG */
+	rc = arm_set_tos_fw_info((uintptr_t)event_log_base,
+				 event_log_cur_size);
+	if (rc != 0) {
+		ERROR("%s(): Unable to update %s_FW_CONFIG\n",
+		      __func__, "TOS");
+		panic();
+	}
+#endif /* defined(SPD_tspd) || defined(SPD_spmd) */
+
+	dump_event_log((uint8_t *)event_log_base, event_log_cur_size);
+}
diff --git a/plat/arm/board/fvp/fvp_bl2_setup.c b/plat/arm/board/fvp/fvp_bl2_setup.c
index f2f2143..5a17a0d 100644
--- a/plat/arm/board/fvp/fvp_bl2_setup.c
+++ b/plat/arm/board/fvp/fvp_bl2_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -9,9 +9,6 @@
 #include <common/debug.h>
 #include <common/desc_image_load.h>
 #include <drivers/arm/sp804_delay_timer.h>
-#if MEASURED_BOOT
-#include <drivers/measured_boot/measured_boot.h>
-#endif
 #include <lib/fconf/fconf.h>
 #include <lib/fconf/fconf_dyn_cfg_getter.h>
 
@@ -73,45 +70,3 @@
 
 	return arm_bl_params;
 }
-#if MEASURED_BOOT
-static int fvp_bl2_plat_handle_post_image_load(unsigned int image_id)
-{
-	const bl_mem_params_node_t *bl_mem_params =
-				get_bl_mem_params_node(image_id);
-
-	assert(bl_mem_params != NULL);
-
-	image_info_t info = bl_mem_params->image_info;
-	int err;
-
-	if ((info.h.attr & IMAGE_ATTRIB_SKIP_LOADING) == 0U) {
-		/* Calculate image hash and record data in Event Log */
-		err = tpm_record_measurement(info.image_base,
-					     info.image_size, image_id);
-		if (err != 0) {
-			ERROR("%s%s image id %u (%i)\n",
-				"BL2: Failed to ", "record", image_id, err);
-			return err;
-		}
-	}
-
-	err = arm_bl2_handle_post_image_load(image_id);
-	if (err != 0) {
-		ERROR("%s%s image id %u (%i)\n",
-			"BL2: Failed to ", "handle", image_id, err);
-	}
-
-	return err;
-}
-
-int arm_bl2_plat_handle_post_image_load(unsigned int image_id)
-{
-	int err = fvp_bl2_plat_handle_post_image_load(image_id);
-
-	if (err != 0) {
-		ERROR("%s() returns %i\n", __func__, err);
-	}
-
-	return err;
-}
-#endif	/* MEASURED_BOOT */
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index 9d3c031..e7a28ac 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -107,6 +107,10 @@
 #if defined(SPD_spmd)
 	ARM_MAP_TRUSTED_DRAM,
 #endif
+#if ENABLE_RME
+	ARM_MAP_RMM_DRAM,
+	ARM_MAP_GPT_L1_DRAM,
+#endif /* ENABLE_RME */
 #ifdef SPD_tspd
 	ARM_MAP_TSP_SEC_MEM,
 #endif
@@ -159,6 +163,9 @@
 #endif
 	/* Required by fconf APIs to read HW_CONFIG dtb loaded into DRAM */
 	ARM_DTB_DRAM_NS,
+#if ENABLE_RME
+	ARM_MAP_GPT_L1_DRAM,
+#endif
 	{0}
 };
 
@@ -191,6 +198,15 @@
 };
 #endif
 
+#ifdef IMAGE_RMM
+const mmap_region_t plat_arm_mmap[] = {
+	V2M_MAP_IOFPGA,
+	MAP_DEVICE0,
+	MAP_DEVICE1,
+	{0}
+};
+#endif
+
 ARM_CASSERT_MMAP
 
 #if FVP_INTERCONNECT_DRIVER != FVP_CCN
diff --git a/plat/arm/board/fvp/fvp_common_measured_boot.c b/plat/arm/board/fvp/fvp_common_measured_boot.c
new file mode 100644
index 0000000..6a403d9
--- /dev/null
+++ b/plat/arm/board/fvp/fvp_common_measured_boot.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <common/desc_image_load.h>
+#include <drivers/measured_boot/event_log/event_log.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+extern event_log_metadata_t fvp_event_log_metadata[];
+
+const event_log_metadata_t *plat_event_log_get_metadata(void)
+{
+	return fvp_event_log_metadata;
+}
+
+int plat_mboot_measure_image(unsigned int image_id, image_info_t *image_data)
+{
+	/* Calculate image hash and record data in Event Log */
+	int err = event_log_measure_and_record(image_data->image_base,
+					       image_data->image_size,
+					       image_id);
+	if (err != 0) {
+		ERROR("%s%s image id %u (%i)\n",
+		      "Failed to ", "record", image_id, err);
+		return err;
+	}
+
+	return 0;
+}
diff --git a/plat/arm/board/fvp/fvp_measured_boot.c b/plat/arm/board/fvp/fvp_measured_boot.c
deleted file mode 100644
index 5dcadba..0000000
--- a/plat/arm/board/fvp/fvp_measured_boot.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2020, Arm Limited. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
-
-#include <drivers/measured_boot/event_log.h>
-#include <plat/arm/common/plat_arm.h>
-
-/* FVP table with platform specific image IDs, names and PCRs */
-static const image_data_t fvp_images_data[] = {
-	{ BL2_IMAGE_ID, BL2_STRING, PCR_0 },		/* Reserved for BL2 */
-	{ BL31_IMAGE_ID, BL31_STRING, PCR_0 },
-	{ BL32_IMAGE_ID, BL32_STRING, PCR_0 },
-	{ BL32_EXTRA1_IMAGE_ID, BL32_EXTRA1_IMAGE_STRING, PCR_0 },
-	{ BL32_EXTRA2_IMAGE_ID, BL32_EXTRA2_IMAGE_STRING, PCR_0 },
-	{ BL33_IMAGE_ID, BL33_STRING, PCR_0 },
-	{ HW_CONFIG_ID, HW_CONFIG_STRING, PCR_0 },
-	{ NT_FW_CONFIG_ID, NT_FW_CONFIG_STRING, PCR_0 },
-	{ SCP_BL2_IMAGE_ID, SCP_BL2_IMAGE_STRING, PCR_0 },
-	{ SOC_FW_CONFIG_ID, SOC_FW_CONFIG_STRING, PCR_0 },
-	{ TOS_FW_CONFIG_ID, TOS_FW_CONFIG_STRING, PCR_0 },
-	{ INVALID_ID, NULL, (unsigned int)(-1) }	/* Terminator */
-};
-
-static const measured_boot_data_t fvp_measured_boot_data = {
-	fvp_images_data,
-	arm_set_nt_fw_info,
-	arm_set_tos_fw_info
-};
-
-/*
- * Function retuns pointer to FVP plat_measured_boot_data_t structure
- */
-const measured_boot_data_t *plat_get_measured_boot_data(void)
-{
-	return &fvp_measured_boot_data;
-}
diff --git a/plat/arm/board/fvp/include/platform_def.h b/plat/arm/board/fvp/include/platform_def.h
index 8b25a54..d89e122 100644
--- a/plat/arm/board/fvp/include/platform_def.h
+++ b/plat/arm/board/fvp/include/platform_def.h
@@ -43,6 +43,11 @@
 #define PLAT_ARM_TRUSTED_DRAM_BASE	UL(0x06000000)
 #define PLAT_ARM_TRUSTED_DRAM_SIZE	UL(0x02000000)	/* 32 MB */
 
+#if ENABLE_RME
+#define PLAT_ARM_RMM_BASE		(RMM_BASE)
+#define PLAT_ARM_RMM_SIZE		(RMM_LIMIT - RMM_BASE)
+#endif
+
 /*
  * Max size of SPMC is 2MB for fvp. With SPMD enabled this value corresponds to
  * max size of BL32 image.
@@ -61,12 +66,13 @@
 #define PLAT_ARM_DRAM2_BASE		ULL(0x880000000)
 #define PLAT_ARM_DRAM2_SIZE		UL(0x80000000)
 
-#define PLAT_HW_CONFIG_DTB_BASE		ULL(0x82000000)
-#define PLAT_HW_CONFIG_DTB_SIZE		ULL(0x8000)
+/* Range of kernel DTB load address */
+#define FVP_DTB_DRAM_MAP_START		ULL(0x82000000)
+#define FVP_DTB_DRAM_MAP_SIZE		ULL(0x02000000)	/* 32 MB */
 
 #define ARM_DTB_DRAM_NS			MAP_REGION_FLAT(		\
-					PLAT_HW_CONFIG_DTB_BASE,	\
-					PLAT_HW_CONFIG_DTB_SIZE,	\
+					FVP_DTB_DRAM_MAP_START,		\
+					FVP_DTB_DRAM_MAP_SIZE,		\
 					MT_MEMORY | MT_RO | MT_NS)
 /*
  * Load address of BL33 for this platform port
@@ -80,15 +86,27 @@
 #if defined(IMAGE_BL31)
 # if SPM_MM
 #  define PLAT_ARM_MMAP_ENTRIES		10
-#  define MAX_XLAT_TABLES		9
+#  if ENABLE_RME
+#   define MAX_XLAT_TABLES		10
+#  else
+#   define MAX_XLAT_TABLES		9
+# endif
 #  define PLAT_SP_IMAGE_MMAP_REGIONS	30
 #  define PLAT_SP_IMAGE_MAX_XLAT_TABLES	10
 # else
 #  define PLAT_ARM_MMAP_ENTRIES		9
 #  if USE_DEBUGFS
-#   define MAX_XLAT_TABLES		8
+#   if ENABLE_RME
+#    define MAX_XLAT_TABLES		9
+#   else
+#    define MAX_XLAT_TABLES		8
+#   endif
 #  else
-#   define MAX_XLAT_TABLES		7
+#   if ENABLE_RME
+#    define MAX_XLAT_TABLES		8
+#   else
+#    define MAX_XLAT_TABLES		7
+#   endif
 #  endif
 # endif
 #elif defined(IMAGE_BL32)
@@ -137,16 +155,17 @@
 #endif
 
 #if RESET_TO_BL31
-/* Size of Trusted SRAM - the first 4KB of shared memory */
+/* Size of Trusted SRAM - the first 4KB of shared memory - GPT L0 Tables */
 #define PLAT_ARM_MAX_BL31_SIZE		(PLAT_ARM_TRUSTED_SRAM_SIZE - \
-					 ARM_SHARED_RAM_SIZE)
+					 ARM_SHARED_RAM_SIZE - \
+					 ARM_L0_GPT_SIZE)
 #else
 /*
  * Since BL31 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL31_SIZE is
  * calculated using the current BL31 PROGBITS debug size plus the sizes of
  * BL2 and BL1-RW
  */
-#define PLAT_ARM_MAX_BL31_SIZE		UL(0x3D000)
+#define PLAT_ARM_MAX_BL31_SIZE		(UL(0x3D000) - ARM_L0_GPT_SIZE)
 #endif /* RESET_TO_BL31 */
 
 #ifndef __aarch64__
@@ -177,7 +196,7 @@
 # if TRUSTED_BOARD_BOOT
 #  define PLATFORM_STACK_SIZE		UL(0x1000)
 # else
-#  define PLATFORM_STACK_SIZE		UL(0x440)
+#  define PLATFORM_STACK_SIZE		UL(0x600)
 # endif
 #elif defined(IMAGE_BL2U)
 # define PLATFORM_STACK_SIZE		UL(0x400)
@@ -185,6 +204,8 @@
 #  define PLATFORM_STACK_SIZE		UL(0x800)
 #elif defined(IMAGE_BL32)
 # define PLATFORM_STACK_SIZE		UL(0x440)
+#elif defined(IMAGE_RMM)
+# define PLATFORM_STACK_SIZE		UL(0x440)
 #endif
 
 #define MAX_IO_DEVICES			3
@@ -222,6 +243,9 @@
 #define PLAT_ARM_TSP_UART_BASE		V2M_IOFPGA_UART2_BASE
 #define PLAT_ARM_TSP_UART_CLK_IN_HZ	V2M_IOFPGA_UART2_CLK_IN_HZ
 
+#define PLAT_ARM_TRP_UART_BASE		V2M_IOFPGA_UART3_BASE
+#define PLAT_ARM_TRP_UART_CLK_IN_HZ	V2M_IOFPGA_UART3_CLK_IN_HZ
+
 #define PLAT_FVP_SMMUV3_BASE		UL(0x2b400000)
 
 /* CCI related constants */
@@ -317,4 +341,9 @@
 #define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32)
 #endif
 
+/*
+ * Maximum size of Event Log buffer used in Measured Boot Event Log driver
+ */
+#define	PLAT_ARM_EVENT_LOG_MAX_SIZE		UL(0x400)
+
 #endif /* PLATFORM_DEF_H */
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index 73f09e5..70b1051 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -186,6 +186,10 @@
 BL2_SOURCES		+=	plat/arm/common/fconf/fconf_nv_cntr_getter.c
 endif
 
+ifeq (${ENABLE_RME},1)
+BL2_SOURCES		+=	plat/arm/board/fvp/aarch64/fvp_helpers.S
+endif
+
 ifeq (${BL2_AT_EL3},1)
 BL2_SOURCES		+=	plat/arm/board/fvp/${ARCH}/fvp_helpers.S	\
 				plat/arm/board/fvp/fvp_bl2_el3_setup.c		\
@@ -372,7 +376,10 @@
 BL2_SOURCES		+=	plat/arm/board/fvp/fvp_trusted_boot.c
 
 ifeq (${MEASURED_BOOT},1)
-BL2_SOURCES		+=	plat/arm/board/fvp/fvp_measured_boot.c
+BL1_SOURCES		+=	plat/arm/board/fvp/fvp_common_measured_boot.c	\
+				plat/arm/board/fvp/fvp_bl1_measured_boot.c
+BL2_SOURCES		+=	plat/arm/board/fvp/fvp_common_measured_boot.c	\
+				plat/arm/board/fvp/fvp_bl2_measured_boot.c
 endif
 
 # FVP being a development platform, enable capability to disable Authentication
diff --git a/plat/arm/board/fvp/trp/trp-fvp.mk b/plat/arm/board/fvp/trp/trp-fvp.mk
new file mode 100644
index 0000000..a450541
--- /dev/null
+++ b/plat/arm/board/fvp/trp/trp-fvp.mk
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# TRP source files specific to FVP platform
+
+RMM_SOURCES		+=	plat/arm/board/fvp/aarch64/fvp_helpers.S
+
+include plat/arm/common/trp/arm_trp.mk
+
diff --git a/plat/arm/board/fvp_r/fvp_r_bl1_context_mgmt.c b/plat/arm/board/fvp_r/fvp_r_bl1_context_mgmt.c
index 7ae853b..c6544b4 100644
--- a/plat/arm/board/fvp_r/fvp_r_bl1_context_mgmt.c
+++ b/plat/arm/board/fvp_r/fvp_r_bl1_context_mgmt.c
@@ -15,7 +15,7 @@
 #include <plat/common/platform.h>
 
 
-void cm_prepare_el2_exit(uint32_t security_state);
+void cm_prepare_el2_exit(void);
 
 /* Following contains the cpu context pointers. */
 static void *bl1_cpu_context_ptr[2];
@@ -81,6 +81,9 @@
 	/* Allow platform to make change */
 	bl1_plat_set_ep_info(image_id, next_bl_ep);
 
+	/* Prepare context for the next EL */
+	cm_prepare_el2_exit();
+
 	/* Indicate that image is in execution state. */
 	desc->state = IMAGE_STATE_EXECUTED;
 
diff --git a/plat/arm/board/fvp_r/fvp_r_bl1_setup.c b/plat/arm/board/fvp_r/fvp_r_bl1_setup.c
index 5e31d39..68872c1 100644
--- a/plat/arm/board/fvp_r/fvp_r_bl1_setup.c
+++ b/plat/arm/board/fvp_r/fvp_r_bl1_setup.c
@@ -9,12 +9,12 @@
 
 #include <assert.h>
 
-#include "../../../../lib/xlat_mpu/xlat_mpu.h"
 #include <bl1/bl1.h>
 #include <common/tbbr/tbbr_img_def.h>
 #include <drivers/arm/sp805.h>
 #include <lib/fconf/fconf.h>
 #include <lib/fconf/fconf_dyn_cfg_getter.h>
+#include <lib/xlat_mpu/xlat_mpu.h>
 
 #include "fvp_r_private.h"
 #include <plat/arm/common/arm_config.h>
@@ -140,7 +140,6 @@
  */
 void arm_bl1_platform_setup(void)
 {
-	image_desc_t *desc;
 	uint32_t fw_config_max_size;
 
 	/* Initialise the IO layer and register platform IO devices */
@@ -157,8 +156,7 @@
 	fw_config_max_size = ARM_FW_CONFIG_LIMIT - ARM_FW_CONFIG_BASE;
 	set_config_info(ARM_FW_CONFIG_BASE, fw_config_max_size, FW_CONFIG_ID);
 
-	desc = bl1_plat_get_image_desc(BL33_IMAGE_ID);
-	assert(desc != NULL);
+	assert(bl1_plat_get_image_desc(BL33_IMAGE_ID) != NULL);
 
 	/*
 	 * Allow access to the System counter timer module and program
diff --git a/plat/arm/board/fvp_r/fvp_r_context_mgmt.c b/plat/arm/board/fvp_r/fvp_r_context_mgmt.c
index 678b879..d172d2d 100644
--- a/plat/arm/board/fvp_r/fvp_r_context_mgmt.c
+++ b/plat/arm/board/fvp_r/fvp_r_context_mgmt.c
@@ -4,25 +4,50 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#include <lib/el3_runtime/context_mgmt.h>
-#include <lib/el3_runtime/pubsub_events.h>
+#include <arch_helpers.h>
 
-#include <platform_def.h>
+/************************************************************
+ * For R-class everything is in secure world.
+ * Prepare the CPU system registers for first entry into EL1
+ ************************************************************/
+void cm_prepare_el2_exit(void)
+{
+	uint64_t hcr_el2 = 0U;
 
+	/*
+	 * The use of ARMv8.3 pointer authentication (PAuth) is governed
+	 * by fields in HCR_EL2, which trigger a 'trap to EL2' if not
+	 * enabled. This register initialized at boot up, update PAuth
+	 * bits.
+	 *
+	 * HCR_API_BIT: Set to one to disable traps to EL2 if lower ELs
+	 * access PAuth registers
+	 *
+	 * HCR_APK_BIT: Set to one to disable traps to EL2 if lower ELs
+	 * access PAuth instructions
+	 */
+	hcr_el2 = read_hcr_el2();
+	write_hcr_el2(hcr_el2 | HCR_API_BIT | HCR_APK_BIT);
 
-/*******************************************************************************
- * File contains EL2 equivalents of EL3 functions from
- * .../lib/el3_runtime/aarch64/context_mgmt.c
- ******************************************************************************/
+	/*
+	 * Initialise CNTHCTL_EL2. All fields are architecturally UNKNOWN
+	 * on reset and are set to zero except for field(s) listed below.
+	 *
+	 * CNTHCTL_EL2.EL1PCEN: Set to one to disable traps to EL2
+	 * if lower ELs accesses to the physical timer registers.
+	 *
+	 * CNTHCTL_EL2.EL1PCTEN: Set to one to disable traps to EL2
+	 * if lower ELs access to the physical counter registers.
+	 */
+	write_cnthctl_el2(CNTHCTL_RESET_VAL | EL1PCEN_BIT | EL1PCTEN_BIT);
 
-/*******************************************************************************
- * Prepare the CPU system registers for first entry into secure or normal world
- *
- * The majority of the work needed is only for switching to non-secure, which
- * is not available on v8-R64 cores, so this function is very simple.
- ******************************************************************************/
-void cm_prepare_el2_exit(uint32_t security_state)
-{
-	cm_el1_sysregs_context_restore(security_state);
-	cm_set_next_eret_context(security_state);
+	/*
+	 * On Armv8-R, the EL1&0 memory system architecture is configurable
+	 * as a VMSA or PMSA. All the fields architecturally UNKNOWN on reset
+	* and are set to zero except for field listed below.
+	*
+	* VCTR_EL2.MSA: Set to one to ensure the VMSA is enabled so that
+	* rich OS can boot.
+	*/
+	write_vtcr_el2(VTCR_RESET_VAL | VTCR_EL2_MSA);
 }
diff --git a/plat/arm/board/fvp_r/platform.mk b/plat/arm/board/fvp_r/platform.mk
index 39509dd..8f5878f 100644
--- a/plat/arm/board/fvp_r/platform.mk
+++ b/plat/arm/board/fvp_r/platform.mk
@@ -11,6 +11,7 @@
 override NEED_BL2	:= no
 override NEED_BL2U	:= no
 override NEED_BL31	:= no
+NEED_BL32		:= no
 
 override CTX_INCLUDE_AARCH32_REGS	:=	0
 
@@ -56,70 +57,90 @@
 $(error "Incorrect CCN driver chosen on FVP_R port")
 endif
 
-PLAT_INCLUDES		:=	-Iplat/arm/board/fvp_r/include
-
-PLAT_BL_COMMON_SOURCES	:=	plat/arm/board/fvp_r/fvp_r_common.c
-
-FVP_R_CPU_LIBS		:=	lib/cpus/${ARCH}/aem_generic.S
+include plat/arm/board/common/board_common.mk
+include plat/arm/common/arm_common.mk
 
-# select a different set of CPU files, depending on whether we compile for
-# hardware assisted coherency cores or not
-ifeq (${HW_ASSISTED_COHERENCY}, 0)
-# Cores used without DSU
-#	FVP_R_CPU_LIBS	+=	lib/cpus/aarch64/fvp_r.S
-else
-# Cores used with DSU only
-#	FVP_R_CPU_LIBS	+=	lib/cpus/aarch64/fvp_r.S
-endif
+PLAT_INCLUDES		:=	-Iplat/arm/board/fvp_r/include
 
-BL1_SOURCES		+=	drivers/arm/sp805/sp805.c			\
-				drivers/delay_timer/delay_timer.c		\
-				drivers/io/io_semihosting.c			\
-				lib/semihosting/semihosting.c			\
-				lib/semihosting/${ARCH}/semihosting_call.S	\
-				plat/arm/board/fvp_r/fvp_r_bl1_arch_setup.c	\
-				plat/arm/board/fvp_r/fvp_r_bl1_setup.c		\
+FVP_R_BL_COMMON_SOURCES	:=	plat/arm/board/fvp_r/fvp_r_common.c		\
 				plat/arm/board/fvp_r/fvp_r_context_mgmt.c	\
+				plat/arm/board/fvp_r/fvp_r_context.S		\
+				plat/arm/board/fvp_r/fvp_r_debug.S		\
 				plat/arm/board/fvp_r/fvp_r_err.c		\
+				plat/arm/board/fvp_r/fvp_r_helpers.S		\
+				plat/arm/board/fvp_r/fvp_r_misc_helpers.S	\
+				plat/arm/board/fvp_r/fvp_r_pauth_helpers.S
+
+FVP_R_BL1_SOURCES	:=	plat/arm/board/fvp_r/fvp_r_bl1_arch_setup.c	\
+				plat/arm/board/fvp_r/fvp_r_bl1_setup.c		\
 				plat/arm/board/fvp_r/fvp_r_io_storage.c		\
 				plat/arm/board/fvp_r/fvp_r_bl1_context_mgmt.c	\
 				plat/arm/board/fvp_r/fvp_r_bl1_entrypoint.S	\
 				plat/arm/board/fvp_r/fvp_r_bl1_exceptions.S	\
-				plat/arm/board/fvp_r/fvp_r_bl1_main.c		\
-				plat/arm/board/fvp_r/fvp_r_context.S		\
-				plat/arm/board/fvp_r/fvp_r_debug.S		\
-				plat/arm/board/fvp_r/fvp_r_helpers.S		\
-				plat/arm/board/fvp_r/fvp_r_misc_helpers.S	\
-				plat/arm/board/fvp_r/fvp_r_pauth_helpers.S	\
-				${FVP_R_CPU_LIBS}				\
-				${FVP_R_INTERCONNECT_SOURCES}
+				plat/arm/board/fvp_r/fvp_r_bl1_main.c
+
+FVP_R_CPU_LIBS		:=	lib/cpus/${ARCH}/aem_generic.S
+
+FVP_R_DYNC_CFG_SOURCES	:=	common/fdt_wrappers.c				\
+				common/uuid.c					\
+				plat/arm/common/arm_dyn_cfg.c			\
+				plat/arm/common/arm_dyn_cfg_helpers.c
+
+ifeq (${TRUSTED_BOARD_BOOT},1)
+FVP_R_AUTH_SOURCES	:=	drivers/auth/auth_mod.c				\
+				drivers/auth/crypto_mod.c			\
+				drivers/auth/img_parser_mod.c			\
+				lib/fconf/fconf_tbbr_getter.c			\
+				bl1/tbbr/tbbr_img_desc.c			\
+				plat/arm/common/arm_bl1_fwu.c			\
+				plat/common/tbbr/plat_tbbr.c			\
+				drivers/auth/tbbr/tbbr_cot_bl1_r64.c		\
+				drivers/auth/tbbr/tbbr_cot_common.c		\
+				plat/arm/board/common/board_arm_trusted_boot.c	\
+				plat/arm/board/common/rotpk/arm_dev_rotpk.S	\
+				plat/arm/board/fvp_r/fvp_r_trusted_boot.c
+
+FVP_R_BL1_SOURCES	+=	${MBEDTLS_SOURCES}				\
+				${FVP_R_AUTH_SOURCES}
+endif
 
 ifeq (${USE_SP804_TIMER},1)
-BL1_SOURCES		+=	drivers/arm/sp804/sp804_delay_timer.c
+FVP_R_BL_COMMON_SOURCES		+=	drivers/arm/sp804/sp804_delay_timer.c
 else
-BL1_SOURCES		+=	drivers/delay_timer/generic_delay_timer.c
+FVP_R_BL_COMMON_SOURCES		+=	drivers/delay_timer/generic_delay_timer.c
 endif
 
 # Enable Activity Monitor Unit extensions by default
 ENABLE_AMU			:=	1
 
 ifneq (${ENABLE_STACK_PROTECTOR},0)
-PLAT_BL_COMMON_SOURCES	+=	plat/arm/board/fvp_r/fvp_r_stack_protector.c
+FVP_R_BL_COMMON_SOURCES	+=	plat/arm/board/fvp_r/fvp_r_stack_protector.c
 endif
 
-NEED_BL32 := no
-
-ifneq (${BL2_AT_EL3}, 0)
-    override BL1_SOURCES =
-endif
-
-include plat/arm/board/common/board_common.mk
-include plat/arm/common/arm_common.mk
-
-ifeq (${TRUSTED_BOARD_BOOT}, 1)
-BL1_SOURCES		+=	plat/arm/board/fvp_r/fvp_r_trusted_boot.c
-
-# FVP being a development platform, enable capability to disable Authentication
-# dynamically if TRUSTED_BOARD_BOOT is set.
-DYN_DISABLE_AUTH	:=	1
-endif
+override BL1_SOURCES	:=	drivers/arm/sp805/sp805.c			\
+				drivers/cfi/v2m/v2m_flash.c			\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/io/io_fip.c				\
+				drivers/io/io_memmap.c				\
+				drivers/io/io_storage.c				\
+				drivers/io/io_semihosting.c			\
+				lib/cpus/aarch64/cpu_helpers.S			\
+				lib/cpus/errata_report.c			\
+				lib/cpus/aarch64/dsu_helpers.S			\
+				lib/el3_runtime/aarch64/context.S		\
+				lib/el3_runtime/aarch64/context_mgmt.c		\
+				lib/fconf/fconf.c				\
+				lib/fconf/fconf_dyn_cfg_getter.c		\
+				lib/semihosting/semihosting.c			\
+				lib/semihosting/${ARCH}/semihosting_call.S	\
+				plat/arm/common/arm_bl1_setup.c			\
+				plat/arm/common/arm_err.c			\
+				plat/arm/common/arm_io_storage.c		\
+				plat/arm/common/fconf/arm_fconf_io.c		\
+				plat/common/plat_bl1_common.c			\
+				plat/common/aarch64/platform_up_stack.S		\
+				${FVP_R_BL1_SOURCES}				\
+				${FVP_R_BL_COMMON_SOURCES}			\
+				${FVP_R_CPU_LIBS}				\
+				${FVP_R_DYNC_CFG_SOURCES}			\
+				${FVP_R_INTERCONNECT_SOURCES}
diff --git a/plat/arm/board/juno/include/platform_def.h b/plat/arm/board/juno/include/platform_def.h
index 5299a7b..d61ba5d 100644
--- a/plat/arm/board/juno/include/platform_def.h
+++ b/plat/arm/board/juno/include/platform_def.h
@@ -53,12 +53,13 @@
 #define PLAT_ARM_DRAM2_BASE		ULL(0x880000000)
 #define PLAT_ARM_DRAM2_SIZE		ULL(0x180000000)
 
-#define PLAT_HW_CONFIG_DTB_BASE		ULL(0x82000000)
-#define PLAT_HW_CONFIG_DTB_SIZE		ULL(0x00008000) /* 32KB */
+/* Range of kernel DTB load address */
+#define JUNO_DTB_DRAM_MAP_START		ULL(0x82000000)
+#define JUNO_DTB_DRAM_MAP_SIZE		ULL(0x00008000) /* 32KB */
 
 #define ARM_DTB_DRAM_NS			MAP_REGION_FLAT(		\
-					PLAT_HW_CONFIG_DTB_BASE,	\
-					PLAT_HW_CONFIG_DTB_SIZE,	\
+					JUNO_DTB_DRAM_MAP_START,	\
+					JUNO_DTB_DRAM_MAP_SIZE,		\
 					MT_MEMORY | MT_RO | MT_NS)
 
 /* virtual address used by dynamic mem_protect for chunk_base */
diff --git a/plat/arm/common/aarch64/arm_bl2_mem_params_desc.c b/plat/arm/common/aarch64/arm_bl2_mem_params_desc.c
index 6a8943d..0666e57 100644
--- a/plat/arm/common/aarch64/arm_bl2_mem_params_desc.c
+++ b/plat/arm/common/aarch64/arm_bl2_mem_params_desc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -75,8 +75,10 @@
 	    .image_info.image_base = BL31_BASE,
 	    .image_info.image_max_size = BL31_LIMIT - BL31_BASE,
 
-# ifdef BL32_BASE
+# if defined(BL32_BASE)
 	    .next_handoff_image_id = BL32_IMAGE_ID,
+# elif ENABLE_RME
+	    .next_handoff_image_id = RMM_IMAGE_ID,
 # else
 	    .next_handoff_image_id = BL33_IMAGE_ID,
 # endif
@@ -99,6 +101,22 @@
 		    VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING),
 	    .next_handoff_image_id = INVALID_IMAGE_ID,
     },
+
+# if ENABLE_RME
+	/* Fill RMM related information */
+    {
+	    .image_id = RMM_IMAGE_ID,
+	    SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
+		    VERSION_2, entry_point_info_t, EP_REALM | EXECUTABLE),
+	    .ep_info.pc = RMM_BASE,
+	    SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
+		    VERSION_2, image_info_t, 0),
+	    .image_info.image_base = RMM_BASE,
+	    .image_info.image_max_size = RMM_LIMIT - RMM_BASE,
+	    .next_handoff_image_id = BL33_IMAGE_ID,
+    },
+# endif
+
 # ifdef BL32_BASE
 	/* Fill BL32 related information */
     {
@@ -113,7 +131,11 @@
 	    .image_info.image_base = BL32_BASE,
 	    .image_info.image_max_size = BL32_LIMIT - BL32_BASE,
 
+# if ENABLE_RME
+	    .next_handoff_image_id = RMM_IMAGE_ID,
+# else
 	    .next_handoff_image_id = BL33_IMAGE_ID,
+# endif
     },
 
 	/*
diff --git a/plat/arm/common/arm_bl1_setup.c b/plat/arm/common/arm_bl1_setup.c
index 872de3e..320bb82 100644
--- a/plat/arm/common/arm_bl1_setup.c
+++ b/plat/arm/common/arm_bl1_setup.c
@@ -32,7 +32,7 @@
 #define MAP_BL1_TOTAL		MAP_REGION_FLAT(			\
 					bl1_tzram_layout.total_base,	\
 					bl1_tzram_layout.total_size,	\
-					MT_MEMORY | MT_RW | MT_SECURE)
+					MT_MEMORY | MT_RW | EL3_PAS)
 /*
  * If SEPARATE_CODE_AND_RODATA=1 we define a region for each section
  * otherwise one region is defined containing both
@@ -41,17 +41,17 @@
 #define MAP_BL1_RO		MAP_REGION_FLAT(			\
 					BL_CODE_BASE,			\
 					BL1_CODE_END - BL_CODE_BASE,	\
-					MT_CODE | MT_SECURE),		\
+					MT_CODE | EL3_PAS),		\
 				MAP_REGION_FLAT(			\
 					BL1_RO_DATA_BASE,		\
 					BL1_RO_DATA_END			\
 						- BL_RO_DATA_BASE,	\
-					MT_RO_DATA | MT_SECURE)
+					MT_RO_DATA | EL3_PAS)
 #else
 #define MAP_BL1_RO		MAP_REGION_FLAT(			\
 					BL_CODE_BASE,			\
 					BL1_CODE_END - BL_CODE_BASE,	\
-					MT_CODE | MT_SECURE)
+					MT_CODE | EL3_PAS)
 #endif
 
 /* Data structure which holds the extents of the trusted SRAM for BL1*/
diff --git a/plat/arm/common/arm_bl2_setup.c b/plat/arm/common/arm_bl2_setup.c
index 5b26a1d..08c014d 100644
--- a/plat/arm/common/arm_bl2_setup.c
+++ b/plat/arm/common/arm_bl2_setup.c
@@ -9,6 +9,7 @@
 
 #include <platform_def.h>
 
+#include <arch_features.h>
 #include <arch_helpers.h>
 #include <common/bl_common.h>
 #include <common/debug.h>
@@ -17,10 +18,16 @@
 #include <drivers/partition/partition.h>
 #include <lib/fconf/fconf.h>
 #include <lib/fconf/fconf_dyn_cfg_getter.h>
+#if ENABLE_RME
+#include <lib/gpt_rme/gpt_rme.h>
+#endif /* ENABLE_RME */
 #ifdef SPD_opteed
 #include <lib/optee_utils.h>
 #endif
 #include <lib/utils.h>
+#if ENABLE_RME
+#include <plat/arm/common/arm_pas_def.h>
+#endif /* ENABLE_RME */
 #include <plat/arm/common/plat_arm.h>
 #include <plat/common/platform.h>
 
@@ -41,15 +48,18 @@
 #pragma weak bl2_platform_setup
 #pragma weak bl2_plat_arch_setup
 #pragma weak bl2_plat_sec_mem_layout
-#if MEASURED_BOOT
-#pragma weak bl2_plat_get_hash
-#endif
 
+#if ENABLE_RME
+#define MAP_BL2_TOTAL		MAP_REGION_FLAT(			\
+					bl2_tzram_layout.total_base,	\
+					bl2_tzram_layout.total_size,	\
+					MT_MEMORY | MT_RW | MT_ROOT)
+#else
 #define MAP_BL2_TOTAL		MAP_REGION_FLAT(			\
 					bl2_tzram_layout.total_base,	\
 					bl2_tzram_layout.total_size,	\
 					MT_MEMORY | MT_RW | MT_SECURE)
-
+#endif /* ENABLE_RME */
 
 #pragma weak arm_bl2_plat_handle_post_image_load
 
@@ -105,8 +115,10 @@
  */
 void arm_bl2_platform_setup(void)
 {
+#if !ENABLE_RME
 	/* Initialize the secure environment */
 	plat_arm_security_setup();
+#endif
 
 #if defined(PLAT_ARM_MEM_PROT_ADDR)
 	arm_nor_psci_do_static_mem_protect();
@@ -118,9 +130,54 @@
 	arm_bl2_platform_setup();
 }
 
+#if ENABLE_RME
+
+static void arm_bl2_plat_gpt_setup(void)
+{
+	/*
+	 * The GPT library might modify the gpt regions structure to optimize
+	 * the layout, so the array cannot be constant.
+	 */
+	pas_region_t pas_regions[] = {
+		ARM_PAS_KERNEL,
+		ARM_PAS_SECURE,
+		ARM_PAS_REALM,
+		ARM_PAS_EL3_DRAM,
+		ARM_PAS_GPTS
+	};
+
+	/* Initialize entire protected space to GPT_GPI_ANY. */
+	if (gpt_init_l0_tables(GPCCR_PPS_4GB, ARM_L0_GPT_ADDR_BASE,
+		ARM_L0_GPT_SIZE) < 0) {
+		ERROR("gpt_init_l0_tables() failed!\n");
+		panic();
+	}
+
+	/* Carve out defined PAS ranges. */
+	if (gpt_init_pas_l1_tables(GPCCR_PGS_4K,
+				   ARM_L1_GPT_ADDR_BASE,
+				   ARM_L1_GPT_SIZE,
+				   pas_regions,
+				   (unsigned int)(sizeof(pas_regions) /
+				   sizeof(pas_region_t))) < 0) {
+		ERROR("gpt_init_pas_l1_tables() failed!\n");
+		panic();
+	}
+
+	INFO("Enabling Granule Protection Checks\n");
+	if (gpt_enable() < 0) {
+		ERROR("gpt_enable() failed!\n");
+		panic();
+	}
+}
+
+#endif /* ENABLE_RME */
+
 /*******************************************************************************
- * Perform the very early platform specific architectural setup here. At the
- * moment this is only initializes the mmu in a quick and dirty way.
+ * Perform the very early platform specific architectural setup here.
+ * When RME is enabled the secure environment is initialised before
+ * initialising and enabling Granule Protection.
+ * This function initialises the MMU in a quick and dirty way.
  ******************************************************************************/
 void arm_bl2_plat_arch_setup(void)
 {
@@ -143,13 +200,29 @@
 		ARM_MAP_BL_COHERENT_RAM,
 #endif
 		ARM_MAP_BL_CONFIG_REGION,
+#if ENABLE_RME
+		ARM_MAP_L0_GPT_REGION,
+#endif
 		{0}
 	};
 
+#if ENABLE_RME
+	/* Initialise the secure environment */
+	plat_arm_security_setup();
+#endif
 	setup_page_tables(bl_regions, plat_arm_get_mmap());
 
 #ifdef __aarch64__
+#if ENABLE_RME
+	/* BL2 runs in EL3 when RME enabled. */
+	assert(get_armv9_2_feat_rme_support() != 0U);
+	enable_mmu_el3(0);
+
+	/* Initialise and enable granule protection after MMU. */
+	arm_bl2_plat_gpt_setup();
+#else
 	enable_mmu_el1(0);
+#endif
 #else
 	enable_mmu_svc_mon(0);
 #endif
@@ -247,11 +320,3 @@
 {
 	return arm_bl2_plat_handle_post_image_load(image_id);
 }
-
-#if MEASURED_BOOT
-/* Read TCG_DIGEST_SIZE bytes of BL2 hash data */
-void bl2_plat_get_hash(void *data)
-{
-	arm_bl2_get_hash(data);
-}
-#endif
diff --git a/plat/arm/common/arm_bl31_setup.c b/plat/arm/common/arm_bl31_setup.c
index b819888..6472590 100644
--- a/plat/arm/common/arm_bl31_setup.c
+++ b/plat/arm/common/arm_bl31_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -13,6 +13,9 @@
 #include <drivers/console.h>
 #include <lib/debugfs.h>
 #include <lib/extensions/ras.h>
+#if ENABLE_RME
+#include <lib/gpt_rme/gpt_rme.h>
+#endif
 #include <lib/mmio.h>
 #include <lib/xlat_tables/xlat_tables_compat.h>
 #include <plat/arm/common/plat_arm.h>
@@ -25,6 +28,9 @@
  */
 static entry_point_info_t bl32_image_ep_info;
 static entry_point_info_t bl33_image_ep_info;
+#if ENABLE_RME
+static entry_point_info_t rmm_image_ep_info;
+#endif
 
 #if !RESET_TO_BL31
 /*
@@ -43,7 +49,7 @@
 #define MAP_BL31_TOTAL		MAP_REGION_FLAT(			\
 					BL31_START,			\
 					BL31_END - BL31_START,		\
-					MT_MEMORY | MT_RW | MT_SECURE)
+					MT_MEMORY | MT_RW | EL3_PAS)
 #if RECLAIM_INIT_CODE
 IMPORT_SYM(unsigned long, __INIT_CODE_START__, BL_INIT_CODE_BASE);
 IMPORT_SYM(unsigned long, __INIT_CODE_END__, BL_CODE_END_UNALIGNED);
@@ -58,7 +64,7 @@
 					BL_INIT_CODE_BASE,		\
 					BL_INIT_CODE_END		\
 						- BL_INIT_CODE_BASE,	\
-					MT_CODE | MT_SECURE)
+					MT_CODE | EL3_PAS)
 #endif
 
 #if SEPARATE_NOBITS_REGION
@@ -66,7 +72,7 @@
 					BL31_NOBITS_BASE,		\
 					BL31_NOBITS_LIMIT 		\
 						- BL31_NOBITS_BASE,	\
-					MT_MEMORY | MT_RW | MT_SECURE)
+					MT_MEMORY | MT_RW | EL3_PAS)
 
 #endif
 /*******************************************************************************
@@ -80,8 +86,18 @@
 	entry_point_info_t *next_image_info;
 
 	assert(sec_state_is_valid(type));
-	next_image_info = (type == NON_SECURE)
-			? &bl33_image_ep_info : &bl32_image_ep_info;
+	if (type == NON_SECURE) {
+		next_image_info = &bl33_image_ep_info;
+	}
+#if ENABLE_RME
+	else if (type == REALM) {
+		next_image_info = &rmm_image_ep_info;
+	}
+#endif
+	else {
+		next_image_info = &bl32_image_ep_info;
+	}
+
 	/*
 	 * None of the images on the ARM development platforms can have 0x0
 	 * as the entrypoint
@@ -169,21 +185,31 @@
 	bl_params_node_t *bl_params = params_from_bl2->head;
 
 	/*
-	 * Copy BL33 and BL32 (if present), entry point information.
+	 * Copy BL33, BL32 and RMM (if present), entry point information.
 	 * They are stored in Secure RAM, in BL2's address space.
 	 */
 	while (bl_params != NULL) {
-		if (bl_params->image_id == BL32_IMAGE_ID)
+		if (bl_params->image_id == BL32_IMAGE_ID) {
 			bl32_image_ep_info = *bl_params->ep_info;
-
-		if (bl_params->image_id == BL33_IMAGE_ID)
+		}
+#if ENABLE_RME
+		else if (bl_params->image_id == RMM_IMAGE_ID) {
+			rmm_image_ep_info = *bl_params->ep_info;
+		}
+#endif
+		else if (bl_params->image_id == BL33_IMAGE_ID) {
 			bl33_image_ep_info = *bl_params->ep_info;
+		}
 
 		bl_params = bl_params->next_params_info;
 	}
 
 	if (bl33_image_ep_info.pc == 0U)
 		panic();
+#if ENABLE_RME
+	if (rmm_image_ep_info.pc == 0U)
+		panic();
+#endif
 #endif /* RESET_TO_BL31 */
 
 # if ARM_LINUX_KERNEL_AS_BL33
@@ -193,7 +219,11 @@
 	 * tree blob (DTB) in x0, while x1-x3 are reserved for future use and
 	 * must be 0.
 	 */
+#if RESET_TO_BL31
 	bl33_image_ep_info.args.arg0 = (u_register_t)ARM_PRELOADED_DTB_BASE;
+#else
+	bl33_image_ep_info.args.arg0 = (u_register_t)hw_config;
+#endif
 	bl33_image_ep_info.args.arg1 = 0U;
 	bl33_image_ep_info.args.arg2 = 0U;
 	bl33_image_ep_info.args.arg3 = 0U;
@@ -355,6 +385,9 @@
 {
 	const mmap_region_t bl_regions[] = {
 		MAP_BL31_TOTAL,
+#if ENABLE_RME
+		ARM_MAP_L0_GPT_REGION,
+#endif
 #if RECLAIM_INIT_CODE
 		MAP_BL_INIT_CODE,
 #endif
@@ -376,6 +409,19 @@
 
 	enable_mmu_el3(0);
 
+#if ENABLE_RME
+	/*
+	 * Initialise Granule Protection library and enable GPC for the primary
+	 * processor. The tables have already been initialized by a previous BL
+	 * stage, so there is no need to provide any PAS here. This function
+	 * sets up pointers to those tables.
+	 */
+	if (gpt_runtime_init() < 0) {
+		ERROR("gpt_runtime_init() failed!\n");
+		panic();
+	}
+#endif /* ENABLE_RME */
+
 	arm_setup_romlib();
 }
 
diff --git a/plat/arm/common/arm_common.mk b/plat/arm/common/arm_common.mk
index dc8c6d0..a20e258 100644
--- a/plat/arm/common/arm_common.mk
+++ b/plat/arm/common/arm_common.mk
@@ -52,9 +52,10 @@
 $(eval $(call add_define,ARM_RECOM_STATE_ID_ENC))
 
 # Process ARM_DISABLE_TRUSTED_WDOG flag
-# By default, Trusted Watchdog is always enabled unless SPIN_ON_BL1_EXIT is set
+# By default, Trusted Watchdog is always enabled unless
+# SPIN_ON_BL1_EXIT or ENABLE_RME is set
 ARM_DISABLE_TRUSTED_WDOG	:=	0
-ifeq (${SPIN_ON_BL1_EXIT}, 1)
+ifneq ($(filter 1,${SPIN_ON_BL1_EXIT} ${ENABLE_RME}),)
 ARM_DISABLE_TRUSTED_WDOG	:=	1
 endif
 $(eval $(call assert_boolean,ARM_DISABLE_TRUSTED_WDOG))
@@ -94,10 +95,13 @@
   ifndef PRELOADED_BL33_BASE
     $(error "PRELOADED_BL33_BASE must be set if ARM_LINUX_KERNEL_AS_BL33 is used.")
   endif
-  ifndef ARM_PRELOADED_DTB_BASE
-    $(error "ARM_PRELOADED_DTB_BASE must be set if ARM_LINUX_KERNEL_AS_BL33 is used.")
+  ifeq (${RESET_TO_BL31},1)
+    ifndef ARM_PRELOADED_DTB_BASE
+      $(error "ARM_PRELOADED_DTB_BASE must be set if ARM_LINUX_KERNEL_AS_BL33 is
+       used with RESET_TO_BL31.")
+    endif
+    $(eval $(call add_define,ARM_PRELOADED_DTB_BASE))
   endif
-  $(eval $(call add_define,ARM_PRELOADED_DTB_BASE))
 endif
 
 # Arm Ethos-N NPU SiP service
@@ -355,13 +359,8 @@
 
     # Include the selected chain of trust sources.
     ifeq (${COT},tbbr)
-        ifeq (${PLAT},fvp_r)
-            BL1_SOURCES	+=	drivers/auth/tbbr/tbbr_cot_common.c		\
-				drivers/auth/tbbr/tbbr_cot_bl1_r64.c
-        else
             BL1_SOURCES	+=	drivers/auth/tbbr/tbbr_cot_common.c		\
 				drivers/auth/tbbr/tbbr_cot_bl1.c
-        endif
         ifneq (${COT_DESC_IN_DTB},0)
             BL2_SOURCES	+=	lib/fconf/fconf_cot_getter.c
         else
@@ -407,7 +406,7 @@
 endif
 
 ifeq (${MEASURED_BOOT},1)
-    MEASURED_BOOT_MK := drivers/measured_boot/measured_boot.mk
+    MEASURED_BOOT_MK := drivers/measured_boot/event_log/event_log.mk
     $(info Including ${MEASURED_BOOT_MK})
     include ${MEASURED_BOOT_MK}
 endif
diff --git a/plat/arm/common/arm_dyn_cfg.c b/plat/arm/common/arm_dyn_cfg.c
index 30473be..6aae9ae 100644
--- a/plat/arm/common/arm_dyn_cfg.c
+++ b/plat/arm/common/arm_dyn_cfg.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -15,10 +15,6 @@
 #include <common/tbbr/tbbr_img_def.h>
 #if TRUSTED_BOARD_BOOT
 #include <drivers/auth/mbedtls/mbedtls_config.h>
-#if MEASURED_BOOT
-#include <drivers/auth/crypto_mod.h>
-#include <mbedtls/md.h>
-#endif
 #endif
 #include <lib/fconf/fconf.h>
 #include <lib/fconf/fconf_dyn_cfg_getter.h>
@@ -115,82 +111,13 @@
 		 * images. It's critical because BL2 won't be able to proceed
 		 * without the heap info.
 		 *
-		 * In MEASURED_BOOT case flushing is done in
-		 * arm_bl1_set_bl2_hash() function which is called after heap
-		 * information is written in the DTB.
+		 * In MEASURED_BOOT case flushing is done in a function which
+		 * is called after heap information is written in the DTB.
 		 */
 		flush_dcache_range(tb_fw_cfg_dtb, fdt_totalsize(dtb));
 #endif /* !MEASURED_BOOT */
 	}
-}
-
-#if MEASURED_BOOT
-/*
- * Calculates and writes BL2 hash data to TB_FW_CONFIG DTB.
- * Executed only from BL1.
- */
-void arm_bl1_set_bl2_hash(const image_desc_t *image_desc)
-{
-	unsigned char hash_data[MBEDTLS_MD_MAX_SIZE];
-	const image_info_t image_info = image_desc->image_info;
-	uintptr_t tb_fw_cfg_dtb;
-	int err;
-	const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
-
-	tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
-	assert(tb_fw_config_info != NULL);
-
-	tb_fw_cfg_dtb = tb_fw_config_info->config_addr;
-
-	/*
-	 * If tb_fw_cfg_dtb==NULL then DTB is not present for the current
-	 * platform. As such, we cannot write to the DTB at all and pass
-	 * measured data.
-	 */
-	if (tb_fw_cfg_dtb == 0UL) {
-		panic();
-	}
-
-	/* Calculate hash */
-	err = crypto_mod_calc_hash(MBEDTLS_MD_ID,
-					(void *)image_info.image_base,
-					image_info.image_size, hash_data);
-	if (err != 0) {
-		ERROR("%scalculate%s\n", "BL1: unable to ",
-						" BL2 hash");
-		panic();
-	}
-
-	err = arm_set_bl2_hash_info((void *)tb_fw_cfg_dtb, hash_data);
-	if (err < 0) {
-		ERROR("%swrite%sdata%s\n", "BL1: unable to ",
-					" BL2 hash ", "to DTB\n");
-		panic();
-	}
-
-	/*
-	 * Ensure that the info written to the DTB is visible to other
-	 * images. It's critical because BL2 won't be able to proceed
-	 * without the heap info and its hash data.
-	 */
-	flush_dcache_range(tb_fw_cfg_dtb, fdt_totalsize((void *)tb_fw_cfg_dtb));
-}
-
-/*
- * Reads TCG_DIGEST_SIZE bytes of BL2 hash data from the DTB.
- * Executed only from BL2.
- */
-void arm_bl2_get_hash(void *data)
-{
-	const void *bl2_hash;
-
-	assert(data != NULL);
-
-	/* Retrieve TCG_DIGEST_SIZE bytes of BL2 hash data from the DTB */
-	bl2_hash = FCONF_GET_PROPERTY(tbbr, dyn_config, bl2_hash_data);
-	(void)memcpy(data, bl2_hash, TCG_DIGEST_SIZE);
 }
-#endif /* MEASURED_BOOT */
 #endif /* TRUSTED_BOARD_BOOT */
 
 /*
diff --git a/plat/arm/common/arm_dyn_cfg_helpers.c b/plat/arm/common/arm_dyn_cfg_helpers.c
index 5f20c8d..6a2a6f8 100644
--- a/plat/arm/common/arm_dyn_cfg_helpers.c
+++ b/plat/arm/common/arm_dyn_cfg_helpers.c
@@ -11,6 +11,8 @@
 #endif
 #include <common/fdt_wrappers.h>
 
+#include <lib/fconf/fconf.h>
+#include <lib/fconf/fconf_dyn_cfg_getter.h>
 #include <libfdt.h>
 
 #include <plat/arm/common/arm_dyn_cfg_helpers.h>
@@ -20,18 +22,15 @@
 #define DTB_PROP_MBEDTLS_HEAP_SIZE "mbedtls_heap_size"
 
 #if MEASURED_BOOT
-#define DTB_PROP_BL2_HASH_DATA	"bl2_hash_data"
 #ifdef SPD_opteed
 /*
  * Currently OP-TEE does not support reading DTBs from Secure memory
  * and this property should be removed when this feature is supported.
  */
 #define DTB_PROP_HW_SM_LOG_ADDR	"tpm_event_log_sm_addr"
-#endif
+#endif /* SPD_opteed */
 #define DTB_PROP_HW_LOG_ADDR	"tpm_event_log_addr"
 #define DTB_PROP_HW_LOG_SIZE    "tpm_event_log_size"
-
-static int dtb_root = -1;
 #endif /* MEASURED_BOOT */
 
 /*******************************************************************************
@@ -81,9 +80,8 @@
  */
 int arm_set_dtb_mbedtls_heap_info(void *dtb, void *heap_addr, size_t heap_size)
 {
-#if !MEASURED_BOOT
 	int dtb_root;
-#endif
+
 	/*
 	 * Verify that the DTB is valid, before attempting to write to it,
 	 * and get the DTB root node.
@@ -123,32 +121,8 @@
 
 #if MEASURED_BOOT
 /*
- * This function writes the BL2 hash data in HW_FW_CONFIG DTB.
- * When it is called, it is guaranteed that a DTB is available.
- *
- * This function is supposed to be called only by BL1.
- *
- * Returns:
- *	0 = success
- *    < 0 = error
- */
-int arm_set_bl2_hash_info(void *dtb, void *data)
-{
-	assert(dtb_root >= 0);
-
-	/*
-	 * Write the BL2 hash data in the DTB.
-	 */
-	return fdtw_write_inplace_bytes(dtb, dtb_root,
-					DTB_PROP_BL2_HASH_DATA,
-					TCG_DIGEST_SIZE, data);
-}
-
-/*
  * Write the Event Log address and its size in the DTB.
  *
- * This function is supposed to be called only by BL2.
- *
  * Returns:
  *	0 = success
  *    < 0 = error
@@ -231,14 +205,20 @@
  *	0 = success
  *    < 0 = error
  */
-int arm_set_tos_fw_info(uintptr_t config_base, uintptr_t log_addr,
-			size_t log_size)
+int arm_set_tos_fw_info(uintptr_t log_addr, size_t log_size)
 {
+	uintptr_t config_base;
+	const bl_mem_params_node_t *cfg_mem_params;
 	int err;
 
-	assert(config_base != 0UL);
 	assert(log_addr != 0UL);
 
+	/* Get the config load address and size of TOS_FW_CONFIG */
+	cfg_mem_params = get_bl_mem_params_node(TOS_FW_CONFIG_ID);
+	assert(cfg_mem_params != NULL);
+
+	config_base = cfg_mem_params->image_info.image_base;
+
 	/* Write the Event Log address and its size in the DTB */
 	err = arm_set_event_log_info(config_base,
 #ifdef SPD_opteed
@@ -263,23 +243,25 @@
  *	0 = success
  *    < 0 = error
  */
-int arm_set_nt_fw_info(uintptr_t config_base,
+int arm_set_nt_fw_info(
 #ifdef SPD_opteed
 			uintptr_t log_addr,
 #endif
 			size_t log_size, uintptr_t *ns_log_addr)
 {
+	uintptr_t config_base;
 	uintptr_t ns_addr;
 	const bl_mem_params_node_t *cfg_mem_params;
 	int err;
 
-	assert(config_base != 0UL);
 	assert(ns_log_addr != NULL);
 
 	/* Get the config load address and size from NT_FW_CONFIG */
 	cfg_mem_params = get_bl_mem_params_node(NT_FW_CONFIG_ID);
 	assert(cfg_mem_params != NULL);
 
+	config_base = cfg_mem_params->image_info.image_base;
+
 	/* Calculate Event Log address in Non-secure memory */
 	ns_addr = cfg_mem_params->image_info.image_base +
 			cfg_mem_params->image_info.image_max_size;
@@ -300,4 +282,87 @@
 	*ns_log_addr = (err < 0) ? 0UL : ns_addr;
 	return err;
 }
+
+/*
+ * This function writes the Event Log address and its size
+ * in the TB_FW_CONFIG DTB.
+ *
+ * This function is supposed to be called only by BL1.
+ *
+ * Returns:
+ *     0 = success
+ *   < 0 = error
+ */
+int arm_set_tb_fw_info(uintptr_t log_addr, size_t log_size)
+{
+	/*
+	 * Read tb_fw_config device tree for Event Log properties
+	 * and write the Event Log address and its size in the DTB
+	 */
+	const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
+	uintptr_t tb_fw_cfg_dtb;
+	int err;
+
+	tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
+	assert(tb_fw_config_info != NULL);
+
+	tb_fw_cfg_dtb = tb_fw_config_info->config_addr;
+
+	err = arm_set_event_log_info(tb_fw_cfg_dtb,
+#ifdef SPD_opteed
+				     0UL,
+#endif
+				     log_addr, log_size);
+	return err;
+}
+
+/*
+ * This function reads the Event Log address and its size
+ * properties present in TB_FW_CONFIG DTB.
+ *
+ * This function is supposed to be called only by BL2.
+ *
+ * Returns:
+ *     0 = success
+ *   < 0 = error
+ * Alongside returns Event Log address and its size.
+ */
+
+int arm_get_tb_fw_info(uint64_t *log_addr, size_t *log_size)
+{
+	/* As libfdt uses void *, we can't avoid this cast */
+	const struct dyn_cfg_dtb_info_t *tb_fw_config_info;
+	int node, rc;
+
+	tb_fw_config_info = FCONF_GET_PROPERTY(dyn_cfg, dtb, TB_FW_CONFIG_ID);
+	assert(tb_fw_config_info != NULL);
+
+	void *dtb = (void *)tb_fw_config_info->config_addr;
+	const char *compatible = "arm,tpm_event_log";
+
+	/* Assert the node offset point to compatible property */
+	node = fdt_node_offset_by_compatible(dtb, -1, compatible);
+	if (node < 0) {
+		WARN("The compatible property '%s'%s", compatible,
+		     " not specified in TB_FW config.\n");
+		return node;
+	}
+
+	VERBOSE("Dyn cfg: '%s'%s", compatible, " found in the config\n");
+
+	rc = fdt_read_uint64(dtb, node, DTB_PROP_HW_LOG_ADDR, log_addr);
+	if (rc != 0) {
+		ERROR("%s%s", DTB_PROP_HW_LOG_ADDR,
+		      " not specified in TB_FW config.\n");
+		return rc;
+	}
+
+	rc = fdt_read_uint32(dtb, node, DTB_PROP_HW_LOG_SIZE, (uint32_t *)log_size);
+	if (rc != 0) {
+		ERROR("%s%s", DTB_PROP_HW_LOG_SIZE,
+		      " not specified in TB_FW config.\n");
+	}
+
+	return rc;
+}
 #endif /* MEASURED_BOOT */
diff --git a/plat/arm/common/fconf/arm_fconf_io.c b/plat/arm/common/fconf/arm_fconf_io.c
index 86fd6d5..aea2f38 100644
--- a/plat/arm/common/fconf/arm_fconf_io.c
+++ b/plat/arm/common/fconf/arm_fconf_io.c
@@ -67,6 +67,7 @@
 	[SOC_FW_CONFIG_ID] = {UUID_SOC_FW_CONFIG},
 	[TOS_FW_CONFIG_ID] = {UUID_TOS_FW_CONFIG},
 	[NT_FW_CONFIG_ID] = {UUID_NT_FW_CONFIG},
+	[RMM_IMAGE_ID] = {UUID_REALM_MONITOR_MGMT_FIRMWARE},
 #endif /* ARM_IO_IN_DTB */
 #if TRUSTED_BOARD_BOOT
 	[TRUSTED_BOOT_FW_CERT_ID] = {UUID_TRUSTED_BOOT_FW_CERT},
@@ -162,6 +163,11 @@
 		(uintptr_t)&arm_uuid_spec[BL33_IMAGE_ID],
 		open_fip
 	},
+	[RMM_IMAGE_ID] = {
+		&fip_dev_handle,
+		(uintptr_t)&arm_uuid_spec[RMM_IMAGE_ID],
+		open_fip
+	},
 	[HW_CONFIG_ID] = {
 		&fip_dev_handle,
 		(uintptr_t)&arm_uuid_spec[HW_CONFIG_ID],
diff --git a/plat/arm/common/trp/arm_trp.mk b/plat/arm/common/trp/arm_trp.mk
new file mode 100644
index 0000000..997111f
--- /dev/null
+++ b/plat/arm/common/trp/arm_trp.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+# TRP source files common to ARM standard platforms
+RMM_SOURCES		+=	plat/arm/common/trp/arm_trp_setup.c	\
+				plat/arm/common/arm_topology.c		\
+				plat/common/aarch64/platform_mp_stack.S
diff --git a/plat/arm/common/trp/arm_trp_setup.c b/plat/arm/common/trp/arm_trp_setup.c
new file mode 100644
index 0000000..8e48293
--- /dev/null
+++ b/plat/arm/common/trp/arm_trp_setup.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_def.h>
+
+/*******************************************************************************
+ * Initialize the UART
+ ******************************************************************************/
+static console_t arm_trp_runtime_console;
+
+void arm_trp_early_platform_setup(void)
+{
+	/*
+	 * Initialize a different console than already in use to display
+	 * messages from trp
+	 */
+	int rc = console_pl011_register(PLAT_ARM_TRP_UART_BASE,
+					PLAT_ARM_TRP_UART_CLK_IN_HZ,
+					ARM_CONSOLE_BAUDRATE,
+					&arm_trp_runtime_console);
+	if (rc == 0) {
+		panic();
+	}
+
+	console_set_scope(&arm_trp_runtime_console,
+			  CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME);
+}
+
+void trp_early_platform_setup(void)
+{
+	arm_trp_early_platform_setup();
+}
diff --git a/plat/common/plat_bl1_common.c b/plat/common/plat_bl1_common.c
index 1c6d68b..bcf9f89 100644
--- a/plat/common/plat_bl1_common.c
+++ b/plat/common/plat_bl1_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -27,9 +27,6 @@
 #pragma weak bl1_plat_fwu_done
 #pragma weak bl1_plat_handle_pre_image_load
 #pragma weak bl1_plat_handle_post_image_load
-#if MEASURED_BOOT
-#pragma weak bl1_plat_set_bl2_hash
-#endif
 
 unsigned int bl1_plat_get_next_image_id(void)
 {
@@ -118,12 +115,3 @@
 		(void *) bl2_secram_layout);
 	return 0;
 }
-
-#if MEASURED_BOOT
-/*
- * Calculates and writes BL2 hash data to TB_FW_CONFIG DTB.
- */
-void bl1_plat_set_bl2_hash(const image_desc_t *image_desc)
-{
-}
-#endif
diff --git a/plat/marvell/armada/a3k/common/a3700_common.mk b/plat/marvell/armada/a3k/common/a3700_common.mk
index 9550452..c3f78c5 100644
--- a/plat/marvell/armada/a3k/common/a3700_common.mk
+++ b/plat/marvell/armada/a3k/common/a3700_common.mk
@@ -76,6 +76,7 @@
 
 ifdef WTP
 
+# Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
 $(if $(wildcard $(value WTP)/*),,$(error "'WTP=$(value WTP)' was specified, but '$(value WTP)' directory does not exist"))
 $(if $(shell git -C $(value WTP) rev-parse --show-cdup 2>&1),$(error "'WTP=$(value WTP)' was specified, but '$(value WTP)' does not contain valid A3700-utils-marvell git repository"))
 
@@ -143,6 +144,7 @@
 CRYPTOPP_INCDIR		?= $(CRYPTOPP_PATH)
 
 $(TBB): FORCE
+	# Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
 	$(if $(CRYPTOPP_LIBDIR),,$(error "Platform '$(PLAT)' for WTP image tool requires CRYPTOPP_PATH or CRYPTOPP_LIBDIR. Please set CRYPTOPP_PATH or CRYPTOPP_LIBDIR to point to the right directory"))
 	$(if $(CRYPTOPP_INCDIR),,$(error "Platform '$(PLAT)' for WTP image tool requires CRYPTOPP_PATH or CRYPTOPP_INCDIR. Please set CRYPTOPP_PATH or CRYPTOPP_INCDIR to point to the right directory"))
 	$(if $(wildcard $(CRYPTOPP_LIBDIR)/*),,$(error "Either 'CRYPTOPP_PATH' or 'CRYPTOPP_LIB' was set to '$(CRYPTOPP_LIBDIR)', but '$(CRYPTOPP_LIBDIR)' does not exist"))
@@ -159,6 +161,7 @@
 	$(Q)cp -a $(WTMI_MULTI_IMG) $(BUILD_PLAT)/wtmi.bin
 
 $(TIMDDRTOOL): FORCE
+	# Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
 	$(if $(value MV_DDR_PATH),,$(error "Platform '${PLAT}' for ddr tool requires MV_DDR_PATH. Please set MV_DDR_PATH to point to the right directory"))
 	$(if $(wildcard $(value MV_DDR_PATH)/*),,$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' directory does not exist"))
 	$(if $(shell git -C $(value MV_DDR_PATH) rev-parse --show-cdup 2>&1),$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' does not contain valid mv-ddr-marvell git repository"))
diff --git a/plat/marvell/armada/a8k/a70x0_mochabin/board/dram_port.c b/plat/marvell/armada/a8k/a70x0_mochabin/board/dram_port.c
new file mode 100644
index 0000000..68d335b
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0_mochabin/board/dram_port.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2021 Sartura Ltd.
+ * Copyright (C) 2021 Globalscale technologies, Inc.
+ * Copyright (C) 2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+
+#include <mv_ddr_if.h>
+#include <plat_marvell.h>
+
+/*
+ * This function may modify the default DRAM parameters
+ * based on information received from SPD or bootloader
+ * configuration located on non volatile storage
+ */
+void plat_marvell_dram_update_topology(void)
+{
+}
+
+/*
+ * This struct provides the DRAM training code with
+ * the appropriate board DRAM configuration
+ */
+#if DDR_TOPOLOGY == 0
+static struct mv_ddr_topology_map board_topology_map_2g = {
+/* 1CS 4Gb x4 devices of Samsung K4A4G085WF */
+	DEBUG_LEVEL_ERROR,
+	0x1, /* active interfaces */
+	/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
+	{ { { {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0} },
+	   SPEED_BIN_DDR_2400R,		/* speed_bin */
+	   MV_DDR_DEV_WIDTH_8BIT,	/* sdram device width */
+	   MV_DDR_DIE_CAP_4GBIT,	/* die capacity */
+	   MV_DDR_FREQ_SAR,		/* frequency */
+	   0, 0,			/* cas_l, cas_wl */
+	   MV_DDR_TEMP_LOW} },		/* temperature */
+	BUS_MASK_32BIT,	/* subphys mask */
+	MV_DDR_CFG_DEFAULT,		/* ddr configuration data source */
+	NOT_COMBINED,			/* ddr twin-die combined*/
+	{ {0} },			/* raw spd data */
+	{0},				/* timing parameters */
+	{				/* electrical configuration */
+		{			/* memory electrical configuration */
+			MV_DDR_RTT_NOM_PARK_RZQ_DISABLE,	/* rtt_nom */
+			{
+				MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
+				MV_DDR_RTT_NOM_PARK_RZQ_DIV1  /* rtt_park 2cs */
+			},
+			{
+				MV_DDR_RTT_WR_DYN_ODT_OFF,	/* rtt_wr 1cs */
+				MV_DDR_RTT_WR_RZQ_DIV2		/* rtt_wr 2cs */
+			},
+			MV_DDR_DIC_RZQ_DIV7	/* dic */
+		},
+		{			/* phy electrical configuration */
+			MV_DDR_OHM_30,	/* data_drv_p */
+			MV_DDR_OHM_30,	/* data_drv_n */
+			MV_DDR_OHM_30,	/* ctrl_drv_p */
+			MV_DDR_OHM_30,	/* ctrl_drv_n */
+			{
+				MV_DDR_OHM_60,	/* odt_p 1cs */
+				MV_DDR_OHM_120	/* odt_p 2cs */
+			},
+			{
+				MV_DDR_OHM_60,	/* odt_n 1cs */
+				MV_DDR_OHM_120	/* odt_n 2cs */
+			},
+		},
+		{			/* mac electrical configuration */
+			MV_DDR_ODT_CFG_NORMAL,		/* odtcfg_pattern */
+			MV_DDR_ODT_CFG_ALWAYS_ON,	/* odtcfg_write */
+			MV_DDR_ODT_CFG_NORMAL,		/* odtcfg_read */
+		},
+	}
+};
+#endif
+
+#if DDR_TOPOLOGY == 1
+static struct mv_ddr_topology_map board_topology_map_4g = {
+/* 1CS 8Gb x4 devices of Samsung K4A8G085WC-BCTD */
+	DEBUG_LEVEL_ERROR,
+	0x1, /* active interfaces */
+	/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
+	{ { { {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0},
+	      {0x1, 0x2, 0, 0} },
+	   SPEED_BIN_DDR_2400R,		/* speed_bin */
+	   MV_DDR_DEV_WIDTH_8BIT,	/* sdram device width */
+	   MV_DDR_DIE_CAP_8GBIT,	/* die capacity */
+	   MV_DDR_FREQ_SAR,		/* frequency */
+	   0, 0,			/* cas_l, cas_wl */
+	   MV_DDR_TEMP_LOW} },		/* temperature */
+	BUS_MASK_32BIT,	/* subphys mask */
+	MV_DDR_CFG_DEFAULT,		/* ddr configuration data source */
+	NOT_COMBINED,			/* ddr twin-die combined*/
+	{ {0} },			/* raw spd data */
+	{0},				/* timing parameters */
+	{				/* electrical configuration */
+		{			/* memory electrical configuration */
+			MV_DDR_RTT_NOM_PARK_RZQ_DISABLE,	/* rtt_nom */
+			{
+				MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
+				MV_DDR_RTT_NOM_PARK_RZQ_DIV1  /* rtt_park 2cs */
+			},
+			{
+				MV_DDR_RTT_WR_DYN_ODT_OFF,	/* rtt_wr 1cs */
+				MV_DDR_RTT_WR_RZQ_DIV2		/* rtt_wr 2cs */
+			},
+			MV_DDR_DIC_RZQ_DIV7	/* dic */
+		},
+		{			/* phy electrical configuration */
+			MV_DDR_OHM_30,	/* data_drv_p */
+			MV_DDR_OHM_30,	/* data_drv_n */
+			MV_DDR_OHM_30,	/* ctrl_drv_p */
+			MV_DDR_OHM_30,	/* ctrl_drv_n */
+			{
+				MV_DDR_OHM_60,	/* odt_p 1cs */
+				MV_DDR_OHM_120	/* odt_p 2cs */
+			},
+			{
+				MV_DDR_OHM_60,	/* odt_n 1cs */
+				MV_DDR_OHM_120	/* odt_n 2cs */
+			},
+		},
+		{			/* mac electrical configuration */
+			MV_DDR_ODT_CFG_NORMAL,		/* odtcfg_pattern */
+			MV_DDR_ODT_CFG_ALWAYS_ON,	/* odtcfg_write */
+			MV_DDR_ODT_CFG_NORMAL,		/* odtcfg_read */
+		},
+	}
+};
+#endif
+
+#if DDR_TOPOLOGY == 2
+static struct mv_ddr_topology_map board_topology_map_8g = {
+/* 2CS 8Gb x8 devices of Micron MT40A1G8WE-083E IT */
+	DEBUG_LEVEL_ERROR,
+	0x1, /* active interfaces */
+	/* cs_mask, mirror, dqs_swap, ck_swap X subphys */
+	{ { { {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0},
+	      {0x3, 0x2, 0, 0} },
+	   SPEED_BIN_DDR_2400R,		/* speed_bin */
+	   MV_DDR_DEV_WIDTH_8BIT,	/* sdram device width */
+	   MV_DDR_DIE_CAP_8GBIT,	/* die capacity */
+	   MV_DDR_FREQ_SAR,		/* frequency */
+	   0, 0,			/* cas_l, cas_wl */
+	   MV_DDR_TEMP_LOW} },		/* temperature */
+	BUS_MASK_32BIT,	/* subphys mask */
+	MV_DDR_CFG_DEFAULT,		/* ddr configuration data source */
+	NOT_COMBINED,			/* ddr twin-die combined*/
+	{ {0} },			/* raw spd data */
+	{0},				/* timing parameters */
+	{				/* electrical configuration */
+		{			/* memory electrical configuration */
+			MV_DDR_RTT_NOM_PARK_RZQ_DISABLE,	/* rtt_nom */
+			{
+				MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */
+				MV_DDR_RTT_NOM_PARK_RZQ_DIV1  /* rtt_park 2cs */
+			},
+			{
+				MV_DDR_RTT_WR_DYN_ODT_OFF,	/* rtt_wr 1cs */
+				MV_DDR_RTT_WR_RZQ_DIV2		/* rtt_wr 2cs */
+			},
+			MV_DDR_DIC_RZQ_DIV7	/* dic */
+		},
+		{			/* phy electrical configuration */
+			MV_DDR_OHM_30,	/* data_drv_p */
+			MV_DDR_OHM_30,	/* data_drv_n */
+			MV_DDR_OHM_30,	/* ctrl_drv_p */
+			MV_DDR_OHM_30,	/* ctrl_drv_n */
+			{
+				MV_DDR_OHM_60,	/* odt_p 1cs */
+				MV_DDR_OHM_120	/* odt_p 2cs */
+			},
+			{
+				MV_DDR_OHM_60,	/* odt_n 1cs */
+				MV_DDR_OHM_120	/* odt_n 2cs */
+			},
+		},
+		{			/* mac electrical configuration */
+			MV_DDR_ODT_CFG_NORMAL,		/* odtcfg_pattern */
+			MV_DDR_ODT_CFG_ALWAYS_ON,	/* odtcfg_write */
+			MV_DDR_ODT_CFG_NORMAL,		/* odtcfg_read */
+		},
+	}
+};
+#endif
+
+struct mv_ddr_topology_map *mv_ddr_topology_map_get(void)
+{
+/* a70x0_mochabin board supports 3 DDR4 models (2G/1CS, 4G/1CS, 8G/2CS) */
+#if DDR_TOPOLOGY == 0
+	return &board_topology_map_2g;
+#elif DDR_TOPOLOGY == 1
+	return &board_topology_map_4g;
+#elif DDR_TOPOLOGY == 2
+	return &board_topology_map_8g;
+#else
+	#error "Unknown DDR topology"
+#endif
+}
diff --git a/plat/marvell/armada/a8k/a70x0_mochabin/board/marvell_plat_config.c b/plat/marvell/armada/a8k/a70x0_mochabin/board/marvell_plat_config.c
new file mode 100644
index 0000000..1ed6323
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0_mochabin/board/marvell_plat_config.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2021 Sartura Ltd.
+ * Copyright (C) 2021 Globalscale technologies, Inc.
+ * Copyright (C) 2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#include <armada_common.h>
+
+/*
+ * If bootrom is currently at BLE there's no need to include the memory
+ * maps structure at this point
+ */
+#include <mvebu_def.h>
+#ifndef IMAGE_BLE
+
+/*****************************************************************************
+ * AMB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win amb_memory_map[] = {
+	/* CP0 SPI1 CS0 Direct Mode access */
+	{0xf900,	0x1000000,	AMB_SPI1_CS0_ID},
+};
+
+int marvell_get_amb_memory_map(struct addr_map_win **win,
+			       uint32_t *size, uintptr_t base)
+{
+	*win = amb_memory_map;
+	if (*win == NULL)
+		*size = 0;
+	else
+		*size = ARRAY_SIZE(amb_memory_map);
+
+	return 0;
+}
+#endif
+
+/*****************************************************************************
+ * IO_WIN Configuration
+ *****************************************************************************
+ */
+struct addr_map_win io_win_memory_map[] = {
+#ifndef IMAGE_BLE
+	/* MCI 0 indirect window */
+	{MVEBU_MCI_REG_BASE_REMAP(0),	0x100000, MCI_0_TID},
+	/* MCI 1 indirect window */
+	{MVEBU_MCI_REG_BASE_REMAP(1),	0x100000, MCI_1_TID},
+#endif
+};
+
+uint32_t marvell_get_io_win_gcr_target(int ap_index)
+{
+	return PIDI_TID;
+}
+
+int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win,
+				  uint32_t *size)
+{
+	*win = io_win_memory_map;
+	if (*win == NULL)
+		*size = 0;
+	else
+		*size = ARRAY_SIZE(io_win_memory_map);
+
+	return 0;
+}
+
+#ifndef IMAGE_BLE
+/*****************************************************************************
+ * IOB Configuration
+ *****************************************************************************
+ */
+struct addr_map_win iob_memory_map[] = {
+	/* PEX1_X1 window */
+	{0x00000000f7000000,	0x1000000,	PEX1_TID},
+	/* PEX2_X1 window */
+	{0x00000000f8000000,	0x1000000,	PEX2_TID},
+	{0x00000000c0000000,	0x30000000,	PEX2_TID},
+	{0x0000000800000000,	0x100000000,	PEX2_TID},
+	/* PEX0_X4 window */
+	{0x00000000f6000000,	0x1000000,	PEX0_TID},
+	/* SPI1_CS0 (RUNIT) window */
+	{0x00000000f9000000,	0x1000000,	RUNIT_TID},
+};
+
+int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size,
+			       uintptr_t base)
+{
+	*win = iob_memory_map;
+	*size = ARRAY_SIZE(iob_memory_map);
+
+	return 0;
+}
+#endif
+
+/*****************************************************************************
+ * CCU Configuration
+ *****************************************************************************
+ */
+struct addr_map_win ccu_memory_map[] = {	/* IO window */
+#ifdef IMAGE_BLE
+	{0x00000000f2000000,	0x4000000,	IO_0_TID}, /* IO window */
+#else
+#if LLC_SRAM
+	/* This entry is prepared for OP-TEE OS that enables the LLC SRAM
+	 * and changes the window target to SRAM_TID.
+	 */
+	{PLAT_MARVELL_LLC_SRAM_BASE, PLAT_MARVELL_LLC_SRAM_SIZE, DRAM_0_TID},
+#endif
+	{0x00000000f2000000,	0xe000000,	IO_0_TID},
+	{0x00000000c0000000,	0x30000000,	IO_0_TID}, /* IO window */
+	{0x0000000800000000,	0x100000000,	IO_0_TID}, /* IO window */
+#endif
+};
+
+uint32_t marvell_get_ccu_gcr_target(int ap)
+{
+	return DRAM_0_TID;
+}
+
+int marvell_get_ccu_memory_map(int ap_index, struct addr_map_win **win,
+			       uint32_t *size)
+{
+	*win = ccu_memory_map;
+	*size = ARRAY_SIZE(ccu_memory_map);
+
+	return 0;
+}
+
+#ifdef IMAGE_BLE
+/*****************************************************************************
+ * SKIP IMAGE Configuration
+ *****************************************************************************
+ */
+#if PLAT_RECOVERY_IMAGE_ENABLE
+void *plat_marvell_get_skip_image_data(void)
+{
+	/* No recovery button on a70x0_mochabin board */
+	return NULL;
+}
+#endif
+#endif
diff --git a/plat/marvell/armada/a8k/a70x0_mochabin/board/phy-porting-layer.h b/plat/marvell/armada/a8k/a70x0_mochabin/board/phy-porting-layer.h
new file mode 100644
index 0000000..ab76c31
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0_mochabin/board/phy-porting-layer.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2021 Sartura Ltd.
+ * Copyright (C) 2021 Globalscale technologies, Inc.
+ * Copyright (C) 2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef __PHY_PORTING_LAYER_H
+#define __PHY_PORTING_LAYER_H
+
+#define MAX_LANE_NR		6
+
+static const struct xfi_params
+	xfi_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
+	/* AP0 */
+	{
+		/* CP 0 */
+		{
+			{ 0 }, /* Comphy0 */
+			{ 0 }, /* Comphy1 */
+			{ 0 }, /* Comphy2 */
+			{ 0 }, /* Comphy3 */
+			{ .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf, .align90 = 0x60,
+			  .g1_dfe_res = 0x1, .g1_amp = 0x1c, .g1_emph = 0xe,
+			  .g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1, .g1_tx_emph_en = 0x1,
+			  .g1_tx_emph = 0x0, .g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0,
+			  .g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2,
+			  .valid = 1 }, /* Comphy4 */
+			{ 0 }, /* Comphy5 */
+		},
+	},
+};
+
+static const struct sata_params
+	sata_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
+	/* AP0 */
+	{
+		/* CP 0 */
+		{
+			{ 0 }, /* Comphy0 */
+			{ 0 }, /* Comphy1 */
+			{ .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e,
+			  .g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe,
+			  .g1_emph_en = 0x1, .g2_emph_en = 0x1, .g3_emph_en = 0x1,
+			  .g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1, .g3_tx_amp_adj = 0x1,
+			  .g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0, .g3_tx_emph_en = 0x0,
+			  .g1_tx_emph = 0x1, .g2_tx_emph = 0x1, .g3_tx_emph = 0x1,
+			  .g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4, .g3_ffe_cap_sel = 0xf,
+			  .align90 = 0x61,
+			  .g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3, .g3_rx_selmuff = 0x3,
+			  .g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0, .g3_rx_selmufi = 0x3,
+			  .g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1, .g3_rx_selmupf = 0x2,
+			  .g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0, .g3_rx_selmupi = 0x2,
+			  .polarity_invert = COMPHY_POLARITY_NO_INVERT,
+			  .valid = 0x1
+			}, /* Comphy2 */
+			{ .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e,
+			  .g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe,
+			  .g1_emph_en = 0x1, .g2_emph_en = 0x1, .g3_emph_en = 0x1,
+			  .g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1, .g3_tx_amp_adj = 0x1,
+			  .g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0, .g3_tx_emph_en = 0x0,
+			  .g1_tx_emph = 0x1, .g2_tx_emph = 0x1, .g3_tx_emph = 0x1,
+			  .g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4, .g3_ffe_cap_sel = 0xf,
+			  .align90 = 0x61,
+			  .g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3, .g3_rx_selmuff = 0x3,
+			  .g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0, .g3_rx_selmufi = 0x3,
+			  .g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1, .g3_rx_selmupf = 0x2,
+			  .g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0, .g3_rx_selmupi = 0x2,
+			  .polarity_invert = COMPHY_POLARITY_NO_INVERT,
+			  .valid = 0x1
+			}, /* Comphy3 */
+			{ 0 }, /* Comphy4 */
+			{ 0 }, /* Comphy5 */
+		},
+	},
+};
+
+static const struct usb_params
+	usb_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = {
+	[0 ... AP_NUM-1][0 ... CP_NUM-1][0 ... MAX_LANE_NR-1] = {
+		.polarity_invert = COMPHY_POLARITY_NO_INVERT
+	},
+};
+
+#endif /* __PHY_PORTING_LAYER_H */
diff --git a/plat/marvell/armada/a8k/a70x0_mochabin/mvebu_def.h b/plat/marvell/armada/a8k/a70x0_mochabin/mvebu_def.h
new file mode 100644
index 0000000..768f735
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0_mochabin/mvebu_def.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2021 Marvell International Ltd.
+ *
+ * SPDX-License-Identifier:     BSD-3-Clause
+ * https://spdx.org/licenses
+ */
+
+#ifndef MVEBU_DEF_H
+#define MVEBU_DEF_H
+
+#include <a8k_plat_def.h>
+
+#define CP_COUNT		1	/* A70x0 has single CP0 */
+
+#endif /* MVEBU_DEF_H */
diff --git a/plat/marvell/armada/a8k/a70x0_mochabin/platform.mk b/plat/marvell/armada/a8k/a70x0_mochabin/platform.mk
new file mode 100644
index 0000000..2495591
--- /dev/null
+++ b/plat/marvell/armada/a8k/a70x0_mochabin/platform.mk
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2021 Marvell International Ltd.
+#
+# SPDX-License-Identifier:     BSD-3-Clause
+# https://spdx.org/licenses
+#
+
+PCI_EP_SUPPORT		:= 0
+
+CP_NUM			:= 1
+$(eval $(call add_define,CP_NUM))
+
+DOIMAGE_SEC     	:=	tools/doimage/secure/sec_img_7K.cfg
+
+MARVELL_MOCHI_DRV	:=	drivers/marvell/mochi/apn806_setup.c
+
+BOARD_DIR		:= $(shell dirname $(lastword $(MAKEFILE_LIST)))
+include plat/marvell/armada/a8k/common/a8k_common.mk
+
+include plat/marvell/armada/common/marvell_common.mk
diff --git a/plat/marvell/armada/a8k/common/a8k_common.mk b/plat/marvell/armada/a8k/common/a8k_common.mk
index 30e6280..4d8a87f 100644
--- a/plat/marvell/armada/a8k/common/a8k_common.mk
+++ b/plat/marvell/armada/a8k/common/a8k_common.mk
@@ -75,6 +75,10 @@
 # This define specifies DDR type for BLE
 $(eval $(call add_define,CONFIG_DDR4))
 
+# This define specifies DDR topology for BLE
+DDR_TOPOLOGY	?= 0
+$(eval $(call add_define,DDR_TOPOLOGY))
+
 MARVELL_GIC_SOURCES	:=	drivers/arm/gic/common/gic_common.c	\
 				drivers/arm/gic/v2/gicv2_main.c		\
 				drivers/arm/gic/v2/gicv2_helpers.c	\
@@ -166,7 +170,7 @@
 BLE_PATH	?=  $(PLAT_COMMON_BASE)/ble
 
 include ${BLE_PATH}/ble.mk
-$(eval $(call MAKE_BL,e))
+$(eval $(call MAKE_BL,ble))
 
 clean realclean distclean: mrvl_clean
 
diff --git a/plat/marvell/armada/a8k/common/ble/ble.mk b/plat/marvell/armada/a8k/common/ble/ble.mk
index 87e2ce0..e41ab3e 100644
--- a/plat/marvell/armada/a8k/common/ble/ble.mk
+++ b/plat/marvell/armada/a8k/common/ble/ble.mk
@@ -28,6 +28,7 @@
 $(BLE_OBJS): $(MV_DDR_LIB)
 
 $(MV_DDR_LIB): FORCE
+	# Do not remove! Following checks are required to ensure correct TF-A builds, removing these checks leads to broken TF-A builds
 	$(if $(value MV_DDR_PATH),,$(error "Platform '$(PLAT)' for BLE requires MV_DDR_PATH. Please set MV_DDR_PATH to point to the right directory"))
 	$(if $(wildcard $(value MV_DDR_PATH)/*),,$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' directory does not exist"))
 	$(if $(shell git -C $(value MV_DDR_PATH) rev-parse --show-cdup 2>&1),$(error "'MV_DDR_PATH=$(value MV_DDR_PATH)' was specified, but '$(value MV_DDR_PATH)' does not contain valid mv-ddr-marvell git repository"))
diff --git a/plat/mediatek/common/mtk_cirq.c b/plat/mediatek/common/mtk_cirq.c
index de37986..9cf7144 100644
--- a/plat/mediatek/common/mtk_cirq.c
+++ b/plat/mediatek/common/mtk_cirq.c
@@ -541,11 +541,9 @@
 
 void mt_cirq_sw_reset(void)
 {
-#ifdef CIRQ_NEED_SW_RESET
 	uint32_t st;
 
 	st = mmio_read_32(CIRQ_CON);
 	st |= (CIRQ_SW_RESET << CIRQ_CON_SW_RST_BITS);
 	mmio_write_32(CIRQ_CON, st);
-#endif
 }
diff --git a/plat/mediatek/mt8183/drivers/sspm/sspm.c b/plat/mediatek/mt8183/drivers/sspm/sspm.c
index 3917638..6e76124 100644
--- a/plat/mediatek/mt8183/drivers/sspm/sspm.c
+++ b/plat/mediatek/mt8183/drivers/sspm/sspm.c
@@ -149,7 +149,7 @@
 
 	while (sspm_ipi_recv_non_blocking(IPI_ID_PLATFORM,
 					  &ipi_data,
-					  sizeof(ipi_data))
+					  sizeof(ipi_data) / sizeof(uint32_t))
 					  && count) {
 		mdelay(100);
 		count--;
diff --git a/plat/mediatek/mt8195/drivers/dfd/plat_dfd.c b/plat/mediatek/mt8195/drivers/dfd/plat_dfd.c
new file mode 100644
index 0000000..c083318
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/dfd/plat_dfd.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <mtk_sip_svc.h>
+#include <plat_dfd.h>
+
+static bool dfd_enabled;
+static uint64_t dfd_base_addr;
+static uint64_t dfd_chain_length;
+static uint64_t dfd_cache_dump;
+
+static void dfd_setup(uint64_t base_addr, uint64_t chain_length,
+		      uint64_t cache_dump)
+{
+	mmio_write_32(MTK_WDT_LATCH_CTL2, MTK_WDT_LATCH_CTL2_VAL);
+	mmio_write_32(MTK_WDT_INTERVAL, MTK_WDT_INTERVAL_VAL);
+	mmio_write_32(MTK_DRM_LATCH_CTL2, MTK_DRM_LATCH_CTL2_VAL);
+	mmio_write_32(MTK_DRM_LATCH_CTL1, MTK_DRM_LATCH_CTL1_VAL);
+
+	/* Bit[2] = 0 (default=1), disable dfd apb bus protect_en */
+	mmio_clrbits_32(DFD_O_INTRF_MCU_PWR_CTL_MASK, 0x1 << 2);
+
+	/* Bit[0] : enable?mcusys_vproc?external_off?dfd?trigger -> 1 */
+	mmio_setbits_32(DFD_V50_GROUP_0_63_DIFF, 0x1);
+
+	/* bit[0]: rg_rw_dfd_internal_dump_en -> 1 */
+	/* bit[2]: rg_rw_dfd_clock_stop_en -> 1 */
+	sync_writel(DFD_INTERNAL_CTL, 0x5);
+
+	/* bit[13]: xreset_b_update_disable */
+	mmio_setbits_32(DFD_INTERNAL_CTL, 0x1 << 13);
+
+	/*
+	 * bit[10:3]: DFD trigger selection mask
+	 * bit[3]: rg_rw_dfd_trigger_sel[0] = 1(enable wdt trigger)
+	 * bit[4]: rg_rw_dfd_trigger_sel[1] = 1(enable HW trigger)
+	 * bit[5]: rg_rw_dfd_trigger_sel[2] = 1(enable SW trigger)
+	 * bit[6]: rg_rw_dfd_trigger_sel[3] = 1(enable SW non-security trigger)
+	 * bit[7]: rg_rw_dfd_trigger_sel[4] = 1(enable timer trigger)
+	 */
+	mmio_setbits_32(DFD_INTERNAL_CTL, 0x1F << 3);
+
+	/*
+	 * bit[9]  : rg_rw_dfd_trigger_sel[6] = 1(cpu_eb_sw_dfd_trigger)
+	 * bit[10] : rg_rw_dfd_trigger_sel[7] = 1(cpu_eb_wdt_dfd_trigger)
+	 */
+	mmio_setbits_32(DFD_INTERNAL_CTL, 0x3 << 9);
+
+	/* bit[20:19]: rg_dfd_armpll_div_mux_sel switch to PLL2 for DFD */
+	mmio_setbits_32(DFD_INTERNAL_CTL, 0x3 << 19);
+
+	/*
+	 * bit[0]: rg_rw_dfd_auto_power_on = 1
+	 * bit[2:1]: rg_rw_dfd_auto_power_on_dely = 1(10us)
+	 * bit[4:2]: rg_rw_dfd_power_on_wait_time = 1(20us)
+	 */
+	mmio_write_32(DFD_INTERNAL_PWR_ON, 0xB);
+
+	/* longest scan chain length */
+	mmio_write_32(DFD_CHAIN_LENGTH0, chain_length);
+
+	/* bit[1:0]: rg_rw_dfd_shift_clock_ratio */
+	mmio_write_32(DFD_INTERNAL_SHIFT_CLK_RATIO, 0x0);
+
+	/* rg_dfd_test_so_over_64 */
+	mmio_write_32(DFD_INTERNAL_TEST_SO_OVER_64, 0x1);
+
+	/* DFD3.0 */
+	mmio_write_32(DFD_TEST_SI_0, 0x0);
+	mmio_write_32(DFD_TEST_SI_1, 0x0);
+	mmio_write_32(DFD_TEST_SI_2, 0x0);
+	mmio_write_32(DFD_TEST_SI_3, 0x0);
+
+	/* for iLDO feature */
+	sync_writel(DFD_POWER_CTL, 0xF9);
+
+	/* read offset */
+	sync_writel(DFD_READ_ADDR, DFD_READ_ADDR_VAL);
+
+	/* for DFD-3.0 setup */
+	sync_writel(DFD_V30_CTL, 0xD);
+
+	/* set base address */
+	mmio_write_32(DFD_O_SET_BASEADDR_REG, base_addr >> 24);
+	mmio_write_32(DFD_O_REG_0, 0);
+
+	/* setup global variables for suspend and resume */
+	dfd_enabled = true;
+	dfd_base_addr = base_addr;
+	dfd_chain_length = chain_length;
+	dfd_cache_dump = cache_dump;
+
+	if ((cache_dump & DFD_CACHE_DUMP_ENABLE) != 0UL) {
+		mmio_write_32(MTK_DRM_LATCH_CTL2, MTK_DRM_LATCH_CTL2_CACHE_VAL);
+		sync_writel(DFD_V35_ENABLE, 0x1);
+		sync_writel(DFD_V35_TAP_NUMBER, 0xB);
+		sync_writel(DFD_V35_TAP_EN, DFD_V35_TAP_EN_VAL);
+		sync_writel(DFD_V35_SEQ0_0, DFD_V35_SEQ0_0_VAL);
+
+		/* Cache dump only mode */
+		sync_writel(DFD_V35_CTL, 0x1);
+		mmio_write_32(DFD_INTERNAL_NUM_OF_TEST_SO_GROUP, 0xF);
+		mmio_write_32(DFD_CHAIN_LENGTH0, DFD_CHAIN_LENGTH_VAL);
+		mmio_write_32(DFD_CHAIN_LENGTH1, DFD_CHAIN_LENGTH_VAL);
+		mmio_write_32(DFD_CHAIN_LENGTH2, DFD_CHAIN_LENGTH_VAL);
+		mmio_write_32(DFD_CHAIN_LENGTH3, DFD_CHAIN_LENGTH_VAL);
+
+		if ((cache_dump & DFD_PARITY_ERR_TRIGGER) != 0UL) {
+			sync_writel(DFD_HW_TRIGGER_MASK, 0xC);
+			mmio_setbits_32(DFD_INTERNAL_CTL, 0x1 << 4);
+		}
+	}
+	dsbsy();
+}
+
+void dfd_resume(void)
+{
+	if (dfd_enabled == true) {
+		dfd_setup(dfd_base_addr, dfd_chain_length, dfd_cache_dump);
+	}
+}
+
+uint64_t dfd_smc_dispatcher(uint64_t arg0, uint64_t arg1,
+			    uint64_t arg2, uint64_t arg3)
+{
+	uint64_t ret = 0L;
+
+	switch (arg0) {
+	case PLAT_MTK_DFD_SETUP_MAGIC:
+		INFO("[%s] DFD setup call from kernel\n", __func__);
+		dfd_setup(arg1, arg2, arg3);
+		break;
+	case PLAT_MTK_DFD_READ_MAGIC:
+		/* only allow to access DFD register base + 0x200 */
+		if (arg1 <= 0x200) {
+			ret = mmio_read_32(MISC1_CFG_BASE + arg1);
+		}
+		break;
+	case PLAT_MTK_DFD_WRITE_MAGIC:
+		/* only allow to access DFD register base + 0x200 */
+		if (arg1 <= 0x200) {
+			sync_writel(MISC1_CFG_BASE + arg1, arg2);
+		}
+		break;
+	default:
+		ret = MTK_SIP_E_INVALID_PARAM;
+		break;
+	}
+
+	return ret;
+}
diff --git a/plat/mediatek/mt8195/drivers/dfd/plat_dfd.h b/plat/mediatek/mt8195/drivers/dfd/plat_dfd.h
new file mode 100644
index 0000000..2a7e979
--- /dev/null
+++ b/plat/mediatek/mt8195/drivers/dfd/plat_dfd.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2021, MediaTek Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DFD_H
+#define PLAT_DFD_H
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+#include <platform_def.h>
+
+#define sync_writel(addr, val)	do { mmio_write_32((addr), (val)); \
+				dsbsy(); \
+				} while (0)
+
+#define PLAT_MTK_DFD_SETUP_MAGIC		(0x99716150)
+#define PLAT_MTK_DFD_READ_MAGIC			(0x99716151)
+#define PLAT_MTK_DFD_WRITE_MAGIC		(0x99716152)
+
+#define MTK_DRM_LATCH_CTL1                      (DRM_BASE + 0x40)
+#define MTK_DRM_LATCH_CTL2			(DRM_BASE + 0x44)
+
+#define MTK_WDT_BASE				(RGU_BASE)
+#define MTK_WDT_INTERVAL			(MTK_WDT_BASE + 0x10)
+#define MTK_WDT_LATCH_CTL2			(MTK_WDT_BASE + 0x48)
+
+#define MCU_BIU_BASE				(MCUCFG_BASE)
+#define MISC1_CFG_BASE				(MCU_BIU_BASE + 0xE040)
+#define DFD_INTERNAL_CTL			(MISC1_CFG_BASE + 0x00)
+#define DFD_INTERNAL_PWR_ON			(MISC1_CFG_BASE + 0x08)
+#define DFD_CHAIN_LENGTH0			(MISC1_CFG_BASE + 0x0C)
+#define DFD_INTERNAL_SHIFT_CLK_RATIO		(MISC1_CFG_BASE + 0x10)
+#define DFD_CHAIN_LENGTH1			(MISC1_CFG_BASE + 0x1C)
+#define DFD_CHAIN_LENGTH2			(MISC1_CFG_BASE + 0x20)
+#define DFD_CHAIN_LENGTH3			(MISC1_CFG_BASE + 0x24)
+#define DFD_INTERNAL_TEST_SO_0			(MISC1_CFG_BASE + 0x28)
+#define DFD_INTERNAL_NUM_OF_TEST_SO_GROUP	(MISC1_CFG_BASE + 0x30)
+#define DFD_INTERNAL_TEST_SO_OVER_64		(MISC1_CFG_BASE + 0x34)
+#define DFD_INTERNAL_SW_NS_TRIGGER		(MISC1_CFG_BASE + 0x3c)
+#define DFD_V30_CTL				(MISC1_CFG_BASE + 0x48)
+#define DFD_V30_BASE_ADDR			(MISC1_CFG_BASE + 0x4C)
+#define DFD_POWER_CTL				(MISC1_CFG_BASE + 0x50)
+#define DFD_TEST_SI_0				(MISC1_CFG_BASE + 0x58)
+#define DFD_TEST_SI_1				(MISC1_CFG_BASE + 0x5C)
+#define DFD_CLEAN_STATUS			(MISC1_CFG_BASE + 0x60)
+#define DFD_TEST_SI_2				(MISC1_CFG_BASE + 0x1D8)
+#define DFD_TEST_SI_3				(MISC1_CFG_BASE + 0x1DC)
+#define DFD_READ_ADDR				(MISC1_CFG_BASE + 0x1E8)
+#define DFD_HW_TRIGGER_MASK			(MISC1_CFG_BASE + 0xBC)
+
+#define DFD_V35_ENABLE				(MCU_BIU_BASE + 0xE0A8)
+#define DFD_V35_TAP_NUMBER			(MCU_BIU_BASE + 0xE0AC)
+#define DFD_V35_TAP_EN				(MCU_BIU_BASE + 0xE0B0)
+#define DFD_V35_CTL				(MCU_BIU_BASE + 0xE0B4)
+#define DFD_V35_SEQ0_0				(MCU_BIU_BASE + 0xE0C0)
+#define DFD_V35_SEQ0_1				(MCU_BIU_BASE + 0xE0C4)
+#define DFD_V50_GROUP_0_63_DIFF			(MCU_BIU_BASE + 0xE2AC)
+
+#define DFD_O_PROTECT_EN_REG			(0x10001220)
+#define DFD_O_INTRF_MCU_PWR_CTL_MASK		(0x10001A3C)
+#define DFD_O_SET_BASEADDR_REG			(0x10043000)
+#define DFD_O_REG_0				(0x10001390)
+
+#define DFD_CACHE_DUMP_ENABLE			1U
+#define DFD_PARITY_ERR_TRIGGER			2U
+
+#define	DFD_V35_TAP_EN_VAL			(0x43FF)
+#define	DFD_V35_SEQ0_0_VAL			(0x63668820)
+#define DFD_READ_ADDR_VAL			(0x40000008)
+#define DFD_CHAIN_LENGTH_VAL			(0xFFFFFFFF)
+
+#define MTK_WDT_LATCH_CTL2_VAL			(0x9507FFFF)
+#define MTK_WDT_INTERVAL_VAL			(0x6600000A)
+#define MTK_DRM_LATCH_CTL2_VAL			(0x950600C8)
+#define MTK_DRM_LATCH_CTL2_CACHE_VAL		(0x95065DC0)
+
+#define MTK_DRM_LATCH_CTL1_VAL			(0x95000013)
+
+void dfd_resume(void);
+uint64_t dfd_smc_dispatcher(uint64_t arg0, uint64_t arg1,
+			    uint64_t arg2, uint64_t arg3);
+
+#endif /* PLAT_DFD_H */
diff --git a/plat/mediatek/mt8195/include/plat_sip_calls.h b/plat/mediatek/mt8195/include/plat_sip_calls.h
index 181aec0..ce25c6f 100644
--- a/plat/mediatek/mt8195/include/plat_sip_calls.h
+++ b/plat/mediatek/mt8195/include/plat_sip_calls.h
@@ -10,7 +10,11 @@
 /*******************************************************************************
  * Plat SiP function constants
  ******************************************************************************/
-#define MTK_PLAT_SIP_NUM_CALLS    2
+#define MTK_PLAT_SIP_NUM_CALLS    4
+
+/* DFD */
+#define MTK_SIP_KERNEL_DFD_AARCH32	0x82000205
+#define MTK_SIP_KERNEL_DFD_AARCH64	0xC2000205
 
 /* DP/eDP */
 #define MTK_SIP_DP_CONTROL_AARCH32	0x82000523
diff --git a/plat/mediatek/mt8195/include/platform_def.h b/plat/mediatek/mt8195/include/platform_def.h
index 44de8eb..68301d6 100644
--- a/plat/mediatek/mt8195/include/platform_def.h
+++ b/plat/mediatek/mt8195/include/platform_def.h
@@ -24,7 +24,9 @@
 #define TOPCKGEN_BASE           (IO_PHYS + 0x00000000)
 #define INFRACFG_AO_BASE        (IO_PHYS + 0x00001000)
 #define SPM_BASE		(IO_PHYS + 0x00006000)
+#define RGU_BASE		(IO_PHYS + 0x00007000)
 #define APMIXEDSYS              (IO_PHYS + 0x0000C000)
+#define DRM_BASE		(IO_PHYS + 0x0000D000)
 #define SSPM_MBOX_BASE          (IO_PHYS + 0x00480000)
 #define PERICFG_AO_BASE         (IO_PHYS + 0x01003000)
 #define VPPSYS0_BASE            (IO_PHYS + 0x04000000)
diff --git a/plat/mediatek/mt8195/plat_pm.c b/plat/mediatek/mt8195/plat_pm.c
index 2beeb02..b77ab27 100644
--- a/plat/mediatek/mt8195/plat_pm.c
+++ b/plat/mediatek/mt8195/plat_pm.c
@@ -17,6 +17,7 @@
 #include <mtk_ptp3_common.h>
 #include <mtspmc.h>
 #include <plat/common/platform.h>
+#include <plat_dfd.h>
 #include <plat_mtk_lpm.h>
 #include <plat_params.h>
 #include <plat_pm.h>
@@ -166,6 +167,8 @@
 	mt_gic_distif_restore();
 	gic_sgi_restore_all();
 
+	dfd_resume();
+
 	plat_mt_pm_invoke_no_check(pwr_mcusys_on_finished, cpu, state);
 }
 
diff --git a/plat/mediatek/mt8195/plat_sip_calls.c b/plat/mediatek/mt8195/plat_sip_calls.c
index ee36898..ddc7502 100644
--- a/plat/mediatek/mt8195/plat_sip_calls.c
+++ b/plat/mediatek/mt8195/plat_sip_calls.c
@@ -10,6 +10,7 @@
 #include <mt_spm.h>
 #include <mt_spm_vcorefs.h>
 #include <mtk_sip_svc.h>
+#include <plat_dfd.h>
 #include "plat_sip_calls.h"
 
 uintptr_t mediatek_plat_sip_handler(uint32_t smc_fid,
@@ -35,6 +36,11 @@
 		ret = spm_vcorefs_v2_args(x1, x2, x3, &x4);
 		SMC_RET2(handle, ret, x4);
 		break;
+	case MTK_SIP_KERNEL_DFD_AARCH32:
+	case MTK_SIP_KERNEL_DFD_AARCH64:
+		ret = dfd_smc_dispatcher(x1, x2, x3, x4);
+		SMC_RET1(handle, ret);
+		break;
 	default:
 		ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
 		break;
diff --git a/plat/mediatek/mt8195/platform.mk b/plat/mediatek/mt8195/platform.mk
index 48a2f72..ef7ff81 100644
--- a/plat/mediatek/mt8195/platform.mk
+++ b/plat/mediatek/mt8195/platform.mk
@@ -15,6 +15,7 @@
                  -I${MTK_PLAT}/common/drivers/uart/               \
                  -I${MTK_PLAT}/common/lpm/                        \
                  -I${MTK_PLAT_SOC}/drivers/dcm                    \
+                 -I${MTK_PLAT_SOC}/drivers/dfd                    \
                  -I${MTK_PLAT_SOC}/drivers/dp/                    \
                  -I${MTK_PLAT_SOC}/drivers/emi_mpu/               \
                  -I${MTK_PLAT_SOC}/drivers/gpio/                  \
@@ -60,6 +61,7 @@
                 ${MTK_PLAT_SOC}/bl31_plat_setup.c                     \
                 ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm.c                 \
                 ${MTK_PLAT_SOC}/drivers/dcm/mtk_dcm_utils.c           \
+                ${MTK_PLAT_SOC}/drivers/dfd/plat_dfd.c                \
                 ${MTK_PLAT_SOC}/drivers/dp/mt_dp.c                    \
                 ${MTK_PLAT_SOC}/drivers/emi_mpu/emi_mpu.c             \
                 ${MTK_PLAT_SOC}/drivers/gpio/mtgpio.c                 \
diff --git a/plat/qemu/common/qemu_pm.c b/plat/qemu/common/qemu_pm.c
index c4ffcf9..c2b5091 100644
--- a/plat/qemu/common/qemu_pm.c
+++ b/plat/qemu/common/qemu_pm.c
@@ -208,8 +208,8 @@
 #ifdef SECURE_GPIO_BASE
 	ERROR("QEMU System Power off: with GPIO.\n");
 	gpio_set_direction(SECURE_GPIO_POWEROFF, GPIO_DIR_OUT);
-	gpio_set_value(SECURE_GPIO_POWEROFF, GPIO_LEVEL_HIGH);
 	gpio_set_value(SECURE_GPIO_POWEROFF, GPIO_LEVEL_LOW);
+	gpio_set_value(SECURE_GPIO_POWEROFF, GPIO_LEVEL_HIGH);
 #else
 	semihosting_exit(ADP_STOPPED_APPLICATION_EXIT, 0);
 	ERROR("QEMU System Off: semihosting call unexpectedly returned.\n");
@@ -222,8 +222,8 @@
 	ERROR("QEMU System Reset: with GPIO.\n");
 #ifdef SECURE_GPIO_BASE
 	gpio_set_direction(SECURE_GPIO_RESET, GPIO_DIR_OUT);
-	gpio_set_value(SECURE_GPIO_RESET, GPIO_LEVEL_HIGH);
 	gpio_set_value(SECURE_GPIO_RESET, GPIO_LEVEL_LOW);
+	gpio_set_value(SECURE_GPIO_RESET, GPIO_LEVEL_HIGH);
 #else
 	ERROR("QEMU System Reset: operation not handled.\n");
 #endif
diff --git a/plat/st/stm32mp1/platform.mk b/plat/st/stm32mp1/platform.mk
index 1c2c9f0..28463f1 100644
--- a/plat/st/stm32mp1/platform.mk
+++ b/plat/st/stm32mp1/platform.mk
@@ -323,7 +323,7 @@
 		-c plat/st/stm32mp1/stm32mp1.S -o $@
 endif
 
-$(eval $(call MAKE_LD,${STM32_TF_LINKERFILE},plat/st/stm32mp1/stm32mp1.ld.S,2))
+$(eval $(call MAKE_LD,${STM32_TF_LINKERFILE},plat/st/stm32mp1/stm32mp1.ld.S,bl2))
 
 tf-a-%.elf: stm32mp1-%.o ${STM32_TF_LINKERFILE}
 	@echo "  LDS     $<"
diff --git a/services/arm_arch_svc/arm_arch_svc_setup.c b/services/arm_arch_svc/arm_arch_svc_setup.c
index 37bfc62..1d4423c 100644
--- a/services/arm_arch_svc/arm_arch_svc_setup.c
+++ b/services/arm_arch_svc/arm_arch_svc_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -11,9 +11,19 @@
 #include <lib/cpus/wa_cve_2018_3639.h>
 #include <lib/smccc.h>
 #include <services/arm_arch_svc.h>
+#include <services/rmi_svc.h>
+#include <services/rmmd_svc.h>
 #include <smccc_helpers.h>
 #include <plat/common/platform.h>
 
+#if ENABLE_RME
+/* Setup Arm architecture Services */
+static int32_t arm_arch_svc_setup(void)
+{
+	return rmmd_setup();
+}
+#endif
+
 static int32_t smccc_version(void)
 {
 	return MAKE_SMCCC_VERSION(SMCCC_MAJOR_VERSION, SMCCC_MINOR_VERSION);
@@ -133,6 +143,16 @@
 		SMC_RET0(handle);
 #endif
 	default:
+#if ENABLE_RME
+		/*
+		 * RMI functions are allocated from the Arch service range. Call
+		 * the RMM dispatcher to handle RMI calls.
+		 */
+		if (is_rmi_fid(smc_fid)) {
+			return rmmd_rmi_handler(smc_fid, x1, x2, x3, x4, cookie,
+						handle, flags);
+		}
+#endif
 		WARN("Unimplemented Arm Architecture Service Call: 0x%x \n",
 			smc_fid);
 		SMC_RET1(handle, SMC_UNK);
@@ -145,6 +165,10 @@
 		OEN_ARM_START,
 		OEN_ARM_END,
 		SMC_TYPE_FAST,
+#if ENABLE_RME
+		arm_arch_svc_setup,
+#else
 		NULL,
+#endif
 		arm_arch_svc_smc_handler
 );
diff --git a/services/std_svc/rmmd/aarch64/rmmd_helpers.S b/services/std_svc/rmmd/aarch64/rmmd_helpers.S
new file mode 100644
index 0000000..6229baf
--- /dev/null
+++ b/services/std_svc/rmmd/aarch64/rmmd_helpers.S
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "../rmmd_private.h"
+#include <asm_macros.S>
+
+	.global rmmd_rmm_enter
+	.global rmmd_rmm_exit
+
+	/* ---------------------------------------------------------------------
+	 * This function is called with SP_EL0 as stack. Here we stash our EL3
+	 * callee-saved registers on to the stack as a part of saving the C
+	 * runtime and enter the secure payload.
+	 * 'x0' contains a pointer to the memory where the address of the C
+	 *  runtime context is to be saved.
+	 * ---------------------------------------------------------------------
+	 */
+func rmmd_rmm_enter
+	/* Make space for the registers that we're going to save */
+	mov	x3, sp
+	str	x3, [x0, #0]
+	sub	sp, sp, #RMMD_C_RT_CTX_SIZE
+
+	/* Save callee-saved registers on to the stack */
+	stp	x19, x20, [sp, #RMMD_C_RT_CTX_X19]
+	stp	x21, x22, [sp, #RMMD_C_RT_CTX_X21]
+	stp	x23, x24, [sp, #RMMD_C_RT_CTX_X23]
+	stp	x25, x26, [sp, #RMMD_C_RT_CTX_X25]
+	stp	x27, x28, [sp, #RMMD_C_RT_CTX_X27]
+	stp	x29, x30, [sp, #RMMD_C_RT_CTX_X29]
+
+	/* ---------------------------------------------------------------------
+	 * Everything is setup now. el3_exit() will use the secure context to
+	 * restore to the general purpose and EL3 system registers to ERET
+	 * into the secure payload.
+	 * ---------------------------------------------------------------------
+	 */
+	b	el3_exit
+endfunc rmmd_rmm_enter
+
+	/* ---------------------------------------------------------------------
+	 * This function is called with 'x0' pointing to a C runtime context.
+	 * It restores the saved registers and jumps to that runtime with 'x0'
+	 * as the new SP register. This destroys the C runtime context that had
+	 * been built on the stack below the saved context by the caller. Later
+	 * the second parameter 'x1' is passed as a return value to the caller.
+	 * ---------------------------------------------------------------------
+	 */
+func rmmd_rmm_exit
+	/* Restore the previous stack */
+	mov	sp, x0
+
+	/* Restore callee-saved registers on to the stack */
+	ldp	x19, x20, [x0, #(RMMD_C_RT_CTX_X19 - RMMD_C_RT_CTX_SIZE)]
+	ldp	x21, x22, [x0, #(RMMD_C_RT_CTX_X21 - RMMD_C_RT_CTX_SIZE)]
+	ldp	x23, x24, [x0, #(RMMD_C_RT_CTX_X23 - RMMD_C_RT_CTX_SIZE)]
+	ldp	x25, x26, [x0, #(RMMD_C_RT_CTX_X25 - RMMD_C_RT_CTX_SIZE)]
+	ldp	x27, x28, [x0, #(RMMD_C_RT_CTX_X27 - RMMD_C_RT_CTX_SIZE)]
+	ldp	x29, x30, [x0, #(RMMD_C_RT_CTX_X29 - RMMD_C_RT_CTX_SIZE)]
+
+	/* ---------------------------------------------------------------------
+	 * This should take us back to the instruction after the call to the
+	 * last rmmd_rmm_enter().* Place the second parameter to x0
+	 * so that the caller will see it as a return value from the original
+	 * entry call.
+	 * ---------------------------------------------------------------------
+	 */
+	mov	x0, x1
+	ret
+endfunc rmmd_rmm_exit
diff --git a/services/std_svc/rmmd/rmmd.mk b/services/std_svc/rmmd/rmmd.mk
new file mode 100644
index 0000000..bac0a9f
--- /dev/null
+++ b/services/std_svc/rmmd/rmmd.mk
@@ -0,0 +1,18 @@
+#
+# Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+ifneq (${ARCH},aarch64)
+        $(error "Error: RMMD is only supported on aarch64.")
+endif
+
+include services/std_svc/rmmd/trp/trp.mk
+
+RMMD_SOURCES	+=	$(addprefix services/std_svc/rmmd/,	\
+			${ARCH}/rmmd_helpers.S			\
+			rmmd_main.c)
+
+# Let the top-level Makefile know that we intend to include RMM image
+NEED_RMM	:=	yes
diff --git a/services/std_svc/rmmd/rmmd_initial_context.h b/services/std_svc/rmmd/rmmd_initial_context.h
new file mode 100644
index 0000000..d7a743d
--- /dev/null
+++ b/services/std_svc/rmmd/rmmd_initial_context.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RMMD_INITIAL_CONTEXT_H
+#define RMMD_INITIAL_CONTEXT_H
+
+#include <arch.h>
+
+/*
+ * SPSR_EL2
+ *   M=0x9 (0b1001 EL2h)
+ *   M[4]=0
+ *   DAIF=0xF Exceptions masked on entry.
+ *   BTYPE=0  BTI not yet supported.
+ *   SSBS=0   Not yet supported.
+ *   IL=0     Not an illegal exception return.
+ *   SS=0     Not single stepping.
+ *   PAN=1    RMM shouldn't access realm memory.
+ *   UAO=0
+ *   DIT=0
+ *   TCO=0
+ *   NZCV=0
+ */
+#define REALM_SPSR_EL2		(					\
+					SPSR_M_EL2H			| \
+					(0xF << SPSR_DAIF_SHIFT)	| \
+					SPSR_PAN_BIT			\
+				)
+
+#endif /* RMMD_INITIAL_CONTEXT_H */
diff --git a/services/std_svc/rmmd/rmmd_main.c b/services/std_svc/rmmd/rmmd_main.c
new file mode 100644
index 0000000..dacd150
--- /dev/null
+++ b/services/std_svc/rmmd/rmmd_main.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <arch_features.h>
+#include <bl31/bl31.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <context.h>
+#include <lib/el3_runtime/context_mgmt.h>
+#include <lib/el3_runtime/pubsub.h>
+#include <lib/gpt_rme/gpt_rme.h>
+
+#include <lib/spinlock.h>
+#include <lib/utils.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/common_def.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <services/gtsi_svc.h>
+#include <services/rmi_svc.h>
+#include <services/rmmd_svc.h>
+#include <smccc_helpers.h>
+#include "rmmd_initial_context.h"
+#include "rmmd_private.h"
+
+/*******************************************************************************
+ * RMM context information.
+ ******************************************************************************/
+rmmd_rmm_context_t rmm_context[PLATFORM_CORE_COUNT];
+
+/*******************************************************************************
+ * RMM entry point information. Discovered on the primary core and reused
+ * on secondary cores.
+ ******************************************************************************/
+static entry_point_info_t *rmm_ep_info;
+
+/*******************************************************************************
+ * Static function declaration.
+ ******************************************************************************/
+static int32_t rmm_init(void);
+static uint64_t rmmd_smc_forward(uint32_t smc_fid, uint32_t src_sec_state,
+					uint32_t dst_sec_state, uint64_t x1,
+					uint64_t x2, uint64_t x3, uint64_t x4,
+					void *handle);
+
+/*******************************************************************************
+ * This function takes an RMM context pointer and performs a synchronous entry
+ * into it.
+ ******************************************************************************/
+uint64_t rmmd_rmm_sync_entry(rmmd_rmm_context_t *rmm_ctx)
+{
+	uint64_t rc;
+
+	assert(rmm_ctx != NULL);
+
+	cm_set_context(&(rmm_ctx->cpu_ctx), REALM);
+
+	/* Save the current el1/el2 context before loading realm context. */
+	cm_el1_sysregs_context_save(NON_SECURE);
+	cm_el2_sysregs_context_save(NON_SECURE);
+
+	/* Restore the realm context assigned above */
+	cm_el1_sysregs_context_restore(REALM);
+	cm_el2_sysregs_context_restore(REALM);
+	cm_set_next_eret_context(REALM);
+
+	/* Enter RMM */
+	rc = rmmd_rmm_enter(&rmm_ctx->c_rt_ctx);
+
+	/* Save realm context */
+	cm_el1_sysregs_context_save(REALM);
+	cm_el2_sysregs_context_save(REALM);
+
+	/* Restore the el1/el2 context again. */
+	cm_el1_sysregs_context_restore(NON_SECURE);
+	cm_el2_sysregs_context_restore(NON_SECURE);
+
+	return rc;
+}
+
+/*******************************************************************************
+ * This function returns to the place where rmmd_rmm_sync_entry() was
+ * called originally.
+ ******************************************************************************/
+__dead2 void rmmd_rmm_sync_exit(uint64_t rc)
+{
+	rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()];
+
+	/* Get context of the RMM in use by this CPU. */
+	assert(cm_get_context(REALM) == &(ctx->cpu_ctx));
+
+	/*
+	 * The RMMD must have initiated the original request through a
+	 * synchronous entry into RMM. Jump back to the original C runtime
+	 * context with the value of rc in x0;
+	 */
+	rmmd_rmm_exit(ctx->c_rt_ctx, rc);
+
+	panic();
+}
+
+static void rmm_el2_context_init(el2_sysregs_t *regs)
+{
+	regs->ctx_regs[CTX_SPSR_EL2 >> 3] = REALM_SPSR_EL2;
+	regs->ctx_regs[CTX_SCTLR_EL2 >> 3] = SCTLR_EL2_RES1;
+}
+
+/*******************************************************************************
+ * Jump to the RMM for the first time.
+ ******************************************************************************/
+static int32_t rmm_init(void)
+{
+
+	uint64_t rc;
+
+	rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()];
+
+	INFO("RMM init start.\n");
+	ctx->state = RMM_STATE_RESET;
+
+	/* Initialize RMM EL2 context. */
+	rmm_el2_context_init(&ctx->cpu_ctx.el2_sysregs_ctx);
+
+	rc = rmmd_rmm_sync_entry(ctx);
+	if (rc != 0ULL) {
+		ERROR("RMM initialisation failed 0x%llx\n", rc);
+		panic();
+	}
+
+	ctx->state = RMM_STATE_IDLE;
+	INFO("RMM init end.\n");
+
+	return 1;
+}
+
+/*******************************************************************************
+ * Load and read RMM manifest, setup RMM.
+ ******************************************************************************/
+int rmmd_setup(void)
+{
+	uint32_t ep_attr;
+	unsigned int linear_id = plat_my_core_pos();
+	rmmd_rmm_context_t *rmm_ctx = &rmm_context[linear_id];
+
+	/* Make sure RME is supported. */
+	assert(get_armv9_2_feat_rme_support() != 0U);
+
+	rmm_ep_info = bl31_plat_get_next_image_ep_info(REALM);
+	if (rmm_ep_info == NULL) {
+		WARN("No RMM image provided by BL2 boot loader, Booting "
+		     "device without RMM initialization. SMCs destined for "
+		     "RMM will return SMC_UNK\n");
+		return -ENOENT;
+	}
+
+	/* Under no circumstances will this parameter be 0 */
+	assert(rmm_ep_info->pc == RMM_BASE);
+
+	/* Initialise an entrypoint to set up the CPU context */
+	ep_attr = EP_REALM;
+	if ((read_sctlr_el3() & SCTLR_EE_BIT) != 0U) {
+		ep_attr |= EP_EE_BIG;
+	}
+
+	SET_PARAM_HEAD(rmm_ep_info, PARAM_EP, VERSION_1, ep_attr);
+	rmm_ep_info->spsr = SPSR_64(MODE_EL2,
+					MODE_SP_ELX,
+					DISABLE_ALL_EXCEPTIONS);
+
+	/* Initialise RMM context with this entry point information */
+	cm_setup_context(&rmm_ctx->cpu_ctx, rmm_ep_info);
+
+	INFO("RMM setup done.\n");
+
+	/* Register init function for deferred init.  */
+	bl31_register_rmm_init(&rmm_init);
+
+	return 0;
+}
+
+/*******************************************************************************
+ * Forward SMC to the other security state
+ ******************************************************************************/
+static uint64_t	rmmd_smc_forward(uint32_t smc_fid, uint32_t src_sec_state,
+					uint32_t dst_sec_state, uint64_t x1,
+					uint64_t x2, uint64_t x3, uint64_t x4,
+					void *handle)
+{
+	/* Save incoming security state */
+	cm_el1_sysregs_context_save(src_sec_state);
+	cm_el2_sysregs_context_save(src_sec_state);
+
+	/* Restore outgoing security state */
+	cm_el1_sysregs_context_restore(dst_sec_state);
+	cm_el2_sysregs_context_restore(dst_sec_state);
+	cm_set_next_eret_context(dst_sec_state);
+
+	SMC_RET8(cm_get_context(dst_sec_state), smc_fid, x1, x2, x3, x4,
+			SMC_GET_GP(handle, CTX_GPREG_X5),
+			SMC_GET_GP(handle, CTX_GPREG_X6),
+			SMC_GET_GP(handle, CTX_GPREG_X7));
+}
+
+/*******************************************************************************
+ * This function handles all SMCs in the range reserved for RMI. Each call is
+ * either forwarded to the other security state or handled by the RMM dispatcher
+ ******************************************************************************/
+uint64_t rmmd_rmi_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
+				uint64_t x3, uint64_t x4, void *cookie,
+				void *handle, uint64_t flags)
+{
+	rmmd_rmm_context_t *ctx = &rmm_context[plat_my_core_pos()];
+	uint32_t src_sec_state;
+
+	/* Determine which security state this SMC originated from */
+	src_sec_state = caller_sec_state(flags);
+
+	/* RMI must not be invoked by the Secure world */
+	if (src_sec_state == SMC_FROM_SECURE) {
+		WARN("RMM: RMI invoked by secure world.\n");
+		SMC_RET1(handle, SMC_UNK);
+	}
+
+	/*
+	 * Forward an RMI call from the Normal world to the Realm world as it
+	 * is.
+	 */
+	if (src_sec_state == SMC_FROM_NON_SECURE) {
+		VERBOSE("RMM: RMI call from non-secure world.\n");
+		return rmmd_smc_forward(smc_fid, NON_SECURE, REALM,
+					x1, x2, x3, x4, handle);
+	}
+
+	assert(src_sec_state == SMC_FROM_REALM);
+
+	switch (smc_fid) {
+	case RMI_RMM_REQ_COMPLETE:
+		if (ctx->state == RMM_STATE_RESET) {
+			VERBOSE("RMM: running rmmd_rmm_sync_exit\n");
+			rmmd_rmm_sync_exit(x1);
+		}
+
+		return rmmd_smc_forward(x1, REALM, NON_SECURE,
+					x2, x3, x4, 0, handle);
+
+	default:
+		WARN("RMM: Unsupported RMM call 0x%08x\n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
+
+/*******************************************************************************
+ * This cpu has been turned on. Enter RMM to initialise R-EL2.  Entry into RMM
+ * is done after initialising minimal architectural state that guarantees safe
+ * execution.
+ ******************************************************************************/
+static void *rmmd_cpu_on_finish_handler(const void *arg)
+{
+	int32_t rc;
+	uint32_t linear_id = plat_my_core_pos();
+	rmmd_rmm_context_t *ctx = &rmm_context[linear_id];
+
+	ctx->state = RMM_STATE_RESET;
+
+	/* Initialise RMM context with this entry point information */
+	cm_setup_context(&ctx->cpu_ctx, rmm_ep_info);
+
+	/* Initialize RMM EL2 context. */
+	rmm_el2_context_init(&ctx->cpu_ctx.el2_sysregs_ctx);
+
+	rc = rmmd_rmm_sync_entry(ctx);
+	if (rc != 0) {
+		ERROR("RMM initialisation failed (%d) on CPU%d\n", rc,
+		      linear_id);
+		panic();
+	}
+
+	ctx->state = RMM_STATE_IDLE;
+	return NULL;
+}
+
+/* Subscribe to PSCI CPU on to initialize RMM on secondary */
+SUBSCRIBE_TO_EVENT(psci_cpu_on_finish, rmmd_cpu_on_finish_handler);
+
+static int gtsi_transition_granule(uint64_t pa,
+					unsigned int src_sec_state,
+					unsigned int target_pas)
+{
+	int ret;
+
+	ret = gpt_transition_pas(pa, PAGE_SIZE_4KB, src_sec_state, target_pas);
+
+	/* Convert TF-A error codes into GTSI error codes */
+	if (ret == -EINVAL) {
+		ERROR("[GTSI] Transition failed: invalid %s\n", "address");
+		ERROR("       PA: 0x%llx, SRC: %d, PAS: %d\n", pa,
+		      src_sec_state, target_pas);
+		ret = GRAN_TRANS_RET_BAD_ADDR;
+	} else if (ret == -EPERM) {
+		ERROR("[GTSI] Transition failed: invalid %s\n", "caller/PAS");
+		ERROR("       PA: 0x%llx, SRC: %d, PAS: %d\n", pa,
+		      src_sec_state, target_pas);
+		ret = GRAN_TRANS_RET_BAD_PAS;
+	}
+
+	return ret;
+}
+
+/*******************************************************************************
+ * This function handles all SMCs in the range reserved for GTF.
+ ******************************************************************************/
+uint64_t rmmd_gtsi_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
+				uint64_t x3, uint64_t x4, void *cookie,
+				void *handle, uint64_t flags)
+{
+	uint32_t src_sec_state;
+
+	/* Determine which security state this SMC originated from */
+	src_sec_state = caller_sec_state(flags);
+
+	if (src_sec_state != SMC_FROM_REALM) {
+		WARN("RMM: GTF call originated from secure or normal world\n");
+		SMC_RET1(handle, SMC_UNK);
+	}
+
+	switch (smc_fid) {
+	case SMC_ASC_MARK_REALM:
+		SMC_RET1(handle, gtsi_transition_granule(x1, SMC_FROM_REALM,
+								GPT_GPI_REALM));
+	case SMC_ASC_MARK_NONSECURE:
+		SMC_RET1(handle, gtsi_transition_granule(x1, SMC_FROM_REALM,
+								GPT_GPI_NS));
+	default:
+		WARN("RMM: Unsupported GTF call 0x%08x\n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
diff --git a/services/std_svc/rmmd/rmmd_private.h b/services/std_svc/rmmd/rmmd_private.h
new file mode 100644
index 0000000..d170bcd
--- /dev/null
+++ b/services/std_svc/rmmd/rmmd_private.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RMMD_PRIVATE_H
+#define RMMD_PRIVATE_H
+
+#include <context.h>
+
+/*******************************************************************************
+ * Constants that allow assembler code to preserve callee-saved registers of the
+ * C runtime context while performing a security state switch.
+ ******************************************************************************/
+#define RMMD_C_RT_CTX_X19		0x0
+#define RMMD_C_RT_CTX_X20		0x8
+#define RMMD_C_RT_CTX_X21		0x10
+#define RMMD_C_RT_CTX_X22		0x18
+#define RMMD_C_RT_CTX_X23		0x20
+#define RMMD_C_RT_CTX_X24		0x28
+#define RMMD_C_RT_CTX_X25		0x30
+#define RMMD_C_RT_CTX_X26		0x38
+#define RMMD_C_RT_CTX_X27		0x40
+#define RMMD_C_RT_CTX_X28		0x48
+#define RMMD_C_RT_CTX_X29		0x50
+#define RMMD_C_RT_CTX_X30		0x58
+
+#define RMMD_C_RT_CTX_SIZE		0x60
+#define RMMD_C_RT_CTX_ENTRIES		(RMMD_C_RT_CTX_SIZE >> DWORD_SHIFT)
+
+#ifndef __ASSEMBLER__
+#include <stdint.h>
+#include <services/rmi_svc.h>
+
+typedef enum rmm_state {
+	RMM_STATE_RESET = 0,
+	RMM_STATE_IDLE
+} rmm_state_t;
+
+/*
+ * Data structure used by the RMM dispatcher (RMMD) in EL3 to track context of
+ * the RMM at R-EL2.
+ */
+typedef struct rmmd_rmm_context {
+	uint64_t c_rt_ctx;
+	cpu_context_t cpu_ctx;
+	rmm_state_t state;
+} rmmd_rmm_context_t;
+
+/* Functions used to enter/exit the RMM synchronously */
+uint64_t rmmd_rmm_sync_entry(rmmd_rmm_context_t *ctx);
+__dead2 void rmmd_rmm_sync_exit(uint64_t rc);
+
+/* Assembly helpers */
+uint64_t rmmd_rmm_enter(uint64_t *c_rt_ctx);
+void __dead2 rmmd_rmm_exit(uint64_t c_rt_ctx, uint64_t ret);
+
+/* Reference to PM ops for the RMMD */
+extern const spd_pm_ops_t rmmd_pm;
+
+#endif /* __ASSEMBLER__ */
+
+#endif /* RMMD_PRIVATE_H */
diff --git a/services/std_svc/rmmd/trp/linker.lds b/services/std_svc/rmmd/trp/linker.lds
new file mode 100644
index 0000000..2b7f383
--- /dev/null
+++ b/services/std_svc/rmmd/trp/linker.lds
@@ -0,0 +1,71 @@
+/*
+ * (C) COPYRIGHT 2021 Arm Limited or its affiliates.
+ * ALL RIGHTS RESERVED
+ */
+
+#include <common/bl_common.ld.h>
+#include <lib/xlat_tables/xlat_tables_defs.h>
+
+/* Mapped using 4K pages, requires us to align different sections with
+ * different property at the same granularity. */
+PAGE_SIZE_4K = 4096;
+
+OUTPUT_FORMAT("elf64-littleaarch64")
+OUTPUT_ARCH(aarch64)
+ENTRY(trp_head)
+
+MEMORY {
+	RAM (rwx): ORIGIN = RMM_BASE, LENGTH = RMM_LIMIT - RMM_BASE
+}
+
+
+SECTIONS
+{
+	. = RMM_BASE;
+
+	.text : {
+		*(.head.text)
+		. = ALIGN(8);
+		*(.text*)
+	} >RAM
+
+	. = ALIGN(PAGE_SIZE_4K);
+
+	.rodata : {
+		*(.rodata*)
+	} >RAM
+
+	. = ALIGN(PAGE_SIZE_4K);
+
+	 __RW_START__ = . ;
+
+	.data : {
+		*(.data*)
+	} >RAM
+
+	.bss (NOLOAD) : {
+		__BSS_START__ = .;
+		*(.bss*)
+		__BSS_END__ = .;
+	} >RAM
+	__BSS_SIZE__ = SIZEOF(.bss);
+
+
+	STACK_SECTION >RAM
+
+
+	/*
+	* Define a linker symbol to mark the end of the RW memory area for this
+	* image.
+	*/
+	__RW_END__ = .;
+	__RMM_END__ = .;
+
+
+	/DISCARD/ : { *(.dynstr*) }
+	/DISCARD/ : { *(.dynamic*) }
+	/DISCARD/ : { *(.plt*) }
+	/DISCARD/ : { *(.interp*) }
+	/DISCARD/ : { *(.gnu*) }
+	/DISCARD/ : { *(.note*) }
+}
diff --git a/services/std_svc/rmmd/trp/trp.mk b/services/std_svc/rmmd/trp/trp.mk
new file mode 100644
index 0000000..a4f6e03
--- /dev/null
+++ b/services/std_svc/rmmd/trp/trp.mk
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2021 Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+RMM_SOURCES		+=	services/std_svc/rmmd/trp/trp_entry.S	\
+				services/std_svc/rmmd/trp/trp_main.c
+
+RMM_LINKERFILE		:=	services/std_svc/rmmd/trp/linker.lds
+
+# Include the platform-specific TRP Makefile
+# If no platform-specific TRP Makefile exists, it means TRP is not supported
+# on this platform.
+TRP_PLAT_MAKEFILE := $(wildcard ${PLAT_DIR}/trp/trp-${PLAT}.mk)
+ifeq (,${TRP_PLAT_MAKEFILE})
+  $(error TRP is not supported on platform ${PLAT})
+else
+  include ${TRP_PLAT_MAKEFILE}
+endif
diff --git a/services/std_svc/rmmd/trp/trp_entry.S b/services/std_svc/rmmd/trp/trp_entry.S
new file mode 100644
index 0000000..23b48fb
--- /dev/null
+++ b/services/std_svc/rmmd/trp/trp_entry.S
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2021, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <services/gtsi_svc.h>
+#include <services/rmi_svc.h>
+#include "trp_private.h"
+
+.global trp_head
+.global trp_smc
+
+.section ".head.text", "ax"
+
+	/* ---------------------------------------------
+	 * Populate the params in x0-x7 from the pointer
+	 * to the smc args structure in x0.
+	 * ---------------------------------------------
+	 */
+	.macro restore_args_call_smc
+	ldp	x6, x7, [x0, #TRP_ARG6]
+	ldp	x4, x5, [x0, #TRP_ARG4]
+	ldp	x2, x3, [x0, #TRP_ARG2]
+	ldp	x0, x1, [x0, #TRP_ARG0]
+	smc	#0
+	.endm
+
+	/* ---------------------------------------------
+	 * Entry point for TRP
+	 * ---------------------------------------------
+	 */
+trp_head:
+	bl	plat_set_my_stack
+	bl	plat_is_my_cpu_primary
+	cbz	x0, trp_secondary_cpu_entry
+
+	/* ---------------------------------------------
+	 * Zero out BSS section
+	 * ---------------------------------------------
+	 */
+	ldr	x0, =__BSS_START__
+	ldr	x1, =__BSS_SIZE__
+	bl	zeromem
+
+	bl	trp_setup
+
+	bl	trp_main
+trp_secondary_cpu_entry:
+	mov_imm	x0, RMI_RMM_REQ_COMPLETE
+	mov	x1, xzr
+	smc	#0
+	b	trp_handler
+
+	/* ---------------------------------------------
+	 *   Direct SMC call to BL31 service provided by
+	 *   RMM Dispatcher
+	 * ---------------------------------------------
+	 */
+func trp_smc
+	restore_args_call_smc
+	ret
+endfunc trp_smc
+
+	/* ---------------------------------------------
+	 * RMI call handler
+	 * ---------------------------------------------
+	 */
+func trp_handler
+	bl	trp_rmi_handler
+	restore_args_call_smc
+	b	trp_handler
+endfunc trp_handler
diff --git a/services/std_svc/rmmd/trp/trp_main.c b/services/std_svc/rmmd/trp/trp_main.c
new file mode 100644
index 0000000..2ab9ecc
--- /dev/null
+++ b/services/std_svc/rmmd/trp/trp_main.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+#include <services/gtsi_svc.h>
+#include <services/rmi_svc.h>
+#include <services/trp/platform_trp.h>
+
+#include <platform_def.h>
+#include "trp_private.h"
+
+/*******************************************************************************
+ * Per cpu data structure to populate parameters for an SMC in C code and use
+ * a pointer to this structure in assembler code to populate x0-x7
+ ******************************************************************************/
+static trp_args_t trp_smc_args[PLATFORM_CORE_COUNT];
+
+/*******************************************************************************
+ * Set the arguments for SMC call
+ ******************************************************************************/
+static trp_args_t *set_smc_args(uint64_t arg0,
+				uint64_t arg1,
+				uint64_t arg2,
+				uint64_t arg3,
+				uint64_t arg4,
+				uint64_t arg5,
+				uint64_t arg6,
+				uint64_t arg7)
+{
+	uint32_t linear_id;
+	trp_args_t *pcpu_smc_args;
+
+	/*
+	 * Return to Secure Monitor by raising an SMC. The results of the
+	 * service are passed as an arguments to the SMC
+	 */
+	linear_id = plat_my_core_pos();
+	pcpu_smc_args = &trp_smc_args[linear_id];
+	write_trp_arg(pcpu_smc_args, TRP_ARG0, arg0);
+	write_trp_arg(pcpu_smc_args, TRP_ARG1, arg1);
+	write_trp_arg(pcpu_smc_args, TRP_ARG2, arg2);
+	write_trp_arg(pcpu_smc_args, TRP_ARG3, arg3);
+	write_trp_arg(pcpu_smc_args, TRP_ARG4, arg4);
+	write_trp_arg(pcpu_smc_args, TRP_ARG5, arg5);
+	write_trp_arg(pcpu_smc_args, TRP_ARG6, arg6);
+	write_trp_arg(pcpu_smc_args, TRP_ARG7, arg7);
+
+	return pcpu_smc_args;
+}
+
+/*******************************************************************************
+ * Setup function for TRP.
+ ******************************************************************************/
+void trp_setup(void)
+{
+	/* Perform early platform-specific setup */
+	trp_early_platform_setup();
+}
+
+/* Main function for TRP */
+void trp_main(void)
+{
+	NOTICE("TRP: %s\n", version_string);
+	NOTICE("TRP: %s\n", build_message);
+	INFO("TRP: Memory base : 0x%lx\n", (unsigned long)RMM_BASE);
+	INFO("TRP: Total size : 0x%lx bytes\n", (unsigned long)(RMM_END
+								- RMM_BASE));
+}
+
+/*******************************************************************************
+ * Returning RMI version back to Normal World
+ ******************************************************************************/
+static trp_args_t *trp_ret_rmi_version(void)
+{
+	VERBOSE("RMM version is %u.%u\n", RMI_ABI_VERSION_MAJOR,
+					  RMI_ABI_VERSION_MINOR);
+	return set_smc_args(RMI_RMM_REQ_COMPLETE, RMI_ABI_VERSION,
+			    0, 0, 0, 0, 0, 0);
+}
+
+/*******************************************************************************
+ * Transitioning granule of NON-SECURE type to REALM type
+ ******************************************************************************/
+static trp_args_t *trp_asc_mark_realm(unsigned long long x1)
+{
+	unsigned long long ret;
+
+	VERBOSE("Delegating granule 0x%llx\n", x1);
+	ret = trp_smc(set_smc_args(SMC_ASC_MARK_REALM, x1, 0, 0, 0, 0, 0, 0));
+
+	if (ret != 0ULL) {
+		ERROR("Granule transition from NON-SECURE type to REALM type "
+			"failed 0x%llx\n", ret);
+	}
+	return set_smc_args(RMI_RMM_REQ_COMPLETE, ret, 0, 0, 0, 0, 0, 0);
+}
+
+/*******************************************************************************
+ * Transitioning granule of REALM type to NON-SECURE type
+ ******************************************************************************/
+static trp_args_t *trp_asc_mark_nonsecure(unsigned long long x1)
+{
+	unsigned long long ret;
+
+	VERBOSE("Undelegating granule 0x%llx\n", x1);
+	ret = trp_smc(set_smc_args(SMC_ASC_MARK_NONSECURE, x1, 0, 0, 0, 0, 0, 0));
+
+	if (ret != 0ULL) {
+		ERROR("Granule transition from REALM type to NON-SECURE type "
+			"failed 0x%llx\n", ret);
+	}
+	return set_smc_args(RMI_RMM_REQ_COMPLETE, ret, 0, 0, 0, 0, 0, 0);
+}
+
+/*******************************************************************************
+ * Main RMI SMC handler function
+ ******************************************************************************/
+trp_args_t *trp_rmi_handler(unsigned long fid, unsigned long long x1)
+{
+	switch (fid) {
+	case RMI_RMM_REQ_VERSION:
+		return trp_ret_rmi_version();
+	case RMI_RMM_GRANULE_DELEGATE:
+		return trp_asc_mark_realm(x1);
+	case RMI_RMM_GRANULE_UNDELEGATE:
+		return trp_asc_mark_nonsecure(x1);
+	default:
+		ERROR("Invalid SMC code to %s, FID %lu\n", __func__, fid);
+	}
+	return set_smc_args(SMC_UNK, 0, 0, 0, 0, 0, 0, 0);
+}
diff --git a/services/std_svc/rmmd/trp/trp_private.h b/services/std_svc/rmmd/trp/trp_private.h
new file mode 100644
index 0000000..9231390
--- /dev/null
+++ b/services/std_svc/rmmd/trp/trp_private.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef TRP_PRIVATE_H
+#define TRP_PRIVATE_H
+
+/* Definitions to help the assembler access the SMC/ERET args structure */
+#define TRP_ARGS_SIZE		TRP_ARGS_END
+#define TRP_ARG0		0x0
+#define TRP_ARG1		0x8
+#define TRP_ARG2		0x10
+#define TRP_ARG3		0x18
+#define TRP_ARG4		0x20
+#define TRP_ARG5		0x28
+#define TRP_ARG6		0x30
+#define TRP_ARG7		0x38
+#define TRP_ARGS_END		0x40
+
+#ifndef __ASSEMBLER__
+
+#include <stdint.h>
+
+/* Data structure to hold SMC arguments */
+typedef struct trp_args {
+	uint64_t regs[TRP_ARGS_END >> 3];
+} __aligned(CACHE_WRITEBACK_GRANULE) trp_args_t;
+
+#define write_trp_arg(args, offset, val) (((args)->regs[offset >> 3])	\
+					 = val)
+
+/* Definitions for RMI VERSION */
+#define RMI_ABI_VERSION_MAJOR		U(0x0)
+#define RMI_ABI_VERSION_MINOR		U(0x0)
+#define RMI_ABI_VERSION			((RMI_ABI_VERSION_MAJOR << 16) | \
+					RMI_ABI_VERSION_MINOR)
+
+/* Helper to issue SMC calls to BL31 */
+uint64_t trp_smc(trp_args_t *);
+
+/* The main function to executed only by Primary CPU */
+void trp_main(void);
+
+/* Setup TRP. Executed only by Primary CPU */
+void trp_setup(void);
+
+#endif /* __ASSEMBLER__ */
+#endif /* TRP_PRIVATE_H */
diff --git a/services/std_svc/std_svc_setup.c b/services/std_svc/std_svc_setup.c
index 1917d0a..39db429 100644
--- a/services/std_svc/std_svc_setup.c
+++ b/services/std_svc/std_svc_setup.c
@@ -13,7 +13,9 @@
 #include <lib/pmf/pmf.h>
 #include <lib/psci/psci.h>
 #include <lib/runtime_instr.h>
+#include <services/gtsi_svc.h>
 #include <services/pci_svc.h>
+#include <services/rmmd_svc.h>
 #include <services/sdei.h>
 #include <services/spm_mm_svc.h>
 #include <services/spmd_svc.h>
@@ -158,6 +160,16 @@
 				flags);
 	}
 #endif
+#if ENABLE_RME
+	/*
+	 * Granule transition service interface functions (GTSI) are allocated
+	 * from the Std service range. Call the RMM dispatcher to handle calls.
+	 */
+	if (is_gtsi_fid(smc_fid)) {
+		return rmmd_gtsi_handler(smc_fid, x1, x2, x3, x4, cookie,
+						handle, flags);
+	}
+#endif
 
 #if SMC_PCI_SUPPORT
 	if (is_pci_fid(smc_fid)) {
diff --git a/tools/fiptool/tbbr_config.c b/tools/fiptool/tbbr_config.c
index c1e5217..4998bb2 100644
--- a/tools/fiptool/tbbr_config.c
+++ b/tools/fiptool/tbbr_config.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -67,6 +67,11 @@
 		.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
 		.cmdline_name = "nt-fw"
 	},
+	{
+		.name = "Realm Monitor Management Firmware",
+		.uuid = UUID_REALM_MONITOR_MGMT_FIRMWARE,
+		.cmdline_name = "rmm-fw"
+	},
 	/* Dynamic Configs */
 	{
 		.name = "FW_CONFIG",