mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2026-06-02 09:46:37 +03:00
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 <visitorckw@gmail.com> Tested-by: Daniel Palmer <daniel@0x0f.com> Reviewed-by: Yao Zi <me@ziyao.cc> Reviewed-by: Simon Glass <simon.glass@canonical.com> Reviewed-by: Angelo Dureghello <angelo@kernel-space.org>
This commit is contained in:
@@ -1266,6 +1266,12 @@ S: Maintained
|
||||
F: drivers/serial/serial_goldfish.c
|
||||
F: include/goldfish_tty.h
|
||||
|
||||
GOLDFISH TIMER DRIVER
|
||||
M: Kuan-Wei Chiu <visitorckw@gmail.com>
|
||||
S: Maintained
|
||||
F: drivers/timer/goldfish_timer.c
|
||||
F: include/goldfish_timer.h
|
||||
|
||||
INTERCONNECT:
|
||||
M: Neil Armstrong <neil.armstrong@linaro.org>
|
||||
S: Maintained
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
89
drivers/timer/goldfish_timer.c
Normal file
89
drivers/timer/goldfish_timer.c
Normal file
@@ -0,0 +1,89 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2025, Kuan-Wei Chiu <visitorckw@gmail.com>
|
||||
*
|
||||
* 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),
|
||||
};
|
||||
13
include/goldfish_timer.h
Normal file
13
include/goldfish_timer.h
Normal file
@@ -0,0 +1,13 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
/*
|
||||
* Copyright (C) 2025, Kuan-Wei Chiu <visitorckw@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _GOLDFISH_TIMER_H_
|
||||
#define _GOLDFISH_TIMER_H_
|
||||
|
||||
struct goldfish_timer_plat {
|
||||
phys_addr_t reg;
|
||||
};
|
||||
|
||||
#endif /* _GOLDFISH_TIMER_H_ */
|
||||
Reference in New Issue
Block a user