[Concept,04/15] riscv: timer: Read timebase frequency from the firmware FDT
Commit Message
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(+)
@@ -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.
@@ -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
@@ -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);
}
}