Merge changes from topic "feat_state_rework" into integration

* changes:
  feat(fvp): enable FEAT_HCX by default
  refactor(context-mgmt): move FEAT_HCX save/restore into C
  refactor(cpufeat): convert FEAT_HCX to new scheme
  feat(fvp): enable FEAT_FGT by default
  refactor(context-mgmt): move FEAT_FGT save/restore code into C
  refactor(amu): convert FEAT_AMUv1 to new scheme
  refactor(cpufeat): decouple FGT feature detection and build flags
  refactor(cpufeat): check FEAT_FGT in a new way
  refactor(cpufeat): move helpers into .c file, rename FEAT_STATE_
  feat(aarch64): make ID system register reads non-volatile
diff --git a/bl31/bl31_main.c b/bl31/bl31_main.c
index 2a3d838..e70eb55 100644
--- a/bl31/bl31_main.c
+++ b/bl31/bl31_main.c
@@ -93,15 +93,6 @@
 	/* Perform late platform-specific setup */
 	bl31_plat_arch_setup();
 
-#if ENABLE_FEAT_HCX
-	/*
-	 * Assert that FEAT_HCX is supported on this system, without this check
-	 * an exception would occur during context save/restore if enabled but
-	 * not supported.
-	 */
-	assert(is_feat_hcx_present());
-#endif /* ENABLE_FEAT_HCX */
-
 #if CTX_INCLUDE_PAUTH_REGS
 	/*
 	 * Assert that the ARMv8.3-PAuth registers are present or an access
diff --git a/changelog.yaml b/changelog.yaml
index 1e1f0a1..e100f82 100644
--- a/changelog.yaml
+++ b/changelog.yaml
@@ -101,6 +101,9 @@
       - title: Extended Cache Index (FEAT_CCIDX)
         scope: ccidx
 
+      - title: CPU feature / ID register handling in general
+        scope: cpufeat
+
       - title: Support for the `HCRX_EL2` register (FEAT_HCX)
         scope: hcx
 
diff --git a/common/feat_detect.c b/common/feat_detect.c
index ee34588..a8c40f7 100644
--- a/common/feat_detect.c
+++ b/common/feat_detect.c
@@ -4,24 +4,59 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <arch_features.h>
+#include <common/debug.h>
 #include <common/feat_detect.h>
 
+static bool tainted;
+
 /*******************************************************************************
  * This section lists the wrapper modules for each feature to evaluate the
- * feature states (FEAT_STATE_1 and FEAT_STATE_2) and perform necessary action
- * as below:
+ * feature states (FEAT_STATE_ALWAYS and FEAT_STATE_CHECK) and perform
+ * necessary action as below:
  *
  * It verifies whether the FEAT_XXX (eg: FEAT_SB) is supported by the PE or not.
  * Without this check an exception would occur during context save/restore
  * routines, if the feature is enabled but not supported by PE.
  ******************************************************************************/
 
+#define feat_detect_panic(a, b)		((a) ? (void)0 : feature_panic(b))
+
+/*******************************************************************************
+ * Function : feature_panic
+ * Customised panic function with error logging mechanism to list the feature
+ * not supported by the PE.
+ ******************************************************************************/
+static inline void feature_panic(char *feat_name)
+{
+	ERROR("FEAT_%s not supported by the PE\n", feat_name);
+	panic();
+}
+
+/*******************************************************************************
+ * Function : check_feature
+ * Check for a valid combination of build time flags (ENABLE_FEAT_xxx) and
+ * feature availability on the hardware.
+ * Panics if a feature is forcefully enabled, but not available on the PE.
+ *
+ * We force inlining here to let the compiler optimise away the whole check
+ * if the feature is disabled at build time (FEAT_STATE_DISABLED).
+ ******************************************************************************/
+static inline void __attribute((__always_inline__))
+check_feature(int state, unsigned long field, const char *feat_name)
+{
+	if (state == FEAT_STATE_ALWAYS && field == 0U) {
+		ERROR("FEAT_%s not supported by the PE\n", feat_name);
+		tainted = true;
+	}
+}
+
 /******************************************
  * Feature : FEAT_SB (Speculation Barrier)
  *****************************************/
 static void read_feat_sb(void)
 {
-#if (ENABLE_FEAT_SB == FEAT_STATE_1)
+#if (ENABLE_FEAT_SB == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_armv8_0_feat_sb_present(), "SB");
 #endif
 }
@@ -31,7 +66,7 @@
  *****************************************************/
 static void read_feat_csv2_2(void)
 {
-#if (ENABLE_FEAT_CSV2_2 == FEAT_STATE_1)
+#if (ENABLE_FEAT_CSV2_2 == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_armv8_0_feat_csv2_2_present(), "CSV2_2");
 #endif
 }
@@ -41,7 +76,7 @@
  **********************************************/
 static void read_feat_pan(void)
 {
-#if (ENABLE_FEAT_PAN == FEAT_STATE_1)
+#if (ENABLE_FEAT_PAN == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_armv8_1_pan_present(), "PAN");
 #endif
 }
@@ -51,7 +86,7 @@
  *****************************************************/
 static void read_feat_vhe(void)
 {
-#if (ENABLE_FEAT_VHE == FEAT_STATE_1)
+#if (ENABLE_FEAT_VHE == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_armv8_1_vhe_present(), "VHE");
 #endif
 }
@@ -61,7 +96,7 @@
  ******************************************************************************/
 static void read_feat_ras(void)
 {
-#if (RAS_EXTENSION == FEAT_STATE_1)
+#if (RAS_EXTENSION == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_armv8_2_feat_ras_present(), "RAS");
 #endif
 }
@@ -71,7 +106,7 @@
  ***********************************************/
 static void read_feat_pauth(void)
 {
-#if (ENABLE_PAUTH == FEAT_STATE_1) || (CTX_INCLUDE_PAUTH_REGS == FEAT_STATE_1)
+#if (ENABLE_PAUTH == FEAT_STATE_ALWAYS) || (CTX_INCLUDE_PAUTH_REGS == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_armv8_3_pauth_present(), "PAUTH");
 #endif
 }
@@ -81,27 +116,17 @@
  ***********************************************************/
 static void read_feat_dit(void)
 {
-#if (ENABLE_FEAT_DIT == FEAT_STATE_1)
+#if (ENABLE_FEAT_DIT == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_armv8_4_feat_dit_present(), "DIT");
 #endif
 }
 
-/*********************************************************
- * Feature : FEAT_AMUv1 (Activity Monitors Extensions v1)
- ********************************************************/
-static void read_feat_amuv1(void)
-{
-#if (ENABLE_FEAT_AMUv1 == FEAT_STATE_1)
-	feat_detect_panic(is_armv8_4_feat_amuv1_present(), "AMUv1");
-#endif
-}
-
 /****************************************************************************
  * Feature : FEAT_MPAM (Memory Partitioning and Monitoring (MPAM) Extension)
  ***************************************************************************/
 static void read_feat_mpam(void)
 {
-#if (ENABLE_MPAM_FOR_LOWER_ELS == FEAT_STATE_1)
+#if (ENABLE_MPAM_FOR_LOWER_ELS == FEAT_STATE_ALWAYS)
 	feat_detect_panic(get_mpam_version() != 0U, "MPAM");
 #endif
 }
@@ -111,7 +136,7 @@
  *************************************************************/
 static void read_feat_nv2(void)
 {
-#if (CTX_INCLUDE_NEVE_REGS == FEAT_STATE_1)
+#if (CTX_INCLUDE_NEVE_REGS == FEAT_STATE_ALWAYS)
 	unsigned int nv = get_armv8_4_feat_nv_support();
 
 	feat_detect_panic((nv == ID_AA64MMFR2_EL1_NV2_SUPPORTED), "NV2");
@@ -123,7 +148,7 @@
  **********************************/
 static void read_feat_sel2(void)
 {
-#if (ENABLE_FEAT_SEL2 == FEAT_STATE_1)
+#if (ENABLE_FEAT_SEL2 == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_armv8_4_sel2_present(), "SEL2");
 #endif
 }
@@ -133,7 +158,7 @@
  ***************************************************/
 static void read_feat_trf(void)
 {
-#if (ENABLE_TRF_FOR_NS == FEAT_STATE_1)
+#if (ENABLE_TRF_FOR_NS == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_arm8_4_feat_trf_present(), "TRF");
 #endif
 }
@@ -143,7 +168,7 @@
  ***********************************************/
 static void read_feat_mte(void)
 {
-#if (CTX_INCLUDE_MTE_REGS == FEAT_STATE_1)
+#if (CTX_INCLUDE_MTE_REGS == FEAT_STATE_ALWAYS)
 	unsigned int mte = get_armv8_5_mte_support();
 
 	feat_detect_panic((mte != MTE_UNIMPLEMENTED), "MTE");
@@ -155,7 +180,7 @@
  **********************************************/
 static void read_feat_rng(void)
 {
-#if (ENABLE_FEAT_RNG == FEAT_STATE_1)
+#if (ENABLE_FEAT_RNG == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_armv8_5_rng_present(), "RNG");
 #endif
 }
@@ -165,27 +190,17 @@
  ***************************************************/
 static void read_feat_bti(void)
 {
-#if (ENABLE_BTI == FEAT_STATE_1)
+#if (ENABLE_BTI == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_armv8_5_bti_present(), "BTI");
 #endif
 }
 
-/****************************************
- * Feature : FEAT_FGT (Fine Grain Traps)
- ***************************************/
-static void read_feat_fgt(void)
-{
-#if (ENABLE_FEAT_FGT == FEAT_STATE_1)
-	feat_detect_panic(is_armv8_6_fgt_present(), "FGT");
-#endif
-}
-
 /***********************************************
  * Feature : FEAT_AMUv1p1 (AMU Extensions v1.1)
  **********************************************/
 static void read_feat_amuv1p1(void)
 {
-#if (ENABLE_FEAT_AMUv1p1 == FEAT_STATE_1)
+#if (ENABLE_FEAT_AMUv1p1 == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_armv8_6_feat_amuv1p1_present(), "AMUv1p1");
 #endif
 }
@@ -195,7 +210,7 @@
  ******************************************************/
 static void read_feat_ecv(void)
 {
-#if (ENABLE_FEAT_ECV == FEAT_STATE_1)
+#if (ENABLE_FEAT_ECV == FEAT_STATE_ALWAYS)
 	unsigned int ecv = get_armv8_6_ecv_support();
 
 	feat_detect_panic(((ecv == ID_AA64MMFR0_EL1_ECV_SUPPORTED) ||
@@ -208,27 +223,17 @@
  **********************************************************/
 static void read_feat_twed(void)
 {
-#if (ENABLE_FEAT_TWED == FEAT_STATE_1)
+#if (ENABLE_FEAT_TWED == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_armv8_6_twed_present(), "TWED");
 #endif
 }
 
-/******************************************************************
- * Feature : FEAT_HCX (Extended Hypervisor Configuration Register)
- *****************************************************************/
-static void read_feat_hcx(void)
-{
-#if (ENABLE_FEAT_HCX == FEAT_STATE_1)
-	feat_detect_panic(is_feat_hcx_present(), "HCX");
-#endif
-}
-
 /**************************************************
  * Feature : FEAT_RME (Realm Management Extension)
  *************************************************/
 static void read_feat_rme(void)
 {
-#if (ENABLE_RME == FEAT_STATE_1)
+#if (ENABLE_RME == FEAT_STATE_ALWAYS)
 	feat_detect_panic((get_armv9_2_feat_rme_support() !=
 			ID_AA64PFR0_FEAT_RME_NOT_SUPPORTED), "RME");
 #endif
@@ -239,7 +244,7 @@
  *****************************************************/
 static void read_feat_brbe(void)
 {
-#if (ENABLE_BRBE_FOR_NS == FEAT_STATE_1)
+#if (ENABLE_BRBE_FOR_NS == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_feat_brbe_present(), "BRBE");
 #endif
 }
@@ -249,7 +254,7 @@
  *****************************************************/
 static void read_feat_trbe(void)
 {
-#if (ENABLE_TRBE_FOR_NS == FEAT_STATE_1)
+#if (ENABLE_TRBE_FOR_NS == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_feat_trbe_present(), "TRBE");
 #endif
 }
@@ -259,7 +264,7 @@
  *****************************************************************/
 static void read_feat_rng_trap(void)
 {
-#if (ENABLE_FEAT_RNG_TRAP == FEAT_STATE_1)
+#if (ENABLE_FEAT_RNG_TRAP == FEAT_STATE_ALWAYS)
 	feat_detect_panic(is_feat_rng_trap_present(), "RNG_TRAP");
 #endif
 }
@@ -283,11 +288,14 @@
  * ENABLE_FEAT_xxx = 2 : The feature is enabled but dynamically enabled at runtime
  *                       depending on hardware capability.
  *
- * For better readability, state values are defined with macros namely:
- * { FEAT_STATE_0, FEAT_STATE_1, FEAT_STATE_2 } taking values as their naming.
+ * For better readability, state values are defined with macros, namely:
+ * { FEAT_STATE_DISABLED, FEAT_STATE_ALWAYS, FEAT_STATE_CHECK }, taking values
+ * { 0, 1, 2 }, respectively, as their naming.
  **********************************************************************************/
 void detect_arch_features(void)
 {
+	tainted = false;
+
 	/* v8.0 features */
 	read_feat_sb();
 	read_feat_csv2_2();
@@ -304,7 +312,7 @@
 
 	/* v8.4 features */
 	read_feat_dit();
-	read_feat_amuv1();
+	check_feature(ENABLE_FEAT_AMUv1, read_feat_amu_id_field(), "AMUv1");
 	read_feat_mpam();
 	read_feat_nv2();
 	read_feat_sel2();
@@ -318,12 +326,12 @@
 
 	/* v8.6 features */
 	read_feat_amuv1p1();
-	read_feat_fgt();
+	check_feature(ENABLE_FEAT_FGT, read_feat_fgt_id_field(), "FGT");
 	read_feat_ecv();
 	read_feat_twed();
 
 	/* v8.7 features */
-	read_feat_hcx();
+	check_feature(ENABLE_FEAT_HCX, read_feat_hcx_id_field(), "HCX");
 
 	/* v9.0 features */
 	read_feat_brbe();
@@ -331,4 +339,8 @@
 
 	/* v9.2 features */
 	read_feat_rme();
+
+	if (tainted) {
+		panic();
+	}
 }
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
index 932e885..2b801ac 100644
--- a/include/arch/aarch64/arch_features.h
+++ b/include/arch/aarch64/arch_features.h
@@ -10,6 +10,7 @@
 #include <stdbool.h>
 
 #include <arch_helpers.h>
+#include <common/feat_detect.h>
 
 static inline bool is_armv7_gentimer_present(void)
 {
@@ -97,10 +98,23 @@
 		ID_AA64MMFR1_EL1_TWED_MASK) == ID_AA64MMFR1_EL1_TWED_SUPPORTED);
 }
 
-static inline bool is_armv8_6_fgt_present(void)
+static unsigned int read_feat_fgt_id_field(void)
 {
-	return ((read_id_aa64mmfr0_el1() >> ID_AA64MMFR0_EL1_FGT_SHIFT) &
-		ID_AA64MMFR0_EL1_FGT_MASK) != 0U;
+	return (read_id_aa64mmfr0_el1() >> ID_AA64MMFR0_EL1_FGT_SHIFT) &
+		ID_AA64MMFR0_EL1_FGT_MASK;
+}
+
+static inline bool is_feat_fgt_supported(void)
+{
+	if (ENABLE_FEAT_FGT == FEAT_STATE_DISABLED) {
+		return false;
+	}
+
+	if (ENABLE_FEAT_FGT == FEAT_STATE_ALWAYS) {
+		return true;
+	}
+
+	return read_feat_fgt_id_field() != 0U;
 }
 
 static inline unsigned long int get_armv8_6_ecv_support(void)
@@ -115,10 +129,31 @@
 		ID_AA64ISAR0_RNDR_MASK);
 }
 
+/*******************************************************************************
+ * Functions to identify the presence of the Activity Monitors Extension
+ ******************************************************************************/
+static unsigned int read_feat_amu_id_field(void)
+{
+	return (read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) &
+		ID_AA64PFR0_AMU_MASK;
+}
+
+static inline bool is_feat_amu_supported(void)
+{
+	if (ENABLE_FEAT_AMUv1 == FEAT_STATE_DISABLED) {
+		return false;
+	}
+
+	if (ENABLE_FEAT_AMUv1 == FEAT_STATE_ALWAYS) {
+		return true;
+	}
+
+	return read_feat_amu_id_field() >= ID_AA64PFR0_AMU_V1;
+}
+
 static inline bool is_armv8_6_feat_amuv1p1_present(void)
 {
-	return (((read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) &
-		ID_AA64PFR0_AMU_MASK) >= ID_AA64PFR0_AMU_V1P1);
+	return read_feat_amu_id_field() >= ID_AA64PFR0_AMU_V1P1;
 }
 
 /*
@@ -138,10 +173,23 @@
 		ID_AA64PFR1_MPAM_FRAC_SHIFT) & ID_AA64PFR1_MPAM_FRAC_MASK));
 }
 
-static inline bool is_feat_hcx_present(void)
+static inline unsigned int read_feat_hcx_id_field(void)
 {
-	return (((read_id_aa64mmfr1_el1() >> ID_AA64MMFR1_EL1_HCX_SHIFT) &
-		ID_AA64MMFR1_EL1_HCX_MASK) == ID_AA64MMFR1_EL1_HCX_SUPPORTED);
+	return (read_id_aa64mmfr1_el1() >> ID_AA64MMFR1_EL1_HCX_SHIFT) &
+		ID_AA64MMFR1_EL1_HCX_MASK;
+}
+
+static inline bool is_feat_hcx_supported(void)
+{
+	if (ENABLE_FEAT_HCX == FEAT_STATE_DISABLED) {
+		return false;
+	}
+
+	if (ENABLE_FEAT_HCX == FEAT_STATE_ALWAYS) {
+		return true;
+	}
+
+	return read_feat_hcx_id_field() != 0U;
 }
 
 static inline bool is_feat_rng_trap_present(void)
@@ -226,16 +274,6 @@
 		ID_AA64DFR0_TRACEFILT_MASK) == ID_AA64DFR0_TRACEFILT_SUPPORTED);
 }
 
-/*******************************************************************************
- * Function to identify the presence of FEAT_AMUv1 (Activity Monitors-
- * Extension v1)
- ******************************************************************************/
-static inline bool is_armv8_4_feat_amuv1_present(void)
-{
-	return (((read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) &
-		ID_AA64PFR0_AMU_MASK) >= ID_AA64PFR0_AMU_V1);
-}
-
 /********************************************************************************
  * Function to identify the presence of FEAT_NV2 (Enhanced Nested Virtualization
  * Support)
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index fe9b5a5..86c1dbe 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -27,6 +27,14 @@
 	return v;						\
 }
 
+#define _DEFINE_SYSREG_READ_FUNC_NV(_name, _reg_name)		\
+static inline u_register_t read_ ## _name(void)			\
+{								\
+	u_register_t v;						\
+	__asm__ ("mrs %0, " #_reg_name : "=r" (v));		\
+	return v;						\
+}
+
 #define _DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name)			\
 static inline void write_ ## _name(u_register_t v)			\
 {									\
@@ -58,6 +66,14 @@
 #define DEFINE_RENAME_SYSREG_WRITE_FUNC(_name, _reg_name)	\
 	_DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name)
 
+/* Define read function for ID register (w/o volatile qualifier) */
+#define DEFINE_IDREG_READ_FUNC(_name)			\
+	_DEFINE_SYSREG_READ_FUNC_NV(_name, _name)
+
+/* Define read function for renamed ID register (w/o volatile qualifier) */
+#define DEFINE_RENAME_IDREG_READ_FUNC(_name, _reg_name)	\
+	_DEFINE_SYSREG_READ_FUNC_NV(_name, _reg_name)
+
 /**********************************************************************
  * Macros to create inline functions for system instructions
  *********************************************************************/
@@ -247,14 +263,14 @@
 #define write_daifset(val) SYSREG_WRITE_CONST(daifset, val)
 
 DEFINE_SYSREG_RW_FUNCS(par_el1)
-DEFINE_SYSREG_READ_FUNC(id_pfr1_el1)
-DEFINE_SYSREG_READ_FUNC(id_aa64isar0_el1)
-DEFINE_SYSREG_READ_FUNC(id_aa64isar1_el1)
-DEFINE_RENAME_SYSREG_READ_FUNC(id_aa64isar2_el1, ID_AA64ISAR2_EL1)
-DEFINE_SYSREG_READ_FUNC(id_aa64pfr0_el1)
-DEFINE_SYSREG_READ_FUNC(id_aa64pfr1_el1)
-DEFINE_SYSREG_READ_FUNC(id_aa64dfr0_el1)
-DEFINE_SYSREG_READ_FUNC(id_afr0_el1)
+DEFINE_IDREG_READ_FUNC(id_pfr1_el1)
+DEFINE_IDREG_READ_FUNC(id_aa64isar0_el1)
+DEFINE_IDREG_READ_FUNC(id_aa64isar1_el1)
+DEFINE_RENAME_IDREG_READ_FUNC(id_aa64isar2_el1, ID_AA64ISAR2_EL1)
+DEFINE_IDREG_READ_FUNC(id_aa64pfr0_el1)
+DEFINE_IDREG_READ_FUNC(id_aa64pfr1_el1)
+DEFINE_IDREG_READ_FUNC(id_aa64dfr0_el1)
+DEFINE_IDREG_READ_FUNC(id_afr0_el1)
 DEFINE_SYSREG_READ_FUNC(CurrentEl)
 DEFINE_SYSREG_READ_FUNC(ctr_el0)
 DEFINE_SYSREG_RW_FUNCS(daif)
@@ -367,10 +383,10 @@
 /*******************************************************************************
  * System register accessor prototypes
  ******************************************************************************/
-DEFINE_SYSREG_READ_FUNC(midr_el1)
+DEFINE_IDREG_READ_FUNC(midr_el1)
 DEFINE_SYSREG_READ_FUNC(mpidr_el1)
-DEFINE_SYSREG_READ_FUNC(id_aa64mmfr0_el1)
-DEFINE_SYSREG_READ_FUNC(id_aa64mmfr1_el1)
+DEFINE_IDREG_READ_FUNC(id_aa64mmfr0_el1)
+DEFINE_IDREG_READ_FUNC(id_aa64mmfr1_el1)
 
 DEFINE_SYSREG_RW_FUNCS(scr_el3)
 DEFINE_SYSREG_RW_FUNCS(hcr_el2)
@@ -516,7 +532,7 @@
 DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el3, ZCR_EL3)
 DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el2, ZCR_EL2)
 
-DEFINE_RENAME_SYSREG_READ_FUNC(id_aa64smfr0_el1, ID_AA64SMFR0_EL1)
+DEFINE_RENAME_IDREG_READ_FUNC(id_aa64smfr0_el1, ID_AA64SMFR0_EL1)
 DEFINE_RENAME_SYSREG_RW_FUNCS(smcr_el3, SMCR_EL3)
 
 DEFINE_RENAME_SYSREG_READ_FUNC(erridr_el1, ERRIDR_EL1)
@@ -530,7 +546,7 @@
 DEFINE_RENAME_SYSREG_READ_FUNC(erxmisc1_el1, ERXMISC1_EL1)
 
 /* Armv8.2 Registers */
-DEFINE_RENAME_SYSREG_READ_FUNC(id_aa64mmfr2_el1, ID_AA64MMFR2_EL1)
+DEFINE_RENAME_IDREG_READ_FUNC(id_aa64mmfr2_el1, ID_AA64MMFR2_EL1)
 
 /* Armv8.3 Pointer Authentication Registers */
 DEFINE_RENAME_SYSREG_RW_FUNCS(apiakeyhi_el1, APIAKeyHi_EL1)
@@ -549,6 +565,14 @@
 DEFINE_RENAME_SYSREG_READ_FUNC(rndr, RNDR)
 DEFINE_RENAME_SYSREG_READ_FUNC(rndrrs, RNDRRS)
 
+/* Armv8.6 FEAT_FGT Registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(hdfgrtr_el2, HDFGRTR_EL2)
+DEFINE_RENAME_SYSREG_RW_FUNCS(hafgrtr_el2, HAFGRTR_EL2)
+DEFINE_RENAME_SYSREG_RW_FUNCS(hdfgwtr_el2, HDFGWTR_EL2)
+DEFINE_RENAME_SYSREG_RW_FUNCS(hfgitr_el2, HFGITR_EL2)
+DEFINE_RENAME_SYSREG_RW_FUNCS(hfgrtr_el2, HFGRTR_EL2)
+DEFINE_RENAME_SYSREG_RW_FUNCS(hfgwtr_el2, HFGWTR_EL2)
+
 /* FEAT_HCX Register */
 DEFINE_RENAME_SYSREG_RW_FUNCS(hcrx_el2, HCRX_EL2)
 
diff --git a/include/common/feat_detect.h b/include/common/feat_detect.h
index 0f0f105..788dfb3 100644
--- a/include/common/feat_detect.h
+++ b/include/common/feat_detect.h
@@ -7,26 +7,12 @@
 #ifndef FEAT_DETECT_H
 #define FEAT_DETECT_H
 
-#include <arch_features.h>
-#include <common/debug.h>
-
 /* Function Prototypes */
 void detect_arch_features(void);
 
 /* Macro Definitions */
-#define FEAT_STATE_1	1
-#define FEAT_STATE_2	2
-#define feat_detect_panic(a, b)		((a) ? (void)0 : feature_panic(b))
-
-/*******************************************************************************
- * Function : feature_panic
- * Customised panic module with error logging mechanism to list the feature
- * not supported by the PE.
- ******************************************************************************/
-static inline void feature_panic(char *feat_name)
-{
-	ERROR("FEAT_%s not supported by the PE\n", feat_name);
-	panic();
-}
+#define FEAT_STATE_DISABLED	0
+#define FEAT_STATE_ALWAYS	1
+#define FEAT_STATE_CHECK	2
 
 #endif /* FEAT_DETECT_H */
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
index 6c13166..6986e0e 100644
--- a/include/lib/el3_runtime/aarch64/context.h
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -523,10 +523,6 @@
 void el2_sysregs_context_save_mpam(el2_sysregs_t *regs);
 void el2_sysregs_context_restore_mpam(el2_sysregs_t *regs);
 #endif /* ENABLE_MPAM_FOR_LOWER_ELS */
-#if ENABLE_FEAT_FGT
-void el2_sysregs_context_save_fgt(el2_sysregs_t *regs);
-void el2_sysregs_context_restore_fgt(el2_sysregs_t *regs);
-#endif /* ENABLE_FEAT_FGT */
 #if ENABLE_FEAT_ECV
 void el2_sysregs_context_save_ecv(el2_sysregs_t *regs);
 void el2_sysregs_context_restore_ecv(el2_sysregs_t *regs);
@@ -551,10 +547,6 @@
 void el2_sysregs_context_save_csv2(el2_sysregs_t *regs);
 void el2_sysregs_context_restore_csv2(el2_sysregs_t *regs);
 #endif /* ENABLE_FEAT_CSV2_2 */
-#if ENABLE_FEAT_HCX
-void el2_sysregs_context_save_hcx(el2_sysregs_t *regs);
-void el2_sysregs_context_restore_hcx(el2_sysregs_t *regs);
-#endif /* ENABLE_FEAT_HCX */
 #endif /* CTX_INCLUDE_EL2_REGS */
 
 #if CTX_INCLUDE_FPREGS
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
index aa0327b..b5d61ff 100644
--- a/lib/el3_runtime/aarch64/context.S
+++ b/lib/el3_runtime/aarch64/context.S
@@ -25,10 +25,6 @@
 	.global	el2_sysregs_context_save_mpam
 	.global	el2_sysregs_context_restore_mpam
 #endif /* ENABLE_MPAM_FOR_LOWER_ELS */
-#if ENABLE_FEAT_FGT
-	.global	el2_sysregs_context_save_fgt
-	.global	el2_sysregs_context_restore_fgt
-#endif /* ENABLE_FEAT_FGT */
 #if ENABLE_FEAT_ECV
 	.global	el2_sysregs_context_save_ecv
 	.global	el2_sysregs_context_restore_ecv
@@ -53,10 +49,6 @@
 	.global	el2_sysregs_context_save_csv2
 	.global	el2_sysregs_context_restore_csv2
 #endif /* ENABLE_FEAT_CSV2_2 */
-#if ENABLE_FEAT_HCX
-	.global	el2_sysregs_context_save_hcx
-	.global	el2_sysregs_context_restore_hcx
-#endif /* ENABLE_FEAT_HCX */
 #endif /* CTX_INCLUDE_EL2_REGS */
 
 	.global	el1_sysregs_context_save
@@ -314,45 +306,6 @@
 endfunc el2_sysregs_context_restore_mpam
 #endif /* ENABLE_MPAM_FOR_LOWER_ELS */
 
-#if ENABLE_FEAT_FGT
-func el2_sysregs_context_save_fgt
-	mrs	x13, HDFGRTR_EL2
-#if ENABLE_FEAT_AMUv1
-	mrs	x14, HAFGRTR_EL2
-	stp	x13, x14, [x0, #CTX_HDFGRTR_EL2]
-#else
-	str	x13, [x0, #CTX_HDFGRTR_EL2]
-#endif /* ENABLE_FEAT_AMUv1 */
-	mrs	x15, HDFGWTR_EL2
-	mrs	x16, HFGITR_EL2
-	stp	x15, x16, [x0, #CTX_HDFGWTR_EL2]
-
-	mrs	x9, HFGRTR_EL2
-	mrs	x10, HFGWTR_EL2
-	stp	x9, x10, [x0, #CTX_HFGRTR_EL2]
-	ret
-endfunc el2_sysregs_context_save_fgt
-
-func el2_sysregs_context_restore_fgt
-	#if ENABLE_FEAT_AMUv1
-	ldp	x13, x14, [x0, #CTX_HDFGRTR_EL2]
-	msr	HAFGRTR_EL2, x14
-#else
-	ldr	x13, [x0, #CTX_HDFGRTR_EL2]
-#endif /* ENABLE_FEAT_AMUv1 */
-	msr	HDFGRTR_EL2, x13
-
-	ldp	x15, x16, [x0, #CTX_HDFGWTR_EL2]
-	msr	HDFGWTR_EL2, x15
-	msr	HFGITR_EL2, x16
-
-	ldp	x9, x10, [x0, #CTX_HFGRTR_EL2]
-	msr	HFGRTR_EL2, x9
-	msr	HFGWTR_EL2, x10
-	ret
-endfunc el2_sysregs_context_restore_fgt
-#endif /* ENABLE_FEAT_FGT */
-
 #if ENABLE_FEAT_ECV
 func el2_sysregs_context_save_ecv
 	mrs	x11, CNTPOFF_EL2
@@ -475,19 +428,6 @@
 endfunc el2_sysregs_context_restore_csv2
 #endif /* ENABLE_FEAT_CSV2_2 */
 
-#if ENABLE_FEAT_HCX
-func el2_sysregs_context_save_hcx
-	mrs	x14, hcrx_el2
-	str	x14, [x0, #CTX_HCRX_EL2]
-	ret
-endfunc el2_sysregs_context_save_hcx
-
-func el2_sysregs_context_restore_hcx
-	ldr	x14, [x0, #CTX_HCRX_EL2]
-	msr	hcrx_el2, x14
-	ret
-endfunc el2_sysregs_context_restore_hcx
-#endif /* ENABLE_FEAT_HCX */
 #endif /* CTX_INCLUDE_EL2_REGS */
 
 /* ------------------------------------------------------------------
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 866ac41..3bcefdb 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -320,9 +320,9 @@
 	 * If FEAT_HCX is enabled, enable access to HCRX_EL2 by setting
 	 * SCR_EL3.HXEn.
 	 */
-#if ENABLE_FEAT_HCX
-	scr_el3 |= SCR_HXEn_BIT;
-#endif
+	if (is_feat_hcx_supported()) {
+		scr_el3 |= SCR_HXEn_BIT;
+	}
 
 	/*
 	 * If FEAT_RNG_TRAP is enabled, all reads of the RNDR and RNDRRS
@@ -359,7 +359,7 @@
 		&& (GET_M32(ep->spsr) == MODE32_hyp))) {
 		scr_el3 |= SCR_HCE_BIT;
 
-		if (is_armv8_6_fgt_present()) {
+		if (is_feat_fgt_supported()) {
 			scr_el3 |= SCR_FGTEN_BIT;
 		}
 
@@ -792,6 +792,35 @@
 }
 
 #if CTX_INCLUDE_EL2_REGS
+
+static void el2_sysregs_context_save_fgt(el2_sysregs_t *ctx)
+{
+	if (is_feat_fgt_supported()) {
+		write_ctx_reg(ctx, CTX_HDFGRTR_EL2, read_hdfgrtr_el2());
+		if (is_feat_amu_supported()) {
+			write_ctx_reg(ctx, CTX_HAFGRTR_EL2, read_hafgrtr_el2());
+		}
+		write_ctx_reg(ctx, CTX_HDFGWTR_EL2, read_hdfgwtr_el2());
+		write_ctx_reg(ctx, CTX_HFGITR_EL2, read_hfgitr_el2());
+		write_ctx_reg(ctx, CTX_HFGRTR_EL2, read_hfgrtr_el2());
+		write_ctx_reg(ctx, CTX_HFGWTR_EL2, read_hfgwtr_el2());
+	}
+}
+
+static void el2_sysregs_context_restore_fgt(el2_sysregs_t *ctx)
+{
+	if (is_feat_fgt_supported()) {
+		write_hdfgrtr_el2(read_ctx_reg(ctx, CTX_HDFGRTR_EL2));
+		if (is_feat_amu_supported()) {
+			write_hafgrtr_el2(read_ctx_reg(ctx, CTX_HAFGRTR_EL2));
+		}
+		write_hdfgwtr_el2(read_ctx_reg(ctx, CTX_HDFGWTR_EL2));
+		write_hfgitr_el2(read_ctx_reg(ctx, CTX_HFGITR_EL2));
+		write_hfgrtr_el2(read_ctx_reg(ctx, CTX_HFGRTR_EL2));
+		write_hfgwtr_el2(read_ctx_reg(ctx, CTX_HFGWTR_EL2));
+	}
+}
+
 /*******************************************************************************
  * Save EL2 sysreg context
  ******************************************************************************/
@@ -823,9 +852,9 @@
 #if ENABLE_MPAM_FOR_LOWER_ELS
 		el2_sysregs_context_save_mpam(el2_sysregs_ctx);
 #endif
-#if ENABLE_FEAT_FGT
+
 		el2_sysregs_context_save_fgt(el2_sysregs_ctx);
-#endif
+
 #if ENABLE_FEAT_ECV
 		el2_sysregs_context_save_ecv(el2_sysregs_ctx);
 #endif
@@ -844,9 +873,9 @@
 #if ENABLE_FEAT_CSV2_2
 		el2_sysregs_context_save_csv2(el2_sysregs_ctx);
 #endif
-#if ENABLE_FEAT_HCX
-		el2_sysregs_context_save_hcx(el2_sysregs_ctx);
-#endif
+		if (is_feat_hcx_supported()) {
+			write_ctx_reg(el2_sysregs_ctx, CTX_HCRX_EL2, read_hcrx_el2());
+		}
 	}
 }
 
@@ -881,9 +910,9 @@
 #if ENABLE_MPAM_FOR_LOWER_ELS
 		el2_sysregs_context_restore_mpam(el2_sysregs_ctx);
 #endif
-#if ENABLE_FEAT_FGT
+
 		el2_sysregs_context_restore_fgt(el2_sysregs_ctx);
-#endif
+
 #if ENABLE_FEAT_ECV
 		el2_sysregs_context_restore_ecv(el2_sysregs_ctx);
 #endif
@@ -902,9 +931,9 @@
 #if ENABLE_FEAT_CSV2_2
 		el2_sysregs_context_restore_csv2(el2_sysregs_ctx);
 #endif
-#if ENABLE_FEAT_HCX
-		el2_sysregs_context_restore_hcx(el2_sysregs_ctx);
-#endif
+		if (is_feat_hcx_supported()) {
+			write_hcrx_el2(read_ctx_reg(el2_sysregs_ctx, CTX_HCRX_EL2));
+		}
 	}
 }
 #endif /* CTX_INCLUDE_EL2_REGS */
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index f28a6ff..efbf68f 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -463,6 +463,10 @@
 # enable trace filter control registers access to NS by default
 ENABLE_TRF_FOR_NS		:= 1
 
+# Linux relies on EL3 enablement if those features are present
+ENABLE_FEAT_FGT			:= 2
+ENABLE_FEAT_HCX			:= 2
+
 ifeq (${SPMC_AT_EL3}, 1)
 PLAT_BL_COMMON_SOURCES	+=	plat/arm/board/fvp/fvp_el3_spmc.c
 endif
diff --git a/plat/qti/common/src/qti_pm.c b/plat/qti/common/src/qti_pm.c
index 5f1b7aa..ae361e9 100644
--- a/plat/qti/common/src/qti_pm.c
+++ b/plat/qti/common/src/qti_pm.c
@@ -47,8 +47,7 @@
 #define QTI_CORE_PWRDN_EN_MASK		1
 
 /* cpu power control happens to be same across all CPUs */
-_DEFINE_SYSREG_WRITE_FUNC(cpu_pwrctrl_val, S3_0_C15_C2_7)
-_DEFINE_SYSREG_READ_FUNC(cpu_pwrctrl_val, S3_0_C15_C2_7)
+DEFINE_RENAME_SYSREG_RW_FUNCS(cpu_pwrctrl_val, S3_0_C15_C2_7)
 
 const unsigned int qti_pm_idle_states[] = {
 	qti_make_pwrstate_lvl0(QTI_LOCAL_STATE_OFF,