diff options
| author | Kuan-Wei Chiu <[email protected]> | 2026-01-07 20:18:31 +0000 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2026-02-02 14:24:40 -0600 |
| commit | 909f717eaf299a97fb87307e8606f3fdc6cb0c14 (patch) | |
| tree | 6221580c2b98631290f8df00f3c9f842a5cf31f9 /drivers/timer | |
| parent | bf55b84736d6b220dae11e3b1e7a670918d9daee (diff) | |
timer: Add Goldfish timer driver
Add support for the Goldfish timer driver. This driver utilizes the
Goldfish RTC hardware to provide a nanosecond-resolution timer. This
virtual device is commonly found in QEMU virtual machines (such as the
m68k virt machine) and Android emulators.
The driver implements the standard U-Boot timer UCLASS interface,
exposing a 64-bit monotonically increasing counter with a 1GHz clock
rate derived from the RTC registers.
Signed-off-by: Kuan-Wei Chiu <[email protected]>
Tested-by: Daniel Palmer <[email protected]>
Reviewed-by: Yao Zi <[email protected]>
Reviewed-by: Simon Glass <[email protected]>
Reviewed-by: Angelo Dureghello <[email protected]>
Diffstat (limited to 'drivers/timer')
| -rw-r--r-- | drivers/timer/Kconfig | 8 | ||||
| -rw-r--r-- | drivers/timer/Makefile | 1 | ||||
| -rw-r--r-- | drivers/timer/goldfish_timer.c | 89 |
3 files changed, 98 insertions, 0 deletions
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index f9511503b02..a84a0dc0539 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -340,4 +340,12 @@ config STARFIVE_TIMER Select this to enable support for the timer found on Starfive SoC. +config GOLDFISH_TIMER + bool "Goldfish Timer support" + depends on TIMER + help + Select this to enable support for the Goldfish Timer. + It uses the Goldfish RTC hardware to provide a nanosecond-resolution + timer, commonly found in QEMU virt machines. + endmenu diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile index a72e411fb2f..d8b3f2b65d4 100644 --- a/drivers/timer/Makefile +++ b/drivers/timer/Makefile @@ -36,3 +36,4 @@ obj-$(CONFIG_MCHP_PIT64B_TIMER) += mchp-pit64b-timer.o obj-$(CONFIG_IMX_GPT_TIMER) += imx-gpt-timer.o obj-$(CONFIG_XILINX_TIMER) += xilinx-timer.o obj-$(CONFIG_STARFIVE_TIMER) += starfive-timer.o +obj-$(CONFIG_GOLDFISH_TIMER) += goldfish_timer.o diff --git a/drivers/timer/goldfish_timer.c b/drivers/timer/goldfish_timer.c new file mode 100644 index 00000000000..70673bbd93c --- /dev/null +++ b/drivers/timer/goldfish_timer.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2025, Kuan-Wei Chiu <[email protected]> + * + * Goldfish Timer driver + */ + +#include <dm.h> +#include <goldfish_timer.h> +#include <mapmem.h> +#include <timer.h> +#include <asm/io.h> +#include <linux/errno.h> + +struct goldfish_timer_priv { + void __iomem *base; +}; + +/* Goldfish RTC registers used as Timer */ +#define TIMER_TIME_LOW 0x00 +#define TIMER_TIME_HIGH 0x04 + +static u64 goldfish_timer_get_count(struct udevice *dev) +{ + struct goldfish_timer_priv *priv = dev_get_priv(dev); + u32 low, high; + u64 time; + + /* + * TIMER_TIME_HIGH is only updated when TIMER_TIME_LOW is read. + * We must read LOW before HIGH to latch the high 32-bit value + * and ensure a consistent 64-bit timestamp. + */ + low = readl(priv->base + TIMER_TIME_LOW); + high = readl(priv->base + TIMER_TIME_HIGH); + + time = ((u64)high << 32) | low; + + return time; +} + +static int goldfish_timer_of_to_plat(struct udevice *dev) +{ + struct goldfish_timer_plat *plat = dev_get_plat(dev); + fdt_addr_t addr; + + addr = dev_read_addr(dev); + if (addr != FDT_ADDR_T_NONE) + plat->reg = addr; + + return 0; +} + +static int goldfish_timer_probe(struct udevice *dev) +{ + struct goldfish_timer_plat *plat = dev_get_plat(dev); + struct goldfish_timer_priv *priv = dev_get_priv(dev); + struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev); + + if (!plat->reg) + return -EINVAL; + + priv->base = map_sysmem(plat->reg, 0x20); + + /* Goldfish RTC counts in nanoseconds, so the rate is 1GHz */ + uc_priv->clock_rate = 1000000000; + + return 0; +} + +static const struct timer_ops goldfish_timer_ops = { + .get_count = goldfish_timer_get_count, +}; + +static const struct udevice_id goldfish_timer_ids[] = { + { .compatible = "google,goldfish-rtc" }, + { } +}; + +U_BOOT_DRIVER(goldfish_timer) = { + .name = "goldfish_timer", + .id = UCLASS_TIMER, + .of_match = goldfish_timer_ids, + .of_to_plat = goldfish_timer_of_to_plat, + .plat_auto = sizeof(struct goldfish_timer_plat), + .ops = &goldfish_timer_ops, + .probe = goldfish_timer_probe, + .priv_auto = sizeof(struct goldfish_timer_priv), +}; |
