[PATCH] armv8: Initialize CNTFRQ if at highest exception level

Peter Hoyes peter.hoyes at arm.com
Mon Jul 12 16:04:21 CEST 2021


From: Peter Hoyes <Peter.Hoyes at arm.com>

CNTFRQ_EL0 is only writable from the highest supported exception
level on the platform. For Armv8-A, this is typically EL3, but
technically EL2 and EL3 are optional so it may need to be
initialized at EL2 or EL1. For Armv8-R, the highest exception
level is always EL2.

This patch moves the initialization outside of the switch_el
block and uses a new macro branch_if_not_highest_el which
dynamically detects whether it is at the highest supported
exception level.

Linux's docs state that CNTFRQ_EL0 should be initialized by the
bootloader. If not set, the the U-Boot prompt countdown hangs.

Signed-off-by: Peter Hoyes <Peter.Hoyes at arm.com>
---
 arch/arm/cpu/armv8/start.S    | 13 ++++++++-----
 arch/arm/include/asm/macro.h  | 18 ++++++++++++++++++
 arch/arm/include/asm/system.h |  6 ++++++
 3 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
index 662449156b..8d7cfd7a87 100644
--- a/arch/arm/cpu/armv8/start.S
+++ b/arch/arm/cpu/armv8/start.S
@@ -127,10 +127,6 @@ pie_fixup_done:
 	orr	x0, x0, #0xf			/* SCR_EL3.NS|IRQ|FIQ|EA */
 	msr	scr_el3, x0
 	msr	cptr_el3, xzr			/* Enable FP/SIMD */
-#ifdef COUNTER_FREQUENCY
-	ldr	x0, =COUNTER_FREQUENCY
-	msr	cntfrq_el0, x0			/* Initialize CNTFRQ */
-#endif
 	b	0f
 2:	set_vbar	vbar_el2, x0
 	mov	x0, #0x33ff
@@ -140,7 +136,14 @@ pie_fixup_done:
 	mov	x0, #3 << 20
 	msr	cpacr_el1, x0			/* Enable FP/SIMD */
 0:
-	isb
+
+#ifdef COUNTER_FREQUENCY
+	branch_if_not_highest_el x0, 4f
+	ldr	x0, =COUNTER_FREQUENCY
+	msr	cntfrq_el0, x0			/* Initialize CNTFRQ */
+#endif
+
+4:	isb
 
 	/*
 	 * Enable SMPEN bit for coherency.
diff --git a/arch/arm/include/asm/macro.h b/arch/arm/include/asm/macro.h
index bb33b4bc89..485310d660 100644
--- a/arch/arm/include/asm/macro.h
+++ b/arch/arm/include/asm/macro.h
@@ -77,6 +77,24 @@ lr	.req	x30
 	b.eq	\el1_label
 .endm
 
+/*
+ * Branch if we are not in the highest exception level
+ */
+.macro	branch_if_not_highest_el, xreg, label
+	switch_el \xreg, 3f, 2f, 1f
+
+2:	mrs	\xreg, ID_AA64PFR0_EL1
+	and	\xreg, \xreg, #(ID_AA64PFR0_EL1_EL3)
+	cbnz	\xreg, \label
+	b	3f
+
+1:	mrs	\xreg, ID_AA64PFR0_EL1
+	and	\xreg, \xreg, #(ID_AA64PFR0_EL1_EL3 | ID_AA64PFR0_EL1_EL2)
+	cbnz	\xreg, \label
+
+3:
+.endm
+
 /*
  * Branch if current processor is a Cortex-A57 core.
  */
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 11fceec4d2..8b3a54e64c 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -79,6 +79,12 @@
 #define HCR_EL2_RW_AARCH32	(0 << 31) /* Lower levels are AArch32         */
 #define HCR_EL2_HCD_DIS		(1 << 29) /* Hypervisor Call disabled         */
 
+/*
+ * ID_AA64PFR0_EL1 bits definitions
+ */
+#define ID_AA64PFR0_EL1_EL3	(0xF << 12) /* EL3 implemented                */
+#define ID_AA64PFR0_EL1_EL2	(0xF << 8)  /* EL2 implemented                */
+
 /*
  * CPACR_EL1 bits definitions
  */
-- 
2.25.1



More information about the U-Boot mailing list