[boot-wrapper-aarch64 PATCH] Configure the memory-mapped generic timer
Alexandru Elisei
alexandru.elisei at arm.com
Wed Aug 13 01:54:34 PDT 2025
Linux added a memory-mapped generic timer node to the device tree for FVP
in commit 7556a55b07c0 ("arm64: dts: fvp: Add system timer for broadcast
during CPU idle"). The timer needs to be configured by EL3 before it can be
accessed by lower exception levels.
If the timer isn't accessible to Linux, probing fails:
[ 0.000000] arch_timer: Unable to find a suitable frame in timer @ 0x000000002a810000
[ 0.000000] Failed to initialize '/timer at 2a810000': -22
which leads to KVM failing to initialise properly:
[ 0.532000] kvm [1]: kvm_arch_timer: uninitialized timecounter
Configure the memory-mapped generic timer in boot-wrapper so Linux can use
it.
Configuration consists of:
* Enabling access to the CNTBaseN timer frame, CNTACR<n> and CNTVOFF<n>
registers in the CNTNSAR register.
boot-wrapper tries to enable access to all possible timer frames and
registers for simplicity. This is safe to do, since the CNTNSAR.NS<n> bit
is RES0 if frame n is not implemented.
* Setting the memory-mapped timer register CNTFRQ to COUNTER_FREQ, as
mandated in ARM DDI 0487 L.a, section I5.7.7, "CNTFRQ, Counter-timer
Frequency".
Signed-off-by: Alexandru Elisei <alexandru.elisei at arm.com>
---
Makefile.am | 2 ++
common/platform.c | 10 ++++++++++
2 files changed, 12 insertions(+)
diff --git a/Makefile.am b/Makefile.am
index 0178e5dc1050..7c7098c6a103 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -27,6 +27,7 @@ endef
PHYS_OFFSET := $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findmem.pl $(KERNEL_DTB))
UART_BASE := $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 0 'arm,pl011')
SYSREGS_BASE := $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 0 'arm,vexpress-sysreg' 2> /dev/null)
+TIMER_MEM_BASE := $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findbase.pl $(KERNEL_DTB) 0 'arm,armv7-timer-mem' 2> /dev/null)
COUNTER_FREQ := 100000000
CPU_IDS := $(shell perl -I $(SCRIPT_DIR) $(SCRIPT_DIR)/findcpuids.pl $(KERNEL_DTB))
@@ -36,6 +37,7 @@ DEFINES = -DCOUNTER_FREQ=$(COUNTER_FREQ)
DEFINES += -DCPU_IDS=$(CPU_IDS)
DEFINES += -DNR_CPUS=$(NR_CPUS)
DEFINES += $(if $(SYSREGS_BASE), -DSYSREGS_BASE=$(SYSREGS_BASE), )
+DEFINES += $(if $(TIMER_MEM_BASE), -DTIMER_MEM_BASE=$(TIMER_MEM_BASE), )
DEFINES += -DUART_BASE=$(UART_BASE)
DEFINES += -DSTACK_SIZE=256
diff --git a/common/platform.c b/common/platform.c
index 4e390e101b24..a51a1ef56a5b 100644
--- a/common/platform.c
+++ b/common/platform.c
@@ -31,6 +31,11 @@
#define V2M_SYS(reg) ((void *)SYSREGS_BASE + V2M_SYS_##reg)
#endif
+#ifdef TIMER_MEM_BASE
+#define TIMER_MEM_CNTNSAR 0x004
+#define TIMER_MEM_CNTFRQ 0x000
+#endif
+
void print_char(char c)
{
uint32_t flags;
@@ -124,4 +129,9 @@ void init_platform(void)
raw_writel((1 << 31) | (1 << 30) | (7 << 20) | (0 << 16),
V2M_SYS(CFGCTRL));
#endif
+#ifdef TIMER_MEM_BASE
+ /* Try to enable all the timer frames. */
+ raw_writel(0xff, (void *)TIMER_MEM_BASE + TIMER_MEM_CNTNSAR);
+ raw_writel(COUNTER_FREQ, (void *)TIMER_MEM_BASE + TIMER_MEM_CNTFRQ);
+#endif
}
base-commit: b621b157b42f1fe398520cf499db88aa654c78e2
--
2.50.1
More information about the linux-arm-kernel
mailing list