1 /* $OpenBSD: gfrtc.c,v 1.3 2022/10/17 19:09:46 kettenis Exp $ */
2
3 /*
4 * Copyright (c) 2021 Jonathan Gray <jsg@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * Google Goldfish virtual real-time clock described in
21 * https://android.googlesource.com/platform/external/qemu/+/master/docs/GOLDFISH-VIRTUAL-HARDWARE.TXT
22 */
23
24 #include <sys/param.h>
25 #include <sys/device.h>
26 #include <sys/malloc.h>
27 #include <sys/systm.h>
28
29 #include <machine/bus.h>
30 #include <machine/fdt.h>
31 #include <dev/clock_subr.h>
32
33 #include <dev/ofw/openfirm.h>
34 #include <dev/ofw/fdt.h>
35
36 #define TIME_LOW 0x00
37 #define TIME_HIGH 0x04
38 #define ALARM_LOW 0x0c
39 #define CLEAR_INTERRUPT 0x10
40
41 struct gfrtc_softc {
42 struct device sc_dev;
43 bus_space_tag_t sc_iot;
44 bus_space_handle_t sc_ioh;
45 struct todr_chip_handle sc_todr;
46 };
47
48 int gfrtc_match(struct device *, void *, void *);
49 void gfrtc_attach(struct device *, struct device *, void *);
50 int gfrtc_gettime(struct todr_chip_handle *, struct timeval *);
51 int gfrtc_settime(struct todr_chip_handle *, struct timeval *);
52
53 const struct cfattach gfrtc_ca = {
54 sizeof(struct gfrtc_softc), gfrtc_match, gfrtc_attach
55 };
56
57 struct cfdriver gfrtc_cd = {
58 NULL, "gfrtc", DV_DULL
59 };
60
61 int
gfrtc_gettime(todr_chip_handle_t handle,struct timeval * tv)62 gfrtc_gettime(todr_chip_handle_t handle, struct timeval *tv)
63 {
64 struct gfrtc_softc *sc = handle->cookie;
65 uint64_t tl, th;
66
67 tl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, TIME_LOW);
68 th = bus_space_read_4(sc->sc_iot, sc->sc_ioh, TIME_HIGH);
69
70 NSEC_TO_TIMEVAL((th << 32) | tl, tv);
71
72 return 0;
73 }
74
75 int
gfrtc_settime(todr_chip_handle_t handle,struct timeval * tv)76 gfrtc_settime(todr_chip_handle_t handle, struct timeval *tv)
77 {
78 struct gfrtc_softc *sc = handle->cookie;
79 uint64_t ns;
80
81 ns = TIMEVAL_TO_NSEC(tv);
82
83 bus_space_write_4(sc->sc_iot, sc->sc_ioh, TIME_HIGH, ns >> 32);
84 bus_space_write_4(sc->sc_iot, sc->sc_ioh, TIME_LOW, ns);
85
86 return 0;
87 }
88
89 int
gfrtc_match(struct device * parent,void * match,void * aux)90 gfrtc_match(struct device *parent, void *match, void *aux)
91 {
92 struct fdt_attach_args *faa = aux;
93
94 return OF_is_compatible(faa->fa_node, "google,goldfish-rtc");
95 }
96
97 void
gfrtc_attach(struct device * parent,struct device * self,void * aux)98 gfrtc_attach(struct device *parent, struct device *self, void *aux)
99 {
100 struct fdt_attach_args *faa = aux;
101 struct gfrtc_softc *sc = (struct gfrtc_softc *) self;
102
103 sc->sc_iot = faa->fa_iot;
104
105 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
106 faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
107 printf(": failed to map mem space\n");
108 return;
109 }
110
111 sc->sc_todr.cookie = sc;
112 sc->sc_todr.todr_gettime = gfrtc_gettime;
113 sc->sc_todr.todr_settime = gfrtc_settime;
114 sc->sc_todr.todr_quality = 1000;
115 todr_attach(&sc->sc_todr);
116
117 printf("\n");
118 }
119