Files
u-boot-krane/drivers/rtc/goldfish_rtc.c
T
Kuan-Wei ChiuandTom Rini 47e9c542ee rtc: goldfish: Return error when device address is invalid
goldfish_rtc_of_to_plat() currently returns success even when
dev_read_addr() fails to find a valid address. This leaves plat->reg
unset (or 0) and defers the failure to probe().

Return -EINVAL immediately when the address is FDT_ADDR_T_NONE so the
failure is reported at the of_to_plat stage where it belongs. This
aligns the driver with the recent fix introduced in the goldfish
serial driver by Naveen Kumar Chaudhary. [1]

Link: https://lore.kernel.org/u-boot/vgwnt6mnls3lf3zdm6mz5siztzkvppte4ykszbvifjzukvmksf@maaxe5agqpim/ [1]
Signed-off-by: Kuan-Wei Chiu <visitorckw@gmail.com>
2026-06-23 12:38:01 -06:00

127 lines
2.7 KiB
C

// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright 2023, Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
*
* This driver supports the Google Goldfish virtual platform RTC device.
* The device is provided by the RISC-V virt machine in QEMU. It exposes
* a 64-bit nanosecond timer via two memory-mapped 32-bit registers.
*/
#include <div64.h>
#include <dm.h>
#include <goldfish_rtc.h>
#include <mapmem.h>
#include <rtc.h>
#include <linux/io.h>
/**
* struct goldfish_rtc - private data for RTC driver
*/
struct goldfish_rtc {
/**
* @base: base address for register file
*/
void __iomem *base;
/**
* @isdst: daylight saving time
*/
int isdst;
};
/* Register offsets */
#define GOLDFISH_TIME_LOW 0x00
#define GOLDFISH_TIME_HIGH 0x04
static int goldfish_rtc_get(struct udevice *dev, struct rtc_time *time)
{
struct goldfish_rtc *priv = dev_get_priv(dev);
void __iomem *base = priv->base;
u64 time_high;
u64 time_low;
u64 now;
time_low = __raw_readl(base + GOLDFISH_TIME_LOW);
time_high = __raw_readl(base + GOLDFISH_TIME_HIGH);
now = (time_high << 32) | time_low;
do_div(now, 1000000000U);
rtc_to_tm(now, time);
time->tm_isdst = priv->isdst;
return 0;
}
static int goldfish_rtc_set(struct udevice *dev, const struct rtc_time *time)
{
struct goldfish_rtc *priv = dev_get_priv(dev);
void __iomem *base = priv->base;
u64 now;
if (time->tm_year < 1970)
return -EINVAL;
now = rtc_mktime(time) * 1000000000ULL;
__raw_writel(now >> 32, base + GOLDFISH_TIME_HIGH);
__raw_writel(now, base + GOLDFISH_TIME_LOW);
if (time->tm_isdst > 0)
priv->isdst = 1;
else if (time->tm_isdst < 0)
priv->isdst = -1;
else
priv->isdst = 0;
return 0;
}
static int goldfish_rtc_of_to_plat(struct udevice *dev)
{
struct goldfish_rtc_plat *plat = dev_get_plat(dev);
fdt_addr_t addr;
plat->reg = 0;
addr = dev_read_addr(dev);
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
plat->reg = addr;
return 0;
}
static int goldfish_rtc_probe(struct udevice *dev)
{
struct goldfish_rtc_plat *plat = dev_get_plat(dev);
struct goldfish_rtc *priv = dev_get_priv(dev);
if (!plat->reg)
return -EINVAL;
priv->base = map_sysmem(plat->reg, 0x20);
return 0;
}
static const struct rtc_ops goldfish_rtc_ops = {
.get = goldfish_rtc_get,
.set = goldfish_rtc_set,
};
static const struct udevice_id goldfish_rtc_of_match[] = {
{ .compatible = "google,goldfish-rtc", },
{},
};
U_BOOT_DRIVER(rtc_goldfish) = {
.name = "rtc_goldfish",
.id = UCLASS_RTC,
.ops = &goldfish_rtc_ops,
.probe = goldfish_rtc_probe,
.of_match = goldfish_rtc_of_match,
.of_to_plat = goldfish_rtc_of_to_plat,
.plat_auto = sizeof(struct goldfish_rtc_plat),
.priv_auto = sizeof(struct goldfish_rtc),
};