Merge changes from topic "tftf_refactor"

* changes:
  refactor(neoverse_rd): introduce flash and ros macros
  refactor(neoverse_rd): introduce timer and watchdog macros
  refactor(neoverse_rd): define naming convention for CSS macros
  refactor(neoverse_rd): remove deprecated header files
  refactor(neoverse_rd): refactor header files for second gen platforms
  refactor(neoverse_rd): refactor header files for first gen platforms
diff --git a/include/common/test_helpers.h b/include/common/test_helpers.h
index 3caca39..d6a7ade 100644
--- a/include/common/test_helpers.h
+++ b/include/common/test_helpers.h
@@ -420,4 +420,9 @@
 /* Generate 64-bit random number */
 unsigned long long rand64(void);
 
+/* TRBE Errata */
+#define CORTEX_A520_MIDR        U(0x410FD800)
+#define CORTEX_X4_MIDR          U(0x410FD821)
+#define RXPX_RANGE(x, y, z)     (((x >= y) && (x <= z)) ? true : false)
+bool is_trbe_errata_affected_core(void);
 #endif /* __TEST_HELPERS_H__ */
diff --git a/include/lib/aarch32/arch.h b/include/lib/aarch32/arch.h
index 6f41db9..cfbce56 100644
--- a/include/lib/aarch32/arch.h
+++ b/include/lib/aarch32/arch.h
@@ -23,6 +23,16 @@
 #define MIDR_VAR_MASK		U(0xf0)
 #define MIDR_REV_MASK		U(0xf)
 
+/******************************************************************************
+ * MIDR macros
+ *****************************************************************************/
+/* Extract the partnumber */
+#define EXTRACT_PARTNUM(x)     ((x >> MIDR_PN_SHIFT) & MIDR_PN_MASK)
+/* Extract revision and variant info */
+
+#define EXTRACT_REV_VAR(x)	(x & MIDR_REV_MASK) | ((x >> (MIDR_VAR_SHIFT - MIDR_REV_BITS)) \
+				& MIDR_VAR_MASK)
+
 /*******************************************************************************
  * MPIDR macros
  ******************************************************************************/
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index c45358e..d29f5a6 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -23,6 +23,16 @@
 #define MIDR_PN_MASK		U(0xfff)
 #define MIDR_PN_SHIFT		U(0x4)
 
+/******************************************************************************
+ * MIDR macros
+ *****************************************************************************/
+/* Extract the partnumber */
+#define EXTRACT_PARTNUM(x)     ((x >> MIDR_PN_SHIFT) & MIDR_PN_MASK)
+/* Extract revision and variant info */
+
+#define EXTRACT_REV_VAR(x)	(x & MIDR_REV_MASK) | ((x >> (MIDR_VAR_SHIFT - MIDR_REV_BITS)) \
+				& MIDR_VAR_MASK)
+
 /*******************************************************************************
  * MPIDR macros
  ******************************************************************************/
diff --git a/include/lib/aarch64/arch_features.h b/include/lib/aarch64/arch_features.h
index a2ed5be..f5dd294 100644
--- a/include/lib/aarch64/arch_features.h
+++ b/include/lib/aarch64/arch_features.h
@@ -251,6 +251,11 @@
 		ID_AA64DFR0_PMS_MASK);
 }
 
+static inline bool is_feat_spe_supported(void)
+{
+	return spe_get_version() >= ID_AA64DFR0_SPE;
+}
+
 static inline bool get_feat_pmuv3_supported(void)
 {
 	return (((read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMUVER_SHIFT) &
diff --git a/include/runtime_services/cactus_test_cmds.h b/include/runtime_services/cactus_test_cmds.h
index 0630753..282cfbe 100644
--- a/include/runtime_services/cactus_test_cmds.h
+++ b/include/runtime_services/cactus_test_cmds.h
@@ -201,10 +201,12 @@
 static inline struct ffa_value cactus_mem_send_cmd(
 	ffa_id_t source, ffa_id_t dest, uint32_t mem_func,
 	ffa_memory_handle_t handle, ffa_memory_region_flags_t retrieve_flags,
-	uint16_t word_to_write, bool expect_exception)
+	uint16_t word_to_write, bool expect_exception, bool is_normal_memory)
 {
 	uint64_t _expect_exception = expect_exception ? (1ULL << 32) : 0;
-	uint64_t packed = (uint64_t)word_to_write | _expect_exception;
+	uint64_t _is_normal_memory = is_normal_memory ? (1ULL << 33) : 0;
+	uint64_t packed = (uint64_t)word_to_write | _expect_exception |
+			  _is_normal_memory;
 
 	return cactus_send_cmd(source, dest, CACTUS_MEM_SEND_CMD, mem_func,
 			       handle, retrieve_flags, packed);
@@ -229,7 +231,12 @@
 
 static inline bool cactus_mem_send_expect_exception(struct ffa_value ret)
 {
-	return (bool)(ret.arg7 >> 32);
+	return (bool)((ret.arg7 >> 32) & 0x1);
+}
+
+static inline bool cactus_mem_send_is_normal_memory(struct ffa_value ret)
+{
+	return (bool)((ret.arg7 >> 33) & 0x1);
 }
 
 /**
diff --git a/include/runtime_services/spm_common.h b/include/runtime_services/spm_common.h
index 6c01751..3fe154a 100644
--- a/include/runtime_services/spm_common.h
+++ b/include/runtime_services/spm_common.h
@@ -113,7 +113,8 @@
 bool memory_retrieve(struct mailbox_buffers *mb,
 		     struct ffa_memory_region **retrieved, uint64_t handle,
 		     ffa_id_t sender, struct ffa_memory_access receivers[],
-		     uint32_t receiver_count, ffa_memory_region_flags_t flags);
+		     uint32_t receiver_count, ffa_memory_region_flags_t flags,
+		     bool is_normal_memory);
 
 bool hypervisor_retrieve_request(struct mailbox_buffers *mb, uint64_t handle,
 				 void *out, uint32_t out_size);
diff --git a/spm/cactus/cactus_main.c b/spm/cactus/cactus_main.c
index 1d5cd97..28afbfb 100644
--- a/spm/cactus/cactus_main.c
+++ b/spm/cactus/cactus_main.c
@@ -111,9 +111,9 @@
 }
 
 static const mmap_region_t cactus_mmap[] __attribute__((used)) = {
-	/* PLAT_ARM_DEVICE0 area includes UART2 necessary to console */
-	MAP_REGION_FLAT(PLAT_ARM_DEVICE0_BASE, PLAT_ARM_DEVICE0_SIZE,
+	MAP_REGION_FLAT(PLAT_CACTUS_DEVICE_BASE, PLAT_CACTUS_DEVICE_SIZE,
 			MT_DEVICE | MT_RW),
+
 	/* scratch memory allocated to be used for running SMMU tests */
 	MAP_REGION_FLAT(PLAT_CACTUS_MEMCPY_BASE, PLAT_CACTUS_MEMCPY_RANGE,
 			MT_MEMORY | MT_RW),
@@ -328,7 +328,7 @@
 	register_maintenance_interrupt_handlers();
 
 	/* Invoking self tests */
-	ffa_tests(&mb);
+	ffa_tests(&mb, true);
 	cpu_feature_tests();
 
 msg_loop:
diff --git a/spm/cactus/cactus_tests/cactus_test_memory_sharing.c b/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
index 811c79f..570c648 100644
--- a/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
+++ b/spm/cactus/cactus_tests/cactus_test_memory_sharing.c
@@ -114,6 +114,8 @@
 					 cactus_mem_send_get_retrv_flags(*args);
 	uint32_t words_to_write = cactus_mem_send_words_to_write(*args);
 	bool expect_exception = cactus_mem_send_expect_exception(*args);
+	bool is_normal_memory = cactus_mem_send_is_normal_memory(*args);
+
 
 	struct ffa_memory_access receiver = ffa_memory_access_init(
 		vm_id, FFA_DATA_ACCESS_RW,
@@ -123,7 +125,7 @@
 		0, NULL);
 
 	EXPECT(memory_retrieve(mb, &m, handle, source, &receiver, 1,
-			       retrv_flags),
+			       retrv_flags, is_normal_memory),
 	       true);
 
 	composite = ffa_memory_region_get_composite(m, 0);
@@ -337,7 +339,7 @@
 	}
 
 	ffa_ret = cactus_mem_send_cmd(vm_id, receiver_id, mem_func, handle,
-				      0, 10, false);
+				      0, 10, false, true);
 
 	if (!is_ffa_direct_response(ffa_ret)) {
 		return cactus_error_resp(vm_id, source, CACTUS_ERROR_FFA_CALL);
diff --git a/spm/cactus/plat/arm/fvp/include/sp_platform_def.h b/spm/cactus/plat/arm/fvp/include/sp_platform_def.h
index bb57ce8..390294f 100644
--- a/spm/cactus/plat/arm/fvp/include/sp_platform_def.h
+++ b/spm/cactus/plat/arm/fvp/include/sp_platform_def.h
@@ -18,8 +18,13 @@
 #define PLAT_SP_RX_BASE			ULL(0x7300000)
 #define PLAT_SP_CORE_COUNT		U(8)
 
-#define PLAT_ARM_DEVICE0_BASE		DEVICE0_BASE
-#define PLAT_ARM_DEVICE0_SIZE		DEVICE0_SIZE
+/*
+ * Map the device memory starting from UART2
+ * so UART0 can be lent by tftf in the device memory sharing tests.
+ */
+#define PLAT_CACTUS_DEVICE_BASE		PL011_UART2_BASE
+#define PLAT_CACTUS_DEVICE_SIZE		DEVICE0_SIZE - \
+					(PLAT_CACTUS_DEVICE_BASE - DEVICE0_BASE)
 
 /* Scratch memory used for SMMUv3 driver testing purposes in Cactus SP */
 #define PLAT_CACTUS_MEMCPY_BASE			ULL(0x7400000)
diff --git a/spm/cactus/plat/arm/tc/include/sp_platform_def.h b/spm/cactus/plat/arm/tc/include/sp_platform_def.h
index b3a3514..7211dd0 100644
--- a/spm/cactus/plat/arm/tc/include/sp_platform_def.h
+++ b/spm/cactus/plat/arm/tc/include/sp_platform_def.h
@@ -18,8 +18,8 @@
 #define PLAT_SP_RX_BASE			ULL(0xfe300000)
 #define PLAT_SP_CORE_COUNT		U(8)
 
-#define PLAT_ARM_DEVICE0_BASE		TC_DEVICE0_BASE
-#define PLAT_ARM_DEVICE0_SIZE		TC_DEVICE0_SIZE
+#define PLAT_CACTUS_DEVICE_BASE		TC_DEVICE0_BASE
+#define PLAT_CACTUS_DEVICE_SIZE		TC_DEVICE0_SIZE
 
 /* Scratch memory used for SMMUv3 driver testing purposes in Cactus SP */
 /* SMMUv3 tests are disabled for TC platform */
diff --git a/spm/cactus_mm/cactus_mm_service_loop.c b/spm/cactus_mm/cactus_mm_service_loop.c
index dbec190..4226767 100644
--- a/spm/cactus_mm/cactus_mm_service_loop.c
+++ b/spm/cactus_mm/cactus_mm_service_loop.c
@@ -90,10 +90,13 @@
 			uint32_t ctx_size = svc_values.arg2;
 			uint64_t cookie = svc_values.arg3;
 
-			NOTICE("Cactus: Received MM_COMMUNICATE_AARCH64 call\n");
-			NOTICE("Cactus:   Context address: 0x%llx\n", ctx_addr);
-			NOTICE("Cactus:   Context size   : %u\n", ctx_size);
-			NOTICE("Cactus:   Cookie         : 0x%llx\n", cookie);
+			(void) cookie;
+			(void) ctx_size;
+
+			VERBOSE("Cactus: Received MM_COMMUNICATE_AARCH64 call\n");
+			VERBOSE("Cactus:   Context address: 0x%llx\n", ctx_addr);
+			VERBOSE("Cactus:   Context size   : %u\n", ctx_size);
+			VERBOSE("Cactus:   Cookie         : 0x%llx\n", cookie);
 
 			if (ctx_addr == 0) {
 				ERROR("Context address is invalid\n");
@@ -102,7 +105,7 @@
 			}
 
 			secure_partition_request_info_t *sps = (void *)(uintptr_t) ctx_addr;
-			NOTICE("Received fast secure service request with ID #%u\n",
+			INFO("Received fast secure service request with ID #%u\n",
 			       sps->id);
 			event_status_code = cactus_handle_fast_request(64, sps);
 			break;
@@ -114,10 +117,13 @@
 			uint32_t ctx_size = svc_values.arg2;
 			uint32_t cookie = svc_values.arg3;
 
-			NOTICE("Cactus: Received MM_COMMUNICATE_AARCH32 call\n");
-			NOTICE("Cactus:   Context address: 0x%x\n", ctx_addr);
-			NOTICE("Cactus:   Context size   : %u\n", ctx_size);
-			NOTICE("Cactus:   Cookie         : 0x%x\n", cookie);
+			(void) cookie;
+			(void) ctx_size;
+
+			VERBOSE("Cactus: Received MM_COMMUNICATE_AARCH32 call\n");
+			VERBOSE("Cactus:   Context address: 0x%x\n", ctx_addr);
+			VERBOSE("Cactus:   Context size   : %u\n", ctx_size);
+			VERBOSE("Cactus:   Cookie         : 0x%x\n", cookie);
 
 			if (ctx_addr == 0) {
 				ERROR("Context address is invalid\n");
@@ -126,8 +132,8 @@
 			}
 
 			secure_partition_request_info_t *sps = (void *)(uintptr_t) ctx_addr;
-			NOTICE("Received fast secure service request with ID #%u\n",
-			       sps->id);
+			INFO("Received fast secure service request with ID #%u\n",
+			      sps->id);
 			event_status_code = cactus_handle_fast_request(32, sps);
 			break;
 		  }
diff --git a/spm/cactus_mm/cactus_mm_tests_memory_attributes.c b/spm/cactus_mm/cactus_mm_tests_memory_attributes.c
index 0a7af5f..d0ca6d3 100644
--- a/spm/cactus_mm/cactus_mm_tests_memory_attributes.c
+++ b/spm/cactus_mm/cactus_mm_tests_memory_attributes.c
@@ -44,10 +44,10 @@
 					int pages_count,
 					uint32_t memory_access_controls)
 {
-	INFO("Requesting memory attributes change\n");
-	INFO("  Start address  : %p\n", (void *) base_address);
-	INFO("  Number of pages: %i\n", pages_count);
-	INFO("  Attributes     : 0x%x\n", memory_access_controls);
+	VERBOSE("Requesting memory attributes change\n");
+	VERBOSE("  Start address  : %p\n", (void *) base_address);
+	VERBOSE("  Number of pages: %i\n", pages_count);
+	VERBOSE("  Attributes     : 0x%x\n", memory_access_controls);
 
 	svc_args svc_values = { SP_MEMORY_ATTRIBUTES_SET_AARCH64,
 				base_address,
@@ -62,8 +62,8 @@
  */
 static int32_t request_get_mem_attr(uintptr_t base_address)
 {
-	INFO("Requesting memory attributes\n");
-	INFO("  Base address  : %p\n", (void *) base_address);
+	VERBOSE("Requesting memory attributes\n");
+	VERBOSE("  Base address  : %p\n", (void *) base_address);
 
 	svc_args svc_values = { SP_MEMORY_ATTRIBUTES_GET_AARCH64,
 				base_address };
@@ -105,8 +105,9 @@
 	new_attr = mem_access_perm(SP_MEMORY_ATTRIBUTES_NON_EXEC, SP_MEMORY_ATTRIBUTES_ACCESS_RW);
 
 	ret = request_mem_attr_changes(addr, pages_count, new_attr);
+
 	EXPECT(ret, SPM_SUCCESS);
-	printf("Successfully changed memory attributes\n");
+	VERBOSE("Successfully changed memory attributes\n");
 
 	/* The attributes should be the ones we have just written. */
 	ret = request_get_mem_attr(addr);
@@ -118,12 +119,13 @@
 	     ++data) {
 		*data = 42;
 	}
-	printf("Successfully wrote to the memory\n");
+	VERBOSE("Successfully wrote to the memory\n");
 
 	/* Let's revert back to the original attributes for the next test */
 	ret = request_mem_attr_changes(addr, pages_count, old_attr);
+
 	EXPECT(ret, SPM_SUCCESS);
-	printf("Successfully restored the old attributes\n");
+	VERBOSE("Successfully restored the old attributes\n");
 
 	/* The attributes should be the original ones again. */
 	ret = request_get_mem_attr(addr);
diff --git a/spm/common/sp_tests/sp_test_ffa.c b/spm/common/sp_tests/sp_test_ffa.c
index ba63a0e..6e7fe1a 100644
--- a/spm/common/sp_tests/sp_test_ffa.c
+++ b/spm/common/sp_tests/sp_test_ffa.c
@@ -78,13 +78,13 @@
 /*
  * Test FFA_FEATURES interface.
  */
-static void ffa_features_test(void)
+static void ffa_features_test(bool el1_partition)
 {
 	const struct ffa_features_test *func_id_targets;
 	/* Get common features between tftf and cactus. */
 	unsigned int test_target_size =
 		get_ffa_feature_test_target(&func_id_targets);
-	const struct ffa_features_test feature_id_targets[] = {
+	struct ffa_features_test feature_id_targets[3] = {
 		{"FFA_FEATURE_MEI", FFA_FEATURE_MEI, FFA_SUCCESS_SMC32, 0,
 			FFA_VERSION_1_1},
 		{"FFA_FEATURE_SRI", FFA_FEATURE_SRI, FFA_ERROR, 0,
@@ -97,6 +97,12 @@
 	ffa_features_test_targets(func_id_targets, test_target_size);
 
 	/* Features are expected to be different to tftf. */
+
+	/* EL0 partitions don't support NPI. */
+	if (!el1_partition) {
+		feature_id_targets[2].expected_ret = FFA_ERROR;
+	}
+
 	ffa_features_test_targets(feature_id_targets,
 			ARRAY_SIZE(feature_id_targets));
 }
@@ -234,13 +240,13 @@
 	}
 }
 
-void ffa_tests(struct mailbox_buffers *mb)
+void ffa_tests(struct mailbox_buffers *mb, bool el1_partition)
 {
 	const char *test_ffa_str = "FF-A setup and discovery";
 
 	announce_test_section_start(test_ffa_str);
 
-	ffa_features_test();
+	ffa_features_test(el1_partition);
 	ffa_version_test();
 	ffa_spm_id_get_test();
 	ffa_partition_info_get_test(mb);
diff --git a/spm/common/sp_tests/sp_tests.h b/spm/common/sp_tests/sp_tests.h
index 007c2ca..f56d7e8 100644
--- a/spm/common/sp_tests/sp_tests.h
+++ b/spm/common/sp_tests/sp_tests.h
@@ -13,7 +13,7 @@
  * Self test functions
  */
 
-void ffa_tests(struct mailbox_buffers *mb);
+void ffa_tests(struct mailbox_buffers *mb, bool el1_partition);
 void cpu_feature_tests(void);
 
 #endif /* CACTUS_TESTS_H */
diff --git a/spm/ivy/app/ivy_main.c b/spm/ivy/app/ivy_main.c
index 861ef30..53dbf73 100644
--- a/spm/ivy/app/ivy_main.c
+++ b/spm/ivy/app/ivy_main.c
@@ -47,7 +47,7 @@
 		panic();
 	}
 
-	ffa_tests(&mb);
+	ffa_tests(&mb, false);
 
 	ret = ffa_msg_wait();
 
diff --git a/tftf/tests/common/test_helpers.c b/tftf/tests/common/test_helpers.c
index 6a0b08b..adcac3d 100644
--- a/tftf/tests/common/test_helpers.c
+++ b/tftf/tests/common/test_helpers.c
@@ -160,3 +160,22 @@
 {
 	return ((unsigned long long)rand() << 32) | rand();
 }
+
+/* Check if TRBE erratums 2938996 and 2726228 applies */
+bool is_trbe_errata_affected_core(void)
+{
+        long midr_val = read_midr();
+        long rev_var = EXTRACT_REV_VAR(midr_val);
+
+        if(EXTRACT_PARTNUM(midr_val) == EXTRACT_PARTNUM(CORTEX_A520_MIDR)) {
+                if(RXPX_RANGE(rev_var, 0, 1)) {
+                        return true;
+                }
+        } else if (EXTRACT_PARTNUM(midr_val) == EXTRACT_PARTNUM(CORTEX_X4_MIDR)) {
+                if(RXPX_RANGE(rev_var, 0, 1)) {
+                        return true;
+                }
+        }
+
+        return false;
+}
diff --git a/tftf/tests/extensions/trbe/test_trbe.c b/tftf/tests/extensions/trbe/test_trbe.c
index 8ef9576..4de48dc 100644
--- a/tftf/tests/extensions/trbe/test_trbe.c
+++ b/tftf/tests/extensions/trbe/test_trbe.c
@@ -21,6 +21,12 @@
 
 #ifdef __aarch64__
 	SKIP_TEST_IF_TRBE_NOT_SUPPORTED();
+
+	/* If TRBE errata applies, EL3 disables the feature, SKIP the test */
+	if (is_trbe_errata_affected_core()) {
+		return TEST_RESULT_SKIPPED;
+	}
+
 	read_trblimitr_el1();
 	read_trbptr_el1();
 	read_trbbaser_el1();
diff --git a/tftf/tests/misc_tests/test_asymmetric_features.c b/tftf/tests/misc_tests/test_asymmetric_features.c
new file mode 100644
index 0000000..25b2421
--- /dev/null
+++ b/tftf/tests/misc_tests/test_asymmetric_features.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <arch.h>
+#include <arch_helpers.h>
+#include <arm_arch_svc.h>
+#include <events.h>
+#include <plat_topology.h>
+#include <platform.h>
+#include <platform_def.h>
+#include <power_management.h>
+#include <psci.h>
+#include <smccc.h>
+#include <sync.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+
+static event_t cpu_has_entered_test[PLATFORM_CORE_COUNT];
+
+static volatile bool undef_injection_triggered;
+
+static unsigned int test_result;
+
+static bool undef_injection_handler(void)
+{
+	uint64_t esr_el2 = read_esr_el2();
+	if (EC_BITS(esr_el2) == EC_UNKNOWN) {
+		undef_injection_triggered = true;
+		return true;
+	}
+
+	return false;
+}
+
+static test_result_t test_trbe(void)
+{
+	unsigned int mpid = read_mpidr_el1() & MPID_MASK;
+	unsigned int core_pos = platform_get_core_pos(mpid);
+	bool check_if_affected = is_trbe_errata_affected_core();
+
+	read_trblimitr_el1();
+
+	if (undef_injection_triggered == true && check_if_affected == true) {
+		test_result = TEST_RESULT_SUCCESS;
+		undef_injection_triggered = false;
+		tftf_testcase_printf("Undef injection triggered for core = %d "
+				     "when accessing TRB_LIMTR\n", core_pos);
+	} else if (undef_injection_triggered == false && check_if_affected == false) {
+		test_result = TEST_RESULT_SUCCESS;
+		tftf_testcase_printf("TRB_LIMITR register accessible for core "
+				     "= %d\n", core_pos);
+	} else {
+		test_result = TEST_RESULT_FAIL;
+	}
+
+	return test_result;
+}
+
+static test_result_t test_spe(void)
+{
+	unsigned int mpid = read_mpidr_el1() & MPID_MASK;
+	unsigned int core_pos = platform_get_core_pos(mpid);
+
+	read_pmscr_el1();
+
+	if (undef_injection_triggered == true && !is_feat_spe_supported()) {
+		test_result = TEST_RESULT_SUCCESS;
+		undef_injection_triggered = false;
+		tftf_testcase_printf("Undef injection triggered for core = %d "
+				     "when accessing PMSCR_EL1\n", core_pos);
+	} else if (undef_injection_triggered == false &&
+		   is_feat_spe_supported()) {
+		test_result = TEST_RESULT_SUCCESS;
+		tftf_testcase_printf("PMSCR_EL1 register accessible for core = "
+				     "%d\n", core_pos);
+	} else {
+		test_result = TEST_RESULT_FAIL;
+	}
+
+	return test_result;
+}
+
+/*
+ * Non-lead cpu function that checks if trblimitr_el1 is accessible,
+ * on affected cores this causes a undef injection and passes.In cores that
+ * are not affected test just passes. It fails in other cases.
+ */
+static test_result_t non_lead_cpu_fn(void)
+{
+	unsigned int mpid = read_mpidr_el1() & MPID_MASK;
+	unsigned int core_pos = platform_get_core_pos(mpid);
+	test_result_t result;
+
+	test_result = TEST_RESULT_SUCCESS;
+
+	/* Signal to the lead CPU that the calling CPU has entered the test */
+	tftf_send_event(&cpu_has_entered_test[core_pos]);
+
+	result = test_trbe();
+	if (result != TEST_RESULT_SUCCESS) {
+		tftf_testcase_printf("test_trbe_enabled failed with result "
+				     "%d\n", result);
+		test_result = result;
+	}
+
+	result = test_spe();
+	if (result != TEST_RESULT_SUCCESS) {
+		tftf_testcase_printf("test_spe_support failed with result %d\n",
+				     result);
+		test_result = result;
+	}
+
+	/* Ensure that EL3 still functional */
+	smc_args args;
+	smc_ret_values smc_ret;
+	memset(&args, 0, sizeof(args));
+	args.fid = SMCCC_VERSION;
+	smc_ret = tftf_smc(&args);
+
+	tftf_testcase_printf("SMCCC Version = %d.%d\n",
+			(int)((smc_ret.ret0 >> SMCCC_VERSION_MAJOR_SHIFT) & SMCCC_VERSION_MAJOR_MASK),
+			(int)((smc_ret.ret0 >> SMCCC_VERSION_MINOR_SHIFT) & SMCCC_VERSION_MINOR_MASK));
+
+	return test_result;
+}
+
+/* This function kicks off non-lead cpus and the non-lead cpu function
+ * checks if errata is applied or not using the test.
+ */
+test_result_t test_asymmetric_features(void)
+{
+	unsigned int lead_mpid;
+	unsigned int cpu_mpid, cpu_node;
+	unsigned int core_pos;
+	int psci_ret;
+
+	test_result_t result;
+
+	test_result = TEST_RESULT_SUCCESS;
+
+	undef_injection_triggered = false;
+
+	register_custom_sync_exception_handler(undef_injection_handler);
+
+	lead_mpid = read_mpidr_el1() & MPID_MASK;
+
+	/* Testing TRBE and SPE feature in Lead core */
+	result = test_trbe();
+	if (result != TEST_RESULT_SUCCESS) {
+		tftf_testcase_printf("test_trbe_enabled failed with result "
+				     "%d\n", result);
+		test_result = result;
+	}
+
+	result = test_spe();
+	if (result != TEST_RESULT_SUCCESS) {
+		tftf_testcase_printf("test_spe_support failed with result %d\n",
+				     result);
+		test_result = result;
+	}
+
+	SKIP_TEST_IF_LESS_THAN_N_CPUS(2);
+
+	/* Power on all CPUs */
+	for_each_cpu(cpu_node) {
+		cpu_mpid = tftf_get_mpidr_from_node(cpu_node);
+		/* Skip lead CPU as it is already powered on */
+		if (cpu_mpid == lead_mpid)
+			continue;
+
+		psci_ret = tftf_cpu_on(cpu_mpid, (uintptr_t) non_lead_cpu_fn, 0);
+		if (psci_ret != PSCI_E_SUCCESS) {
+			tftf_testcase_printf(
+					"Failed to power on CPU 0x%x (%d)\n",
+					cpu_mpid, psci_ret);
+			return TEST_RESULT_SKIPPED;
+		}
+	}
+
+	/* Wait for non-lead CPUs to enter the test */
+	for_each_cpu(cpu_node) {
+		cpu_mpid = tftf_get_mpidr_from_node(cpu_node);
+		/* Skip lead CPU */
+		if (cpu_mpid == lead_mpid)
+			continue;
+
+		core_pos = platform_get_core_pos(cpu_mpid);
+		tftf_wait_for_event(&cpu_has_entered_test[core_pos]);
+		if (test_result == TEST_RESULT_FAIL)
+			break;
+	}
+
+	unregister_custom_sync_exception_handler();
+
+	return test_result;
+}
diff --git a/tftf/tests/runtime_services/secure_service/spm_common.c b/tftf/tests/runtime_services/secure_service/spm_common.c
index 53f4981..06e76db 100644
--- a/tftf/tests/runtime_services/secure_service/spm_common.c
+++ b/tftf/tests/runtime_services/secure_service/spm_common.c
@@ -270,12 +270,17 @@
 bool memory_retrieve(struct mailbox_buffers *mb,
 		     struct ffa_memory_region **retrieved, uint64_t handle,
 		     ffa_id_t sender, struct ffa_memory_access receivers[],
-		     uint32_t receiver_count, ffa_memory_region_flags_t flags)
+		     uint32_t receiver_count, ffa_memory_region_flags_t flags,
+		     bool is_normal_memory)
 {
 	struct ffa_value ret;
 	uint32_t fragment_size;
 	uint32_t total_size;
 	uint32_t descriptor_size;
+	enum ffa_memory_type memory_type = is_normal_memory ?
+		FFA_MEMORY_NORMAL_MEM : FFA_MEMORY_DEVICE_MEM;
+	enum ffa_memory_cacheability memory_cacheability = is_normal_memory ?
+		FFA_MEMORY_CACHE_WRITE_BACK : FFA_MEMORY_DEV_NGNRNE;
 
 	if (retrieved == NULL || mb == NULL) {
 		ERROR("Invalid parameters!\n");
@@ -284,8 +289,7 @@
 
 	descriptor_size = ffa_memory_retrieve_request_init(
 		mb->send, handle, sender, receivers, receiver_count, 0, flags,
-		FFA_MEMORY_NORMAL_MEM, FFA_MEMORY_CACHE_WRITE_BACK,
-		FFA_MEMORY_INNER_SHAREABLE);
+		memory_type, memory_cacheability, FFA_MEMORY_INNER_SHAREABLE);
 
 	ret = ffa_mem_retrieve_req(descriptor_size, descriptor_size);
 
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c b/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c
index cda7d22..552d2f9 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_exceptions.c
@@ -90,7 +90,7 @@
 	 * Tell SP to expect an exception.
 	 */
 	ret = cactus_mem_send_cmd(SENDER, RECEIVER, FFA_MEM_SHARE_SMC64,
-				  handle, 0, 1, true);
+				  handle, 0, 1, true, true);
 
 	/* Undelegate the shared page. */
 	retmm = host_rmi_granule_undelegate((u_register_t)&share_page);
diff --git a/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c b/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
index 3f7e270..ad4040a 100644
--- a/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
+++ b/tftf/tests/runtime_services/secure_service/test_ffa_memory_sharing.c
@@ -177,7 +177,7 @@
  */
 static test_result_t test_memory_send_sp(uint32_t mem_func, ffa_id_t borrower,
 					 struct ffa_memory_region_constituent *constituents,
-					 size_t constituents_count)
+					 size_t constituents_count, bool is_normal_memory)
 {
 	struct ffa_value ret;
 	ffa_memory_handle_t handle;
@@ -186,10 +186,13 @@
 	unsigned int rme_supported = get_armv9_2_feat_rme_support();
 	const bool check_gpc_fault =
 		mem_func != FFA_MEM_SHARE_SMC64 &&
-		rme_supported != 0U;
+		rme_supported != 0U && is_normal_memory;
 
-	/* Arbitrarily write 5 words after using memory. */
-	const uint32_t nr_words_to_write = 5;
+	/*
+	 * For normal memory arbitrarilty write 5 words after using memory.
+	 * For device just write 1 so we only write in the data register of the device.
+	 */
+	const uint32_t nr_words_to_write = is_normal_memory ? 5 : 1;
 
 	struct ffa_memory_access receiver =
 		ffa_memory_access_init_permissions_from_mem_func(borrower,
@@ -232,7 +235,7 @@
 	ptr = (uint32_t *)constituents[0].address;
 
 	ret = cactus_mem_send_cmd(SENDER, borrower, mem_func, handle, 0,
-				  nr_words_to_write, false);
+				  nr_words_to_write, false, is_normal_memory);
 
 	if (!is_ffa_direct_response(ret) ||
 	    cactus_get_response(ret) != CACTUS_SUCCESS) {
@@ -295,7 +298,7 @@
 				sizeof(struct ffa_memory_region_constituent);
 
 	return test_memory_send_sp(FFA_MEM_SHARE_SMC64, RECEIVER, constituents,
-				   constituents_count);
+				   constituents_count, true);
 }
 
 test_result_t test_mem_lend_sp(void)
@@ -309,7 +312,7 @@
 				sizeof(struct ffa_memory_region_constituent);
 
 	return test_memory_send_sp(FFA_MEM_LEND_SMC64, RECEIVER, constituents,
-				   constituents_count);
+				   constituents_count, true);
 }
 
 test_result_t test_mem_donate_sp(void)
@@ -320,7 +323,7 @@
 	const uint32_t constituents_count = sizeof(constituents) /
 				sizeof(struct ffa_memory_region_constituent);
 	return test_memory_send_sp(FFA_MEM_DONATE_SMC64, RECEIVER, constituents,
-				   constituents_count);
+				   constituents_count, true);
 }
 
 test_result_t test_consecutive_donate(void)
@@ -335,7 +338,7 @@
 
 	test_result_t ret = test_memory_send_sp(FFA_MEM_DONATE_SMC64, SP_ID(1),
 						constituents,
-						constituents_count);
+						constituents_count, true);
 
 	if (ret != TEST_RESULT_SUCCESS) {
 		ERROR("Failed at first attempting of sharing.\n");
@@ -362,6 +365,28 @@
 }
 
 /*
+ * Lend device memory to the Secure Partition.
+ */
+test_result_t test_ffa_mem_lend_device_memory_sp(void)
+{
+#if PLAT_fvp || PLAT_tc
+	struct ffa_memory_region_constituent constituents[] = {
+		{(void *)PLAT_ARM_UART_BASE, 1, 0},
+	};
+
+	const uint32_t constituents_count = sizeof(constituents) /
+				sizeof(struct ffa_memory_region_constituent);
+
+	return test_memory_send_sp(FFA_MEM_LEND_SMC64, RECEIVER, constituents,
+				   constituents_count, false);
+#else
+	return TEST_RESULT_SKIPPED;
+#endif
+
+}
+
+
+/*
  * Test requests a memory send operation between cactus SPs.
  * Cactus SP should reply to TFTF on whether the test succeeded or not.
  */
@@ -527,7 +552,7 @@
 
 	ret = cactus_mem_send_cmd(SENDER, RECEIVER, FFA_MEM_LEND_SMC64, handle,
 				  FFA_MEMORY_REGION_FLAG_CLEAR,
-				  nr_words_to_write, false);
+				  nr_words_to_write, false, true);
 
 	if (!is_ffa_direct_response(ret)) {
 		return TEST_RESULT_FAIL;
@@ -1322,7 +1347,8 @@
 		return TEST_RESULT_FAIL;
 	}
 
-	if (!memory_retrieve(&mb, &m, handle, 0, receivers, ARRAY_SIZE(receivers), 0)) {
+	if (!memory_retrieve(&mb, &m, handle, 0, receivers, ARRAY_SIZE(receivers),
+			     0, true)) {
 		ERROR("Failed to retrieve the memory.\n");
 		return TEST_RESULT_FAIL;
 	}
@@ -1503,7 +1529,8 @@
 		return TEST_RESULT_FAIL;
 	}
 
-	if (!memory_retrieve(&mb, &m, handle, 0, receivers, ARRAY_SIZE(receivers), 0)) {
+	if (!memory_retrieve(&mb, &m, handle, 0, receivers, ARRAY_SIZE(receivers),
+			     0, true)) {
 		ERROR("Failed to retrieve the memory.\n");
 		return TEST_RESULT_FAIL;
 	}
diff --git a/tftf/tests/tests-asymmetric-features.mk b/tftf/tests/tests-asymmetric-features.mk
new file mode 100644
index 0000000..86bb276
--- /dev/null
+++ b/tftf/tests/tests-asymmetric-features.mk
@@ -0,0 +1,7 @@
+#
+# Copyright (c) 2024, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+TESTS_SOURCES	+=	tftf/tests/misc_tests/test_asymmetric_features.c
diff --git a/tftf/tests/tests-asymmetric-features.xml b/tftf/tests/tests-asymmetric-features.xml
new file mode 100644
index 0000000..413ef2c
--- /dev/null
+++ b/tftf/tests/tests-asymmetric-features.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  Copyright (c) 2024, Arm Limited. All rights reserved.
+
+  SPDX-License-Identifier: BSD-3-Clause
+-->
+
+<testsuites>
+  <testsuite name="Asymmetric Features" description="Asymmetric features support">
+      <testcase name="Asymmetric Features"
+                function="test_asymmetric_features" />
+  </testsuite>
+</testsuites>
diff --git a/tftf/tests/tests-memory-access.xml b/tftf/tests/tests-memory-access.xml
index 49965a0..200c5dd 100644
--- a/tftf/tests/tests-memory-access.xml
+++ b/tftf/tests/tests-memory-access.xml
@@ -18,6 +18,8 @@
                function="test_mem_share_sp" />
      <testcase name="Donate Memory to Secure World"
                function="test_mem_donate_sp"/>
+      <testcase name="Lend Device Memory to Secure World"
+	        function="test_ffa_mem_lend_device_memory_sp" />
      <testcase name="Request Share Memory SP-to-SP"
                function="test_req_mem_share_sp_to_sp" />
      <testcase name="Request Lend Memory SP-to-SP"