1*62d244edSkettenis /* $OpenBSD: gfrtc.c,v 1.3 2022/10/17 19:09:46 kettenis Exp $ */
271d9c131Sjsg
371d9c131Sjsg /*
471d9c131Sjsg * Copyright (c) 2021 Jonathan Gray <jsg@openbsd.org>
571d9c131Sjsg *
671d9c131Sjsg * Permission to use, copy, modify, and distribute this software for any
771d9c131Sjsg * purpose with or without fee is hereby granted, provided that the above
871d9c131Sjsg * copyright notice and this permission notice appear in all copies.
971d9c131Sjsg *
1071d9c131Sjsg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1171d9c131Sjsg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1271d9c131Sjsg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1371d9c131Sjsg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1471d9c131Sjsg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1571d9c131Sjsg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1671d9c131Sjsg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1771d9c131Sjsg */
1871d9c131Sjsg
1971d9c131Sjsg /*
2071d9c131Sjsg * Google Goldfish virtual real-time clock described in
2171d9c131Sjsg * https://android.googlesource.com/platform/external/qemu/+/master/docs/GOLDFISH-VIRTUAL-HARDWARE.TXT
2271d9c131Sjsg */
2371d9c131Sjsg
2471d9c131Sjsg #include <sys/param.h>
2571d9c131Sjsg #include <sys/device.h>
2671d9c131Sjsg #include <sys/malloc.h>
2771d9c131Sjsg #include <sys/systm.h>
2871d9c131Sjsg
2971d9c131Sjsg #include <machine/bus.h>
3071d9c131Sjsg #include <machine/fdt.h>
3171d9c131Sjsg #include <dev/clock_subr.h>
3271d9c131Sjsg
3371d9c131Sjsg #include <dev/ofw/openfirm.h>
3471d9c131Sjsg #include <dev/ofw/fdt.h>
3571d9c131Sjsg
3671d9c131Sjsg #define TIME_LOW 0x00
3771d9c131Sjsg #define TIME_HIGH 0x04
3871d9c131Sjsg #define ALARM_LOW 0x0c
3971d9c131Sjsg #define CLEAR_INTERRUPT 0x10
4071d9c131Sjsg
4171d9c131Sjsg struct gfrtc_softc {
4271d9c131Sjsg struct device sc_dev;
4371d9c131Sjsg bus_space_tag_t sc_iot;
4471d9c131Sjsg bus_space_handle_t sc_ioh;
4571d9c131Sjsg struct todr_chip_handle sc_todr;
4671d9c131Sjsg };
4771d9c131Sjsg
4871d9c131Sjsg int gfrtc_match(struct device *, void *, void *);
4971d9c131Sjsg void gfrtc_attach(struct device *, struct device *, void *);
5071d9c131Sjsg int gfrtc_gettime(struct todr_chip_handle *, struct timeval *);
5171d9c131Sjsg int gfrtc_settime(struct todr_chip_handle *, struct timeval *);
5271d9c131Sjsg
53471aeecfSnaddy const struct cfattach gfrtc_ca = {
5471d9c131Sjsg sizeof(struct gfrtc_softc), gfrtc_match, gfrtc_attach
5571d9c131Sjsg };
5671d9c131Sjsg
5771d9c131Sjsg struct cfdriver gfrtc_cd = {
5871d9c131Sjsg NULL, "gfrtc", DV_DULL
5971d9c131Sjsg };
6071d9c131Sjsg
6171d9c131Sjsg int
gfrtc_gettime(todr_chip_handle_t handle,struct timeval * tv)6271d9c131Sjsg gfrtc_gettime(todr_chip_handle_t handle, struct timeval *tv)
6371d9c131Sjsg {
6471d9c131Sjsg struct gfrtc_softc *sc = handle->cookie;
6571d9c131Sjsg uint64_t tl, th;
6671d9c131Sjsg
6771d9c131Sjsg tl = bus_space_read_4(sc->sc_iot, sc->sc_ioh, TIME_LOW);
6871d9c131Sjsg th = bus_space_read_4(sc->sc_iot, sc->sc_ioh, TIME_HIGH);
6971d9c131Sjsg
7071d9c131Sjsg NSEC_TO_TIMEVAL((th << 32) | tl, tv);
7171d9c131Sjsg
7271d9c131Sjsg return 0;
7371d9c131Sjsg }
7471d9c131Sjsg
7571d9c131Sjsg int
gfrtc_settime(todr_chip_handle_t handle,struct timeval * tv)7671d9c131Sjsg gfrtc_settime(todr_chip_handle_t handle, struct timeval *tv)
7771d9c131Sjsg {
7871d9c131Sjsg struct gfrtc_softc *sc = handle->cookie;
7971d9c131Sjsg uint64_t ns;
8071d9c131Sjsg
8171d9c131Sjsg ns = TIMEVAL_TO_NSEC(tv);
8271d9c131Sjsg
8371d9c131Sjsg bus_space_write_4(sc->sc_iot, sc->sc_ioh, TIME_HIGH, ns >> 32);
8471d9c131Sjsg bus_space_write_4(sc->sc_iot, sc->sc_ioh, TIME_LOW, ns);
8571d9c131Sjsg
8671d9c131Sjsg return 0;
8771d9c131Sjsg }
8871d9c131Sjsg
8971d9c131Sjsg int
gfrtc_match(struct device * parent,void * match,void * aux)9071d9c131Sjsg gfrtc_match(struct device *parent, void *match, void *aux)
9171d9c131Sjsg {
9271d9c131Sjsg struct fdt_attach_args *faa = aux;
9371d9c131Sjsg
9471d9c131Sjsg return OF_is_compatible(faa->fa_node, "google,goldfish-rtc");
9571d9c131Sjsg }
9671d9c131Sjsg
9771d9c131Sjsg void
gfrtc_attach(struct device * parent,struct device * self,void * aux)9871d9c131Sjsg gfrtc_attach(struct device *parent, struct device *self, void *aux)
9971d9c131Sjsg {
10071d9c131Sjsg struct fdt_attach_args *faa = aux;
10171d9c131Sjsg struct gfrtc_softc *sc = (struct gfrtc_softc *) self;
10271d9c131Sjsg
10371d9c131Sjsg sc->sc_iot = faa->fa_iot;
10471d9c131Sjsg
10571d9c131Sjsg if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
10671d9c131Sjsg faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
10771d9c131Sjsg printf(": failed to map mem space\n");
10871d9c131Sjsg return;
10971d9c131Sjsg }
11071d9c131Sjsg
11171d9c131Sjsg sc->sc_todr.cookie = sc;
11271d9c131Sjsg sc->sc_todr.todr_gettime = gfrtc_gettime;
11371d9c131Sjsg sc->sc_todr.todr_settime = gfrtc_settime;
114*62d244edSkettenis sc->sc_todr.todr_quality = 1000;
115*62d244edSkettenis todr_attach(&sc->sc_todr);
11671d9c131Sjsg
11771d9c131Sjsg printf("\n");
11871d9c131Sjsg }
119