1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright 2023, Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
4  *
5  * This driver supports the Google Goldfish virtual platform RTC device.
6  * The device is provided by the RISC-V virt machine in QEMU. It exposes
7  * a 64-bit nanosecond timer via two memory-mapped 32-bit registers.
8  */
9 
10 #include <div64.h>
11 #include <dm.h>
12 #include <mapmem.h>
13 #include <rtc.h>
14 #include <linux/io.h>
15 
16 /**
17  * struct goldfish_rtc - private data for RTC driver
18  */
19 struct goldfish_rtc {
20 	/**
21 	 * @base: base address for register file
22 	 */
23 	void __iomem *base;
24 	/**
25 	 * @isdst: daylight saving time
26 	 */
27 	int isdst;
28 };
29 
30 /* Register offsets */
31 #define GOLDFISH_TIME_LOW	0x00
32 #define GOLDFISH_TIME_HIGH	0x04
33 
goldfish_rtc_get(struct udevice * dev,struct rtc_time * time)34 static int goldfish_rtc_get(struct udevice *dev, struct rtc_time *time)
35 {
36 	struct goldfish_rtc *priv = dev_get_priv(dev);
37 	void __iomem *base = priv->base;
38 	u64 time_high;
39 	u64 time_low;
40 	u64 now;
41 
42 	time_low = ioread32(base + GOLDFISH_TIME_LOW);
43 	time_high = ioread32(base + GOLDFISH_TIME_HIGH);
44 	now = (time_high << 32) | time_low;
45 
46 	do_div(now, 1000000000U);
47 
48 	rtc_to_tm(now, time);
49 	time->tm_isdst = priv->isdst;
50 
51 	return 0;
52 }
53 
goldfish_rtc_set(struct udevice * dev,const struct rtc_time * time)54 static int goldfish_rtc_set(struct udevice *dev, const struct rtc_time *time)
55 {
56 	struct goldfish_rtc *priv = dev_get_priv(dev);
57 	void __iomem *base = priv->base;
58 	u64 now;
59 
60 	if (time->tm_year < 1970)
61 		return -EINVAL;
62 
63 	now = rtc_mktime(time) * 1000000000ULL;
64 	iowrite32(now >> 32, base + GOLDFISH_TIME_HIGH);
65 	iowrite32(now, base + GOLDFISH_TIME_LOW);
66 
67 	if (time->tm_isdst > 0)
68 		priv->isdst = 1;
69 	else if (time->tm_isdst < 0)
70 		priv->isdst = -1;
71 	else
72 		priv->isdst = 0;
73 
74 	return 0;
75 }
76 
goldfish_rtc_probe(struct udevice * dev)77 static int goldfish_rtc_probe(struct udevice *dev)
78 {
79 	struct goldfish_rtc *priv = dev_get_priv(dev);
80 	fdt_addr_t addr;
81 
82 	addr = dev_read_addr(dev);
83 	if (addr == FDT_ADDR_T_NONE)
84 		return -EINVAL;
85 	priv->base = map_sysmem(addr, 0x20);
86 
87 	return 0;
88 }
89 
90 static const struct rtc_ops goldfish_rtc_ops = {
91 	.get = goldfish_rtc_get,
92 	.set = goldfish_rtc_set,
93 };
94 
95 static const struct udevice_id goldfish_rtc_of_match[] = {
96 	{ .compatible = "google,goldfish-rtc", },
97 	{},
98 };
99 
100 U_BOOT_DRIVER(rtc_goldfish) = {
101 	.name		= "rtc_goldfish",
102 	.id		= UCLASS_RTC,
103 	.ops		= &goldfish_rtc_ops,
104 	.probe		= goldfish_rtc_probe,
105 	.of_match	= goldfish_rtc_of_match,
106 	.priv_auto	= sizeof(struct goldfish_rtc),
107 };
108