diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2018-06-16 14:11:36 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2018-06-16 14:11:36 +0000 |
commit | 6dab2ce942a618ebe8b0dbd293d4843cd22d6b9e (patch) | |
tree | ffda7bf862658bff98327911270a8570bc06b581 /sys/dev/fdt | |
parent | 0a555aacecd6c598301c0094ec28b8a3dca9f18c (diff) |
Add imxrtc(4), a driver for the "secure" RTC in the Low Power Domain of the
SNVS block found on i.MX7 and i.MX8.
Diffstat (limited to 'sys/dev/fdt')
-rw-r--r-- | sys/dev/fdt/files.fdt | 6 | ||||
-rw-r--r-- | sys/dev/fdt/imxrtc.c | 166 |
2 files changed, 171 insertions, 1 deletions
diff --git a/sys/dev/fdt/files.fdt b/sys/dev/fdt/files.fdt index 8b5a1443a1b..62de92fee6b 100644 --- a/sys/dev/fdt/files.fdt +++ b/sys/dev/fdt/files.fdt @@ -1,4 +1,4 @@ -# $OpenBSD: files.fdt,v 1.63 2018/06/05 20:41:19 kettenis Exp $ +# $OpenBSD: files.fdt,v 1.64 2018/06/16 14:11:35 kettenis Exp $ # # Config file and device description for machine-independent FDT code. # Included by ports that need it. @@ -239,6 +239,10 @@ device imxpd: fdt attach imxpd at fdt file dev/fdt/imxpd.c imxpd +device imxrtc +attach imxrtc at fdt +file dev/fdt/imxrtc.c imxrtc + device imxuart attach imxuart at fdt file dev/fdt/imxuart.c imxuart diff --git a/sys/dev/fdt/imxrtc.c b/sys/dev/fdt/imxrtc.c new file mode 100644 index 00000000000..1ae4f240810 --- /dev/null +++ b/sys/dev/fdt/imxrtc.c @@ -0,0 +1,166 @@ +/* $OpenBSD: imxrtc.c,v 1.1 2018/06/16 14:11:35 kettenis Exp $ */ +/* + * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/intr.h> +#include <machine/bus.h> +#include <machine/fdt.h> + +#include <dev/ofw/openfirm.h> +#include <dev/ofw/fdt.h> +#include <dev/ofw/ofw_misc.h> + +#include <dev/clock_subr.h> + +extern todr_chip_handle_t todr_handle; + +/* Registers. */ +#define LPCR 0x38 +#define LPCR_SRTC_ENV (1 << 0) +#define LPSR 0x4c +#define LPSRTCMR 0x50 +#define LPSRTCLR 0x54 + +#define HREAD4(sc, reg) \ + (regmap_read_4((sc)->sc_rm, (reg))) +#define HWRITE4(sc, reg, val) \ + regmap_write_4((sc)->sc_rm, (reg), (val)) + +struct imxrtc_softc { + struct device sc_dev; + struct regmap *sc_rm; + + struct todr_chip_handle sc_todr; +}; + +int imxrtc_match(struct device *, void *, void *); +void imxrtc_attach(struct device *, struct device *, void *); + +struct cfattach imxrtc_ca = { + sizeof (struct imxrtc_softc), imxrtc_match, imxrtc_attach +}; + +struct cfdriver imxrtc_cd = { + NULL, "imxrtc", DV_DULL +}; + +int imxrtc_gettime(struct todr_chip_handle *, struct timeval *); +int imxrtc_settime(struct todr_chip_handle *, struct timeval *); + +int +imxrtc_match(struct device *parent, void *match, void *aux) +{ + struct fdt_attach_args *faa = aux; + + return OF_is_compatible(faa->fa_node, "fsl,sec-v4.0-mon-rtc-lp"); +} + +void +imxrtc_attach(struct device *parent, struct device *self, void *aux) +{ + struct imxrtc_softc *sc = (struct imxrtc_softc *)self; + struct fdt_attach_args *faa = aux; + uint32_t regmap; + + regmap = OF_getpropint(faa->fa_node, "regmap", 0); + sc->sc_rm = regmap_byphandle(regmap); + if (sc->sc_rm == NULL) { + printf(": no registers\n"); + return; + } + + printf("\n"); + + sc->sc_todr.cookie = sc; + sc->sc_todr.todr_gettime = imxrtc_gettime; + sc->sc_todr.todr_settime = imxrtc_settime; + todr_handle = &sc->sc_todr; +} + +int +imxrtc_gettime(struct todr_chip_handle *handle, struct timeval *tv) +{ + struct imxrtc_softc *sc = handle->cookie; + uint64_t mr, lr, srtc, srtc2; + uint32_t cr; + int retries; + int s; + + cr = HREAD4(sc, LPCR); + if ((cr & LPCR_SRTC_ENV) == 0) + return EINVAL; + + /* + * Read counters until we read back the same values twice. + * This shouldn't take more than two attempts; throw in an + * extra round just in case. + */ + s = splhigh(); + mr = HREAD4(sc, LPSRTCMR); + lr = HREAD4(sc, LPSRTCLR); + srtc = (mr << 32) | lr; + for (retries = 3; retries > 0; retries--) { + mr = HREAD4(sc, LPSRTCMR); + lr = HREAD4(sc, LPSRTCLR); + srtc2 = (mr << 32) | lr; + if (srtc == srtc2) + break; + srtc = srtc2; + } + splx(s); + if (retries == 0) + return EIO; + + tv->tv_sec = srtc / 32768; + tv->tv_usec = ((srtc % 32768) * 1000000U) / 32768U; + return 0; +} + +int +imxrtc_settime(struct todr_chip_handle *handle, struct timeval *tv) +{ + struct imxrtc_softc *sc = handle->cookie; + uint64_t srtc; + uint32_t cr; + int timeout; + + /* Disable RTC. */ + cr = HREAD4(sc, LPCR); + cr &= ~LPCR_SRTC_ENV; + HWRITE4(sc, LPCR, cr); + for (timeout = 1000000; timeout > 0; timeout--) { + if ((HREAD4(sc, LPCR) & LPCR_SRTC_ENV) == 0) + break; + } + + srtc = tv->tv_sec * 32768 + (tv->tv_usec * 32768U / 1000000U); + HWRITE4(sc, LPSRTCMR, srtc >> 32); + HWRITE4(sc, LPSRTCLR, srtc & 0xffffffff); + + /* Enable RTC. */ + cr |= LPCR_SRTC_ENV; + HWRITE4(sc, LPCR, cr); + for (timeout = 1000000; timeout > 0; timeout--) { + if (HREAD4(sc, LPCR) & LPCR_SRTC_ENV) + break; + } + + return 0; +} |