mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH v3 0/8] PBL: enable timeouts in read_poll_timeout macros
@ 2026-08-17 14:01 Stefan Kerkmann
  2026-08-17 14:01 ` [PATCH v3 1/8] RISC-V: setup_c: avoid clearing BSS twice Stefan Kerkmann
                   ` (8 more replies)
  0 siblings, 9 replies; 19+ messages in thread
From: Stefan Kerkmann @ 2026-08-17 14:01 UTC (permalink / raw)
  To: Sascha Hauer, open list:BAREBOX; +Cc: Stefan Kerkmann

Without a time source the read_poll_timeout functions will deadlock in
the PBL if the break condition is never met. This series introduces the
necessary timing functions in the PBL for arches/socs implementing
PBL_CLOCKSOURCE, which is every ARMv8 SoC as they implement an
architected timer and selected ARMv7 SoCs.

Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
---
Changes in v3:
- Added PBL constructor support for ARM/ARM64/RISC-V
- Changed the implementation to PBL_CLOCKSOURCE
- Link to v2: https://patch.msgid.link/20260811-feature-pbl-get-time-ns-v2-0-754ee021b19d@pengutronix.de

Changes in v2:
- Strictly guard the pbl timer support on 32bit ARM for ARMv7 only builds
- Link to v1: https://lore.kernel.org/r/20250121-feature-pbl-get-time-ns-v1-0-c3d493397846@pengutronix.de

To: Sascha Hauer <s.hauer@pengutronix.de>
To: "open list:BAREBOX" <barebox@lists.infradead.org>

---
Stefan Kerkmann (8):
      RISC-V: setup_c: avoid clearing BSS twice
      ARM/ARM64/RISC-V: pbl: add constructor support
      clocksource: allow re-init for same clock
      drivers: arm_architected_timer: refactor for pbl compatibility
      ARM: layerscape: re-init pbl clocksource
      ARM: socfpga: agilex5: re-init pbl clocksource
      ARM64: enable PBL_CLOCKSOURCE compatibility
      linux/iopoll: enable polled timeouts for PBL_CLOCKSOURCE

 arch/arm/cpu/setupc_32.S                           |  3 +++
 arch/arm/cpu/setupc_64.S                           |  3 +++
 .../include/asm/hardware/arm_architected_timer.h   | 21 +++++++++++++++++++
 arch/arm/lib/pbl.lds.S                             |  8 ++++++++
 arch/arm/lib64/Makefile                            |  3 ++-
 arch/arm/lib64/clocksource.c                       | 10 +++++++++
 arch/arm/lib64/delay.c                             | 19 -----------------
 arch/arm/mach-layerscape/lowlevel-ls1028a.c        |  6 +++++-
 arch/arm/mach-layerscape/lowlevel-ls1046a.c        |  5 ++++-
 arch/arm/mach-socfpga/agilex5-clock-manager.c      |  7 +++----
 arch/riscv/lib/pbl.lds.S                           |  9 ++++++++
 arch/riscv/lib/setupc.S                            | 22 +++++++++++++++++++-
 common/clock.c                                     |  3 ++-
 drivers/clocksource/Kconfig                        |  1 +
 drivers/clocksource/Makefile                       |  2 +-
 drivers/clocksource/arm_architected_timer.c        | 24 ++++++++++++++--------
 include/asm-generic/sections.h                     |  2 ++
 include/linux/iopoll.h                             |  6 +++---
 pbl/Makefile                                       |  1 +
 pbl/ctors.c                                        | 13 ++++++++++++
 20 files changed, 128 insertions(+), 40 deletions(-)
---
base-commit: 3317ac1baff3b0226caba7f83f3da61bc407343a
change-id: 20250121-feature-pbl-get-time-ns-6d9e8874d582

Best regards,
--  
Stefan Kerkmann <s.kerkmann@pengutronix.de>




^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 1/8] RISC-V: setup_c: avoid clearing BSS twice
  2026-08-17 14:01 [PATCH v3 0/8] PBL: enable timeouts in read_poll_timeout macros Stefan Kerkmann
@ 2026-08-17 14:01 ` Stefan Kerkmann
  2026-08-17 14:01 ` [PATCH v3 2/8] ARM/ARM64/RISC-V: pbl: add constructor support Stefan Kerkmann
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 19+ messages in thread
From: Stefan Kerkmann @ 2026-08-17 14:01 UTC (permalink / raw)
  To: Sascha Hauer, open list:BAREBOX; +Cc: Stefan Kerkmann

This commit duplicates what is already implemented for ARM(64)[1].
Currently setup_c() isn't called twice but might be in the future.

[1]: 11c389397c ("ARM: setup_c: avoid clearing BSS twice")

Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
---
 arch/riscv/lib/setupc.S | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/lib/setupc.S b/arch/riscv/lib/setupc.S
index 423de4181e..5370e8a48e 100644
--- a/arch/riscv/lib/setupc.S
+++ b/arch/riscv/lib/setupc.S
@@ -10,13 +10,30 @@
  */
 .section .text.setup_c
 ENTRY(setup_c)
+	addi	sp, sp, -SZREG * 2
+	REG_S	ra, SZREG(sp)
+	lla	a0, bss_cleared
+	lw	a1, 0(a0)
+	bnez	a1, zeroed
 	lla	a0, __bss_start
 	li	a1, 0
 	lla	a2, __bss_stop
 	sub	a2, a2, a0
-	j	__memset
+	jal	__memset
+	lla	a0, bss_cleared
+	li	a1, 1
+	sw	a1, 0(a0)
+zeroed:
+	REG_L	ra, SZREG(sp)
+	addi	sp, sp, SZREG * 2
+	ret
 ENDPROC(setup_c)
 
+.section .data.bss_cleared
+.balign 4
+bss_cleared:
+	.word 	0
+
 /*
  * void relocate_to_adr(unsigned long targetadr)
  *

-- 
2.47.3




^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 2/8] ARM/ARM64/RISC-V: pbl: add constructor support
  2026-08-17 14:01 [PATCH v3 0/8] PBL: enable timeouts in read_poll_timeout macros Stefan Kerkmann
  2026-08-17 14:01 ` [PATCH v3 1/8] RISC-V: setup_c: avoid clearing BSS twice Stefan Kerkmann
@ 2026-08-17 14:01 ` Stefan Kerkmann
  2026-08-18 12:08   ` [PATCH] amend! " Stefan Kerkmann
  2026-08-19  9:39   ` [PATCH v3 2/8] " Sascha Hauer
  2026-08-17 14:01 ` [PATCH v3 3/8] clocksource: allow re-init for same clock Stefan Kerkmann
                   ` (6 subsequent siblings)
  8 siblings, 2 replies; 19+ messages in thread
From: Stefan Kerkmann @ 2026-08-17 14:01 UTC (permalink / raw)
  To: Sascha Hauer, open list:BAREBOX; +Cc: Stefan Kerkmann

This commit allows running functions marked with
__attribute__((constructor))[1] automatically after the C environment is
setup in setup_c, which most likely will be early setup code shared
across SoCs/Arches in the PBL.

[1]: https://gcc.gnu.org/onlinedocs/gcc-16.2.0/gcc/Common-Attributes.html#index-constructor

Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
---
 arch/arm/cpu/setupc_32.S       |  3 +++
 arch/arm/cpu/setupc_64.S       |  3 +++
 arch/arm/lib/pbl.lds.S         |  8 ++++++++
 arch/riscv/lib/pbl.lds.S       |  9 +++++++++
 arch/riscv/lib/setupc.S        |  3 +++
 include/asm-generic/sections.h |  2 ++
 pbl/Makefile                   |  1 +
 pbl/ctors.c                    | 13 +++++++++++++
 8 files changed, 42 insertions(+)

diff --git a/arch/arm/cpu/setupc_32.S b/arch/arm/cpu/setupc_32.S
index fadfc28ae1..f34b144556 100644
--- a/arch/arm/cpu/setupc_32.S
+++ b/arch/arm/cpu/setupc_32.S
@@ -23,6 +23,9 @@ ENTRY(setup_c)
 	ldr	r0, =bss_cleared
 	mov	r1, #1
 	str	r1, [r0]		/* mark bss cleared */
+#ifdef __PBL__
+	bl	pbl_do_ctors
+#endif
 1:	pop	{r4, pc}
 ENDPROC(setup_c)
 
diff --git a/arch/arm/cpu/setupc_64.S b/arch/arm/cpu/setupc_64.S
index a0767c5136..e3c6149e27 100644
--- a/arch/arm/cpu/setupc_64.S
+++ b/arch/arm/cpu/setupc_64.S
@@ -22,6 +22,9 @@ ENTRY(setup_c)
 	adr_l	x0, bss_cleared
 	mov	w1, #1
 	str	w1, [x0]		/* mark bss cleared */
+#ifdef __PBL__
+	bl	pbl_do_ctors
+#endif
 	mov	x30, x15
 1:	ret
 ENDPROC(setup_c)
diff --git a/arch/arm/lib/pbl.lds.S b/arch/arm/lib/pbl.lds.S
index 9c51f5eb3a..72aca83495 100644
--- a/arch/arm/lib/pbl.lds.S
+++ b/arch/arm/lib/pbl.lds.S
@@ -78,6 +78,14 @@ SECTIONS
 	. = ALIGN(4);
 	.rodata : { *(.rodata*) }
 
+	. = ALIGN(ASM_SZPTR);
+	__ctors_start = .;
+	.init_array : {
+		KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*)))
+		KEEP(*(.init_array))
+	}
+	__ctors_end = .;
+
 	.barebox_imd : { BAREBOX_IMD }
 
 	. = ALIGN(PBL_SEGMENT_ALIGN);
diff --git a/arch/riscv/lib/pbl.lds.S b/arch/riscv/lib/pbl.lds.S
index 3a37d01475..17cd61ff75 100644
--- a/arch/riscv/lib/pbl.lds.S
+++ b/arch/riscv/lib/pbl.lds.S
@@ -4,6 +4,7 @@
 #include <linux/sizes.h>
 #include <asm/barebox.lds.h>
 #include <asm-generic/memory_layout.h>
+#include <asm-generic/pointer.h>
 
 OUTPUT_ARCH(BAREBOX_OUTPUT_ARCH)
 OUTPUT_FORMAT(BAREBOX_OUTPUT_FORMAT)
@@ -32,6 +33,14 @@ SECTIONS
 	__start_rodata = .;
 	.rodata : { *(.rodata*) }
 
+	. = ALIGN(ASM_SZPTR);
+	__ctors_start = .;
+	.init_array : {
+		KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*)))
+		KEEP(*(.init_array))
+	}
+	__ctors_end = .;
+
 	.barebox_imd : { BAREBOX_IMD }
 
 	__end_rodata = .;
diff --git a/arch/riscv/lib/setupc.S b/arch/riscv/lib/setupc.S
index 5370e8a48e..938c78350c 100644
--- a/arch/riscv/lib/setupc.S
+++ b/arch/riscv/lib/setupc.S
@@ -23,6 +23,9 @@ ENTRY(setup_c)
 	lla	a0, bss_cleared
 	li	a1, 1
 	sw	a1, 0(a0)
+#ifdef __PBL__
+	jal	pbl_do_ctors
+#endif
 zeroed:
 	REG_L	ra, SZREG(sp)
 	addi	sp, sp, SZREG * 2
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
index 816e30341d..c7c576970a 100644
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -49,4 +49,6 @@ static inline bool in_barebox_efi_runtime(unsigned long addr)
 	       addr < (unsigned long)__efi_runtime_stop;
 }
 
+void pbl_do_ctors(void);
+
 #endif /* _ASM_GENERIC_SECTIONS_H_ */
diff --git a/pbl/Makefile b/pbl/Makefile
index 4506f192fe..7ce8cee077 100644
--- a/pbl/Makefile
+++ b/pbl/Makefile
@@ -3,6 +3,7 @@
 #
 # only unsed by the pbl
 #
+pbl-y += ctors.o
 pbl-y += misc.o
 pbl-y += string.o
 pbl-y += malloc.o
diff --git a/pbl/ctors.c b/pbl/ctors.c
new file mode 100644
index 0000000000..fcab599877
--- /dev/null
+++ b/pbl/ctors.c
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <asm-generic/sections.h>
+
+typedef void (*ctor_fn_t)(void);
+
+void pbl_do_ctors(void)
+{
+	ctor_fn_t *fn = (ctor_fn_t *)__ctors_start;
+
+	for (; fn < (ctor_fn_t *)__ctors_end; fn++)
+		(*fn)();
+}

-- 
2.47.3




^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 3/8] clocksource: allow re-init for same clock
  2026-08-17 14:01 [PATCH v3 0/8] PBL: enable timeouts in read_poll_timeout macros Stefan Kerkmann
  2026-08-17 14:01 ` [PATCH v3 1/8] RISC-V: setup_c: avoid clearing BSS twice Stefan Kerkmann
  2026-08-17 14:01 ` [PATCH v3 2/8] ARM/ARM64/RISC-V: pbl: add constructor support Stefan Kerkmann
@ 2026-08-17 14:01 ` Stefan Kerkmann
  2026-08-17 14:01 ` [PATCH v3 4/8] drivers: arm_architected_timer: refactor for pbl compatibility Stefan Kerkmann
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 19+ messages in thread
From: Stefan Kerkmann @ 2026-08-17 14:01 UTC (permalink / raw)
  To: Sascha Hauer, open list:BAREBOX; +Cc: Stefan Kerkmann

A clocksource might need to be re-initialized if fundamental parameter
changes e.g. the clock frequency. With the change the init sequence
which sets the global clocksource can be called unconditionally again
for the same clock.

Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
---
 common/clock.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/common/clock.c b/common/clock.c
index 87109f3efc..fc770ac853 100644
--- a/common/clock.c
+++ b/common/clock.c
@@ -216,7 +216,8 @@ void clocksource_srand(void)
 
 int init_clock(struct clocksource *cs)
 {
-	if (current_clock && cs->priority <= current_clock->priority)
+	if (current_clock && cs != current_clock &&
+	    cs->priority <= current_clock->priority)
 		return 0;
 
 	if (cs->init) {

-- 
2.47.3




^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 4/8] drivers: arm_architected_timer: refactor for pbl compatibility
  2026-08-17 14:01 [PATCH v3 0/8] PBL: enable timeouts in read_poll_timeout macros Stefan Kerkmann
                   ` (2 preceding siblings ...)
  2026-08-17 14:01 ` [PATCH v3 3/8] clocksource: allow re-init for same clock Stefan Kerkmann
@ 2026-08-17 14:01 ` Stefan Kerkmann
  2026-08-20  7:04   ` Sascha Hauer
  2026-08-17 14:01 ` [PATCH v3 5/8] ARM: layerscape: re-init pbl clocksource Stefan Kerkmann
                   ` (4 subsequent siblings)
  8 siblings, 1 reply; 19+ messages in thread
From: Stefan Kerkmann @ 2026-08-17 14:01 UTC (permalink / raw)
  To: Sascha Hauer, open list:BAREBOX; +Cc: Stefan Kerkmann

All ARMv8-A cores implement the 64bit wide generic timer CNTPCT[1]. Thus
the driver is the candidate for all AARCH64 SoCs to implement
PBL_CLOCKSOURCE compatibilty.

There is one catch though: the CNTFRQ_EL0 register[2] must be programmed
by the bootrom, barebox or the tf-a before the `arm_arch_timer_init`
call or the clocksource setup will return with -ENODEV. A later
re-initialization is also possible by calling `arm_arch_timer_init`
again.

[1]: See "ARM Architecture Reference Manual for A-profile architecture
(rev L.a)", chapter D12 "The Generic Timer in AArch64 state"
[2]: See "ARM Architecture Reference Manual for A-profile architecture
(rev L.a)", chapter D12.1.2.1 "Initializing and reading the system
effective frequency"

Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
---
 .../include/asm/hardware/arm_architected_timer.h   | 21 +++++++++++++++++++
 drivers/clocksource/Makefile                       |  2 +-
 drivers/clocksource/arm_architected_timer.c        | 24 ++++++++++++++--------
 3 files changed, 38 insertions(+), 9 deletions(-)

diff --git a/arch/arm/include/asm/hardware/arm_architected_timer.h b/arch/arm/include/asm/hardware/arm_architected_timer.h
new file mode 100644
index 0000000000..e0c1fd84fd
--- /dev/null
+++ b/arch/arm/include/asm/hardware/arm_architected_timer.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ASM_ARM_HARDWARE_ARCH_TIMER_H
+#define __ASM_ARM_HARDWARE_ARCH_TIMER_H
+
+#include <linux/types.h>
+
+/**
+ * arm_arch_timer_init() - Initialize the ARM architected timer as global
+ * clocksource
+ * @cntfrq: The timer frequency, if zero the frequency is read from the
+ *          CNTFRQ_EL0 register
+ *
+ * This function is meant to be called in a PBL constructor or in the driver
+ * probe function.
+ *
+ * Return: 0 on success, -ENODEV if the timer frequency can not be determined
+ */
+int arm_arch_timer_init(uint64_t cntfrq);
+
+#endif
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index dff8255650..0c92477247 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_CLOCKSOURCE_ORION)   += orion.o
 obj-$(CONFIG_CLOCKSOURCE_UEMD)    += uemd.o
 obj-$(CONFIG_CLOCKSOURCE_ROCKCHIP)+= rk_timer.o
 obj-$(CONFIG_CLOCKSOURCE_ATMEL_PIT) += timer-atmel-pit.o
-obj-$(CONFIG_CLOCKSOURCE_ARM_ARCHITECTED_TIMER) += arm_architected_timer.o
+obj-pbl-$(CONFIG_CLOCKSOURCE_ARM_ARCHITECTED_TIMER) += arm_architected_timer.o
 ifneq ($(CONFIG_CPU_V8),y)
 CFLAGS_arm_architected_timer.o := -march=armv7-a
 endif
diff --git a/drivers/clocksource/arm_architected_timer.c b/drivers/clocksource/arm_architected_timer.c
index daced94c0e..ea5f5b8e05 100644
--- a/drivers/clocksource/arm_architected_timer.c
+++ b/drivers/clocksource/arm_architected_timer.c
@@ -9,6 +9,7 @@
 #include <linux/clk.h>
 #include <io.h>
 #include <asm/system.h>
+#include <asm/hardware/arm_architected_timer.h>
 
 static uint64_t arm_arch_clocksource_read(void)
 {
@@ -22,22 +23,29 @@ static struct clocksource cs = {
 	.priority = 70,
 };
 
-static int arm_arch_timer_probe(struct device *dev)
+int arm_arch_timer_init(uint64_t cntfrq)
 {
-	u32 cntfrq;
-	int ret;
-
-	/* Some platforms don't set CNTFRQ_EL0 before barebox */
-	ret = of_property_read_u32(dev->of_node, "clock-frequency", &cntfrq);
-
-	if (ret)
+	if (!cntfrq)
 		cntfrq = get_cntfrq();
 
+	if (!cntfrq)
+		return -ENODEV;
+
 	cs.mult = clocksource_hz2mult(cntfrq, cs.shift);
 
 	return init_clock(&cs);
 }
 
+static int arm_arch_timer_probe(struct device *dev)
+{
+	u32 cntfrq = 0;
+
+	/* Some platforms don't set CNTFRQ_EL0 before barebox */
+	of_property_read_u32(dev->of_node, "clock-frequency", &cntfrq);
+
+	return arm_arch_timer_init(cntfrq);
+}
+
 static struct of_device_id arm_arch_timer_dt_ids[] = {
 	{ .compatible = "arm,armv7-timer", },
 	{ .compatible = "arm,armv8-timer", },

-- 
2.47.3




^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 5/8] ARM: layerscape: re-init pbl clocksource
  2026-08-17 14:01 [PATCH v3 0/8] PBL: enable timeouts in read_poll_timeout macros Stefan Kerkmann
                   ` (3 preceding siblings ...)
  2026-08-17 14:01 ` [PATCH v3 4/8] drivers: arm_architected_timer: refactor for pbl compatibility Stefan Kerkmann
@ 2026-08-17 14:01 ` Stefan Kerkmann
  2026-08-17 15:42   ` Ahmad Fatoum
  2026-08-20  6:59   ` Sascha Hauer
  2026-08-17 14:01 ` [PATCH v3 6/8] ARM: socfpga: agilex5: " Stefan Kerkmann
                   ` (3 subsequent siblings)
  8 siblings, 2 replies; 19+ messages in thread
From: Stefan Kerkmann @ 2026-08-17 14:01 UTC (permalink / raw)
  To: Sascha Hauer, open list:BAREBOX; +Cc: Stefan Kerkmann

After setting the cntfrq the global PBL clocksource must be
re-initialized to function correctly.

Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
---
 arch/arm/mach-layerscape/lowlevel-ls1028a.c | 6 +++++-
 arch/arm/mach-layerscape/lowlevel-ls1046a.c | 5 ++++-
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/arch/arm/mach-layerscape/lowlevel-ls1028a.c b/arch/arm/mach-layerscape/lowlevel-ls1028a.c
index fd013b2b52..ed9284d55a 100644
--- a/arch/arm/mach-layerscape/lowlevel-ls1028a.c
+++ b/arch/arm/mach-layerscape/lowlevel-ls1028a.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 #include <common.h>
 #include <io.h>
+#include <asm/hardware/arm_architected_timer.h>
 #include <asm/syscounter.h>
 #include <asm/system.h>
 #include <mach/layerscape/errata.h>
@@ -35,8 +36,11 @@ static void ls1028a_timer_init(void)
 
 void ls1028a_init_lowlevel(void)
 {
+	const uint64_t cntfrq = 25000000;
+
 	scfg_init(SCFG_ENDIANESS_LITTLE);
-	set_cntfrq(25000000);
+	set_cntfrq(cntfrq);
+	arm_arch_timer_init(cntfrq);
 	ls1028a_timer_init();
 	ls1028a_errata();
 }
diff --git a/arch/arm/mach-layerscape/lowlevel-ls1046a.c b/arch/arm/mach-layerscape/lowlevel-ls1046a.c
index 1307c05eaf..cc2793acf2 100644
--- a/arch/arm/mach-layerscape/lowlevel-ls1046a.c
+++ b/arch/arm/mach-layerscape/lowlevel-ls1046a.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 #include <common.h>
 #include <io.h>
+#include <asm/hardware/arm_architected_timer.h>
 #include <asm/syscounter.h>
 #include <asm/system.h>
 #include <mach/layerscape/errata.h>
@@ -222,11 +223,13 @@ void ls1046a_init_lowlevel(void)
 {
 	struct ccsr_cci400 __iomem *cci = IOMEM(LSCH2_CCI400_ADDR);
 	struct ccsr_scfg *scfg = IOMEM(LSCH2_SCFG_ADDR);
+	const uint64_t cntfrq = 25000000;
 
 	scfg_init(SCFG_ENDIANESS_BIG);
 	init_csu();
 	ls1046a_init_l2_latency();
-	set_cntfrq(25000000);
+	set_cntfrq(cntfrq);
+	arm_arch_timer_init(cntfrq);
 	syscnt_enable(IOMEM(LSCH2_SYS_COUNTER_ADDR));
 
 	/* Make DMA master reads and writes snoopable */

-- 
2.47.3




^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 6/8] ARM: socfpga: agilex5: re-init pbl clocksource
  2026-08-17 14:01 [PATCH v3 0/8] PBL: enable timeouts in read_poll_timeout macros Stefan Kerkmann
                   ` (4 preceding siblings ...)
  2026-08-17 14:01 ` [PATCH v3 5/8] ARM: layerscape: re-init pbl clocksource Stefan Kerkmann
@ 2026-08-17 14:01 ` Stefan Kerkmann
  2026-08-17 14:01 ` [PATCH v3 7/8] ARM64: enable PBL_CLOCKSOURCE compatibility Stefan Kerkmann
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 19+ messages in thread
From: Stefan Kerkmann @ 2026-08-17 14:01 UTC (permalink / raw)
  To: Sascha Hauer, open list:BAREBOX; +Cc: Stefan Kerkmann

After changing the cntfrq register the global PBL clocksource must be
re-initialized. The inline assembly was dropped in favor of the
set_cntfrq function, the subsequent read is a no-op and dropped without
a replacement.

Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
---
 arch/arm/mach-socfpga/agilex5-clock-manager.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-socfpga/agilex5-clock-manager.c b/arch/arm/mach-socfpga/agilex5-clock-manager.c
index 4ce7a2d4a2..0b0425efc1 100644
--- a/arch/arm/mach-socfpga/agilex5-clock-manager.c
+++ b/arch/arm/mach-socfpga/agilex5-clock-manager.c
@@ -5,6 +5,7 @@
 
 #include <common.h>
 #include <io.h>
+#include <asm/hardware/arm_architected_timer.h>
 #include <asm/system.h>
 #include <dt-bindings/clock/intel,agilex5-clkmgr.h>
 #include <linux/bitops.h>
@@ -252,8 +253,6 @@ static void clk_basic_init(struct socfpga_clk_plat *plat,
 {
 	u32 vcocalib;
 	u32 cntfrq = COUNTER_FREQUENCY_REAL;
-	u32 counter_freq = 0;
-
 
 	if (!cfg)
 		return;
@@ -361,8 +360,8 @@ static void clk_basic_init(struct socfpga_clk_plat *plat,
 
 	/* Update with accurate clock frequency */
 	if (current_el() == 3) {
-		asm volatile("msr cntfrq_el0, %0" : : "r" (cntfrq) : "memory");
-		asm volatile("mrs %0, cntfrq_el0" : "=r" (counter_freq));
+		set_cntfrq(cntfrq);
+		arm_arch_timer_init(cntfrq);
 	}
 
 	/* Out of boot mode */

-- 
2.47.3




^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 7/8] ARM64: enable PBL_CLOCKSOURCE compatibility
  2026-08-17 14:01 [PATCH v3 0/8] PBL: enable timeouts in read_poll_timeout macros Stefan Kerkmann
                   ` (5 preceding siblings ...)
  2026-08-17 14:01 ` [PATCH v3 6/8] ARM: socfpga: agilex5: " Stefan Kerkmann
@ 2026-08-17 14:01 ` Stefan Kerkmann
  2026-08-17 14:01 ` [PATCH v3 8/8] linux/iopoll: enable polled timeouts for PBL_CLOCKSOURCE Stefan Kerkmann
  2026-08-19  7:03 ` [PATCH v3 0/8] PBL: enable timeouts in read_poll_timeout macros Sascha Hauer
  8 siblings, 0 replies; 19+ messages in thread
From: Stefan Kerkmann @ 2026-08-17 14:01 UTC (permalink / raw)
  To: Sascha Hauer, open list:BAREBOX; +Cc: Stefan Kerkmann

All ARMv8-A cores implement the 64bit wide generic timer CNTPCT[1]. If
the architected timer driver is enabled the barebox PBL automatically is
PBL_CLOCKSOURCE compatible.

The setup of the PBL clocksource is implemented in the newly added PBL
constructors which are called at the end of setup_c. There is one catch
though:

The CNTFRQ_EL0 register[2] must be programmed by the bootrom, barebox or
the tf-a before the `arm_arch_timer_init` call. A later
re-initialization is also possible by calling `arm_arch_timer_init`
again.

[1]: See "ARM Architecture Reference Manual for A-profile architecture
(rev L.a)", chapter D12 "The Generic Timer in AArch64 state"
[2]: See "ARM Architecture Reference Manual for A-profile architecture
(rev L.a)", chapter D12.1.2.1 "Initializing and reading the system
effective frequency"

Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
---
 arch/arm/lib64/Makefile      |  3 ++-
 arch/arm/lib64/clocksource.c | 10 ++++++++++
 arch/arm/lib64/delay.c       | 19 -------------------
 drivers/clocksource/Kconfig  |  1 +
 4 files changed, 13 insertions(+), 20 deletions(-)

diff --git a/arch/arm/lib64/Makefile b/arch/arm/lib64/Makefile
index f28cf81ab3..218de68a54 100644
--- a/arch/arm/lib64/Makefile
+++ b/arch/arm/lib64/Makefile
@@ -10,4 +10,5 @@ obj-pbl-y   += runtime-offset.o
 obj-pbl-y   += setjmp.o
 obj-pbl-y   += reloc.o
 obj-y += io.o
-pbl-y	+= div0.o delay.o
+pbl-$(CONFIG_CLOCKSOURCE_ARM_ARCHITECTED_TIMER)	+= clocksource.o
+pbl-y	+= div0.o
diff --git a/arch/arm/lib64/clocksource.c b/arch/arm/lib64/clocksource.c
new file mode 100644
index 0000000000..f992be09b8
--- /dev/null
+++ b/arch/arm/lib64/clocksource.c
@@ -0,0 +1,10 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <debug_ll.h>
+#include <asm/hardware/arm_architected_timer.h>
+
+__attribute__((constructor)) static void init_arch_clock(void)
+{
+	if (arm_arch_timer_init(0))
+		puts_ll("Failed to setup architected timer\n");
+}
diff --git a/arch/arm/lib64/delay.c b/arch/arm/lib64/delay.c
deleted file mode 100644
index 78eab33f8d..0000000000
--- a/arch/arm/lib64/delay.c
+++ /dev/null
@@ -1,19 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-
-#include <asm/system.h>
-#include <clock.h>
-#include <common.h>
-
-void udelay(unsigned long us)
-{
-	unsigned long cntfrq = get_cntfrq();
-	unsigned long ticks = (us * cntfrq) / 1000000;
-	unsigned long start = get_cntpct();
-
-	while ((long)(start + ticks - get_cntpct()) > 0);
-}
-
-void mdelay(unsigned long ms)
-{
-	udelay(ms * 1000);
-}
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 5ee83d2b38..6cf68d8be4 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -79,6 +79,7 @@ config CLOCKSOURCE_ARM_ARCHITECTED_TIMER
 	bool "ARM architected timer clock source" if COMPILE_TEST
 	default y
 	depends on ARM && (CPU_64v8 || CPU_V7)
+	select PBL_CLOCKSOURCE if CPU_64v8
 
 config CLOCKSOURCE_ARM_GLOBAL_TIMER
 	bool "ARM global timer clock source" if COMPILE_TEST

-- 
2.47.3




^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH v3 8/8] linux/iopoll: enable polled timeouts for PBL_CLOCKSOURCE
  2026-08-17 14:01 [PATCH v3 0/8] PBL: enable timeouts in read_poll_timeout macros Stefan Kerkmann
                   ` (6 preceding siblings ...)
  2026-08-17 14:01 ` [PATCH v3 7/8] ARM64: enable PBL_CLOCKSOURCE compatibility Stefan Kerkmann
@ 2026-08-17 14:01 ` Stefan Kerkmann
  2026-08-19  7:03 ` [PATCH v3 0/8] PBL: enable timeouts in read_poll_timeout macros Sascha Hauer
  8 siblings, 0 replies; 19+ messages in thread
From: Stefan Kerkmann @ 2026-08-17 14:01 UTC (permalink / raw)
  To: Sascha Hauer, open list:BAREBOX; +Cc: Stefan Kerkmann

This enables the usage of the polled timeout functions in the barebox
pbl with real timeouts for supported architectures. Currently only
AARCH64 and MACH_AM33XX is enabled.

Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
---
 include/linux/iopoll.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/include/linux/iopoll.h b/include/linux/iopoll.h
index a6fade2a11..21014b73da 100644
--- a/include/linux/iopoll.h
+++ b/include/linux/iopoll.h
@@ -12,7 +12,7 @@
 #include <clock.h>
 #include <pbl.h>
 
-#if IN_PROPER
+#if IN_PROPER || IS_ENABLED(CONFIG_PBL_CLOCKSOURCE)
 # define read_poll_get_time_ns()	get_time_ns()
 # define read_poll_is_timeout(s, t)	is_timeout(s, t)
 #else
@@ -38,8 +38,8 @@
  * When available, you'll probably want to use one of the specialized
  * macros defined below rather than this macro directly.
  *
- * We do not have timing functions in the PBL, so ignore the timeout value and
- * loop infinitely here.
+ * We might not have timing functions in the PBL, so ignore the timeout value
+ * and loop infinitely here.
  */
 #define read_poll_timeout(op, val, cond, timeout_us, args...)	\
 ({ \

-- 
2.47.3




^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 5/8] ARM: layerscape: re-init pbl clocksource
  2026-08-17 14:01 ` [PATCH v3 5/8] ARM: layerscape: re-init pbl clocksource Stefan Kerkmann
@ 2026-08-17 15:42   ` Ahmad Fatoum
  2026-08-20  6:59   ` Sascha Hauer
  1 sibling, 0 replies; 19+ messages in thread
From: Ahmad Fatoum @ 2026-08-17 15:42 UTC (permalink / raw)
  To: Stefan Kerkmann, Sascha Hauer, open list:BAREBOX



On 8/17/26 4:01 PM, Stefan Kerkmann wrote:
> After setting the cntfrq the global PBL clocksource must be
> re-initialized to function correctly.
> 
> Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>

Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>

I was unsure at first, but these function are indeed only called after
relocation.

Cheers,
Ahmad

> ---
>  arch/arm/mach-layerscape/lowlevel-ls1028a.c | 6 +++++-
>  arch/arm/mach-layerscape/lowlevel-ls1046a.c | 5 ++++-
>  2 files changed, 9 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/mach-layerscape/lowlevel-ls1028a.c b/arch/arm/mach-layerscape/lowlevel-ls1028a.c
> index fd013b2b52..ed9284d55a 100644
> --- a/arch/arm/mach-layerscape/lowlevel-ls1028a.c
> +++ b/arch/arm/mach-layerscape/lowlevel-ls1028a.c
> @@ -1,6 +1,7 @@
>  // SPDX-License-Identifier: GPL-2.0+
>  #include <common.h>
>  #include <io.h>
> +#include <asm/hardware/arm_architected_timer.h>
>  #include <asm/syscounter.h>
>  #include <asm/system.h>
>  #include <mach/layerscape/errata.h>
> @@ -35,8 +36,11 @@ static void ls1028a_timer_init(void)
>  
>  void ls1028a_init_lowlevel(void)
>  {
> +	const uint64_t cntfrq = 25000000;
> +
>  	scfg_init(SCFG_ENDIANESS_LITTLE);
> -	set_cntfrq(25000000);
> +	set_cntfrq(cntfrq);
> +	arm_arch_timer_init(cntfrq);
>  	ls1028a_timer_init();
>  	ls1028a_errata();
>  }
> diff --git a/arch/arm/mach-layerscape/lowlevel-ls1046a.c b/arch/arm/mach-layerscape/lowlevel-ls1046a.c
> index 1307c05eaf..cc2793acf2 100644
> --- a/arch/arm/mach-layerscape/lowlevel-ls1046a.c
> +++ b/arch/arm/mach-layerscape/lowlevel-ls1046a.c
> @@ -1,6 +1,7 @@
>  // SPDX-License-Identifier: GPL-2.0+
>  #include <common.h>
>  #include <io.h>
> +#include <asm/hardware/arm_architected_timer.h>
>  #include <asm/syscounter.h>
>  #include <asm/system.h>
>  #include <mach/layerscape/errata.h>
> @@ -222,11 +223,13 @@ void ls1046a_init_lowlevel(void)
>  {
>  	struct ccsr_cci400 __iomem *cci = IOMEM(LSCH2_CCI400_ADDR);
>  	struct ccsr_scfg *scfg = IOMEM(LSCH2_SCFG_ADDR);
> +	const uint64_t cntfrq = 25000000;
>  
>  	scfg_init(SCFG_ENDIANESS_BIG);
>  	init_csu();
>  	ls1046a_init_l2_latency();
> -	set_cntfrq(25000000);
> +	set_cntfrq(cntfrq);
> +	arm_arch_timer_init(cntfrq);
>  	syscnt_enable(IOMEM(LSCH2_SYS_COUNTER_ADDR));
>  
>  	/* Make DMA master reads and writes snoopable */
> 

-- 
Pengutronix e.K.                  |                             |
Steuerwalder Str. 21              | http://www.pengutronix.de/  |
31137 Hildesheim, Germany         | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686  | Fax:   +49-5121-206917-5555 |




^ permalink raw reply	[flat|nested] 19+ messages in thread

* [PATCH] amend! ARM/ARM64/RISC-V: pbl: add constructor support
  2026-08-17 14:01 ` [PATCH v3 2/8] ARM/ARM64/RISC-V: pbl: add constructor support Stefan Kerkmann
@ 2026-08-18 12:08   ` Stefan Kerkmann
  2026-08-19  9:39   ` [PATCH v3 2/8] " Sascha Hauer
  1 sibling, 0 replies; 19+ messages in thread
From: Stefan Kerkmann @ 2026-08-18 12:08 UTC (permalink / raw)
  To: Sascha Hauer, open list:BAREBOX; +Cc: Stefan Kerkmann

ARM/ARM64/RISC-V: pbl: add constructor support

This commit allows running functions marked with
__attribute__((constructor))[1] automatically after the C environment is
setup in setup_c, which most likely will be early setup code shared
across SoCs/Arches in the PBL.

The ARM64 setup_c function saved the link register (x30) in the caller
save register (x15). This is fragile as a constructor might use x15,
thus save it on the stack just like ARM32 and RISC-V.

[1]: https://gcc.gnu.org/onlinedocs/gcc-16.2.0/gcc/Common-Attributes.html#index-constructor

Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
---
 arch/arm/cpu/setupc_64.S | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/arch/arm/cpu/setupc_64.S b/arch/arm/cpu/setupc_64.S
index e3c6149e27..b1cfea47b1 100644
--- a/arch/arm/cpu/setupc_64.S
+++ b/arch/arm/cpu/setupc_64.S
@@ -10,10 +10,10 @@
  * setup_c: clear bss if not yet done
  */
 ENTRY(setup_c)
+	str x30, [sp, #-16]!
 	adr_l	x0, bss_cleared
 	ldr	w1, [x0]
 	cbnz	w1, 1f			/* skip if already done */
-	mov	x15, x30
 	adr_l	x0, __bss_start
 	mov	x1, #0
 	adr_l	x2, __bss_stop
@@ -25,8 +25,9 @@ ENTRY(setup_c)
 #ifdef __PBL__
 	bl	pbl_do_ctors
 #endif
-	mov	x30, x15
-1:	ret
+1:
+	ldr x30, [sp], #16
+	ret
 ENDPROC(setup_c)
 
 .section .data.bss_cleared
-- 
2.47.3




^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 0/8] PBL: enable timeouts in read_poll_timeout macros
  2026-08-17 14:01 [PATCH v3 0/8] PBL: enable timeouts in read_poll_timeout macros Stefan Kerkmann
                   ` (7 preceding siblings ...)
  2026-08-17 14:01 ` [PATCH v3 8/8] linux/iopoll: enable polled timeouts for PBL_CLOCKSOURCE Stefan Kerkmann
@ 2026-08-19  7:03 ` Sascha Hauer
  8 siblings, 0 replies; 19+ messages in thread
From: Sascha Hauer @ 2026-08-19  7:03 UTC (permalink / raw)
  To: open list:BAREBOX, Stefan Kerkmann


On Mon, 17 Aug 2026 16:01:11 +0200, Stefan Kerkmann wrote:
> Without a time source the read_poll_timeout functions will deadlock in
> the PBL if the break condition is never met. This series introduces the
> necessary timing functions in the PBL for arches/socs implementing
> PBL_CLOCKSOURCE, which is every ARMv8 SoC as they implement an
> architected timer and selected ARMv7 SoCs.
> 
> 
> [...]

Applied, thanks!

[1/8] RISC-V: setup_c: avoid clearing BSS twice
      https://git.pengutronix.de/cgit/barebox/commit/?id=01c4186b3ea2 (link may not be stable)
[2/8] ARM/ARM64/RISC-V: pbl: add constructor support
      https://git.pengutronix.de/cgit/barebox/commit/?id=bb07ef11d630 (link may not be stable)
[3/8] clocksource: allow re-init for same clock
      https://git.pengutronix.de/cgit/barebox/commit/?id=ac074413caca (link may not be stable)
[4/8] drivers: arm_architected_timer: refactor for pbl compatibility
      https://git.pengutronix.de/cgit/barebox/commit/?id=863ed4398f64 (link may not be stable)
[5/8] ARM: layerscape: re-init pbl clocksource
      https://git.pengutronix.de/cgit/barebox/commit/?id=0e1c3c77947d (link may not be stable)
[6/8] ARM: socfpga: agilex5: re-init pbl clocksource
      https://git.pengutronix.de/cgit/barebox/commit/?id=b28ad579be5a (link may not be stable)
[7/8] ARM64: enable PBL_CLOCKSOURCE compatibility
      https://git.pengutronix.de/cgit/barebox/commit/?id=da7fa356d4a2 (link may not be stable)
[8/8] linux/iopoll: enable polled timeouts for PBL_CLOCKSOURCE
      https://git.pengutronix.de/cgit/barebox/commit/?id=16e6243f96fd (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer@pengutronix.de>




^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 2/8] ARM/ARM64/RISC-V: pbl: add constructor support
  2026-08-17 14:01 ` [PATCH v3 2/8] ARM/ARM64/RISC-V: pbl: add constructor support Stefan Kerkmann
  2026-08-18 12:08   ` [PATCH] amend! " Stefan Kerkmann
@ 2026-08-19  9:39   ` Sascha Hauer
  1 sibling, 0 replies; 19+ messages in thread
From: Sascha Hauer @ 2026-08-19  9:39 UTC (permalink / raw)
  To: Stefan Kerkmann; +Cc: open list:BAREBOX, Stefan Kerkmann

Hi Stefan,

On 2026-08-17 16:01, Stefan Kerkmann wrote:
> This commit allows running functions marked with
> __attribute__((constructor))[1] automatically after the C environment is
> setup in setup_c, which most likely will be early setup code shared
> across SoCs/Arches in the PBL.

This breaks hosttools_defconfig, sandbox_defconfig and targettools_defconfig with:

/usr/bin/ld: pbl/ctors.pbl.o: in function `pbl_do_ctors':
ctors.c:(.text.pbl_do_ctors+0x9): undefined reference to `__ctors_end'
/usr/bin/ld: ctors.c:(.text.pbl_do_ctors+0x11): undefined reference to `__ctors_start'

Could you send a fixup?




^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 5/8] ARM: layerscape: re-init pbl clocksource
  2026-08-17 14:01 ` [PATCH v3 5/8] ARM: layerscape: re-init pbl clocksource Stefan Kerkmann
  2026-08-17 15:42   ` Ahmad Fatoum
@ 2026-08-20  6:59   ` Sascha Hauer
  2026-08-20  8:06     ` Stefan Kerkmann
  1 sibling, 1 reply; 19+ messages in thread
From: Sascha Hauer @ 2026-08-20  6:59 UTC (permalink / raw)
  To: Stefan Kerkmann; +Cc: open list:BAREBOX, Stefan Kerkmann

On 2026-08-17 16:01, Stefan Kerkmann wrote:
> After setting the cntfrq the global PBL clocksource must be
> re-initialized to function correctly.
> 
> Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
> ---
>  arch/arm/mach-layerscape/lowlevel-ls1028a.c | 6 +++++-
>  arch/arm/mach-layerscape/lowlevel-ls1046a.c | 5 ++++-
>  2 files changed, 9 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/mach-layerscape/lowlevel-ls1028a.c b/arch/arm/mach-layerscape/lowlevel-ls1028a.c
> index fd013b2b52..ed9284d55a 100644
> --- a/arch/arm/mach-layerscape/lowlevel-ls1028a.c
> +++ b/arch/arm/mach-layerscape/lowlevel-ls1028a.c
> @@ -1,6 +1,7 @@
>  // SPDX-License-Identifier: GPL-2.0+
>  #include <common.h>
>  #include <io.h>
> +#include <asm/hardware/arm_architected_timer.h>
>  #include <asm/syscounter.h>
>  #include <asm/system.h>
>  #include <mach/layerscape/errata.h>
> @@ -35,8 +36,11 @@ static void ls1028a_timer_init(void)
>  
>  void ls1028a_init_lowlevel(void)
>  {
> +	const uint64_t cntfrq = 25000000;
> +
>  	scfg_init(SCFG_ENDIANESS_LITTLE);
> -	set_cntfrq(25000000);
> +	set_cntfrq(cntfrq);
> +	arm_arch_timer_init(cntfrq);
>  	ls1028a_timer_init();
>  	ls1028a_errata();
>  }

I had to squash this patch together with the next two to avoid
intermediate compile breakage. Otherwise we get an undefined reference
to clocksource_hz2mult().

One thing that strikes me here is that first arm_arch_timer_init() is
called and afterwards ls1028a_timer_init(). I have no idea what timer
ls1028a_timer_init() initializes and if that has anything to do with
the architected timer, but if it has the order should likely be the
other way round.

Sascha

--
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |




^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 4/8] drivers: arm_architected_timer: refactor for pbl compatibility
  2026-08-17 14:01 ` [PATCH v3 4/8] drivers: arm_architected_timer: refactor for pbl compatibility Stefan Kerkmann
@ 2026-08-20  7:04   ` Sascha Hauer
  2026-08-20  7:32     ` Stefan Kerkmann
  0 siblings, 1 reply; 19+ messages in thread
From: Sascha Hauer @ 2026-08-20  7:04 UTC (permalink / raw)
  To: Stefan Kerkmann; +Cc: open list:BAREBOX, Stefan Kerkmann

On 2026-08-17 16:01, Stefan Kerkmann wrote:
> All ARMv8-A cores implement the 64bit wide generic timer CNTPCT[1]. Thus
> the driver is the candidate for all AARCH64 SoCs to implement
> PBL_CLOCKSOURCE compatibilty.
> 
> There is one catch though: the CNTFRQ_EL0 register[2] must be programmed
> by the bootrom, barebox or the tf-a before the `arm_arch_timer_init`
> call or the clocksource setup will return with -ENODEV. A later
> re-initialization is also possible by calling `arm_arch_timer_init`
> again.
> 
> [1]: See "ARM Architecture Reference Manual for A-profile architecture
> (rev L.a)", chapter D12 "The Generic Timer in AArch64 state"
> [2]: See "ARM Architecture Reference Manual for A-profile architecture
> (rev L.a)", chapter D12.1.2.1 "Initializing and reading the system
> effective frequency"
> 
> Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
> ---
>  .../include/asm/hardware/arm_architected_timer.h   | 21 +++++++++++++++++++
>  drivers/clocksource/Makefile                       |  2 +-
>  drivers/clocksource/arm_architected_timer.c        | 24 ++++++++++++++--------
>  3 files changed, 38 insertions(+), 9 deletions(-)
> 
> diff --git a/arch/arm/include/asm/hardware/arm_architected_timer.h b/arch/arm/include/asm/hardware/arm_architected_timer.h
> new file mode 100644
> index 0000000000..e0c1fd84fd
> --- /dev/null
> +++ b/arch/arm/include/asm/hardware/arm_architected_timer.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +
> +#ifndef __ASM_ARM_HARDWARE_ARCH_TIMER_H
> +#define __ASM_ARM_HARDWARE_ARCH_TIMER_H
> +
> +#include <linux/types.h>
> +
> +/**
> + * arm_arch_timer_init() - Initialize the ARM architected timer as global
> + * clocksource
> + * @cntfrq: The timer frequency, if zero the frequency is read from the
> + *          CNTFRQ_EL0 register
> + *
> + * This function is meant to be called in a PBL constructor or in the driver
> + * probe function.
> + *
> + * Return: 0 on success, -ENODEV if the timer frequency can not be determined
> + */
> +int arm_arch_timer_init(uint64_t cntfrq);
> +
> +#endif
> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
> index dff8255650..0c92477247 100644
> --- a/drivers/clocksource/Makefile
> +++ b/drivers/clocksource/Makefile
> @@ -13,7 +13,7 @@ obj-$(CONFIG_CLOCKSOURCE_ORION)   += orion.o
>  obj-$(CONFIG_CLOCKSOURCE_UEMD)    += uemd.o
>  obj-$(CONFIG_CLOCKSOURCE_ROCKCHIP)+= rk_timer.o
>  obj-$(CONFIG_CLOCKSOURCE_ATMEL_PIT) += timer-atmel-pit.o
> -obj-$(CONFIG_CLOCKSOURCE_ARM_ARCHITECTED_TIMER) += arm_architected_timer.o
> +obj-pbl-$(CONFIG_CLOCKSOURCE_ARM_ARCHITECTED_TIMER) += arm_architected_timer.o
>  ifneq ($(CONFIG_CPU_V8),y)
>  CFLAGS_arm_architected_timer.o := -march=armv7-a
>  endif
> diff --git a/drivers/clocksource/arm_architected_timer.c b/drivers/clocksource/arm_architected_timer.c
> index daced94c0e..ea5f5b8e05 100644
> --- a/drivers/clocksource/arm_architected_timer.c
> +++ b/drivers/clocksource/arm_architected_timer.c
> @@ -9,6 +9,7 @@
>  #include <linux/clk.h>
>  #include <io.h>
>  #include <asm/system.h>
> +#include <asm/hardware/arm_architected_timer.h>
>  
>  static uint64_t arm_arch_clocksource_read(void)
>  {
> @@ -22,22 +23,29 @@ static struct clocksource cs = {
>  	.priority = 70,
>  };
>  
> -static int arm_arch_timer_probe(struct device *dev)
> +int arm_arch_timer_init(uint64_t cntfrq)
>  {
> -	u32 cntfrq;
> -	int ret;
> -
> -	/* Some platforms don't set CNTFRQ_EL0 before barebox */
> -	ret = of_property_read_u32(dev->of_node, "clock-frequency", &cntfrq);
> -
> -	if (ret)
> +	if (!cntfrq)
>  		cntfrq = get_cntfrq();

I wonder if we should just drop the cntfrq argument. All users call
set_cntfrq() before calling this, so get_cntfrq() should return the
correct value and we can rely on it.

Sascha

--
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |




^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 4/8] drivers: arm_architected_timer: refactor for pbl compatibility
  2026-08-20  7:04   ` Sascha Hauer
@ 2026-08-20  7:32     ` Stefan Kerkmann
  2026-08-20  8:00       ` Sascha Hauer
  0 siblings, 1 reply; 19+ messages in thread
From: Stefan Kerkmann @ 2026-08-20  7:32 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: open list:BAREBOX

Hi Sascha,

On 8/20/26 09:04, Sascha Hauer wrote:
> On 2026-08-17 16:01, Stefan Kerkmann wrote:
>> All ARMv8-A cores implement the 64bit wide generic timer CNTPCT[1]. Thus
>> the driver is the candidate for all AARCH64 SoCs to implement
>> PBL_CLOCKSOURCE compatibilty.
>>
>> There is one catch though: the CNTFRQ_EL0 register[2] must be programmed
>> by the bootrom, barebox or the tf-a before the `arm_arch_timer_init`
>> call or the clocksource setup will return with -ENODEV. A later
>> re-initialization is also possible by calling `arm_arch_timer_init`
>> again.
>>
>> [1]: See "ARM Architecture Reference Manual for A-profile architecture
>> (rev L.a)", chapter D12 "The Generic Timer in AArch64 state"
>> [2]: See "ARM Architecture Reference Manual for A-profile architecture
>> (rev L.a)", chapter D12.1.2.1 "Initializing and reading the system
>> effective frequency"
>>
>> Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
>> ---
>>  .../include/asm/hardware/arm_architected_timer.h   | 21 +++++++++++++++++++
>>  drivers/clocksource/Makefile                       |  2 +-
>>  drivers/clocksource/arm_architected_timer.c        | 24 ++++++++++++++--------
>>  3 files changed, 38 insertions(+), 9 deletions(-)
>>
>> diff --git a/arch/arm/include/asm/hardware/arm_architected_timer.h b/arch/arm/include/asm/hardware/arm_architected_timer.h
>> new file mode 100644
>> index 0000000000..e0c1fd84fd
>> --- /dev/null
>> +++ b/arch/arm/include/asm/hardware/arm_architected_timer.h
>> @@ -0,0 +1,21 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +
>> +#ifndef __ASM_ARM_HARDWARE_ARCH_TIMER_H
>> +#define __ASM_ARM_HARDWARE_ARCH_TIMER_H
>> +
>> +#include <linux/types.h>
>> +
>> +/**
>> + * arm_arch_timer_init() - Initialize the ARM architected timer as global
>> + * clocksource
>> + * @cntfrq: The timer frequency, if zero the frequency is read from the
>> + *          CNTFRQ_EL0 register
>> + *
>> + * This function is meant to be called in a PBL constructor or in the driver
>> + * probe function.
>> + *
>> + * Return: 0 on success, -ENODEV if the timer frequency can not be determined
>> + */
>> +int arm_arch_timer_init(uint64_t cntfrq);
>> +
>> +#endif
>> diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
>> index dff8255650..0c92477247 100644
>> --- a/drivers/clocksource/Makefile
>> +++ b/drivers/clocksource/Makefile
>> @@ -13,7 +13,7 @@ obj-$(CONFIG_CLOCKSOURCE_ORION)   += orion.o
>>  obj-$(CONFIG_CLOCKSOURCE_UEMD)    += uemd.o
>>  obj-$(CONFIG_CLOCKSOURCE_ROCKCHIP)+= rk_timer.o
>>  obj-$(CONFIG_CLOCKSOURCE_ATMEL_PIT) += timer-atmel-pit.o
>> -obj-$(CONFIG_CLOCKSOURCE_ARM_ARCHITECTED_TIMER) += arm_architected_timer.o
>> +obj-pbl-$(CONFIG_CLOCKSOURCE_ARM_ARCHITECTED_TIMER) += arm_architected_timer.o
>>  ifneq ($(CONFIG_CPU_V8),y)
>>  CFLAGS_arm_architected_timer.o := -march=armv7-a
>>  endif
>> diff --git a/drivers/clocksource/arm_architected_timer.c b/drivers/clocksource/arm_architected_timer.c
>> index daced94c0e..ea5f5b8e05 100644
>> --- a/drivers/clocksource/arm_architected_timer.c
>> +++ b/drivers/clocksource/arm_architected_timer.c
>> @@ -9,6 +9,7 @@
>>  #include <linux/clk.h>
>>  #include <io.h>
>>  #include <asm/system.h>
>> +#include <asm/hardware/arm_architected_timer.h>
>>  
>>  static uint64_t arm_arch_clocksource_read(void)
>>  {
>> @@ -22,22 +23,29 @@ static struct clocksource cs = {
>>  	.priority = 70,
>>  };
>>  
>> -static int arm_arch_timer_probe(struct device *dev)
>> +int arm_arch_timer_init(uint64_t cntfrq)
>>  {
>> -	u32 cntfrq;
>> -	int ret;
>> -
>> -	/* Some platforms don't set CNTFRQ_EL0 before barebox */
>> -	ret = of_property_read_u32(dev->of_node, "clock-frequency", &cntfrq);
>> -
>> -	if (ret)
>> +	if (!cntfrq)
>>  		cntfrq = get_cntfrq();
> 
> I wonder if we should just drop the cntfrq argument. All users call
> set_cntfrq() before calling this, so get_cntfrq() should return the
> correct value and we can rely on it.
> 

Maybe keep the argument and use set_cntfrq in arm_arch_timer_init if the
argument is !=0? Then arm_arch_timer_init is the function to use if a C
environment is available? This would prevent any inconsistency.

> Sascha
> 

Best regards,
Stefan

> --
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> 

-- 
Pengutronix e.K.                       | Stefan Kerkmann             |
Steuerwalder Str. 21                   | https://www.pengutronix.de/ |
31137 Hildesheim, Germany              | Phone: +49-5121-206917-128  |
Amtsgericht Hildesheim, HRA 2686       | Fax:   +49-5121-206917-9    |




^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 4/8] drivers: arm_architected_timer: refactor for pbl compatibility
  2026-08-20  7:32     ` Stefan Kerkmann
@ 2026-08-20  8:00       ` Sascha Hauer
  2026-08-20  8:07         ` Stefan Kerkmann
  0 siblings, 1 reply; 19+ messages in thread
From: Sascha Hauer @ 2026-08-20  8:00 UTC (permalink / raw)
  To: Stefan Kerkmann; +Cc: open list:BAREBOX

On 2026-08-20 09:32, Stefan Kerkmann wrote:
> >> diff --git a/drivers/clocksource/arm_architected_timer.c b/drivers/clocksource/arm_architected_timer.c
> >> index daced94c0e..ea5f5b8e05 100644
> >> --- a/drivers/clocksource/arm_architected_timer.c
> >> +++ b/drivers/clocksource/arm_architected_timer.c
> >> @@ -9,6 +9,7 @@
> >>  #include <linux/clk.h>
> >>  #include <io.h>
> >>  #include <asm/system.h>
> >> +#include <asm/hardware/arm_architected_timer.h>
> >>  
> >>  static uint64_t arm_arch_clocksource_read(void)
> >>  {
> >> @@ -22,22 +23,29 @@ static struct clocksource cs = {
> >>  	.priority = 70,
> >>  };
> >>  
> >> -static int arm_arch_timer_probe(struct device *dev)
> >> +int arm_arch_timer_init(uint64_t cntfrq)
> >>  {
> >> -	u32 cntfrq;
> >> -	int ret;
> >> -
> >> -	/* Some platforms don't set CNTFRQ_EL0 before barebox */
> >> -	ret = of_property_read_u32(dev->of_node, "clock-frequency", &cntfrq);
> >> -
> >> -	if (ret)
> >> +	if (!cntfrq)
> >>  		cntfrq = get_cntfrq();
> > 
> > I wonder if we should just drop the cntfrq argument. All users call
> > set_cntfrq() before calling this, so get_cntfrq() should return the
> > correct value and we can rely on it.
> > 
> 
> Maybe keep the argument and use set_cntfrq in arm_arch_timer_init if the
> argument is !=0? Then arm_arch_timer_init is the function to use if a C
> environment is available? This would prevent any inconsistency.

I am not sure, but set_cntfrq() might only be usable in EL3, so you
would have to be careful about the exception level when calling
arm_arch_timer_init() with a non zero argument.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |




^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 5/8] ARM: layerscape: re-init pbl clocksource
  2026-08-20  6:59   ` Sascha Hauer
@ 2026-08-20  8:06     ` Stefan Kerkmann
  0 siblings, 0 replies; 19+ messages in thread
From: Stefan Kerkmann @ 2026-08-20  8:06 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: open list:BAREBOX

Hi Sascha,

On 8/20/26 08:59, Sascha Hauer wrote:
> On 2026-08-17 16:01, Stefan Kerkmann wrote:
>> After setting the cntfrq the global PBL clocksource must be
>> re-initialized to function correctly.
>>
>> Signed-off-by: Stefan Kerkmann <s.kerkmann@pengutronix.de>
>> ---
>>  arch/arm/mach-layerscape/lowlevel-ls1028a.c | 6 +++++-
>>  arch/arm/mach-layerscape/lowlevel-ls1046a.c | 5 ++++-
>>  2 files changed, 9 insertions(+), 2 deletions(-)
>>
>> diff --git a/arch/arm/mach-layerscape/lowlevel-ls1028a.c b/arch/arm/mach-layerscape/lowlevel-ls1028a.c
>> index fd013b2b52..ed9284d55a 100644
>> --- a/arch/arm/mach-layerscape/lowlevel-ls1028a.c
>> +++ b/arch/arm/mach-layerscape/lowlevel-ls1028a.c
>> @@ -1,6 +1,7 @@
>>  // SPDX-License-Identifier: GPL-2.0+
>>  #include <common.h>
>>  #include <io.h>
>> +#include <asm/hardware/arm_architected_timer.h>
>>  #include <asm/syscounter.h>
>>  #include <asm/system.h>
>>  #include <mach/layerscape/errata.h>
>> @@ -35,8 +36,11 @@ static void ls1028a_timer_init(void)
>>  
>>  void ls1028a_init_lowlevel(void)
>>  {
>> +	const uint64_t cntfrq = 25000000;
>> +
>>  	scfg_init(SCFG_ENDIANESS_LITTLE);
>> -	set_cntfrq(25000000);
>> +	set_cntfrq(cntfrq);
>> +	arm_arch_timer_init(cntfrq);
>>  	ls1028a_timer_init();
>>  	ls1028a_errata();
>>  }
> 
> I had to squash this patch together with the next two to avoid
> intermediate compile breakage. Otherwise we get an undefined reference
> to clocksource_hz2mult().
> 
> One thing that strikes me here is that first arm_arch_timer_init() is
> called and afterwards ls1028a_timer_init(). I have no idea what timer
> ls1028a_timer_init() initializes and if that has anything to do with
> the architected timer, but if it has the order should likely be the
> other way round.
> 

>From my understanding this function enables the per-core timers which are driven
by the global system counter (cntfrq/cntpct) but distinct from it[1]. So the
order should be correct?

[1]: https://support.arm.com/documentation/102379/0104/System-Counter

> Sascha
> 
> --
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
> 

Best regards,
Stefan

-- 
Pengutronix e.K.                       | Stefan Kerkmann             |
Steuerwalder Str. 21                   | https://www.pengutronix.de/ |
31137 Hildesheim, Germany              | Phone: +49-5121-206917-128  |
Amtsgericht Hildesheim, HRA 2686       | Fax:   +49-5121-206917-9    |




^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [PATCH v3 4/8] drivers: arm_architected_timer: refactor for pbl compatibility
  2026-08-20  8:00       ` Sascha Hauer
@ 2026-08-20  8:07         ` Stefan Kerkmann
  0 siblings, 0 replies; 19+ messages in thread
From: Stefan Kerkmann @ 2026-08-20  8:07 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: open list:BAREBOX

Hi Sascha,

On 8/20/26 10:00, Sascha Hauer wrote:
> On 2026-08-20 09:32, Stefan Kerkmann wrote:
>>>> diff --git a/drivers/clocksource/arm_architected_timer.c b/drivers/clocksource/arm_architected_timer.c
>>>> index daced94c0e..ea5f5b8e05 100644
>>>> --- a/drivers/clocksource/arm_architected_timer.c
>>>> +++ b/drivers/clocksource/arm_architected_timer.c
>>>> @@ -9,6 +9,7 @@
>>>>  #include <linux/clk.h>
>>>>  #include <io.h>
>>>>  #include <asm/system.h>
>>>> +#include <asm/hardware/arm_architected_timer.h>
>>>>  
>>>>  static uint64_t arm_arch_clocksource_read(void)
>>>>  {
>>>> @@ -22,22 +23,29 @@ static struct clocksource cs = {
>>>>  	.priority = 70,
>>>>  };
>>>>  
>>>> -static int arm_arch_timer_probe(struct device *dev)
>>>> +int arm_arch_timer_init(uint64_t cntfrq)
>>>>  {
>>>> -	u32 cntfrq;
>>>> -	int ret;
>>>> -
>>>> -	/* Some platforms don't set CNTFRQ_EL0 before barebox */
>>>> -	ret = of_property_read_u32(dev->of_node, "clock-frequency", &cntfrq);
>>>> -
>>>> -	if (ret)
>>>> +	if (!cntfrq)
>>>>  		cntfrq = get_cntfrq();
>>>
>>> I wonder if we should just drop the cntfrq argument. All users call
>>> set_cntfrq() before calling this, so get_cntfrq() should return the
>>> correct value and we can rely on it.
>>>
>>
>> Maybe keep the argument and use set_cntfrq in arm_arch_timer_init if the
>> argument is !=0? Then arm_arch_timer_init is the function to use if a C
>> environment is available? This would prevent any inconsistency.
> 
> I am not sure, but set_cntfrq() might only be usable in EL3, so you
> would have to be careful about the exception level when calling
> arm_arch_timer_init() with a non zero argument.
> 

Yes, it would have to be guarded by an el3 check.

> Sascha
> 

Best regards,
Stefan

-- 
Pengutronix e.K.                       | Stefan Kerkmann             |
Steuerwalder Str. 21                   | https://www.pengutronix.de/ |
31137 Hildesheim, Germany              | Phone: +49-5121-206917-128  |
Amtsgericht Hildesheim, HRA 2686       | Fax:   +49-5121-206917-9    |




^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2026-08-20  8:08 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-08-17 14:01 [PATCH v3 0/8] PBL: enable timeouts in read_poll_timeout macros Stefan Kerkmann
2026-08-17 14:01 ` [PATCH v3 1/8] RISC-V: setup_c: avoid clearing BSS twice Stefan Kerkmann
2026-08-17 14:01 ` [PATCH v3 2/8] ARM/ARM64/RISC-V: pbl: add constructor support Stefan Kerkmann
2026-08-18 12:08   ` [PATCH] amend! " Stefan Kerkmann
2026-08-19  9:39   ` [PATCH v3 2/8] " Sascha Hauer
2026-08-17 14:01 ` [PATCH v3 3/8] clocksource: allow re-init for same clock Stefan Kerkmann
2026-08-17 14:01 ` [PATCH v3 4/8] drivers: arm_architected_timer: refactor for pbl compatibility Stefan Kerkmann
2026-08-20  7:04   ` Sascha Hauer
2026-08-20  7:32     ` Stefan Kerkmann
2026-08-20  8:00       ` Sascha Hauer
2026-08-20  8:07         ` Stefan Kerkmann
2026-08-17 14:01 ` [PATCH v3 5/8] ARM: layerscape: re-init pbl clocksource Stefan Kerkmann
2026-08-17 15:42   ` Ahmad Fatoum
2026-08-20  6:59   ` Sascha Hauer
2026-08-20  8:06     ` Stefan Kerkmann
2026-08-17 14:01 ` [PATCH v3 6/8] ARM: socfpga: agilex5: " Stefan Kerkmann
2026-08-17 14:01 ` [PATCH v3 7/8] ARM64: enable PBL_CLOCKSOURCE compatibility Stefan Kerkmann
2026-08-17 14:01 ` [PATCH v3 8/8] linux/iopoll: enable polled timeouts for PBL_CLOCKSOURCE Stefan Kerkmann
2026-08-19  7:03 ` [PATCH v3 0/8] PBL: enable timeouts in read_poll_timeout macros Sascha Hauer

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox