[Concept,04/15] riscv: timer: Read timebase frequency from the firmware FDT

Message ID 20260212001410.1919749-5-sjg@u-boot.org
State New
Headers
Series riscv: Add EFI-application support |

Commit Message

Simon Glass Feb. 12, 2026, 12:13 a.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

The RISC-V timer driver reads the clock rate from
/cpus/timebase-frequency in U-Boot's own device tree. For EFI
applications this property may not be present, since the embedded
DTB is minimal.

Add a fallback that reads the timebase frequency from the firmware-
provided FDT, which is available via the EFI configuration tables.
To support this, scan for EFI_FDT_GUID in scan_tables() and store
the address via a new gd_set_firmware_fdt_addr() accessor.

Co-developed-by: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 drivers/timer/riscv_timer.c       | 13 +++++++++++++
 include/asm-generic/global_data.h |  8 ++++++++
 lib/efi_client/efi_app.c          |  3 +++
 3 files changed, 24 insertions(+)
  

Patch

diff --git a/drivers/timer/riscv_timer.c b/drivers/timer/riscv_timer.c
index 1f4980ceb38..ca28d1297d7 100644
--- a/drivers/timer/riscv_timer.c
+++ b/drivers/timer/riscv_timer.c
@@ -15,8 +15,12 @@ 
 #include <dm.h>
 #include <errno.h>
 #include <fdt_support.h>
+#include <mapmem.h>
 #include <timer.h>
 #include <asm/csr.h>
+#include <asm/global_data.h>
+
+DECLARE_GLOBAL_DATA_PTR;
 
 static u64 notrace riscv_timer_get_count(struct udevice *dev)
 {
@@ -89,6 +93,15 @@  static int riscv_timer_probe(struct udevice *dev)
 					       "/cpus", "timebase-frequency", 0);
 	}
 
+	/* For EFI apps, try the firmware-provided FDT */
+	if (!rate && IS_ENABLED(CONFIG_EFI_APP) &&
+	    gd_firmware_fdt_addr()) {
+		void *fw_fdt = map_sysmem(gd_firmware_fdt_addr(), 0);
+
+		rate = fdt_getprop_u32_default(fw_fdt, "/cpus",
+					       "timebase-frequency", 0);
+	}
+
 	uc_priv->clock_rate = rate;
 
 	/* With rate==0, timer uclass post_probe might later fail with -EINVAL.
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index b17a2e4650b..86204e372aa 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -563,6 +563,14 @@  static_assert(sizeof(struct global_data) == GD_SIZE);
 #define gd_set_smbios_start(addr)
 #endif
 
+#ifdef CONFIG_RISCV
+#define gd_firmware_fdt_addr()		gd->arch.firmware_fdt_addr
+#define gd_set_firmware_fdt_addr(addr)	gd->arch.firmware_fdt_addr = addr
+#else
+#define gd_firmware_fdt_addr()		0UL
+#define gd_set_firmware_fdt_addr(addr)
+#endif
+
 #if CONFIG_IS_ENABLED(MULTI_DTB_FIT)
 #define gd_multi_dtb_fit()	gd->multi_dtb_fit
 #define gd_set_multi_dtb_fit(_dtb)	gd->multi_dtb_fit = _dtb
diff --git a/lib/efi_client/efi_app.c b/lib/efi_client/efi_app.c
index 178571d9970..d36ed959f95 100644
--- a/lib/efi_client/efi_app.c
+++ b/lib/efi_client/efi_app.c
@@ -172,6 +172,7 @@  static void scan_tables(struct efi_system_table *sys_table)
 	efi_guid_t acpi = EFI_ACPI_TABLE_GUID;
 	efi_guid_t smbios = SMBIOS_TABLE_GUID;
 	efi_guid_t smbios3 = SMBIOS3_TABLE_GUID;
+	efi_guid_t fdt = EFI_FDT_GUID;
 	uint i;
 
 	for (i = 0; i < sys_table->nr_tables; i++) {
@@ -182,6 +183,8 @@  static void scan_tables(struct efi_system_table *sys_table)
 		else if (!memcmp(&tab->guid, &smbios, sizeof(efi_guid_t)) ||
 			 !memcmp(&tab->guid, &smbios3, sizeof(efi_guid_t)))
 			gd_set_smbios_start(map_to_sysmem(tab->table));
+		else if (!memcmp(&tab->guid, &fdt, sizeof(efi_guid_t)))
+			gd_set_firmware_fdt_addr((ulong)tab->table);
 	}
 }