xref: /openbsd-src/sys/dev/fdt/gfrtc.c (revision 62d244ed99f17c1263ee095bc7d8fa1f61df02fd)
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