refactor(cpufeat): enable FEAT_DIT for FEAT_STATE_CHECKED

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

Add support for runtime detection (ENABLE_DIT=2), by splitting
is_armv8_4_dit_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).

We use ENABLE_DIT in two occassions in assembly code, where we just set
the DIT bit in the DIT system register.
Protect those two cases by reading the CPU ID register when ENABLE_DIT
is set to 2.

Change the FVP platform default to the now supported dynamic
option (=2), so the right decision can be made by the code at runtime.

Change-Id: I506d352f18e23c60db8cdf08edb449f60adbe098
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
diff --git a/bl32/tsp/tsp_main.c b/bl32/tsp/tsp_main.c
index df9903b..0878ea4 100644
--- a/bl32/tsp/tsp_main.c
+++ b/bl32/tsp/tsp_main.c
@@ -263,7 +263,7 @@
 		results[1] /= service_arg1 ? service_arg1 : 1;
 		break;
 	case TSP_CHECK_DIT:
-		if (!is_armv8_4_dit_present()) {
+		if (!is_feat_dit_supported()) {
 			ERROR("DIT not supported\n");
 			results[0] = 0;
 			results[1] = 0xffff;
diff --git a/common/feat_detect.c b/common/feat_detect.c
index 98b420a..c8a0703 100644
--- a/common/feat_detect.c
+++ b/common/feat_detect.c
@@ -80,16 +80,6 @@
 #endif
 }
 
-/************************************************************
- * Feature : FEAT_DIT (Data Independent Timing Instructions)
- ***********************************************************/
-static void read_feat_dit(void)
-{
-#if (ENABLE_FEAT_DIT == FEAT_STATE_ALWAYS)
-	feat_detect_panic(is_armv8_4_feat_dit_present(), "DIT");
-#endif
-}
-
 /************************************************
  * Feature : FEAT_MTE (Memory Tagging Extension)
  ***********************************************/
@@ -178,7 +168,7 @@
 	read_feat_pauth();
 
 	/* v8.4 features */
-	read_feat_dit();
+	check_feature(ENABLE_FEAT_DIT, read_feat_dit_id_field(), "DIT", 1, 1);
 	check_feature(ENABLE_FEAT_AMU, read_feat_amu_id_field(),
 		      "AMUv1", 1, 2);
 	check_feature(ENABLE_MPAM_FOR_LOWER_ELS, read_feat_mpam_version(),
diff --git a/include/arch/aarch32/arch_features.h b/include/arch/aarch32/arch_features.h
index 7c25b99..62a512b 100644
--- a/include/arch/aarch32/arch_features.h
+++ b/include/arch/aarch32/arch_features.h
@@ -92,6 +92,24 @@
 	return read_feat_coptrc_id_field() != 0U;
 }
 
+static inline unsigned int read_feat_dit_id_field(void)
+{
+	return ISOLATE_FIELD(read_id_pfr0(), ID_PFR0_DIT);
+}
+
+static inline bool is_feat_dit_supported(void)
+{
+	if (ENABLE_FEAT_DIT == FEAT_STATE_DISABLED) {
+		return false;
+	}
+
+	if (ENABLE_FEAT_DIT == FEAT_STATE_ALWAYS) {
+		return true;
+	}
+
+	return read_feat_dit_id_field() != 0U;
+}
+
 static inline bool is_feat_spe_supported(void)
 {
 	/* FEAT_SPE is AArch64 only */
diff --git a/include/arch/aarch64/arch_features.h b/include/arch/aarch64/arch_features.h
index 16f4fb9..40ab82f 100644
--- a/include/arch/aarch64/arch_features.h
+++ b/include/arch/aarch64/arch_features.h
@@ -89,12 +89,6 @@
 		is_feat_pacqarma3_present());
 }
 
-static inline bool is_armv8_4_dit_present(void)
-{
-	return ((read_id_aa64pfr0_el1() >> ID_AA64PFR0_DIT_SHIFT) &
-		ID_AA64PFR0_DIT_MASK) == 1U;
-}
-
 static inline bool is_armv8_4_ttst_present(void)
 {
 	return ((read_id_aa64mmfr2_el1() >> ID_AA64MMFR2_EL1_ST_SHIFT) &
@@ -515,13 +509,22 @@
 		ID_AA64PFR0_RAS_MASK) != ID_AA64PFR0_RAS_NOT_SUPPORTED);
 }
 
+static unsigned int read_feat_dit_id_field(void)
+{
+	return ISOLATE_FIELD(read_id_aa64pfr0_el1(), ID_AA64PFR0_DIT);
+}
+
-/**************************************************************************
- * Function to identify the presence of FEAT_DIT (Data Independent Timing)
- *************************************************************************/
-static inline bool is_armv8_4_feat_dit_present(void)
+static inline bool is_feat_dit_supported(void)
 {
-	return (((read_id_aa64pfr0_el1() >> ID_AA64PFR0_DIT_SHIFT) &
-		ID_AA64PFR0_DIT_MASK) == ID_AA64PFR0_DIT_SUPPORTED);
+	if (ENABLE_FEAT_DIT == FEAT_STATE_DISABLED) {
+		return false;
+	}
+
+	if (ENABLE_FEAT_DIT == FEAT_STATE_ALWAYS) {
+		return true;
+	}
+
+	return read_feat_dit_id_field() != 0U;
 }
 
 static inline unsigned int read_feat_tracever_id_field(void)
diff --git a/include/arch/aarch64/el3_common_macros.S b/include/arch/aarch64/el3_common_macros.S
index 45a86c1..2dee07d 100644
--- a/include/arch/aarch64/el3_common_macros.S
+++ b/include/arch/aarch64/el3_common_macros.S
@@ -243,14 +243,20 @@
 	 * register value for DIT.
 	 */
 #if ENABLE_FEAT_DIT
-#if ENABLE_ASSERTIONS
+#if ENABLE_ASSERTIONS || ENABLE_FEAT_DIT > 1
 	mrs	x0, id_aa64pfr0_el1
 	ubfx	x0, x0, #ID_AA64PFR0_DIT_SHIFT, #ID_AA64PFR0_DIT_LENGTH
+#if ENABLE_FEAT_DIT > 1
+	cbz	x0, 1f
+#else
 	cmp	x0, #ID_AA64PFR0_DIT_SUPPORTED
 	ASM_ASSERT(eq)
+#endif
+
 #endif /* ENABLE_ASSERTIONS */
 	mov	x0, #DIT_BIT
 	msr	DIT, x0
+1:
 #endif
 	.endm
 
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
index 013a505..7691171 100644
--- a/lib/el3_runtime/aarch64/context.S
+++ b/lib/el3_runtime/aarch64/context.S
@@ -553,8 +553,14 @@
 	 * always enable DIT in EL3
 	 */
 #if ENABLE_FEAT_DIT
+#if ENABLE_FEAT_DIT == 2
+	mrs	x8, id_aa64pfr0_el1
+	and	x8, x8, #(ID_AA64PFR0_DIT_MASK << ID_AA64PFR0_DIT_SHIFT)
+	cbz	x8, 1f
+#endif
 	mov     x8, #DIT_BIT
 	msr     DIT, x8
+1:
 #endif /* ENABLE_FEAT_DIT */
 	.endm /* set_unset_pstate_bits */
 
diff --git a/plat/arm/board/fvp/platform.mk b/plat/arm/board/fvp/platform.mk
index e81f1eb..214064b 100644
--- a/plat/arm/board/fvp/platform.mk
+++ b/plat/arm/board/fvp/platform.mk
@@ -70,6 +70,7 @@
 ENABLE_TRBE_FOR_NS		:= 2
 ENABLE_SYS_REG_TRACE_FOR_NS	:= 2
 ENABLE_FEAT_CSV2_2		:= 2
+ENABLE_FEAT_DIT			:= 2
 ENABLE_FEAT_PAN			:= 2
 ENABLE_FEAT_VHE			:= 2
 CTX_INCLUDE_NEVE_REGS		:= 2