refactor(trf): enable FEAT_TRF for FEAT_STATE_CHECKED

At the moment we only support FEAT_TRF to be either unconditionally
compiled in, or to be not supported at all.

Add support for runtime detection (ENABLE_TRF_FOR_NS=2), by splitting
is_feat_trf_present() into an ID register reading function and a second
function to report the support status. That function considers both
build time settings and runtime information (if needed), and is used
before we access TRF related registers.
Also move the context saving code from assembly to C, and use the new
is_feat_trf_supported() function to guard its execution.

The FVP platform decided to compile in support unconditionally (=1),
even though FEAT_TRF is an ARMv8.4 feature, so is not available with the
FVP model's default command line.
Change that to the now supported dynamic option (=2), so the right
decision can be made by the code at runtime.

Change-Id: Ia97b01adbe24970a4d837afd463dc5506b7295a3
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
diff --git a/bl31/bl31.mk b/bl31/bl31.mk
index ebb664e..e9590d5 100644
--- a/bl31/bl31.mk
+++ b/bl31/bl31.mk
@@ -124,7 +124,7 @@
 BL31_SOURCES		+=      lib/extensions/sys_reg_trace/aarch64/sys_reg_trace.c
 endif
 
-ifeq (${ENABLE_TRF_FOR_NS},1)
+ifneq (${ENABLE_TRF_FOR_NS},0)
 BL31_SOURCES		+=	lib/extensions/trf/aarch64/trf.c
 endif
 
diff --git a/bl32/sp_min/sp_min.mk b/bl32/sp_min/sp_min.mk
index b2f4e4c..2a6612a 100644
--- a/bl32/sp_min/sp_min.mk
+++ b/bl32/sp_min/sp_min.mk
@@ -50,7 +50,7 @@
 BL32_SOURCES		+=	lib/extensions/sys_reg_trace/aarch32/sys_reg_trace.c
 endif
 
-ifeq (${ENABLE_TRF_FOR_NS},1)
+ifneq (${ENABLE_TRF_FOR_NS},0)
 BL32_SOURCES		+=	lib/extensions/trf/aarch32/trf.c
 endif
 
diff --git a/common/feat_detect.c b/common/feat_detect.c
index 4c54cb5..5fb56b9 100644
--- a/common/feat_detect.c
+++ b/common/feat_detect.c
@@ -162,16 +162,6 @@
 #endif
 }
 
-/****************************************************
- * Feature : FEAT_TRF (Self-hosted Trace Extensions)
- ***************************************************/
-static void read_feat_trf(void)
-{
-#if (ENABLE_TRF_FOR_NS == FEAT_STATE_ALWAYS)
-	feat_detect_panic(is_arm8_4_feat_trf_present(), "TRF");
-#endif
-}
-
 /************************************************
  * Feature : FEAT_MTE (Memory Tagging Extension)
  ***********************************************/
@@ -306,7 +296,8 @@
 	read_feat_mpam();
 	read_feat_nv2();
 	read_feat_sel2();
-	read_feat_trf();
+	check_feature(ENABLE_TRF_FOR_NS, read_feat_trf_id_field(),
+		      "TRF", 1, 1);
 
 	/* v8.5 features */
 	read_feat_mte();
diff --git a/include/arch/aarch32/arch_features.h b/include/arch/aarch32/arch_features.h
index a7d3fe6..a5a5e27 100644
--- a/include/arch/aarch32/arch_features.h
+++ b/include/arch/aarch32/arch_features.h
@@ -10,6 +10,7 @@
 #include <stdbool.h>
 
 #include <arch_helpers.h>
+#include <common/feat_detect.h>
 
 #define ISOLATE_FIELD(reg, feat)					\
 	((unsigned int)(((reg) >> (feat ## _SHIFT)) & (feat ## _MASK)))
@@ -24,4 +25,22 @@
 	return ISOLATE_FIELD(read_id_mmfr4(), ID_MMFR4_CNP) != 0U;
 }
 
+static inline unsigned int read_feat_trf_id_field(void)
+{
+	return ISOLATE_FIELD(read_id_dfr0(), ID_DFR0_TRACEFILT);
+}
+
+static inline bool is_feat_trf_supported(void)
+{
+	if (ENABLE_TRF_FOR_NS == FEAT_STATE_DISABLED) {
+		return false;
+	}
+
+	if (ENABLE_TRF_FOR_NS == FEAT_STATE_ALWAYS) {
+		return true;
+	}
+
+	return read_feat_trf_id_field() != 0U;
+}
+
 #endif /* ARCH_FEATURES_H */
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
index 9f6af39..9ff81aa 100644
--- a/include/arch/aarch64/arch_features.h
+++ b/include/arch/aarch64/arch_features.h
@@ -268,10 +268,22 @@
 /*************************************************************************
  * Function to identify the presence of FEAT_TRF (TraceLift)
  ************************************************************************/
-static inline bool is_arm8_4_feat_trf_present(void)
+static inline unsigned int read_feat_trf_id_field(void)
+{
+	return ISOLATE_FIELD(read_id_aa64dfr0_el1(), ID_AA64DFR0_TRACEFILT);
+}
+
+static inline bool is_feat_trf_supported(void)
 {
-	return (((read_id_aa64dfr0_el1() >> ID_AA64DFR0_TRACEFILT_SHIFT) &
-		ID_AA64DFR0_TRACEFILT_MASK) == ID_AA64DFR0_TRACEFILT_SUPPORTED);
+	if (ENABLE_TRF_FOR_NS == FEAT_STATE_DISABLED) {
+		return false;
+	}
+
+	if (ENABLE_TRF_FOR_NS == FEAT_STATE_ALWAYS) {
+		return true;
+	}
+
+	return read_feat_trf_id_field() != 0U;
 }
 
 /********************************************************************************
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index 86c1dbe..5d99778 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -555,6 +555,9 @@
 /* Armv8.4 Data Independent Timing Register */
 DEFINE_RENAME_SYSREG_RW_FUNCS(dit, DIT)
 
+/* Armv8.4 FEAT_TRF Register */
+DEFINE_RENAME_SYSREG_RW_FUNCS(trfcr_el2, TRFCR_EL2)
+
 /* Armv8.5 MTE Registers */
 DEFINE_RENAME_SYSREG_RW_FUNCS(tfsre0_el1, TFSRE0_EL1)
 DEFINE_RENAME_SYSREG_RW_FUNCS(tfsr_el1, TFSR_EL1)
diff --git a/include/lib/el3_runtime/aarch64/context.h b/include/lib/el3_runtime/aarch64/context.h
index 6986e0e..57cf5f0 100644
--- a/include/lib/el3_runtime/aarch64/context.h
+++ b/include/lib/el3_runtime/aarch64/context.h
@@ -539,10 +539,6 @@
 void el2_sysregs_context_save_nv2(el2_sysregs_t *regs);
 void el2_sysregs_context_restore_nv2(el2_sysregs_t *regs);
 #endif /* CTX_INCLUDE_NEVE_REGS */
-#if ENABLE_TRF_FOR_NS
-void el2_sysregs_context_save_trf(el2_sysregs_t *regs);
-void el2_sysregs_context_restore_trf(el2_sysregs_t *regs);
-#endif /* ENABLE_TRF_FOR_NS */
 #if ENABLE_FEAT_CSV2_2
 void el2_sysregs_context_save_csv2(el2_sysregs_t *regs);
 void el2_sysregs_context_restore_csv2(el2_sysregs_t *regs);
diff --git a/lib/el3_runtime/aarch32/context_mgmt.c b/lib/el3_runtime/aarch32/context_mgmt.c
index af8edf5..e494a86 100644
--- a/lib/el3_runtime/aarch32/context_mgmt.c
+++ b/lib/el3_runtime/aarch32/context_mgmt.c
@@ -11,6 +11,7 @@
 #include <platform_def.h>
 
 #include <arch.h>
+#include <arch_features.h>
 #include <arch_helpers.h>
 #include <common/bl_common.h>
 #include <context.h>
@@ -143,9 +144,9 @@
 	sys_reg_trace_enable();
 #endif /* ENABLE_SYS_REG_TRACE_FOR_NS */
 
-#if ENABLE_TRF_FOR_NS
-	trf_enable();
-#endif /* ENABLE_TRF_FOR_NS */
+	if (is_feat_trf_supported()) {
+		trf_enable();
+	}
 #endif
 }
 
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
index 722b8ae..d439148 100644
--- a/lib/el3_runtime/aarch64/context.S
+++ b/lib/el3_runtime/aarch64/context.S
@@ -41,10 +41,6 @@
 	.global	el2_sysregs_context_save_nv2
 	.global	el2_sysregs_context_restore_nv2
 #endif /* CTX_INCLUDE_NEVE_REGS */
-#if ENABLE_TRF_FOR_NS
-	.global	el2_sysregs_context_save_trf
-	.global	el2_sysregs_context_restore_trf
-#endif /* ENABLE_TRF_FOR_NS */
 #if ENABLE_FEAT_CSV2_2
 	.global	el2_sysregs_context_save_csv2
 	.global	el2_sysregs_context_restore_csv2
@@ -536,26 +532,6 @@
 endfunc el2_sysregs_context_restore_nv2
 #endif /* CTX_INCLUDE_NEVE_REGS */
 
-#if ENABLE_TRF_FOR_NS
-func el2_sysregs_context_save_trf
-	/*
-	 * TRFCR_EL2 register is saved only when FEAT_TRF is supported.
-	 */
-	mrs	x12, TRFCR_EL2
-	str	x12, [x0, #CTX_TRFCR_EL2]
-	ret
-endfunc el2_sysregs_context_save_trf
-
-func el2_sysregs_context_restore_trf
-	/*
-	 * TRFCR_EL2 register is restored only when FEAT_TRF is supported.
-	 */
-	ldr	x12, [x0, #CTX_TRFCR_EL2]
-	msr	TRFCR_EL2, x12
-	ret
-endfunc el2_sysregs_context_restore_trf
-#endif /* ENABLE_TRF_FOR_NS */
-
 #if ENABLE_FEAT_CSV2_2
 func el2_sysregs_context_save_csv2
 	/*
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 54e257b..4d2079d 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -507,9 +507,9 @@
 	sys_reg_trace_enable(ctx);
 #endif /* ENABLE_SYS_REG_TRACE_FOR_NS */
 
-#if ENABLE_TRF_FOR_NS
-	trf_enable();
-#endif /* ENABLE_TRF_FOR_NS */
+	if (is_feat_trf_supported()) {
+		trf_enable();
+	}
 #endif
 }
 
@@ -875,9 +875,9 @@
 #if CTX_INCLUDE_NEVE_REGS
 		el2_sysregs_context_save_nv2(el2_sysregs_ctx);
 #endif
-#if ENABLE_TRF_FOR_NS
-		el2_sysregs_context_save_trf(el2_sysregs_ctx);
-#endif
+		if (is_feat_trf_supported()) {
+			write_ctx_reg(el2_sysregs_ctx, CTX_TRFCR_EL2, read_trfcr_el2());
+		}
 #if ENABLE_FEAT_CSV2_2
 		el2_sysregs_context_save_csv2(el2_sysregs_ctx);
 #endif
@@ -935,9 +935,9 @@
 #if CTX_INCLUDE_NEVE_REGS
 		el2_sysregs_context_restore_nv2(el2_sysregs_ctx);
 #endif
-#if ENABLE_TRF_FOR_NS
-		el2_sysregs_context_restore_trf(el2_sysregs_ctx);
-#endif
+		if (is_feat_trf_supported()) {
+			write_trfcr_el2(read_ctx_reg(el2_sysregs_ctx, CTX_TRFCR_EL2));
+		}
 #if ENABLE_FEAT_CSV2_2
 		el2_sysregs_context_restore_csv2(el2_sysregs_ctx);
 #endif
diff --git a/lib/extensions/trf/aarch32/trf.c b/lib/extensions/trf/aarch32/trf.c
index 834092d..0c63efa 100644
--- a/lib/extensions/trf/aarch32/trf.c
+++ b/lib/extensions/trf/aarch32/trf.c
@@ -10,26 +10,15 @@
 #include <arch_helpers.h>
 #include <lib/extensions/trf.h>
 
-static bool trf_supported(void)
-{
-	uint32_t features;
-
-	features = read_id_dfr0() >> ID_DFR0_TRACEFILT_SHIFT;
-	return ((features & ID_DFR0_TRACEFILT_MASK) ==
-		ID_DFR0_TRACEFILT_SUPPORTED);
-}
-
 void trf_enable(void)
 {
 	uint32_t val;
 
-	if (trf_supported()) {
-		/*
-		 * Allow access of trace filter control registers from
-		 * non-monitor mode
-		 */
-		val = read_sdcr();
-		val &= ~SDCR_TTRF_BIT;
-		write_sdcr(val);
-	}
+	/*
+	 * Allow access of trace filter control registers from
+	 * non-monitor mode
+	 */
+	val = read_sdcr();
+	val &= ~SDCR_TTRF_BIT;
+	write_sdcr(val);
 }
diff --git a/lib/extensions/trf/aarch64/trf.c b/lib/extensions/trf/aarch64/trf.c
index 1da5dce..941692b 100644
--- a/lib/extensions/trf/aarch64/trf.c
+++ b/lib/extensions/trf/aarch64/trf.c
@@ -4,33 +4,21 @@
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#include <stdbool.h>
-
 #include <arch.h>
+#include <arch_features.h>
 #include <arch_helpers.h>
 #include <lib/extensions/trf.h>
 
-static bool trf_supported(void)
-{
-	uint64_t features;
-
-	features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_TRACEFILT_SHIFT;
-	return ((features & ID_AA64DFR0_TRACEFILT_MASK) ==
-		ID_AA64DFR0_TRACEFILT_SUPPORTED);
-}
-
 void trf_enable(void)
 {
 	uint64_t val;
 
-	if (trf_supported()) {
-		/*
-		 * MDCR_EL3.TTRF = b0
-		 * Allow access of trace filter control registers from NS-EL2
-		 * and NS-EL1 when NS-EL2 is implemented but not used
-		 */
-		val = read_mdcr_el3();
-		val &= ~MDCR_TTRF_BIT;
-		write_mdcr_el3(val);
-	}
+	/*
+	 * MDCR_EL3.TTRF = b0
+	 * Allow access of trace filter control registers from NS-EL2
+	 * and NS-EL1 when NS-EL2 is implemented but not used
+	 */
+	val = read_mdcr_el3();
+	val &= ~MDCR_TTRF_BIT;
+	write_mdcr_el3(val);
 }
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index dda7e6c..9b09a6b 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -461,7 +461,7 @@
 ENABLE_SYS_REG_TRACE_FOR_NS	:= 1
 
 # enable trace filter control registers access to NS by default
-ENABLE_TRF_FOR_NS		:= 1
+ENABLE_TRF_FOR_NS		:= 2
 
 # Linux relies on EL3 enablement if those features are present
 ENABLE_FEAT_FGT			:= 2