Merge changes from topic "bk/smccc_feature"

* changes:
  fix(brbe): report BRBE support with later revisions
  test(SMCCC): test SMCCC_ARCH_FEATURE_AVAILABILITY
  refactor(SMCCC): use a macro to check for the SMCCC version
  feat: add register definitions needed for SMCCC_ARCH_FEATURE_AVAILABILITY
diff --git a/include/common/test_helpers.h b/include/common/test_helpers.h
index fe29ee5..124cc4e 100644
--- a/include/common/test_helpers.h
+++ b/include/common/test_helpers.h
@@ -88,6 +88,34 @@
 		}								\
 	} while (0)
 
+#define SKIP_TEST_IF_SMCCC_VERSION_LT(major, minor)				\
+	do {									\
+		smc_args args = {0};						\
+		smc_ret_values ret;						\
+		args.fid = SMCCC_VERSION;					\
+		ret = tftf_smc(&args);						\
+		if ((int32_t)ret.ret0 < MAKE_SMCCC_VERSION(major, minor)) {	\
+			tftf_testcase_printf(					\
+				"Unexpected SMCCC version: 0x%x\n",		\
+			       (int)ret.ret0);					\
+			return TEST_RESULT_SKIPPED;				\
+		}								\
+	} while (0)
+
+#define SKIP_TEST_IF_SMCCC_FUNC_NOT_SUPPORTED(func)				\
+	do {									\
+		smc_ret_values ret;						\
+		smc_args args = {0};						\
+		args.fid = SMCCC_ARCH_FEATURES;					\
+		args.arg1 = func;						\
+		ret = tftf_smc(&args);						\
+		if ((int)ret.ret0 == SMC_ARCH_CALL_NOT_SUPPORTED) {		\
+			tftf_testcase_printf(					\
+				#func " is not implemented\n");			\
+			return TEST_RESULT_SKIPPED;				\
+		}								\
+	} while (0)
+
 #define SKIP_TEST_IF_DIT_NOT_SUPPORTED()					\
 	do {									\
 		if (!is_armv8_4_dit_present()) {				\
@@ -212,7 +240,7 @@
 
 #define SKIP_TEST_IF_TRBE_NOT_SUPPORTED()					\
 	do {									\
-		if (!get_armv9_0_trbe_support()) {				\
+		if (!is_feat_trbe_present()) {					\
 			tftf_testcase_printf("ARMv9-TRBE not supported\n");	\
 			return TEST_RESULT_SKIPPED;				\
 		}								\
diff --git a/include/lib/aarch32/arch_features.h b/include/lib/aarch32/arch_features.h
index 3c6a338..999f7ec 100644
--- a/include/lib/aarch32/arch_features.h
+++ b/include/lib/aarch32/arch_features.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -59,4 +59,11 @@
 {
 	return 0;
 }
+
+static inline unsigned int amu_get_version(void)
+{
+	return (unsigned int)(read_id_pfr0() >> ID_PFR0_AMU_SHIFT) &
+		ID_PFR0_AMU_MASK;
+}
+
 #endif /* ARCH_FEATURES_H */
diff --git a/include/lib/aarch64/arch.h b/include/lib/aarch64/arch.h
index f0c10ef..c640fc7 100644
--- a/include/lib/aarch64/arch.h
+++ b/include/lib/aarch64/arch.h
@@ -218,6 +218,12 @@
 #define ID_AA64PFR0_CSV2_SUPPORTED		ULL(0x1)
 #define ID_AA64PFR0_CSV2_2_SUPPORTED		ULL(0x2)
 
+/* ID_AA64DFR0_EL1.DoubleLock definitions */
+#define ID_AA64DFR0_DOUBLELOCK_SHIFT		U(36)
+#define ID_AA64DFR0_DOUBLELOCK_MASK		ULL(0xf)
+#define ID_AA64DFR0_DOUBLELOCK_WIDTH		U(4)
+#define DOUBLELOCK_IMPLEMENTED			ULL(0)
+
 /* ID_AA64DFR0_EL1.PMS definitions (for ARMv8.2+) */
 #define ID_AA64DFR0_PMS_SHIFT		U(32)
 #define ID_AA64DFR0_PMS_LENGTH		U(4)
@@ -260,6 +266,7 @@
 /* ID_DFR0_EL1.Tracefilt definitions */
 #define ID_AA64DFR0_TRACEFILT_SHIFT		U(40)
 #define ID_AA64DFR0_TRACEFILT_MASK		U(0xf)
+#define ID_AA64DFR0_TRACEFILT_WIDTH		U(4)
 #define ID_AA64DFR0_TRACEFILT_SUPPORTED		U(1)
 
 /* ID_AA64DFR0_EL1.PMUVer definitions */
@@ -611,37 +618,110 @@
 
 /* SCR definitions */
 #define SCR_RES1_BITS		((U(1) << 4) | (U(1) << 5))
-#define SCR_AMVOFFEN_BIT	(UL(1) << 35)
-#define SCR_ATA_BIT		(U(1) << 26)
-#define SCR_FIEN_BIT		(U(1) << 21)
-#define SCR_API_BIT		(U(1) << 17)
-#define SCR_APK_BIT		(U(1) << 16)
-#define SCR_TWE_BIT		(U(1) << 13)
-#define SCR_TWI_BIT		(U(1) << 12)
-#define SCR_ST_BIT		(U(1) << 11)
-#define SCR_RW_BIT		(U(1) << 10)
-#define SCR_SIF_BIT		(U(1) << 9)
-#define SCR_HCE_BIT		(U(1) << 8)
-#define SCR_SMD_BIT		(U(1) << 7)
-#define SCR_EA_BIT		(U(1) << 3)
-#define SCR_FIQ_BIT		(U(1) << 2)
-#define SCR_IRQ_BIT		(U(1) << 1)
-#define SCR_NS_BIT		(U(1) << 0)
+#define SCR_NSE_SHIFT		U(62)
+#define SCR_FGTEN2_BIT		(UL(1) << 59)
+#define SCR_NSE_BIT		(ULL(1) << SCR_NSE_SHIFT)
+#define SCR_EnIDCP128_BIT	(UL(1) << 55)
+#define SCR_PFAREn_BIT		(UL(1) << 53)
+#define SCR_TWERR_BIT		(UL(1) << 52)
+#define SCR_TMEA_BIT		(UL(1) << 51)
+#define SCR_EnFPM_BIT		(UL(1) << 50)
+#define SCR_MECEn_BIT		(UL(1) << 49)
+#define SCR_GPF_BIT		(UL(1) << 48)
+#define SCR_D128En_BIT		(UL(1) << 47)
+#define SCR_AIEn_BIT		(UL(1) << 46)
+#define SCR_TWEDEL_SHIFT	U(30)
+#define SCR_TWEDEL_MASK		ULL(0xf)
+#define SCR_PIEN_BIT		(UL(1) << 45)
+#define SCR_SCTLR2En_BIT	(UL(1) << 44)
+#define SCR_TCR2EN_BIT		(UL(1) << 43)
+#define SCR_RCWMASKEn_BIT	(UL(1) << 42)
+#define SCR_ENTP2_SHIFT		U(41)
+#define SCR_TRNDR_BIT		(UL(1) << 40)
+#define SCR_GCSEn_BIT		(UL(1) << 39)
+#define SCR_HXEn_BIT		(UL(1) << 38)
+#define SCR_ADEn_BIT		(UL(1) << 37)
+#define SCR_EnAS0_BIT		(UL(1) << 36)
+#define SCR_ENTP2_BIT		(UL(1) << SCR_ENTP2_SHIFT)
+#define SCR_AMVOFFEN_SHIFT	U(35)
+#define SCR_AMVOFFEN_BIT	(UL(1) << SCR_AMVOFFEN_SHIFT)
+#define SCR_TME_BIT		(UL(1) << 34)
+#define SCR_TWEDEn_BIT		(UL(1) << 29)
+#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_NMEA_BIT		(UL(1) << 20)
+#define SCR_EASE_BIT		(UL(1) << 19)
+#define SCR_EEL2_BIT		(UL(1) << 18)
+#define SCR_API_BIT		(UL(1) << 17)
+#define SCR_APK_BIT		(UL(1) << 16)
+#define SCR_TERR_BIT		(UL(1) << 15)
+#define SCR_TLOR_BIT		(UL(1) << 14)
+#define SCR_TWE_BIT		(UL(1) << 13)
+#define SCR_TWI_BIT		(UL(1) << 12)
+#define SCR_ST_BIT		(UL(1) << 11)
+#define SCR_RW_BIT		(UL(1) << 10)
+#define SCR_SIF_BIT		(UL(1) << 9)
+#define SCR_HCE_BIT		(UL(1) << 8)
+#define SCR_SMD_BIT		(UL(1) << 7)
+#define SCR_EA_BIT		(UL(1) << 3)
+#define SCR_FIQ_BIT		(UL(1) << 2)
+#define SCR_IRQ_BIT		(UL(1) << 1)
+#define SCR_NS_BIT		(UL(1) << 0)
+#define SCR_RES1_BITS		((U(1) << 4) | (U(1) << 5))
 #define SCR_VALID_BIT_MASK	U(0x2f8f)
 #define SCR_RESET_VAL		SCR_RES1_BITS
 
 /* MDCR_EL3 definitions */
+#define MDCR_EnSTEPOP_BIT	(ULL(1) << 50)
+#define MDCR_ETBAD(x)		((x) << 48)
+#define MDCR_EnITE_BIT		(ULL(1) << 47)
+#define MDCR_EPMSSAD(x)		(ULL(x) << 45)
+#define MDCR_EnPMSS_BIT		(ULL(1) << 44)
+#define MDCR_EBWE_BIT		(ULL(1) << 43)
+#define MDCR_EnPMS3_BIT		(ULL(1) << 42)
+#define MDCR_PMEE(x)		((x) << 40)
+#define MDCR_EnTB2_BIT		(ULL(1) << 39)
+#define MDCR_E3BREC_BIT		(ULL(1) << 38)
+#define MDCR_E3BREW_BIT		(ULL(1) << 37)
+#define MDCR_EnPMSN_BIT		(ULL(1) << 36)
+#define MDCR_MPMX_BIT		(ULL(1) << 35)
+#define MDCR_MCCD_BIT		(ULL(1) << 34)
+#define MDCR_SBRBE_SHIFT	U(32)
+#define MDCR_SBRBE_MASK		ULL(0x3)
+#define MDCR_SBRBE(x)		(ULL(x) << MDCR_SBRBE_SHIFT)
+#define MDCR_PMSSE(x)		((x) << 30)
+#define MDCR_NSTBE_BIT		(ULL(1) << 26)
+#define MDCR_NSTB(x)		((x) << 24)
+#define MDCR_NSTB_EL1		ULL(0x3)
+#define MDCR_NSTBE_BIT		(ULL(1) << 26)
+#define MDCR_MTPME_BIT		(ULL(1) << 28)
+#define MDCR_TDCC_BIT		(ULL(1) << 27)
+#define MDCR_SCCD_BIT		(ULL(1) << 23)
+#define MDCR_ETAD_BIT		(ULL(1) << 22)
+#define MDCR_EPMAD_BIT		(ULL(1) << 21)
+#define MDCR_EDAD_BIT		(ULL(1) << 20)
+#define MDCR_TTRF_BIT		(ULL(1) << 19)
+#define MDCR_STE_BIT		(ULL(1) << 18)
+#define MDCR_SPME_BIT		(ULL(1) << 17)
+#define MDCR_SDD_BIT		(ULL(1) << 16)
 #define MDCR_SPD32(x)		((x) << 14)
 #define MDCR_SPD32_LEGACY	ULL(0x0)
 #define MDCR_SPD32_DISABLE	ULL(0x2)
 #define MDCR_SPD32_ENABLE	ULL(0x3)
-#define MDCR_SDD_BIT		(ULL(1) << 16)
 #define MDCR_NSPB(x)		((x) << 12)
 #define MDCR_NSPB_EL1		ULL(0x3)
+#define MDCR_NSPBE_BIT		(ULL(1) << 11)
 #define MDCR_TDOSA_BIT		(ULL(1) << 10)
 #define MDCR_TDA_BIT		(ULL(1) << 9)
+#define MDCR_EnPM2_BIT		(ULL(1) << 7)
 #define MDCR_TPM_BIT		(ULL(1) << 6)
-#define MDCR_SCCD_BIT		(ULL(1) << 23)
+#define MDCR_EDADE_BIT		(ULL(1) << 4)
+#define MDCR_ETADE_BIT		(ULL(1) << 3)
+#define MDCR_EPMADE_BIT		(ULL(1) << 2)
+#define MDCR_RLTE_BIT		(ULL(1) << 0)
 #define MDCR_EL3_RESET_VAL	ULL(0x0)
 
 /* MDCR_EL2 definitions */
@@ -707,6 +787,14 @@
 #define EVNTI_SHIFT		U(4)
 #define EVNTI_MASK		U(0xf)
 
+/* CPTR_EL3 definitions */
+#define CPTR_EL3_TCPAC_BIT	(ULL(1) << 31)
+#define CPTR_EL3_TAM_BIT	(ULL(1) << 30)
+#define CPTR_EL3_TTA_BIT	(ULL(1) << 20)
+#define CPTR_EL3_ESM_BIT	(ULL(1) << 12)
+#define CPTR_EL3_TFP_BIT	(ULL(1) << 10)
+#define CPTR_EL3_EZ_BIT		(ULL(1) << 8)
+
 /* CPTR_EL2 definitions */
 #define CPTR_EL2_RES1		((ULL(1) << 13) | (ULL(1) << 9) | (ULL(0xff)))
 #define CPTR_EL2_TCPAC_BIT	(ULL(1) << 31)
@@ -1285,6 +1373,7 @@
 
 /* MPAM register definitions */
 #define MPAM3_EL3_MPAMEN_BIT		(ULL(1) << 63)
+#define MPAM3_EL3_TRAPLOWER_BIT		(ULL(1) << 62)
 #define MPAMHCR_EL2_TRAP_MPAMIDR_EL1	(ULL(1) << 31)
 
 #define MPAM2_EL2_TRAPMPAM0EL1		(ULL(1) << 49)
diff --git a/include/lib/aarch64/arch_features.h b/include/lib/aarch64/arch_features.h
index 27f5c82..cee8dd2 100644
--- a/include/lib/aarch64/arch_features.h
+++ b/include/lib/aarch64/arch_features.h
@@ -120,12 +120,6 @@
 		(read_id_aa64isar2_el1() & mask_id_aa64isar2)) != 0U;
 }
 
-static inline bool is_armv8_4_amuv1_present(void)
-{
-	return ((read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) &
-		ID_AA64PFR0_AMU_MASK) == 1U;
-}
-
 static inline bool is_armv8_4_dit_present(void)
 {
 	return ((read_id_aa64pfr0_el1() >> ID_AA64PFR0_DIT_SHIFT) &
@@ -186,13 +180,6 @@
 		ID_AA64DFR0_DEBUG_SHIFT);
 }
 
-static inline bool get_armv9_0_trbe_support(void)
-{
-	return ((read_id_aa64dfr0_el1() >> ID_AA64DFR0_TRACEBUFFER_SHIFT) &
-		ID_AA64DFR0_TRACEBUFFER_MASK) ==
-		ID_AA64DFR0_TRACEBUFFER_SUPPORTED;
-}
-
 static inline bool get_armv8_4_trf_support(void)
 {
 	return ((read_id_aa64dfr0_el1() >> ID_AA64DFR0_TRACEFILT_SHIFT) &
@@ -233,7 +220,7 @@
 static inline bool get_feat_brbe_support(void)
 {
 	return ((read_id_aa64dfr0_el1() >> ID_AA64DFR0_BRBE_SHIFT) &
-		ID_AA64DFR0_BRBE_MASK) ==
+		ID_AA64DFR0_BRBE_MASK) >=
 		ID_AA64DFR0_BRBE_SUPPORTED;
 }
 
@@ -474,6 +461,22 @@
 		ID_AA64ISAR1_LS64_MASK);
 }
 
+static inline unsigned int amu_get_version(void)
+{
+	return (unsigned int)(read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) &
+		ID_AA64PFR0_AMU_MASK;
+}
+
+static inline bool is_feat_amuv1_present(void)
+{
+	return amu_get_version() >= ID_AA64PFR0_AMU_V1;
+}
+
+static inline bool is_feat_amuv1p1_present(void)
+{
+	return amu_get_version() >= ID_AA64PFR0_AMU_V1P1;
+}
+
 static inline bool is_feat_trbe_present(void)
 {
 	return EXTRACT(ID_AA64DFR0_TRACEBUFFER, read_id_aa64dfr0_el1())
@@ -555,4 +558,10 @@
 	return (((read_id_aa64mmfr3_el1() >> ID_AA64MMFR3_EL1_D128_SHIFT) &
 		ID_AA64MMFR3_EL1_D128_MASK) == ID_AA64MMFR3_EL1_D128_SUPPORTED);
 }
+
+static inline bool is_feat_doublelock_present(void)
+{
+	return EXTRACT(ID_AA64DFR0_DOUBLELOCK, read_id_aa64dfr0_el1())
+			>= DOUBLELOCK_IMPLEMENTED;
+}
 #endif /* ARCH_FEATURES_H */
diff --git a/include/lib/extensions/amu.h b/include/lib/extensions/amu.h
index 3ce053d..838e4b9 100644
--- a/include/lib/extensions/amu.h
+++ b/include/lib/extensions/amu.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2017-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -61,8 +61,6 @@
 
 CASSERT(AMU_GROUP1_COUNTERS_MASK <= 0xffff, invalid_amu_group1_counters_mask);
 
-unsigned int amu_get_version(void);
-
 uint64_t amu_group0_cnt_read(unsigned int idx);
 #if __aarch64__
 uint64_t amu_group0_voffset_read(unsigned int idx);
diff --git a/include/runtime_services/arm_arch_svc.h b/include/runtime_services/arm_arch_svc.h
index 0d2eb38..0b4e2ad 100644
--- a/include/runtime_services/arm_arch_svc.h
+++ b/include/runtime_services/arm_arch_svc.h
@@ -13,5 +13,6 @@
 #define SMCCC_ARCH_WORKAROUND_1	0x80008000
 #define SMCCC_ARCH_WORKAROUND_2	0x80007FFF
 #define SMCCC_ARCH_WORKAROUND_3	0x80003FFF
+#define SMCCC_ARCH_FEATURE_AVAILABILITY		U(0x80000003)
 
 #endif /* __ARM_ARCH_SVC_H__ */
diff --git a/include/runtime_services/smccc.h b/include/runtime_services/smccc.h
index b898138..513ec8f 100644
--- a/include/runtime_services/smccc.h
+++ b/include/runtime_services/smccc.h
@@ -80,4 +80,9 @@
 #define SMC_GET_SOC_VERSION		0
 #define SMC_GET_SOC_REVISION		1
 
+#define SCR_EL3_OPCODE			U(0x1E1100)
+#define CPTR_EL3_OPCODE			U(0x1E1140)
+#define MDCR_EL3_OPCODE			U(0x1E1320)
+#define MPAM3_EL3_OPCODE		U(0x1EA500)
+
 #endif /* __SMCCC_H__ */
diff --git a/lib/context_mgmt/aarch64/context_el2.c b/lib/context_mgmt/aarch64/context_el2.c
index 3049274..2bea84b 100644
--- a/lib/context_mgmt/aarch64/context_el2.c
+++ b/lib/context_mgmt/aarch64/context_el2.c
@@ -57,7 +57,7 @@
 {
 	if (is_armv8_6_fgt_present()) {
 		EL2_SAVE_CTX_REG(ctx, hdfgrtr_el2);
-		if (is_armv8_4_amuv1_present())
+		if (is_feat_amuv1_present())
 			EL2_SAVE_CTX_REG(ctx, hafgrtr_el2);
 		EL2_SAVE_CTX_REG(ctx, hdfgwtr_el2);
 		EL2_SAVE_CTX_REG(ctx, hfgitr_el2);
@@ -231,7 +231,7 @@
 {
 	if (is_armv8_6_fgt_present()) {
 		EL2_WRITE_MASK_CTX_REG(ctx, hdfgrtr_el2, or_mask);
-		if (is_armv8_4_amuv1_present())
+		if (is_feat_amuv1_present())
 			EL2_WRITE_MASK_CTX_REG(ctx, hafgrtr_el2, or_mask);
 		EL2_WRITE_MASK_CTX_REG(ctx, hdfgwtr_el2, or_mask);
 		EL2_WRITE_MASK_CTX_REG(ctx, hfgitr_el2, or_mask);
diff --git a/lib/extensions/amu/aarch32/amu.c b/lib/extensions/amu/aarch32/amu.c
index f730568..56abf7a 100644
--- a/lib/extensions/amu/aarch32/amu.c
+++ b/lib/extensions/amu/aarch32/amu.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,22 +7,10 @@
 #include <amu.h>
 #include <amu_private.h>
 #include <arch.h>
+#include <arch_features.h>
 #include <arch_helpers.h>
 #include <assert.h>
 
-/*
- * Get AMU version value from pfr0.
- * Return values
- *   ID_PFR0_AMU_V1: FEAT_AMUv1 supported (introduced in ARM v8.4)
- *   ID_PFR0_AMU_V1P1: FEAT_AMUv1p1 supported (introduced in ARM v8.6)
- *   ID_PFR0_AMU_NOT_SUPPORTED: not supported
- */
-unsigned int amu_get_version(void)
-{
-	return (unsigned int)(read_id_pfr0() >> ID_PFR0_AMU_SHIFT) &
-		ID_PFR0_AMU_MASK;
-}
-
 /* Read the group 0 counter identified by the given `idx`. */
 uint64_t amu_group0_cnt_read(unsigned int idx)
 {
diff --git a/lib/extensions/amu/aarch64/amu.c b/lib/extensions/amu/aarch64/amu.c
index 491edde..c089746 100644
--- a/lib/extensions/amu/aarch64/amu.c
+++ b/lib/extensions/amu/aarch64/amu.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -7,21 +7,10 @@
 #include <amu.h>
 #include <amu_private.h>
 #include <arch.h>
+#include <arch_features.h>
 #include <arch_helpers.h>
 #include <assert.h>
 
-/*
- * Get AMU version value from aa64pfr0.
- * Return values
- *   ID_AA64PFR0_AMU_V1: FEAT_AMUv1 supported (introduced in ARM v8.4)
- *   ID_AA64PFR0_AMU_V1P1: FEAT_AMUv1p1 supported (introduced in ARM v8.6)
- *   ID_AA64PFR0_AMU_NOT_SUPPORTED: not supported
- */
-unsigned int amu_get_version(void)
-{
-	return (unsigned int)(read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) &
-		ID_AA64PFR0_AMU_MASK;
-}
 
 /* Check if group 1 counters is implemented */
 int amu_group1_supported(void)
diff --git a/tftf/tests/extensions/amu/test_amu.c b/tftf/tests/extensions/amu/test_amu.c
index 21305a7..0cc4395 100644
--- a/tftf/tests/extensions/amu/test_amu.c
+++ b/tftf/tests/extensions/amu/test_amu.c
@@ -1,11 +1,12 @@
 /*
- * Copyright (c) 2018-2021, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <amu.h>
 #include <arch.h>
+#include <arch_features.h>
 #include <arch_helpers.h>
 #include <assert.h>
 #include <debug.h>
diff --git a/tftf/tests/runtime_services/arm_arch_svc/smccc_arch_workaround_1.c b/tftf/tests/runtime_services/arm_arch_svc/smccc_arch_workaround_1.c
index 93abf15..7babcd1 100644
--- a/tftf/tests/runtime_services/arm_arch_svc/smccc_arch_workaround_1.c
+++ b/tftf/tests/runtime_services/arm_arch_svc/smccc_arch_workaround_1.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2018-2024, Arm Limited. All rights reserved.
  * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -13,6 +13,7 @@
 #include <psci.h>
 #include <smccc.h>
 #include <string.h>
+#include <test_helpers.h>
 #include <tftf_lib.h>
 
 #ifdef __aarch64__
@@ -69,21 +70,11 @@
 {
 	smc_args args;
 	smc_ret_values ret;
-	int32_t expected_ver;
 	unsigned int my_midr, midr_mask;
 	int wa_required;
 	size_t i;
 
-	/* Check if SMCCC version is at least v1.1 */
-	expected_ver = MAKE_SMCCC_VERSION(1, 1);
-	memset(&args, 0, sizeof(args));
-	args.fid = SMCCC_VERSION;
-	ret = tftf_smc(&args);
-	if ((int32_t)ret.ret0 < expected_ver) {
-		tftf_testcase_printf("Unexpected SMCCC version: 0x%x\n",
-		       (int)ret.ret0);
-		return TEST_RESULT_SKIPPED;
-	}
+	SKIP_TEST_IF_SMCCC_VERSION_LT(1, 1);
 
 	/* Check if SMCCC_ARCH_WORKAROUND_1 is required or not */
 	memset(&args, 0, sizeof(args));
diff --git a/tftf/tests/runtime_services/arm_arch_svc/smccc_arch_workaround_2.c b/tftf/tests/runtime_services/arm_arch_svc/smccc_arch_workaround_2.c
index 1557e4f..b5aa636 100644
--- a/tftf/tests/runtime_services/arm_arch_svc/smccc_arch_workaround_2.c
+++ b/tftf/tests/runtime_services/arm_arch_svc/smccc_arch_workaround_2.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019-2020, Arm Limited. All rights reserved.
+ * Copyright (c) 2019-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -12,6 +12,7 @@
 #include <psci.h>
 #include <smccc.h>
 #include <string.h>
+#include <test_helpers.h>
 #include <tftf_lib.h>
 
 #ifdef __aarch64__
@@ -40,20 +41,10 @@
 {
 	smc_args args;
 	smc_ret_values ret;
-	int32_t expected_ver;
 	unsigned int my_midr, midr_mask;
 	size_t i;
 
-	/* Check if SMCCC version is at least v1.1 */
-	expected_ver = MAKE_SMCCC_VERSION(1, 1);
-	memset(&args, 0, sizeof(args));
-	args.fid = SMCCC_VERSION;
-	ret = tftf_smc(&args);
-	if ((int32_t)ret.ret0 < expected_ver) {
-		tftf_testcase_printf("Unexpected SMCCC version: 0x%x\n",
-		       (int)ret.ret0);
-		return TEST_RESULT_SKIPPED;
-	}
+	SKIP_TEST_IF_SMCCC_VERSION_LT(1, 1);
 
 	/* Check if SMCCC_ARCH_WORKAROUND_2 is required or not */
 	memset(&args, 0, sizeof(args));
diff --git a/tftf/tests/runtime_services/arm_arch_svc/smccc_arch_workaround_3.c b/tftf/tests/runtime_services/arm_arch_svc/smccc_arch_workaround_3.c
index ebf40a5..77c50cc 100644
--- a/tftf/tests/runtime_services/arm_arch_svc/smccc_arch_workaround_3.c
+++ b/tftf/tests/runtime_services/arm_arch_svc/smccc_arch_workaround_3.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2022, Arm Limited. All rights reserved.
+ * Copyright (c) 2022-2024, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -12,6 +12,7 @@
 #include <psci.h>
 #include <smccc.h>
 #include <string.h>
+#include <test_helpers.h>
 #include <tftf_lib.h>
 
 #ifdef __aarch64__
@@ -65,21 +66,11 @@
 {
 	smc_args args;
 	smc_ret_values ret;
-	int32_t expected_ver;
 	unsigned int my_midr, midr_mask;
 	int wa_required;
 	size_t i;
 
-	/* Check if SMCCC version is at least v1.1 */
-	expected_ver = MAKE_SMCCC_VERSION(1, 1);
-	memset(&args, 0, sizeof(args));
-	args.fid = SMCCC_VERSION;
-	ret = tftf_smc(&args);
-	if ((int32_t)ret.ret0 < expected_ver) {
-		tftf_testcase_printf("Unexpected SMCCC version: 0x%x\n",
-		       (int)ret.ret0);
-		return TEST_RESULT_SKIPPED;
-	}
+	SKIP_TEST_IF_SMCCC_VERSION_LT(1, 1);
 
 	/* Check if SMCCC_ARCH_WORKAROUND_3 is required or not */
 	memset(&args, 0, sizeof(args));
diff --git a/tftf/tests/runtime_services/arm_arch_svc/smccc_feature_availability.c b/tftf/tests/runtime_services/arm_arch_svc/smccc_feature_availability.c
new file mode 100644
index 0000000..1418ca1
--- /dev/null
+++ b/tftf/tests/runtime_services/arm_arch_svc/smccc_feature_availability.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2024, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <tftf.h>
+
+#include <arm_arch_svc.h>
+#include <smccc.h>
+#include <test_helpers.h>
+#include <tftf_lib.h>
+
+static inline u_register_t get_feature_for_reg(u_register_t reg)
+{
+	smc_args args = {0};
+	smc_ret_values ret;
+
+	args.fid = SMCCC_ARCH_FEATURE_AVAILABILITY | (SMC_64 << FUNCID_CC_SHIFT);
+	args.arg1 = reg;
+	ret = tftf_smc(&args);
+
+	/* APi is pretty simple, support was already checked. This is simpler */
+	assert((int)ret.ret0 == SMC_ARCH_CALL_SUCCESS);
+	return ret.ret1;
+}
+
+static inline bool always_present(void)
+{
+	return true;
+}
+
+/*
+ * Checks that the bit's matches the feature's presence
+ * feat_func should be is_feat_xyz_present(), but get_feat_xyz_support() will
+ * also work.
+ */
+#define CHECK_BIT_SET(feat_func, bit)						\
+	do {									\
+		if (!!feat_func() != !!(reg & bit)) {				\
+			tftf_testcase_printf(					\
+				#feat_func " says feature is %ssupported but "	\
+				#bit " was %sset!\n", feat_func() ? "" : "not ",\
+				(reg & bit) ? "" : "not ");			\
+			bad = true;						\
+		}								\
+		reg &= ~bit;							\
+	} while (0)
+
+/* when support for a new feature is added, we want this test to be
+ * updated. Fail the test so it's noticed. */
+#define CHECK_NO_BITS_SET(reg_name)						\
+	do {									\
+		if (reg != 0) {							\
+			tftf_testcase_printf(					\
+			#reg_name " still has values set: 0x%lx. "		\
+				"Test needs to be updated\n", reg);		\
+			bad = true;						\
+		}								\
+	} while (0)
+
+test_result_t test_smccc_arch_feature_availability(void)
+{
+	SKIP_TEST_IF_AARCH32();
+#ifdef __aarch64__
+
+	SKIP_TEST_IF_SMCCC_VERSION_LT(1, 1);
+	SKIP_TEST_IF_SMCCC_FUNC_NOT_SUPPORTED(SMCCC_ARCH_FEATURE_AVAILABILITY);
+
+	u_register_t reg;
+	bool bad = false;
+
+	reg = get_feature_for_reg(SCR_EL3_OPCODE);
+	CHECK_BIT_SET(is_armv8_9_fgt2_present,			SCR_FGTEN2_BIT);
+	CHECK_BIT_SET(is_feat_fpmr_present,			SCR_EnFPM_BIT);
+	CHECK_BIT_SET(is_feat_d128_supported,			SCR_D128En_BIT);
+	CHECK_BIT_SET(is_feat_s1pie_present,			SCR_PIEN_BIT);
+	CHECK_BIT_SET(is_feat_sctlr2_supported,			SCR_SCTLR2En_BIT);
+	CHECK_BIT_SET(is_feat_tcr2_supported,			SCR_TCR2EN_BIT);
+	CHECK_BIT_SET(is_feat_the_supported,			SCR_RCWMASKEn_BIT);
+	CHECK_BIT_SET(is_feat_sme_supported,			SCR_ENTP2_BIT);
+	CHECK_BIT_SET(is_feat_rng_trap_present,			SCR_TRNDR_BIT);
+	CHECK_BIT_SET(is_feat_gcs_present,			SCR_GCSEn_BIT);
+	CHECK_BIT_SET(get_feat_hcx_support,			SCR_HXEn_BIT);
+	CHECK_BIT_SET(is_feat_ls64_accdata_present,		SCR_ADEn_BIT);
+	CHECK_BIT_SET(is_feat_ls64_accdata_present,		SCR_EnAS0_BIT);
+	CHECK_BIT_SET(is_feat_amuv1p1_present,			SCR_AMVOFFEN_BIT);
+	CHECK_BIT_SET(get_armv8_6_ecv_support,			SCR_ECVEN_BIT);
+	CHECK_BIT_SET(is_armv8_6_fgt_present,			SCR_FGTEN_BIT);
+	CHECK_BIT_SET(is_feat_mte2_present,			SCR_ATA_BIT);
+	CHECK_BIT_SET(is_feat_csv2_2_present,			SCR_EnSCXT_BIT);
+	CHECK_BIT_SET(is_armv8_3_pauth_present,			SCR_APK_BIT);
+	CHECK_BIT_SET(is_feat_ras_present,			SCR_TERR_BIT);
+	CHECK_NO_BITS_SET(SCR_EL3);
+
+	reg = get_feature_for_reg(CPTR_EL3_OPCODE);
+	CHECK_BIT_SET(always_present,				CPTR_EL3_TCPAC_BIT);
+	CHECK_BIT_SET(is_feat_amuv1_present,			CPTR_EL3_TAM_BIT);
+	CHECK_BIT_SET(get_armv8_0_sys_reg_trace_support,	CPTR_EL3_TTA_BIT);
+	CHECK_BIT_SET(is_feat_sme_supported,			CPTR_EL3_ESM_BIT);
+	CHECK_BIT_SET(always_present,				CPTR_EL3_TFP_BIT);
+	CHECK_BIT_SET(is_armv8_2_sve_present,			CPTR_EL3_EZ_BIT);
+	CHECK_NO_BITS_SET(CPTR_EL3);
+
+	reg = get_feature_for_reg(MDCR_EL3_OPCODE);
+	CHECK_BIT_SET(get_feat_brbe_support,			MDCR_SBRBE(1));
+	CHECK_BIT_SET(is_armv8_6_fgt_present,			MDCR_TDCC_BIT);
+	CHECK_BIT_SET(is_feat_trbe_present,			MDCR_NSTB(1));
+	CHECK_BIT_SET(get_armv8_4_trf_support,			MDCR_TTRF_BIT);
+	CHECK_BIT_SET(is_feat_spe_supported,			MDCR_NSPB(1));
+	CHECK_BIT_SET(is_feat_doublelock_present,		MDCR_TDOSA_BIT);
+	CHECK_BIT_SET(always_present,				MDCR_TDA_BIT);
+	CHECK_BIT_SET(get_feat_pmuv3_supported,			MDCR_TPM_BIT);
+	CHECK_NO_BITS_SET(MDCR_EL3);
+
+	reg = get_feature_for_reg(MPAM3_EL3_OPCODE);
+	CHECK_BIT_SET(is_feat_mpam_supported,			MPAM3_EL3_TRAPLOWER_BIT);
+	CHECK_NO_BITS_SET(MPAM3_EL3);
+
+	if (bad)
+		return TEST_RESULT_FAIL;
+
+	return TEST_RESULT_SUCCESS;
+#endif /* __aarch64__ */
+}
diff --git a/tftf/tests/tests-cpu-extensions.mk b/tftf/tests/tests-cpu-extensions.mk
index 39783b1..7375633 100644
--- a/tftf/tests/tests-cpu-extensions.mk
+++ b/tftf/tests/tests-cpu-extensions.mk
@@ -33,4 +33,5 @@
 	runtime_services/arm_arch_svc/smccc_arch_workaround_1.c		\
 	runtime_services/arm_arch_svc/smccc_arch_workaround_2.c		\
 	runtime_services/arm_arch_svc/smccc_arch_workaround_3.c		\
+	runtime_services/arm_arch_svc/smccc_feature_availability.c	\
 )
diff --git a/tftf/tests/tests-cpu-extensions.xml b/tftf/tests/tests-cpu-extensions.xml
index bc09f37..51aa27c 100644
--- a/tftf/tests/tests-cpu-extensions.xml
+++ b/tftf/tests/tests-cpu-extensions.xml
@@ -50,6 +50,7 @@
      <testcase name="SMCCC_ARCH_WORKAROUND_2 test" function="test_smccc_arch_workaround_2" />
      <testcase name="SMCCC_ARCH_WORKAROUND_3 test" function="test_smccc_arch_workaround_3" />
      <testcase name="SMCCC_ARCH_SOC_ID test" function="test_smccc_arch_soc_id" />
+     <testcase name="SMCCC_ARCH_FEATURE_AVAILABILITY test" function="test_smccc_arch_feature_availability" />
   </testsuite>
 
 </testsuites>