* [PATCH v2 0/3] virtio: Add a virtio RTC driver
@ 2026-10-14 19:06 Hung-Chun Tseng
2026-10-14 19:06 ` [PATCH v2 1/3] virtio: rtc: Add " Hung-Chun Tseng
` (2 more replies)
0 siblings, 3 replies; 6+ messages in thread
From: Hung-Chun Tseng @ 2026-10-14 19:06 UTC (permalink / raw)
To: Bin Meng, Tom Rini
Cc: Kuan-Wei Chiu, Simon Glass, Heinrich Schuchardt, u-boot
QEMU v11.1.0 added a virtio RTC device (virtio-rtc-pci and
virtio-rtc-device), but U-Boot has no driver for it. This series adds
one: it finds the first UTC clock on the device and reads it through
the RTC uclass, so "date" and anything else using dm_rtc_get() work on
any virtio-capable QEMU target, not only on machines that also have a
goldfish or PL031 RTC.
Patch 1 adds the driver, patch 2 updates the virtio documentation, and
patch 3 adds a MAINTAINERS entry.
Tested on QEMU v11.1.2 with qemu-riscv64_smode_defconfig:
- With -device virtio-rtc-pci and with -device virtio-rtc-device, the
driver probes. As "date" uses the first RTC, which is the goldfish
RTC on this machine, I also built with RTC_GOLDFISH disabled: "date"
then read the host time from the virtio RTC, advancing between reads.
- Setting the time fails with -ENOSYS, as the clocks are read-only.
- With RTC_GOLDFISH disabled and no virtio RTC device, "date" fails
cleanly with err=-19.
qemu-riscv32_defconfig also builds the driver without libgcc helpers
for the 64-bit division. On sandbox, where VIRTIO_RTC now defaults to y,
"ut dm rtc*" and "ut dm virtio*" pass.
The alarm feature is not supported. I have not added a pytest because
the CI Docker image builds QEMU v10.1.2, which does not have the
device yet.
Changes in v2:
- Patch 1: look for the UTC clock on the first read instead of in
probe(), as the virtqueue must not be used before DRIVER_OK (Bin)
- Patches 2 and 3: add Bin's Reviewed-by
v1: https://lore.kernel.org/u-boot/20261014140716.1181882-1-alan.tseng.cs@gmail.com/
Hung-Chun Tseng (3):
virtio: rtc: Add virtio RTC driver
doc: virtio: Mention the RTC device
MAINTAINERS: Add entry for virtio RTC
MAINTAINERS | 5 +
doc/develop/driver-model/virtio.rst | 4 +-
drivers/virtio/Kconfig | 9 ++
drivers/virtio/Makefile | 1 +
drivers/virtio/virtio-uclass.c | 1 +
drivers/virtio/virtio_rtc.c | 213 ++++++++++++++++++++++++++++
include/virtio.h | 4 +-
7 files changed, 235 insertions(+), 2 deletions(-)
create mode 100644 drivers/virtio/virtio_rtc.c
--
2.43.0
^ permalink raw reply [flat|nested] 6+ messages in thread* [PATCH v2 1/3] virtio: rtc: Add virtio RTC driver 2026-10-14 19:06 [PATCH v2 0/3] virtio: Add a virtio RTC driver Hung-Chun Tseng @ 2026-10-14 19:06 ` Hung-Chun Tseng 2026-10-14 19:46 ` Kuan-Wei Chiu 2026-10-14 19:06 ` [PATCH v2 2/3] doc: virtio: Mention the RTC device Hung-Chun Tseng 2026-10-14 19:06 ` [PATCH v2 3/3] MAINTAINERS: Add entry for virtio RTC Hung-Chun Tseng 2 siblings, 1 reply; 6+ messages in thread From: Hung-Chun Tseng @ 2026-10-14 19:06 UTC (permalink / raw) To: Bin Meng, Tom Rini Cc: Kuan-Wei Chiu, Simon Glass, Heinrich Schuchardt, u-boot Add a driver for the virtio RTC device (virtio device ID 17), which QEMU provides as virtio-rtc-pci and virtio-rtc-device since v11.1.0. The device exposes its clocks through a request virtqueue. As the virtqueue must not be used before the virtio uclass sets DRIVER_OK, which happens after probe(), the first read looks for the clock: it asks for the number of clocks with VIRTIO_RTC_REQ_CFG and picks the first one whose VIRTIO_RTC_REQ_CLOCK_CAP type is UTC, smeared UTC or maybe-smeared UTC. Reading the time sends a VIRTIO_RTC_REQ_READ for that clock and converts the nanoseconds since the epoch with rtc_to_tm(). The clocks are read-only, so there is no set operation, and the optional alarm feature is not negotiated. VIRTIO_RTC defaults to y when VIRTIO and DM_RTC are enabled, like VIRTIO_RNG does for DM_RNG. Signed-off-by: Hung-Chun Tseng <alan.tseng.cs@gmail.com> --- Changes in v2: - Look for the UTC clock on the first virtio_rtc_get() instead of in probe(), as the virtqueue must not be used before DRIVER_OK (Bin) drivers/virtio/Kconfig | 9 ++ drivers/virtio/Makefile | 1 + drivers/virtio/virtio-uclass.c | 1 + drivers/virtio/virtio_rtc.c | 213 +++++++++++++++++++++++++++++++++ include/virtio.h | 4 +- 5 files changed, 227 insertions(+), 1 deletion(-) create mode 100644 drivers/virtio/virtio_rtc.c diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 55b444280..c19138ef2 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -84,4 +84,13 @@ config VIRTIO_9P help This enables the 9P transport driver over virtio. It can be used with QEMU based targets. + +config VIRTIO_RTC + bool "virtio RTC driver" + depends on DM_RTC + depends on VIRTIO + default y + help + This is the virtual RTC driver. It reads the UTC clock of a + virtio RTC device. It can be used with QEMU based targets. endmenu diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index 6e7bcfc8e..ddb5ce4eb 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_VIRTIO_NET) += virtio_net.o obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o obj-$(CONFIG_VIRTIO_RNG) += virtio_rng.o obj-$(CONFIG_VIRTIO_9P) += virtio_9p.o +obj-$(CONFIG_VIRTIO_RTC) += virtio_rtc.o diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c index c163b2fd7..c6cf55922 100644 --- a/drivers/virtio/virtio-uclass.c +++ b/drivers/virtio/virtio-uclass.c @@ -31,6 +31,7 @@ static const char *const virtio_drv_name[VIRTIO_ID_MAX_NUM] = { [VIRTIO_ID_BLOCK] = VIRTIO_BLK_DRV_NAME, [VIRTIO_ID_RNG] = VIRTIO_RNG_DRV_NAME, [VIRTIO_ID_9P] = VIRTIO_9P_DRV_NAME, + [VIRTIO_ID_CLOCK] = VIRTIO_RTC_DRV_NAME, }; int virtio_get_config(struct udevice *vdev, unsigned int offset, diff --git a/drivers/virtio/virtio_rtc.c b/drivers/virtio/virtio_rtc.c new file mode 100644 index 000000000..f5d4a694b --- /dev/null +++ b/drivers/virtio/virtio_rtc.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2026, Hung-Chun Tseng <alan.tseng.cs@gmail.com> + * + * Driver for the virtio RTC device (virtio device ID 17). The device + * exposes one or more read-only clocks through a request virtqueue; this + * driver reads the first UTC clock and reports it through the RTC uclass. + */ + +#include <div64.h> +#include <dm.h> +#include <log.h> +#include <rtc.h> +#include <virtio_types.h> +#include <virtio.h> +#include <virtio_ring.h> +#include <linux/types.h> + +#define VIRTIO_RTC_REQ_READ 0x0001 +#define VIRTIO_RTC_REQ_CFG 0x1000 +#define VIRTIO_RTC_REQ_CLOCK_CAP 0x1001 + +#define VIRTIO_RTC_S_OK 0 + +#define VIRTIO_RTC_CLOCK_UTC 0 +#define VIRTIO_RTC_CLOCK_UTC_SMEARED 3 +#define VIRTIO_RTC_CLOCK_UTC_MAYBE_SMEARED 4 + +struct virtio_rtc_req_head { + __le16 msg_type; + u8 reserved[6]; +} __packed; + +struct virtio_rtc_resp_head { + u8 status; + u8 reserved[7]; +} __packed; + +/* Request for VIRTIO_RTC_REQ_READ and VIRTIO_RTC_REQ_CLOCK_CAP */ +struct virtio_rtc_req_clock { + struct virtio_rtc_req_head head; + __le16 clock_id; + u8 reserved[6]; +} __packed; + +struct virtio_rtc_resp_read { + struct virtio_rtc_resp_head head; + __le64 clock_reading; +} __packed; + +struct virtio_rtc_resp_cfg { + struct virtio_rtc_resp_head head; + __le16 num_clocks; + u8 reserved[6]; +} __packed; + +struct virtio_rtc_resp_clock_cap { + struct virtio_rtc_resp_head head; + u8 type; + u8 leap_second_smearing; + u8 flags; + u8 reserved[5]; +} __packed; + +struct virtio_rtc_priv { + struct virtqueue *vq; + u16 clock_id; + bool clock_found; +}; + +static int virtio_rtc_xfer(struct udevice *dev, void *req, size_t req_len, + void *resp, size_t resp_len) +{ + struct virtio_rtc_priv *priv = dev_get_priv(dev); + struct virtio_rtc_resp_head *head = resp; + struct virtio_sg req_sg = { req, req_len }; + struct virtio_sg resp_sg = { resp, resp_len }; + struct virtio_sg *sgs[] = { &req_sg, &resp_sg }; + unsigned int len; + int ret; + + ret = virtqueue_add(priv->vq, sgs, 1, 1); + if (ret) + return ret; + + virtqueue_kick(priv->vq); + + while (!virtqueue_get_buf(priv->vq, &len)) + ; + + if (len < sizeof(*head) || head->status != VIRTIO_RTC_S_OK) + return -EIO; + + if (len < resp_len) + return -EPROTO; + + return 0; +} + +static bool virtio_rtc_is_utc(u8 type) +{ + return type == VIRTIO_RTC_CLOCK_UTC || + type == VIRTIO_RTC_CLOCK_UTC_SMEARED || + type == VIRTIO_RTC_CLOCK_UTC_MAYBE_SMEARED; +} + +static int virtio_rtc_find_utc_clock(struct udevice *dev) +{ + struct virtio_rtc_priv *priv = dev_get_priv(dev); + struct virtio_rtc_req_head cfg_req = { + .msg_type = cpu_to_le16(VIRTIO_RTC_REQ_CFG), + }; + struct virtio_rtc_resp_cfg cfg = {}; + u16 num_clocks, id; + int ret; + + ret = virtio_rtc_xfer(dev, &cfg_req, sizeof(cfg_req), &cfg, sizeof(cfg)); + if (ret) + return ret; + + num_clocks = le16_to_cpu(cfg.num_clocks); + for (id = 0; id < num_clocks; id++) { + struct virtio_rtc_req_clock req = { + .head.msg_type = cpu_to_le16(VIRTIO_RTC_REQ_CLOCK_CAP), + .clock_id = cpu_to_le16(id), + }; + struct virtio_rtc_resp_clock_cap cap = {}; + + ret = virtio_rtc_xfer(dev, &req, sizeof(req), &cap, sizeof(cap)); + if (ret) + continue; + + if (virtio_rtc_is_utc(cap.type)) { + priv->clock_id = id; + priv->clock_found = true; + return 0; + } + } + + return -ENODEV; +} + +static int virtio_rtc_get(struct udevice *dev, struct rtc_time *time) +{ + struct virtio_rtc_priv *priv = dev_get_priv(dev); + struct virtio_rtc_req_clock req = { + .head.msg_type = cpu_to_le16(VIRTIO_RTC_REQ_READ), + }; + struct virtio_rtc_resp_read resp = {}; + u64 now; + int ret; + + /* + * The virtqueue must not be used before DRIVER_OK, which the virtio + * uclass sets only after probe(), so look for the clock on first use. + */ + if (!priv->clock_found) { + ret = virtio_rtc_find_utc_clock(dev); + if (ret) + return ret; + } + + req.clock_id = cpu_to_le16(priv->clock_id); + + ret = virtio_rtc_xfer(dev, &req, sizeof(req), &resp, sizeof(resp)); + if (ret) + return ret; + + now = le64_to_cpu(resp.clock_reading); + do_div(now, 1000000000U); + rtc_to_tm(now, time); + + return 0; +} + +static int virtio_rtc_bind(struct udevice *dev) +{ + struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(dev->parent); + + /* The alarm feature is not supported */ + virtio_driver_features_init(uc_priv, NULL, 0, NULL, 0); + + return 0; +} + +static int virtio_rtc_probe(struct udevice *dev) +{ + struct virtio_rtc_priv *priv = dev_get_priv(dev); + int ret; + + ret = virtio_find_vqs(dev, 1, &priv->vq); + if (ret < 0) { + debug("%s: virtio_find_vqs failed\n", __func__); + return ret; + } + + return 0; +} + +static const struct rtc_ops virtio_rtc_ops = { + .get = virtio_rtc_get, +}; + +U_BOOT_DRIVER(virtio_rtc) = { + .name = VIRTIO_RTC_DRV_NAME, + .id = UCLASS_RTC, + .bind = virtio_rtc_bind, + .probe = virtio_rtc_probe, + .remove = virtio_reset, + .ops = &virtio_rtc_ops, + .priv_auto = sizeof(struct virtio_rtc_priv), + .flags = DM_FLAG_ACTIVE_DMA, +}; diff --git a/include/virtio.h b/include/virtio.h index b981eead5..95069a2de 100644 --- a/include/virtio.h +++ b/include/virtio.h @@ -32,12 +32,14 @@ #define VIRTIO_ID_BLOCK 2 /* virtio block */ #define VIRTIO_ID_RNG 4 /* virtio rng */ #define VIRTIO_ID_9P 9 /* virtio 9p */ -#define VIRTIO_ID_MAX_NUM 10 +#define VIRTIO_ID_CLOCK 17 /* virtio clock/timer (rtc) */ +#define VIRTIO_ID_MAX_NUM 18 #define VIRTIO_NET_DRV_NAME "virtio-net" #define VIRTIO_BLK_DRV_NAME "virtio-blk" #define VIRTIO_RNG_DRV_NAME "virtio-rng" #define VIRTIO_9P_DRV_NAME "virtio-9p" +#define VIRTIO_RTC_DRV_NAME "virtio-rtc" /* Feature bits for virtio 9P */ #define VIRTIO_9P_MOUNT_TAG 0 -- 2.43.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 1/3] virtio: rtc: Add virtio RTC driver 2026-10-14 19:06 ` [PATCH v2 1/3] virtio: rtc: Add " Hung-Chun Tseng @ 2026-10-14 19:46 ` Kuan-Wei Chiu 0 siblings, 0 replies; 6+ messages in thread From: Kuan-Wei Chiu @ 2026-10-14 19:46 UTC (permalink / raw) To: Hung-Chun Tseng Cc: Bin Meng, Tom Rini, Simon Glass, Heinrich Schuchardt, u-boot Hi Hung-Chun, On Thu, Oct 15, 2026 at 03:06:29AM +0800, Hung-Chun Tseng wrote: > Add a driver for the virtio RTC device (virtio device ID 17), which > QEMU provides as virtio-rtc-pci and virtio-rtc-device since v11.1.0. > > The device exposes its clocks through a request virtqueue. As the > virtqueue must not be used before the virtio uclass sets DRIVER_OK, > which happens after probe(), the first read looks for the clock: it > asks for the number of clocks with VIRTIO_RTC_REQ_CFG and picks the > first one whose VIRTIO_RTC_REQ_CLOCK_CAP type is UTC, smeared UTC or > maybe-smeared UTC. Reading the time sends a VIRTIO_RTC_REQ_READ for > that clock and converts the nanoseconds since the epoch with > rtc_to_tm(). The clocks are read-only, so there is no set operation, > and the optional alarm feature is not negotiated. > > VIRTIO_RTC defaults to y when VIRTIO and DM_RTC are enabled, like > VIRTIO_RNG does for DM_RNG. > > Signed-off-by: Hung-Chun Tseng <alan.tseng.cs@gmail.com> Thanks for the patch. Actually, when I sent out the qemu virtio-rtc code, I also had a local dirty version of the virtio-rtc u-boot driver, but it has been sitting on my TODO list. I might take a closer look at this patch in a day or two. This also reminds me that I still have some other virtio drivers locally that I would like to try upstreaming. I might try to send them out within the next week or two. > --- > > Changes in v2: > - Look for the UTC clock on the first virtio_rtc_get() instead of in > probe(), as the virtqueue must not be used before DRIVER_OK (Bin) I would suggest leaving more time between sending out new patch versions to give people a chance to review and reply, which helps avoid spamming the list with rapid revisions. We have folks in various timezones, and many of them are quite busy. > > drivers/virtio/Kconfig | 9 ++ > drivers/virtio/Makefile | 1 + > drivers/virtio/virtio-uclass.c | 1 + > drivers/virtio/virtio_rtc.c | 213 +++++++++++++++++++++++++++++++++ > include/virtio.h | 4 +- > 5 files changed, 227 insertions(+), 1 deletion(-) > create mode 100644 drivers/virtio/virtio_rtc.c > > diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig > index 55b444280..c19138ef2 100644 > --- a/drivers/virtio/Kconfig > +++ b/drivers/virtio/Kconfig > @@ -84,4 +84,13 @@ config VIRTIO_9P > help > This enables the 9P transport driver over virtio. > It can be used with QEMU based targets. > + > +config VIRTIO_RTC > + bool "virtio RTC driver" > + depends on DM_RTC > + depends on VIRTIO > + default y > + help > + This is the virtual RTC driver. It reads the UTC clock of a > + virtio RTC device. It can be used with QEMU based targets. > endmenu > diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile > index 6e7bcfc8e..ddb5ce4eb 100644 > --- a/drivers/virtio/Makefile > +++ b/drivers/virtio/Makefile > @@ -12,3 +12,4 @@ obj-$(CONFIG_VIRTIO_NET) += virtio_net.o > obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o > obj-$(CONFIG_VIRTIO_RNG) += virtio_rng.o > obj-$(CONFIG_VIRTIO_9P) += virtio_9p.o > +obj-$(CONFIG_VIRTIO_RTC) += virtio_rtc.o > diff --git a/drivers/virtio/virtio-uclass.c b/drivers/virtio/virtio-uclass.c > index c163b2fd7..c6cf55922 100644 > --- a/drivers/virtio/virtio-uclass.c > +++ b/drivers/virtio/virtio-uclass.c > @@ -31,6 +31,7 @@ static const char *const virtio_drv_name[VIRTIO_ID_MAX_NUM] = { > [VIRTIO_ID_BLOCK] = VIRTIO_BLK_DRV_NAME, > [VIRTIO_ID_RNG] = VIRTIO_RNG_DRV_NAME, > [VIRTIO_ID_9P] = VIRTIO_9P_DRV_NAME, > + [VIRTIO_ID_CLOCK] = VIRTIO_RTC_DRV_NAME, > }; > > int virtio_get_config(struct udevice *vdev, unsigned int offset, > diff --git a/drivers/virtio/virtio_rtc.c b/drivers/virtio/virtio_rtc.c > new file mode 100644 > index 000000000..f5d4a694b > --- /dev/null > +++ b/drivers/virtio/virtio_rtc.c > @@ -0,0 +1,213 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Copyright (C) 2026, Hung-Chun Tseng <alan.tseng.cs@gmail.com> > + * > + * Driver for the virtio RTC device (virtio device ID 17). The device > + * exposes one or more read-only clocks through a request virtqueue; this > + * driver reads the first UTC clock and reports it through the RTC uclass. > + */ > + > +#include <div64.h> > +#include <dm.h> > +#include <log.h> > +#include <rtc.h> > +#include <virtio_types.h> > +#include <virtio.h> > +#include <virtio_ring.h> > +#include <linux/types.h> > + > +#define VIRTIO_RTC_REQ_READ 0x0001 > +#define VIRTIO_RTC_REQ_CFG 0x1000 > +#define VIRTIO_RTC_REQ_CLOCK_CAP 0x1001 > + > +#define VIRTIO_RTC_S_OK 0 > + > +#define VIRTIO_RTC_CLOCK_UTC 0 > +#define VIRTIO_RTC_CLOCK_UTC_SMEARED 3 > +#define VIRTIO_RTC_CLOCK_UTC_MAYBE_SMEARED 4 > + > +struct virtio_rtc_req_head { > + __le16 msg_type; > + u8 reserved[6]; > +} __packed; > + > +struct virtio_rtc_resp_head { > + u8 status; > + u8 reserved[7]; > +} __packed; > + > +/* Request for VIRTIO_RTC_REQ_READ and VIRTIO_RTC_REQ_CLOCK_CAP */ > +struct virtio_rtc_req_clock { > + struct virtio_rtc_req_head head; > + __le16 clock_id; > + u8 reserved[6]; > +} __packed; > + > +struct virtio_rtc_resp_read { > + struct virtio_rtc_resp_head head; > + __le64 clock_reading; > +} __packed; > + > +struct virtio_rtc_resp_cfg { > + struct virtio_rtc_resp_head head; > + __le16 num_clocks; > + u8 reserved[6]; > +} __packed; > + > +struct virtio_rtc_resp_clock_cap { > + struct virtio_rtc_resp_head head; > + u8 type; > + u8 leap_second_smearing; > + u8 flags; > + u8 reserved[5]; > +} __packed; > + > +struct virtio_rtc_priv { > + struct virtqueue *vq; > + u16 clock_id; > + bool clock_found; > +}; > + > +static int virtio_rtc_xfer(struct udevice *dev, void *req, size_t req_len, > + void *resp, size_t resp_len) > +{ > + struct virtio_rtc_priv *priv = dev_get_priv(dev); > + struct virtio_rtc_resp_head *head = resp; > + struct virtio_sg req_sg = { req, req_len }; > + struct virtio_sg resp_sg = { resp, resp_len }; > + struct virtio_sg *sgs[] = { &req_sg, &resp_sg }; > + unsigned int len; > + int ret; > + > + ret = virtqueue_add(priv->vq, sgs, 1, 1); > + if (ret) > + return ret; > + > + virtqueue_kick(priv->vq); > + > + while (!virtqueue_get_buf(priv->vq, &len)) IIRC, when I sent out the virtio-9p driver for review, Simon made the same suggestion to add a timeout mechanism to the loop here to prevent potential hangs. While it is true that many other virtio drivers are currently written this way, it is on my TODO list to clean them up. Regards, Kuan-Wei > + ; > + > + if (len < sizeof(*head) || head->status != VIRTIO_RTC_S_OK) > + return -EIO; > + > + if (len < resp_len) > + return -EPROTO; > + > + return 0; > +} > + > +static bool virtio_rtc_is_utc(u8 type) > +{ > + return type == VIRTIO_RTC_CLOCK_UTC || > + type == VIRTIO_RTC_CLOCK_UTC_SMEARED || > + type == VIRTIO_RTC_CLOCK_UTC_MAYBE_SMEARED; > +} > + > +static int virtio_rtc_find_utc_clock(struct udevice *dev) > +{ > + struct virtio_rtc_priv *priv = dev_get_priv(dev); > + struct virtio_rtc_req_head cfg_req = { > + .msg_type = cpu_to_le16(VIRTIO_RTC_REQ_CFG), > + }; > + struct virtio_rtc_resp_cfg cfg = {}; > + u16 num_clocks, id; > + int ret; > + > + ret = virtio_rtc_xfer(dev, &cfg_req, sizeof(cfg_req), &cfg, sizeof(cfg)); > + if (ret) > + return ret; > + > + num_clocks = le16_to_cpu(cfg.num_clocks); > + for (id = 0; id < num_clocks; id++) { > + struct virtio_rtc_req_clock req = { > + .head.msg_type = cpu_to_le16(VIRTIO_RTC_REQ_CLOCK_CAP), > + .clock_id = cpu_to_le16(id), > + }; > + struct virtio_rtc_resp_clock_cap cap = {}; > + > + ret = virtio_rtc_xfer(dev, &req, sizeof(req), &cap, sizeof(cap)); > + if (ret) > + continue; > + > + if (virtio_rtc_is_utc(cap.type)) { > + priv->clock_id = id; > + priv->clock_found = true; > + return 0; > + } > + } > + > + return -ENODEV; > +} > + > +static int virtio_rtc_get(struct udevice *dev, struct rtc_time *time) > +{ > + struct virtio_rtc_priv *priv = dev_get_priv(dev); > + struct virtio_rtc_req_clock req = { > + .head.msg_type = cpu_to_le16(VIRTIO_RTC_REQ_READ), > + }; > + struct virtio_rtc_resp_read resp = {}; > + u64 now; > + int ret; > + > + /* > + * The virtqueue must not be used before DRIVER_OK, which the virtio > + * uclass sets only after probe(), so look for the clock on first use. > + */ > + if (!priv->clock_found) { > + ret = virtio_rtc_find_utc_clock(dev); > + if (ret) > + return ret; > + } > + > + req.clock_id = cpu_to_le16(priv->clock_id); > + > + ret = virtio_rtc_xfer(dev, &req, sizeof(req), &resp, sizeof(resp)); > + if (ret) > + return ret; > + > + now = le64_to_cpu(resp.clock_reading); > + do_div(now, 1000000000U); > + rtc_to_tm(now, time); > + > + return 0; > +} > + > +static int virtio_rtc_bind(struct udevice *dev) > +{ > + struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(dev->parent); > + > + /* The alarm feature is not supported */ > + virtio_driver_features_init(uc_priv, NULL, 0, NULL, 0); > + > + return 0; > +} > + > +static int virtio_rtc_probe(struct udevice *dev) > +{ > + struct virtio_rtc_priv *priv = dev_get_priv(dev); > + int ret; > + > + ret = virtio_find_vqs(dev, 1, &priv->vq); > + if (ret < 0) { > + debug("%s: virtio_find_vqs failed\n", __func__); > + return ret; > + } > + > + return 0; > +} > + > +static const struct rtc_ops virtio_rtc_ops = { > + .get = virtio_rtc_get, > +}; > + > +U_BOOT_DRIVER(virtio_rtc) = { > + .name = VIRTIO_RTC_DRV_NAME, > + .id = UCLASS_RTC, > + .bind = virtio_rtc_bind, > + .probe = virtio_rtc_probe, > + .remove = virtio_reset, > + .ops = &virtio_rtc_ops, > + .priv_auto = sizeof(struct virtio_rtc_priv), > + .flags = DM_FLAG_ACTIVE_DMA, > +}; > diff --git a/include/virtio.h b/include/virtio.h > index b981eead5..95069a2de 100644 > --- a/include/virtio.h > +++ b/include/virtio.h > @@ -32,12 +32,14 @@ > #define VIRTIO_ID_BLOCK 2 /* virtio block */ > #define VIRTIO_ID_RNG 4 /* virtio rng */ > #define VIRTIO_ID_9P 9 /* virtio 9p */ > -#define VIRTIO_ID_MAX_NUM 10 > +#define VIRTIO_ID_CLOCK 17 /* virtio clock/timer (rtc) */ > +#define VIRTIO_ID_MAX_NUM 18 > > #define VIRTIO_NET_DRV_NAME "virtio-net" > #define VIRTIO_BLK_DRV_NAME "virtio-blk" > #define VIRTIO_RNG_DRV_NAME "virtio-rng" > #define VIRTIO_9P_DRV_NAME "virtio-9p" > +#define VIRTIO_RTC_DRV_NAME "virtio-rtc" > > /* Feature bits for virtio 9P */ > #define VIRTIO_9P_MOUNT_TAG 0 > -- > 2.43.0 > ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 2/3] doc: virtio: Mention the RTC device 2026-10-14 19:06 [PATCH v2 0/3] virtio: Add a virtio RTC driver Hung-Chun Tseng 2026-10-14 19:06 ` [PATCH v2 1/3] virtio: rtc: Add " Hung-Chun Tseng @ 2026-10-14 19:06 ` Hung-Chun Tseng 2026-10-14 19:30 ` Kuan-Wei Chiu 2026-10-14 19:06 ` [PATCH v2 3/3] MAINTAINERS: Add entry for virtio RTC Hung-Chun Tseng 2 siblings, 1 reply; 6+ messages in thread From: Hung-Chun Tseng @ 2026-10-14 19:06 UTC (permalink / raw) To: Bin Meng, Tom Rini Cc: Kuan-Wei Chiu, Simon Glass, Heinrich Schuchardt, u-boot The list of supported device types still only named network and block devices. Add the entropy, 9P and RTC devices, and note that the virtio RTC device needs QEMU v11.1.0 or later. Signed-off-by: Hung-Chun Tseng <alan.tseng.cs@gmail.com> Reviewed-by: Bin Meng <bin.meng@processmission.com> --- doc/develop/driver-model/virtio.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/develop/driver-model/virtio.rst b/doc/develop/driver-model/virtio.rst index e5da9f430..211304706 100644 --- a/doc/develop/driver-model/virtio.rst +++ b/doc/develop/driver-model/virtio.rst @@ -28,7 +28,7 @@ queues configuration and buffer transfers are nearly identical. Both MMIO and PCI transport options are supported in U-Boot. The VirtIO spec defines a lots of VirtIO device types, however at present only -network and block device, the most two commonly used devices, are supported. +network, block, entropy (rng), 9P transport and RTC devices are supported. The following QEMU targets are supported. @@ -72,6 +72,8 @@ Requirements ------------ It is required that QEMU v2.5.0+ should be used to test U-Boot VirtIO support on QEMU ARM and x86, and v2.12.0+ on QEMU RISC-V. +The VirtIO RTC device (``-device virtio-rtc-pci`` or +``-device virtio-rtc-device``) requires QEMU v11.1.0+. Testing ------- -- 2.43.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2 2/3] doc: virtio: Mention the RTC device 2026-10-14 19:06 ` [PATCH v2 2/3] doc: virtio: Mention the RTC device Hung-Chun Tseng @ 2026-10-14 19:30 ` Kuan-Wei Chiu 0 siblings, 0 replies; 6+ messages in thread From: Kuan-Wei Chiu @ 2026-10-14 19:30 UTC (permalink / raw) To: Hung-Chun Tseng Cc: Bin Meng, Tom Rini, Simon Glass, Heinrich Schuchardt, u-boot Hi Hung-Chun, On Thu, Oct 15, 2026 at 03:06:30AM +0800, Hung-Chun Tseng wrote: > The list of supported device types still only named network and block > devices. Add the entropy, 9P and RTC devices, and note that the virtio > RTC device needs QEMU v11.1.0 or later. > > Signed-off-by: Hung-Chun Tseng <alan.tseng.cs@gmail.com> > Reviewed-by: Bin Meng <bin.meng@processmission.com> > --- > doc/develop/driver-model/virtio.rst | 4 +++- > 1 file changed, 3 insertions(+), 1 deletion(-) > Nit: Since this patch also mentions other virtio devices, the subject title should be updated to reflect that rather than only mentioning the RTC. > diff --git a/doc/develop/driver-model/virtio.rst b/doc/develop/driver-model/virtio.rst > index e5da9f430..211304706 100644 > --- a/doc/develop/driver-model/virtio.rst > +++ b/doc/develop/driver-model/virtio.rst > @@ -28,7 +28,7 @@ queues configuration and buffer transfers are nearly identical. Both MMIO > and PCI transport options are supported in U-Boot. > > The VirtIO spec defines a lots of VirtIO device types, however at present only > -network and block device, the most two commonly used devices, are supported. > +network, block, entropy (rng), 9P transport and RTC devices are supported. Since u-boot supports more virtio drivers now and likely even more in the future, I'm wondering if we should present them as a bulleted list for better clarity, rather than listing them inline in a sentence. Regards, Kuan-Wei > > The following QEMU targets are supported. > > @@ -72,6 +72,8 @@ Requirements > ------------ > It is required that QEMU v2.5.0+ should be used to test U-Boot VirtIO support > on QEMU ARM and x86, and v2.12.0+ on QEMU RISC-V. > +The VirtIO RTC device (``-device virtio-rtc-pci`` or > +``-device virtio-rtc-device``) requires QEMU v11.1.0+. > > Testing > ------- > -- > 2.43.0 > ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2 3/3] MAINTAINERS: Add entry for virtio RTC 2026-10-14 19:06 [PATCH v2 0/3] virtio: Add a virtio RTC driver Hung-Chun Tseng 2026-10-14 19:06 ` [PATCH v2 1/3] virtio: rtc: Add " Hung-Chun Tseng 2026-10-14 19:06 ` [PATCH v2 2/3] doc: virtio: Mention the RTC device Hung-Chun Tseng @ 2026-10-14 19:06 ` Hung-Chun Tseng 2 siblings, 0 replies; 6+ messages in thread From: Hung-Chun Tseng @ 2026-10-14 19:06 UTC (permalink / raw) To: Bin Meng, Tom Rini Cc: Kuan-Wei Chiu, Simon Glass, Heinrich Schuchardt, u-boot Add myself as the maintainer of the virtio RTC driver. Signed-off-by: Hung-Chun Tseng <alan.tseng.cs@gmail.com> Reviewed-by: Bin Meng <bin.meng@processmission.com> --- MAINTAINERS | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 28d090d3c..2ce94d7f5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1872,6 +1872,11 @@ F: include/virtio*.h F: test/dm/virtio.c F: doc/develop/driver-model/virtio.rst +VIRTIO RTC +M: Hung-Chun Tseng <alan.tseng.cs@gmail.com> +S: Maintained +F: drivers/virtio/virtio_rtc.c + WATCHDOG M: Stefan Roese <stefan.roese@mailbox.org> S: Maintained -- 2.43.0 ^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-10-14 19:46 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-14 19:06 [PATCH v2 0/3] virtio: Add a virtio RTC driver Hung-Chun Tseng 2026-10-14 19:06 ` [PATCH v2 1/3] virtio: rtc: Add " Hung-Chun Tseng 2026-10-14 19:46 ` Kuan-Wei Chiu 2026-10-14 19:06 ` [PATCH v2 2/3] doc: virtio: Mention the RTC device Hung-Chun Tseng 2026-10-14 19:30 ` Kuan-Wei Chiu 2026-10-14 19:06 ` [PATCH v2 3/3] MAINTAINERS: Add entry for virtio RTC Hung-Chun Tseng
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.