Merge "feat(rme): test access outside PAR from Plane N"
diff --git a/include/common/test_helpers.h b/include/common/test_helpers.h
index 1ab35ba..6482d6d 100644
--- a/include/common/test_helpers.h
+++ b/include/common/test_helpers.h
@@ -391,7 +391,7 @@
 	do {									\
 		u_register_t retrmm = 0U;					\
 										\
-		if (!get_armv9_2_feat_rme_support()) {				\
+		if (get_armv9_2_feat_rme_support() == 0U) {			\
 			tftf_testcase_printf("FEAT_RME not supported\n");	\
 			return TEST_RESULT_SKIPPED;				\
 		}								\
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index d9009dd..2a9d0d2 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -1819,4 +1819,10 @@
 #define SYSREG_ID_apgakeyhi_el1			SYSREG_ESR(3, 0, 2,  3, 1)
 #define SYSREG_ID_mpamidr_el1			SYSREG_ESR(3, 0, 10, 4, 4)
 
+/* RNDR definition */
+#define RNDR			S3_3_C2_C4_0
+
+/* RNDRRS definition */
+#define RNDRRS			S3_3_C2_C4_1
+
 #endif /* ARCH_H */
diff --git a/include/lib/aarch64/arch_helpers.h b/include/lib/aarch64/arch_helpers.h
index ed705bf..f562018 100644
--- a/include/lib/aarch64/arch_helpers.h
+++ b/include/lib/aarch64/arch_helpers.h
@@ -483,8 +483,8 @@
 }
 
 /* Armv8.5 FEAT_RNG Registers */
-DEFINE_SYSREG_READ_FUNC(rndr)
-DEFINE_SYSREG_READ_FUNC(rndrrs)
+DEFINE_RENAME_SYSREG_READ_FUNC(rndr, RNDR)
+DEFINE_RENAME_SYSREG_READ_FUNC(rndrrs, RNDRRS)
 
 /* GICv3 System Registers */
 DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el1, ICC_SRE_EL1)
diff --git a/include/lib/pcie/pcie_doe.h b/include/lib/pcie/pcie_doe.h
index bac0dbf..777309a 100644
--- a/include/lib/pcie/pcie_doe.h
+++ b/include/lib/pcie/pcie_doe.h
@@ -111,13 +111,13 @@
 #define SKIP_TEST_IF_DOE_NOT_SUPPORTED(_bdf, _doe_cap_base)			\
 	do {									\
 		/* Test PCIe DOE only for RME */				\
-		if (!get_armv9_2_feat_rme_support()) {				\
+		if (get_armv9_2_feat_rme_support() == 0U) {			\
 			tftf_testcase_printf("FEAT_RME not supported\n");	\
 			return TEST_RESULT_SKIPPED;				\
 		}								\
 										\
 		pcie_init();							\
-		if (pcie_find_doe_device(&(_bdf), &(_doe_cap_base)) != 0) {		\
+		if (pcie_find_doe_device(&(_bdf), &(_doe_cap_base)) != 0) {	\
 			tftf_testcase_printf("PCIe DOE not supported\n");	\
 			return TEST_RESULT_SKIPPED;				\
 		}								\
diff --git a/include/plat/common/platform.h b/include/plat/common/platform.h
index 8103335..e5032fa 100644
--- a/include/plat/common/platform.h
+++ b/include/plat/common/platform.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -25,6 +25,13 @@
 	} while (0)
 
 /*
+ * Represents whether a device memory location is within the system coherent
+ * memory space.
+ */
+#define DEV_MEM_NON_COHERENT			0
+#define DEV_MEM_COHERENT			1
+
+/*
  * The platform structure to represent the valid local power state
  * properties for a particular affinity level. The platform needs to
  * export the array of valid local low power states for each affinity level
@@ -213,4 +220,10 @@
  */
 uintptr_t plat_get_invalid_addr(void);
 
+/*
+ * Retrieve platform PCIe memory region
+ */
+int plat_get_dev_region(uint64_t *dev_base, size_t *dev_size,
+			uint32_t dev_type, uint32_t dev_idx);
+
 #endif /* __PLATFORM_H__ */
diff --git a/include/runtime_services/host_realm_managment/host_da_helper.h b/include/runtime_services/host_realm_managment/host_da_helper.h
new file mode 100644
index 0000000..602c0f5
--- /dev/null
+++ b/include/runtime_services/host_realm_managment/host_da_helper.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef HOST_DA_HELPER_H
+#define HOST_DA_HELPER_H
+
+#include <host_realm_rmi.h>
+
+u_register_t host_dev_mem_map(struct realm *realm, u_register_t dev_pa,
+				long map_level, u_register_t *dev_ipa);
+
+#endif /* HOST_DA_HELPER_H */
diff --git a/include/runtime_services/host_realm_managment/host_realm_rmi.h b/include/runtime_services/host_realm_managment/host_realm_rmi.h
index 4a87ede..20054bd 100644
--- a/include/runtime_services/host_realm_managment/host_realm_rmi.h
+++ b/include/runtime_services/host_realm_managment/host_realm_rmi.h
@@ -324,24 +324,24 @@
 #define RMI_RTT_SET_RIPAS		SMC64_RMI_FID(U(0x19))
 
 /*
- * FID: 0xC4000170
+ * arg0 == RD address
+ * arg1 == map address
+ * arg2 == level
+ * arg3 == PA of the target device memory
  */
-#define SMC_RMI_GRANULE_DEV_DELEGATE		SMC64_RMI_FID(U(0x20))
+#define SMC_RMI_DEV_MEM_MAP		SMC64_RMI_FID(U(0x22))
 
 /*
- * FID: 0xC4000171
+ * arg0 == RD address
+ * arg1 == map address
+ * arg2 == level
+ *
+ * ret1 == Address (PA) of the device memory granule, if ret0 == RMI_SUCCESS
+ *         Otherwise, undefined.
+ * ret2 == Top of the non-live address region. Only valid
+ *         if ret0 == RMI_SUCCESS or ret0 == (RMI_ERROR_RTT, x)
  */
-#define SMC_RMI_GRANULE_DEV_UNDELEGATE		SMC64_RMI_FID(U(0x21))
-
-/*
- * FID: 0xC4000172
- */
-#define SMC_RMI_DEV_MAP				SMC64_RMI_FID(U(0x22))
-
-/*
- * FID: 0xC4000173
- */
-#define SMC_RMI_DEV_UNMAP			SMC64_RMI_FID(U(0x23))
+#define SMC_RMI_DEV_MEM_UNMAP		SMC64_RMI_FID(U(0x23))
 
 /*
  * FID: 0xC4000174
@@ -538,11 +538,13 @@
 #define RMI_UNASSIGNED			UL(0)
 #define RMI_ASSIGNED			UL(1)
 #define RMI_TABLE			UL(2)
+#define RMI_ASSIGNED_DEV		UL(3)
 
 /* RmmRipas enumeration representing realm IPA state */
 #define RMI_EMPTY			UL(0)
 #define RMI_RAM				UL(1)
 #define RMI_DESTROYED			UL(2)
+#define RMI_DEV				UL(3)
 
 /* RmiPmuOverflowStatus enumeration representing PMU overflow status */
 #define RMI_PMU_OVERFLOW_NOT_ACTIVE	0U
@@ -646,6 +648,7 @@
 #define RMI_RETURN_STATUS(ret)		((ret) & 0xFF)
 #define RMI_RETURN_INDEX(ret)		(((ret) >> 8U) & 0xFF)
 #define RTT_MAX_LEVEL			(3L)
+#define RTT_MIN_DEV_BLOCK_LEVEL		(2L)
 #define RTT_MIN_LEVEL			(0L)
 #define RTT_MIN_LEVEL_LPA2		(-1L)
 #define ALIGN_DOWN(x, a)		((uint64_t)(x) & ~(((uint64_t)(a)) - 1ULL))
@@ -1235,4 +1238,10 @@
 u_register_t host_rmi_pdev_stop(u_register_t pdev_ptr);
 u_register_t host_rmi_pdev_destroy(u_register_t pdev_ptr);
 
+u_register_t host_rmi_dev_mem_map(u_register_t rd, u_register_t map_addr,
+				  u_register_t level, u_register_t dev_mem_addr);
+u_register_t host_rmi_dev_mem_unmap(u_register_t rd, u_register_t map_addr,
+				    u_register_t level, u_register_t *pa,
+				    u_register_t *top);
+
 #endif /* HOST_REALM_RMI_H */
diff --git a/plat/arm/fvp/fvp_def.h b/plat/arm/fvp/fvp_def.h
index 3609b86..4b5bd59 100644
--- a/plat/arm/fvp/fvp_def.h
+++ b/plat/arm/fvp/fvp_def.h
@@ -55,9 +55,12 @@
 #define PCIE_MEM_1_BASE			0x50000000
 #define PCIE_MEM_1_SIZE			SZ_256M
 
-/* PCIe memory region #2 256GB */
+/*
+ * PCIe memory region #2 size is 256GB, but only 3GB
+ * are currently supported by GPT library
+ */
 #define PCIE_MEM_2_BASE			0x4000000000
-#define PCIE_MEM_2_SIZE			(SZ_1G * 256)
+#define PCIE_MEM_2_SIZE			(SZ_1G * 3U)
 
 /*******************************************************************************
  * GIC-400 & interrupt handling related constants
diff --git a/plat/arm/fvp/fvp_pcie.c b/plat/arm/fvp/fvp_pcie.c
index c43e42d..38bdf39 100644
--- a/plat/arm/fvp/fvp_pcie.c
+++ b/plat/arm/fvp/fvp_pcie.c
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2024-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <assert.h>
 #include <pcie.h>
 
 #include <platform.h>
@@ -25,3 +26,32 @@
 {
 	return &fvp_pcie_cfg;
 }
+
+/*
+ * Retrieve platform PCIe memory region (Base Platform RevC only)
+ */
+int plat_get_dev_region(uint64_t *base, size_t *size,
+			uint32_t type, uint32_t idx)
+{
+#ifdef __aarch64__
+	assert((base != NULL) && (size != NULL));
+
+	if (type == DEV_MEM_NON_COHERENT) {
+		switch (idx) {
+		case 0U:
+			/* PCIe memory region 1 */
+			*base = PCIE_MEM_1_BASE;
+			*size = PCIE_MEM_1_SIZE;
+			return 0;
+		case 1U:
+			/* PCIe memory region 2 */
+			*base = PCIE_MEM_2_BASE;
+			*size = PCIE_MEM_2_SIZE;
+			return 0;
+		default:
+			break;
+		}
+	}
+#endif
+	return -1;
+}
diff --git a/plat/arm/fvp/plat_setup.c b/plat/arm/fvp/plat_setup.c
index 69cb0a1..f09bf59 100644
--- a/plat/arm/fvp/plat_setup.c
+++ b/plat/arm/fvp/plat_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -36,6 +36,10 @@
 	MAP_REGION_FLAT(FLASH_BASE, FLASH_SIZE, MT_DEVICE | MT_RW | MT_NS),
 #endif
 	MAP_REGION_FLAT(PCIE_CONFIG_BASE, PCIE_CONFIG_SIZE, MT_DEVICE | MT_RW | MT_NS),
+#ifdef __aarch64__
+	MAP_REGION_FLAT(PCIE_MEM_1_BASE, PCIE_MEM_1_SIZE, MT_DEVICE | MT_RW | MT_NS),
+	MAP_REGION_FLAT(PCIE_MEM_2_BASE, PCIE_MEM_2_SIZE, MT_DEVICE | MT_RW | MT_NS),
+#endif
 	MAP_REGION_FLAT(DRAM_BASE, TFTF_BASE - DRAM_BASE, MT_MEMORY | MT_RW | MT_NS),
 	{0}
 };
diff --git a/plat/arm/fvp/platform.mk b/plat/arm/fvp/platform.mk
index ee30721..42df3f7 100644
--- a/plat/arm/fvp/platform.mk
+++ b/plat/arm/fvp/platform.mk
@@ -81,7 +81,7 @@
 $(eval $(call add_define,TFTF_DEFINES,FVP_MAX_PE_PER_CPU))
 
 # Default PA size for FVP platform
-PA_SIZE := 34
+PA_SIZE := 39
 
 $(eval $(call add_define,CACTUS_DEFINES,PA_SIZE))
 $(eval $(call add_define,IVY_DEFINES,PA_SIZE))
diff --git a/plat/common/plat_common.c b/plat/common/plat_common.c
index da58579..c06ad13 100644
--- a/plat/common/plat_common.c
+++ b/plat/common/plat_common.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -26,6 +26,7 @@
 #pragma weak plat_get_prot_regions
 #pragma weak plat_pcie_get_info_table
 #pragma weak plat_get_invalid_addr
+#pragma weak plat_get_dev_region
 
 #if IMAGE_TFTF
 
@@ -160,3 +161,9 @@
 {
 	return (uintptr_t)0x0;
 }
+
+int plat_get_dev_region(uint64_t *dev_base, size_t *dev_size,
+			uint32_t dev_type, uint32_t dev_idx)
+{
+	return -1;
+}
diff --git a/tftf/tests/runtime_services/host_realm_managment/host_da_helper.c b/tftf/tests/runtime_services/host_realm_managment/host_da_helper.c
new file mode 100644
index 0000000..63c02c2
--- /dev/null
+++ b/tftf/tests/runtime_services/host_realm_managment/host_da_helper.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+
+#include <stdint.h>
+
+#include <debug.h>
+#include <host_da_helper.h>
+#include <host_realm_helper.h>
+
+u_register_t host_dev_mem_map(struct realm *realm, u_register_t dev_pa,
+				long map_level, u_register_t *dev_ipa)
+{
+	u_register_t rd = realm->rd;
+	u_register_t map_addr = dev_pa;	/* 1:1 PA->IPA mapping */
+	u_register_t ret;
+
+	*dev_ipa = 0UL;
+
+	ret = host_rmi_dev_mem_map(rd, map_addr, map_level, dev_pa);
+
+	if (RMI_RETURN_STATUS(ret) == RMI_ERROR_RTT) {
+		/* Create missing RTTs and retry */
+		long level = (long)RMI_RETURN_INDEX(ret);
+
+		ret = host_rmi_create_rtt_levels(realm, map_addr,
+						 level, map_level);
+		if (ret != RMI_SUCCESS) {
+			tftf_testcase_printf("%s() failed, 0x%lx\n",
+				"host_rmi_create_rtt_levels", ret);
+			return REALM_ERROR;
+		}
+
+		ret = host_rmi_dev_mem_map(rd, map_addr, map_level, dev_pa);
+	}
+	if (ret != RMI_SUCCESS) {
+		tftf_testcase_printf("%s() failed, 0x%lx\n",
+			"host_rmi_dev_mem_map", ret);
+		return REALM_ERROR;
+	}
+
+	*dev_ipa = map_addr;
+	return REALM_SUCCESS;
+}
diff --git a/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c b/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c
index 72d0876..83ae1c4 100644
--- a/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c
+++ b/tftf/tests/runtime_services/host_realm_managment/host_realm_rmi.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2025, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  *
@@ -1981,3 +1981,28 @@
 	return host_rmi_handler(&(smc_args) {SMC_RMI_PDEV_DESTROY, pdev_ptr},
 				2U).ret0;
 }
+
+u_register_t host_rmi_dev_mem_map(u_register_t rd,
+				  u_register_t map_addr,
+				  u_register_t level,
+				  u_register_t dev_mem_addr)
+{
+	return host_rmi_handler(&(smc_args) {SMC_RMI_DEV_MEM_MAP, rd,
+					map_addr, level, dev_mem_addr}, 5U).ret0;
+}
+
+u_register_t host_rmi_dev_mem_unmap(u_register_t rd,
+				    u_register_t map_addr,
+				    u_register_t level,
+				    u_register_t *pa,
+				    u_register_t *top)
+{
+	smc_ret_values rets;
+
+	rets = host_rmi_handler(&(smc_args) {SMC_RMI_DEV_MEM_UNMAP, rd, map_addr,
+				level, (u_register_t)&rets}, 5U);
+
+	*pa = rets.ret1;
+	*top = rets.ret2;
+	return rets.ret0;
+}
diff --git a/tftf/tests/runtime_services/host_realm_managment/rmi_dev_delegate_tests.c b/tftf/tests/runtime_services/host_realm_managment/rmi_dev_delegate_tests.c
new file mode 100644
index 0000000..b4f7c51
--- /dev/null
+++ b/tftf/tests/runtime_services/host_realm_managment/rmi_dev_delegate_tests.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2024-2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+#include <arch_features.h>
+#include <common_def.h>
+#include <host_realm_helper.h>
+#include <host_realm_mem_layout.h>
+#include <host_shared_data.h>
+#include <pcie_doe.h>
+#include <plat_topology.h>
+#include <platform.h>
+#include <power_management.h>
+#include "rmi_spm_tests.h"
+#include <test_helpers.h>
+
+static test_result_t host_multi_cpu_payload_dev_del_undel(void);
+
+/* Test 2MB of PCIe memory region 2 */
+#define PCIE_MEM_2_TEST_SIZE	SZ_2M
+
+/* Number of dev granules to test */
+#define NUM_DEV_GRANULES	((PCIE_MEM_2_TEST_SIZE / GRANULE_SIZE) / \
+					PLATFORM_CORE_COUNT)
+
+/* Buffer to delegate and undelegate */
+const char *bufferdelegate;
+static char bufferstate[NUM_DEV_GRANULES * PLATFORM_CORE_COUNT];
+
+/*
+ * Overall test for Host in three sections:
+ * 1. Delegate and Undelegate Non-Secure dev granule via
+ * SMC call to realm payload.
+ * 2. Multi CPU delegation where random assignment of states
+ * (realm, non-secure) is assigned to a set of granules.
+ * Each CPU is given a number of dev granules to delegate in
+ * parallel with the other CPUs.
+ * 3. Fail testing of delegation parameters such as
+ * attempting to perform a delegation on the same dev granule
+ * twice and then testing a misaligned address.
+ */
+static test_result_t host_init_buffer_dev_del(void)
+{
+	__unused size_t dev_size;
+
+	host_rmi_init_cmp_result();
+
+	/* Retrieve platform PCIe memory region 2 */
+	if (plat_get_dev_region((uint64_t *)&bufferdelegate, &dev_size,
+				DEV_MEM_NON_COHERENT, 1U) != 0) {
+		tftf_testcase_printf("Cannot retrieve PCIe memory region 2\n");
+		return TEST_RESULT_SKIPPED;
+	}
+
+	assert(dev_size >= PCIE_MEM_2_TEST_SIZE);
+
+	for (uint32_t i = 0; i < (NUM_DEV_GRANULES * PLATFORM_CORE_COUNT) ; i++) {
+		if ((rand() & 1) == 0) {
+			u_register_t retrmm = host_rmi_granule_delegate(
+					(u_register_t)&bufferdelegate[i * GRANULE_SIZE]);
+
+			if (retrmm != RMI_SUCCESS) {
+				tftf_testcase_printf("Delegate operation returns 0x%lx\n",
+						retrmm);
+				return TEST_RESULT_FAIL;
+			}
+			bufferstate[i] = B_DELEGATED;
+		} else {
+			bufferstate[i] = B_UNDELEGATED;
+		}
+	}
+
+	return host_cmp_result();
+}
+
+/*
+ * Delegate and Undelegate Non-Secure Dev Granule
+ */
+test_result_t host_dev_mem_delegate_undelegate(void)
+{
+	__unused size_t dev_size;
+	u_register_t retrmm, rmi_feat_reg0;
+
+	CHECK_DA_SUPPORT_IN_RMI(rmi_feat_reg0);
+
+	host_rmi_init_cmp_result();
+
+	/* Retrieve platform PCIe memory region 2 */
+	if (plat_get_dev_region((uint64_t *)&bufferdelegate, &dev_size,
+				DEV_MEM_NON_COHERENT, 1U) != 0) {
+		tftf_testcase_printf("Cannot retrieve PCIe memory region 2\n");
+		return TEST_RESULT_SKIPPED;
+	}
+
+	assert(dev_size >= PCIE_MEM_2_TEST_SIZE);
+
+	retrmm = host_rmi_granule_delegate((u_register_t)bufferdelegate);
+	if (retrmm != RMI_SUCCESS) {
+		tftf_testcase_printf("Delegate operation returns 0x%lx\n",
+					retrmm);
+		return TEST_RESULT_FAIL;
+	}
+	retrmm = host_rmi_granule_undelegate((u_register_t)bufferdelegate);
+	if (retrmm != RMI_SUCCESS) {
+		tftf_testcase_printf("Undelegate operation returns 0x%lx\n",
+					retrmm);
+		return TEST_RESULT_FAIL;
+	}
+	tftf_testcase_printf("Delegate and undelegate of buffer 0x%lx succeeded\n",
+				(u_register_t)bufferdelegate);
+
+	return host_cmp_result();
+}
+
+/*
+ * Select all CPU's to randomly delegate/undelegate
+ * dev granule pages to stress the delegate mechanism
+ */
+test_result_t host_dev_mem_delundel_multi_cpu(void)
+{
+	u_register_t lead_mpid, target_mpid, retrmm, rmi_feat_reg0;
+	int32_t ret;
+	unsigned int cpu_node;
+
+	CHECK_DA_SUPPORT_IN_RMI(rmi_feat_reg0);
+
+	lead_mpid = read_mpidr_el1() & MPID_MASK;
+
+	host_rmi_init_cmp_result();
+
+	retrmm = host_init_buffer_dev_del();
+	if (retrmm != TEST_RESULT_SUCCESS) {
+		return retrmm;
+	}
+
+	for_each_cpu(cpu_node) {
+		target_mpid = (u_register_t)tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+		if (lead_mpid == target_mpid) {
+			continue;
+		}
+
+		ret = tftf_cpu_on(target_mpid,
+			(uintptr_t)host_multi_cpu_payload_dev_del_undel, 0UL);
+
+		if (ret != PSCI_E_SUCCESS) {
+			ERROR("CPU ON failed for 0x%lx\n", target_mpid);
+			return TEST_RESULT_FAIL;
+		}
+
+	}
+
+	for_each_cpu(cpu_node) {
+		target_mpid = (u_register_t)tftf_get_mpidr_from_node(cpu_node) & MPID_MASK;
+
+		if (lead_mpid == target_mpid) {
+			continue;
+		}
+
+		while (tftf_psci_affinity_info(target_mpid, MPIDR_AFFLVL0) !=
+				PSCI_STATE_OFF) {
+			continue;
+		}
+	}
+
+	/*
+	 * Cleanup to set all dev granules back to undelegated
+	 */
+	for (unsigned int i = 0U; i < (NUM_DEV_GRANULES * PLATFORM_CORE_COUNT) ; i++) {
+		if (bufferstate[i] == B_DELEGATED) {
+			retrmm = host_rmi_granule_undelegate(
+				(u_register_t)&bufferdelegate[i * GRANULE_SIZE]);
+			if (retrmm != RMI_SUCCESS) {
+				tftf_testcase_printf("Undelegate operation returns 0x%lx\n",
+						retrmm);
+				return TEST_RESULT_FAIL;
+			}
+			bufferstate[i] = B_UNDELEGATED;
+		}
+	}
+
+	return host_cmp_result();
+}
+
+/*
+ * Multi CPU testing of delegate and undelegate of dev granules.
+ * The granules are first randomly initialized to either realm or
+ * non secure using the function init_buffer_dev_del() and then
+ * the function below assigns NUM_DEV_GRANULES to each CPU for delegation
+ * or undelgation depending upon the initial state.
+ */
+static test_result_t host_multi_cpu_payload_dev_del_undel(void)
+{
+	__unused size_t dev_size;
+	u_register_t retrmm;
+	unsigned int cpu_node;
+
+	/* Retrieve platform PCIe memory region 2 */
+	if (plat_get_dev_region((uint64_t *)&bufferdelegate, &dev_size,
+				DEV_MEM_NON_COHERENT, 1U) != 0) {
+		tftf_testcase_printf("Cannot retrieve PCIe memory region 2\n");
+		return TEST_RESULT_SKIPPED;
+	}
+
+	assert(dev_size >= PCIE_MEM_2_TEST_SIZE);
+
+	cpu_node = platform_get_core_pos(read_mpidr_el1() & MPID_MASK);
+
+	host_rmi_init_cmp_result();
+
+	for (unsigned int i = 0U; i < NUM_DEV_GRANULES; i++) {
+		if (bufferstate[((cpu_node * NUM_DEV_GRANULES) + i)] == B_UNDELEGATED) {
+			retrmm = host_rmi_granule_delegate((u_register_t)
+				&bufferdelegate[((cpu_node * NUM_DEV_GRANULES) + i) *
+								GRANULE_SIZE]);
+			if (retrmm != RMI_SUCCESS) {
+				tftf_testcase_printf("Delegate operation returns 0x%lx\n",
+							retrmm);
+				return TEST_RESULT_FAIL;
+			}
+			bufferstate[((cpu_node * NUM_DEV_GRANULES) + i)] = B_DELEGATED;
+		} else {
+			retrmm = host_rmi_granule_undelegate((u_register_t)
+				&bufferdelegate[((cpu_node * NUM_DEV_GRANULES) + i) *
+								GRANULE_SIZE]);
+			if (retrmm != RMI_SUCCESS) {
+				tftf_testcase_printf("Undelegate operation returns 0x%lx\n",
+							retrmm);
+				return TEST_RESULT_FAIL;
+			}
+			bufferstate[((cpu_node * NUM_DEV_GRANULES) + i)] = B_UNDELEGATED;
+		}
+	}
+
+	return host_cmp_result();
+}
+
+/*
+ * Fail testing of delegation process. The first is an error expected
+ * for processing the same granule twice and the second is submission of
+ * a misaligned address
+ */
+test_result_t host_fail_dev_mem_del(void)
+{
+	__unused size_t dev_size;
+	u_register_t retrmm, rmi_feat_reg0;
+
+	CHECK_DA_SUPPORT_IN_RMI(rmi_feat_reg0);
+
+	/* Retrieve platform PCIe memory region 2 */
+	if (plat_get_dev_region((uint64_t *)&bufferdelegate, &dev_size,
+				DEV_MEM_NON_COHERENT, 1U) != 0) {
+		tftf_testcase_printf("Cannot retrieve PCIe memory region 2\n");
+		return TEST_RESULT_SKIPPED;
+	}
+
+	assert(dev_size >= PCIE_MEM_2_TEST_SIZE);
+
+	host_rmi_init_cmp_result();
+
+	retrmm = host_rmi_granule_delegate((u_register_t)&bufferdelegate[0]);
+	if (retrmm != RMI_SUCCESS) {
+		tftf_testcase_printf
+			("Delegate operation does not pass as expected for double delegation,"
+				" 0x%lx\n", retrmm);
+		return TEST_RESULT_FAIL;
+	}
+
+	retrmm = host_rmi_granule_delegate((u_register_t)&bufferdelegate[0]);
+	if (retrmm == RMI_SUCCESS) {
+		tftf_testcase_printf
+			("Delegate operation does not fail as expected for double delegation,"
+				" 0x%lx\n", retrmm);
+		return TEST_RESULT_FAIL;
+	}
+
+	retrmm = host_rmi_granule_undelegate((u_register_t)&bufferdelegate[1]);
+	if (retrmm == RMI_SUCCESS) {
+		tftf_testcase_printf
+			("Undelegate operation does not return fail for misaligned address,"
+				" 0x%lx\n", retrmm);
+		return TEST_RESULT_FAIL;
+	}
+
+	retrmm = host_rmi_granule_undelegate((u_register_t)&bufferdelegate[0]);
+	if (retrmm != RMI_SUCCESS) {
+		tftf_testcase_printf
+			("Undelegate operation returns fail for cleanup, 0x%lx\n", retrmm);
+		return TEST_RESULT_FAIL;
+	}
+
+	return host_cmp_result();
+}
diff --git a/tftf/tests/runtime_services/host_realm_managment/rmi_dev_mem_map_tests.c b/tftf/tests/runtime_services/host_realm_managment/rmi_dev_mem_map_tests.c
new file mode 100644
index 0000000..bed1172
--- /dev/null
+++ b/tftf/tests/runtime_services/host_realm_managment/rmi_dev_mem_map_tests.c
@@ -0,0 +1,315 @@
+/*
+ * Copyright (c) 2025, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+#include <arch_features.h>
+#include <host_da_helper.h>
+#include <host_realm_helper.h>
+#include <host_realm_mem_layout.h>
+#include <host_shared_data.h>
+#include <pcie_doe.h>
+#include <plat_topology.h>
+#include <platform.h>
+#include <test_helpers.h>
+
+/* Maximum number of dev memory regions to test */
+#define MAX_DEV_REGIONS		32U
+
+#define NUM_L3_REGIONS		MAX_DEV_REGIONS
+#define NUM_L2_REGIONS		8U
+
+#define NUM_INFO_TESTS		3U
+
+struct dev_mem_info {
+	uintptr_t base_pa;		/* Dev memory region PA */
+	long map_level;			/* RTT level */
+	size_t map_size;		/* RTT level mapping size */
+	unsigned int num_regions;	/* Number of granule/level 2 block regions */
+};
+
+/*
+ * @Test_Aim@ Test device memory map and unmap commands
+ *
+ * Delegate device granules for 2 memory regions.
+ * Dev Mem Map/Unmap 2 device memory regions with page and block mapping levels.
+ * Check returned 'pa' and 'top' output values after Dev Mem Unmap.
+ * Check RTT entries states and RIPAS values after Dev Mem Map/Unmap.
+ * Undelegate device granules.
+ */
+test_result_t host_realm_dev_mem_map_unmap(void)
+{
+	u_register_t rec_flag[] = {RMI_RUNNABLE};
+	u_register_t map_addr[NUM_INFO_TESTS][MAX_DEV_REGIONS];
+	u_register_t feature_flag = 0UL;
+	u_register_t res, rmi_features;
+	__unused size_t dev_size;
+	test_result_t ret = TEST_RESULT_FAIL;
+	long sl = RTT_MIN_LEVEL;
+	struct realm realm;
+	struct rtt_entry rtt;
+	struct dev_mem_info mem_info[NUM_INFO_TESTS] = {
+		/* PCIe memory region 1 */
+		{0UL, RTT_MAX_LEVEL,
+			RTT_MAP_SIZE(RTT_MAX_LEVEL), NUM_L3_REGIONS},
+		/* PCIe memory region 2 */
+		{0UL, RTT_MAX_LEVEL,
+			RTT_MAP_SIZE(RTT_MAX_LEVEL), NUM_L3_REGIONS},
+		/* PCIe memory region 2 */
+		{0UL, RTT_MIN_DEV_BLOCK_LEVEL,
+			RTT_MAP_SIZE(RTT_MIN_DEV_BLOCK_LEVEL), NUM_L2_REGIONS}
+	};
+	unsigned int num[NUM_INFO_TESTS];
+	unsigned int offset, i, j;
+
+	CHECK_DA_SUPPORT_IN_RMI(rmi_features);
+
+	/* Initialise memory test structures */
+
+	/*
+	 * TODO: the test depends on 2 PCIe regions of suitable size and alignment.
+	 * The test can be made more flexible and not depend on 2 PCIe regions.
+	 */
+	/* Retrieve platform PCIe memory region 1 */
+	if (plat_get_dev_region((uint64_t *)&mem_info[0].base_pa, &dev_size,
+				DEV_MEM_NON_COHERENT, 0U) != 0) {
+		tftf_testcase_printf("Cannot retrieve PCIe memory region 0\n");
+		return TEST_RESULT_SKIPPED;
+	}
+
+	if (dev_size < mem_info[0].num_regions * mem_info[0].map_size) {
+		tftf_testcase_printf("PCIe memory region 0 too small\n");
+		return TEST_RESULT_SKIPPED;
+	}
+
+	/* Retrieve platform PCIe memory region 2 */
+	if (plat_get_dev_region((uint64_t *)&mem_info[1].base_pa, &dev_size,
+				DEV_MEM_NON_COHERENT, 1U) != 0) {
+		tftf_testcase_printf("Cannot retrieve PCIe memory region 1\n");
+		return TEST_RESULT_SKIPPED;
+	}
+
+	mem_info[2].base_pa = mem_info[1].base_pa;
+
+	if ((dev_size < mem_info[1].num_regions * mem_info[1].map_size) ||
+	      (dev_size < mem_info[2].num_regions * mem_info[2].map_size)) {
+		tftf_testcase_printf("PCIe memory region 1 too small\n");
+		return TEST_RESULT_SKIPPED;
+	}
+
+	host_rmi_init_cmp_result();
+
+	if (is_feat_52b_on_4k_2_supported()) {
+		feature_flag = RMI_FEATURE_REGISTER_0_LPA2;
+		sl = RTT_MIN_LEVEL_LPA2;
+	}
+
+	if (!host_create_activate_realm_payload(&realm,
+						(u_register_t)REALM_IMAGE_BASE,
+						feature_flag, 0U, sl, rec_flag, 1U, 0U)) {
+		tftf_testcase_printf("Realm creation failed\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	/* Seed the random number generator */
+	assert(is_feat_rng_present());
+	srand((unsigned int)read_rndr());
+
+	/*
+	 * To use two 2MB blocks with level 3 mapping calculate
+	 * random offset from the start of the 1st 2MB block.
+	 */
+	offset = (RTT_L2_BLOCK_SIZE / GRANULE_SIZE) -
+			((unsigned int)rand() % (NUM_L3_REGIONS - 1U));
+
+	mem_info[0].base_pa += offset * GRANULE_SIZE;
+
+	offset = (RTT_L2_BLOCK_SIZE / GRANULE_SIZE) -
+			((unsigned int)rand() % (NUM_L3_REGIONS - 1U));
+
+	mem_info[1].base_pa += offset * GRANULE_SIZE;
+
+	/*
+	 * To use two 1GB blocks with level 2 mapping calculate
+	 * random offset from the start of the 1st 1GB block.
+	 */
+	offset = (RTT_MAP_SIZE(1) / RTT_L2_BLOCK_SIZE) -
+			((unsigned int)rand() % (NUM_L2_REGIONS - 1U));
+
+	mem_info[2].base_pa += offset * RTT_L2_BLOCK_SIZE;
+
+	/* Delegate device granules */
+	for (i = 0U; i < NUM_INFO_TESTS; i++) {
+		/* Number of granules */
+		unsigned int num_granules = (mem_info[i].map_size / GRANULE_SIZE) *
+							mem_info[i].num_regions;
+
+		for (num[i] = 0U; num[i] < num_granules; num[i]++) {
+			res = host_rmi_granule_delegate(mem_info[i].base_pa +
+							num[i] * GRANULE_SIZE);
+			if (res != RMI_SUCCESS) {
+				tftf_testcase_printf(
+					"%s() for 0x%lx failed, 0x%lx\n",
+					"host_rmi_granule_delegate",
+					(mem_info[i].base_pa + num[i] * GRANULE_SIZE),
+					res);
+				goto undelegate_granules;
+			}
+		}
+	}
+
+	/* Map device memory */
+	for (i = 0U; i < NUM_INFO_TESTS; i++) {
+		for (j = 0U; j < mem_info[i].num_regions; j++) {
+			res = host_dev_mem_map(&realm,
+					mem_info[i].base_pa + j * mem_info[i].map_size,
+					mem_info[i].map_level, &map_addr[i][j]);
+			if (res != REALM_SUCCESS) {
+				tftf_testcase_printf("%s() for 0x%lx failed, 0x%lx\n",
+					"host_realm_dev_mem_map",
+					mem_info[i].base_pa + j * mem_info[i].map_size,
+					res);
+				goto undelegate_granules;
+			}
+		}
+	}
+
+	/* Check RTT entries */
+	for (i = 0U; i < NUM_INFO_TESTS; i++) {
+		for (j = 0U; j < mem_info[i].num_regions; j++) {
+			res = host_rmi_rtt_readentry(realm.rd, map_addr[i][j],
+						mem_info[i].map_level, &rtt);
+			if (res != RMI_SUCCESS) {
+				tftf_testcase_printf("%s() for 0x%lx failed, 0x%lx\n",
+					"host_rmi_rtt_readentry",
+					map_addr[i][j], res);
+				goto undelegate_granules;
+			}
+
+			if ((rtt.state != RMI_ASSIGNED_DEV) ||
+				(rtt.ripas != RMI_EMPTY) ||
+				(rtt.walk_level != mem_info[i].map_level) ||
+				(rtt.out_addr != map_addr[i][j])) {
+				tftf_testcase_printf("RTT entry for 0x%lx:\n", map_addr[i][j]);
+				tftf_testcase_printf(
+					"%s level:%ld addr:0x%lx state:%lu ripas:%lu\n",
+					"Expected", mem_info[i].map_level, map_addr[i][j],
+					RMI_ASSIGNED_DEV, RMI_EMPTY);
+				tftf_testcase_printf(
+					"%s level:%ld addr:0x%lx state:%lu ripas:%lu\n",
+					"Read    ", rtt.walk_level,
+					(unsigned long)rtt.out_addr, rtt.state, rtt.ripas);
+				goto undelegate_granules;
+			}
+		}
+	}
+
+	/* Unmap device memory */
+	for (i = 0U; i < NUM_INFO_TESTS; i++) {
+		for (j = 0U; j < mem_info[i].num_regions; j++) {
+			u_register_t pa, pa_exp, top, top_exp;
+
+			res = host_rmi_dev_mem_unmap(realm.rd, map_addr[i][j],
+							mem_info[i].map_level,
+							&pa, &top);
+			if (res != RMI_SUCCESS) {
+				tftf_testcase_printf("%s() for 0x%lx failed, 0x%lx\n",
+							"host_rmi_dev_mem_unmap",
+							map_addr[i][j], res);
+				goto undelegate_granules;
+			}
+
+			INFO("DEV_MEM_UNMAP 0x%lx: pa 0x%lx top 0x%lx\n",
+				map_addr[i][j], pa, top);
+
+			pa_exp = mem_info[i].base_pa + j * mem_info[i].map_size;
+
+			/* Check PA of the device memory region which was unmapped. */
+			if (pa != pa_exp) {
+				tftf_testcase_printf("%s() for 0x%lx failed, "
+						"expected pa 0x%lx, returned 0x%lx\n",
+						"host_rmi_dev_mem_unmap",
+						map_addr[i][j], pa_exp, pa);
+				goto undelegate_granules;
+			}
+
+			/*
+			 * Check top IPA of non-live RTT entries, from entry
+			 * at which the RTT walk terminated.
+			 */
+			if (j == (mem_info[i].num_regions - 1U)) {
+				/* IPA aligned to the previous mapping level */
+				top_exp = ALIGN_DOWN(map_addr[i][j],
+						RTT_MAP_SIZE(mem_info[i].map_level - 1L)) +
+						RTT_MAP_SIZE(mem_info[i].map_level - 1L);
+			} else {
+				/* Next IPA of the current mapping level */
+				top_exp = map_addr[i][j] + mem_info[i].map_size;
+			}
+
+			if (top != top_exp) {
+				tftf_testcase_printf("%s() for 0x%lx failed, "
+						"expected top 0x%lx, returned 0x%lx\n",
+						"host_rmi_dev_mem_unmap",
+						map_addr[i][j], top_exp, top);
+				goto undelegate_granules;
+			}
+		}
+	}
+
+	/* Check RTT entries */
+	for (i = 0U; i < NUM_INFO_TESTS; i++) {
+		for (j = 0U; j < mem_info[i].num_regions; j++) {
+			res = host_rmi_rtt_readentry(realm.rd, map_addr[i][j],
+						mem_info[i].map_level, &rtt);
+			if (res != RMI_SUCCESS) {
+				tftf_testcase_printf("%s() for 0x%lx failed, 0x%lx\n",
+					"host_rmi_rtt_readentry",
+					map_addr[i][j], res);
+				goto undelegate_granules;
+			}
+
+			if ((rtt.state != RMI_UNASSIGNED) ||
+				(rtt.ripas != RMI_EMPTY)) {
+				tftf_testcase_printf("%s() for 0x%lx failed, "
+					"expected state %lu ripas %lu, read %lu %lu",
+					"host_rmi_rtt_readentry",
+					map_addr[i][j], RMI_UNASSIGNED, RMI_EMPTY,
+					rtt.state, rtt.ripas);
+				goto undelegate_granules;
+			}
+		}
+	}
+
+	ret = TEST_RESULT_SUCCESS;
+
+undelegate_granules:
+	for (i = 0U; i < NUM_INFO_TESTS; i++) {
+		for (j = 0U; j < num[i]; j++) {
+			res = host_rmi_granule_undelegate(mem_info[i].base_pa + j * GRANULE_SIZE);
+			if (res != RMI_SUCCESS) {
+				tftf_testcase_printf("%s for 0x%lx failed, 0x%lx\n",
+							"host_rmi_granule_undelegate",
+							(mem_info[i].base_pa + j * GRANULE_SIZE),
+							res);
+				ret = TEST_RESULT_FAIL;
+				break;
+			}
+		}
+	}
+
+	if (!host_destroy_realm(&realm)) {
+		tftf_testcase_printf("host_destroy_realm() failed\n");
+		return TEST_RESULT_FAIL;
+	}
+
+	if (ret == TEST_RESULT_FAIL) {
+		return ret;
+	}
+
+	return host_cmp_result();
+}
+
diff --git a/tftf/tests/tests-realm-payload.mk b/tftf/tests/tests-realm-payload.mk
index 8d9b8b1..fc3524e 100644
--- a/tftf/tests/tests-realm-payload.mk
+++ b/tftf/tests/tests-realm-payload.mk
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2021-2024, Arm Limited. All rights reserved.
+# Copyright (c) 2021-2025, Arm Limited. All rights reserved.
 #
 # SPDX-License-Identifier: BSD-3-Clause
 #
@@ -22,13 +22,16 @@
 
 TESTS_SOURCES	+=							\
 	$(addprefix tftf/tests/runtime_services/host_realm_managment/,	\
+		host_crypto_utils.c					\
+		host_da_helper.c					\
 		host_pmuv3.c						\
-		host_realm_rmi.c					\
 		host_realm_helper.c					\
+		host_realm_rmi.c					\
+		host_rmi_pdev.c						\
 		host_shared_data.c					\
 		rmi_delegate_tests.c					\
-		host_rmi_pdev.c						\
-		host_crypto_utils.c					\
+		rmi_dev_delegate_tests.c				\
+		rmi_dev_mem_map_tests.c					\
 	)
 
 TESTS_SOURCES	+=							\
diff --git a/tftf/tests/tests-realm-payload.xml b/tftf/tests/tests-realm-payload.xml
index 3d88382..5216a9a 100644
--- a/tftf/tests/tests-realm-payload.xml
+++ b/tftf/tests/tests-realm-payload.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 
 <!--
-  Copyright (c) 2021-2024, Arm Limited. All rights reserved.
+  Copyright (c) 2021-2025, Arm Limited. All rights reserved.
 
   SPDX-License-Identifier: BSD-3-Clause
 -->
@@ -68,6 +68,7 @@
 	  function="host_realm_delundel_multi_cpu" />
 	  <testcase name="Testing delegation fails"
 	  function="host_realm_fail_del" />
+	  <!-- Test cases related to PMUv3 support -->
 	  <testcase name="PMUv3 cycle counter functional in Realm"
 	  function="host_realm_pmuv3_cycle_works" />
 	  <testcase name="PMUv3 event counter functional in Realm"
@@ -163,5 +164,15 @@
 	 <!-- Test case for EL3-RMM IDE KM Interface -->
 	  <testcase name="Test for Root Port Key management interface"
 	  function="host_realm_test_root_port_key_management" />
+	  <!-- Test cases related to Dev Mem Delegate and Undelegate -->
+	  <testcase name="Host Dev Mem Delegate and Undelegate"
+	  function="host_dev_mem_delegate_undelegate" />
+	  <testcase name="Multi CPU Realm payload Dev Mem Delegate and Undelegate"
+	  function="host_dev_mem_delundel_multi_cpu" />
+	  <testcase name="Testing Dev Mem delegation fails"
+	  function="host_fail_dev_mem_del" />
+	  <!-- Test cases related to Dev Mem Map and Unmap -->
+	  <testcase name="Realm payload Dev Mem Map and Unmap"
+	  function="host_realm_dev_mem_map_unmap" />
   </testsuite>
 </testsuites>