1 /* $OpenBSD: imxrtc.c,v 1.3 2022/10/17 19:09:46 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 22 #include <machine/intr.h> 23 #include <machine/bus.h> 24 #include <machine/fdt.h> 25 26 #include <dev/ofw/openfirm.h> 27 #include <dev/ofw/fdt.h> 28 #include <dev/ofw/ofw_misc.h> 29 30 #include <dev/clock_subr.h> 31 32 /* Registers. */ 33 #define LPCR 0x38 34 #define LPCR_SRTC_ENV (1 << 0) 35 #define LPSR 0x4c 36 #define LPSRTCMR 0x50 37 #define LPSRTCLR 0x54 38 39 #define HREAD4(sc, reg) \ 40 (regmap_read_4((sc)->sc_rm, (reg))) 41 #define HWRITE4(sc, reg, val) \ 42 regmap_write_4((sc)->sc_rm, (reg), (val)) 43 44 struct imxrtc_softc { 45 struct device sc_dev; 46 struct regmap *sc_rm; 47 48 struct todr_chip_handle sc_todr; 49 }; 50 51 int imxrtc_match(struct device *, void *, void *); 52 void imxrtc_attach(struct device *, struct device *, void *); 53 54 const struct cfattach imxrtc_ca = { 55 sizeof (struct imxrtc_softc), imxrtc_match, imxrtc_attach 56 }; 57 58 struct cfdriver imxrtc_cd = { 59 NULL, "imxrtc", DV_DULL 60 }; 61 62 int imxrtc_gettime(struct todr_chip_handle *, struct timeval *); 63 int imxrtc_settime(struct todr_chip_handle *, struct timeval *); 64 65 int 66 imxrtc_match(struct device *parent, void *match, void *aux) 67 { 68 struct fdt_attach_args *faa = aux; 69 70 return OF_is_compatible(faa->fa_node, "fsl,sec-v4.0-mon-rtc-lp"); 71 } 72 73 void 74 imxrtc_attach(struct device *parent, struct device *self, void *aux) 75 { 76 struct imxrtc_softc *sc = (struct imxrtc_softc *)self; 77 struct fdt_attach_args *faa = aux; 78 uint32_t regmap; 79 80 regmap = OF_getpropint(faa->fa_node, "regmap", 0); 81 sc->sc_rm = regmap_byphandle(regmap); 82 if (sc->sc_rm == NULL) { 83 printf(": no registers\n"); 84 return; 85 } 86 87 printf("\n"); 88 89 sc->sc_todr.cookie = sc; 90 sc->sc_todr.todr_gettime = imxrtc_gettime; 91 sc->sc_todr.todr_settime = imxrtc_settime; 92 sc->sc_todr.todr_quality = 0; 93 todr_attach(&sc->sc_todr); 94 } 95 96 int 97 imxrtc_gettime(struct todr_chip_handle *handle, struct timeval *tv) 98 { 99 struct imxrtc_softc *sc = handle->cookie; 100 uint64_t mr, lr, srtc, srtc2; 101 uint32_t cr; 102 int retries; 103 int s; 104 105 cr = HREAD4(sc, LPCR); 106 if ((cr & LPCR_SRTC_ENV) == 0) 107 return EINVAL; 108 109 /* 110 * Read counters until we read back the same values twice. 111 * This shouldn't take more than two attempts; throw in an 112 * extra round just in case. 113 */ 114 s = splhigh(); 115 mr = HREAD4(sc, LPSRTCMR); 116 lr = HREAD4(sc, LPSRTCLR); 117 srtc = (mr << 32) | lr; 118 for (retries = 3; retries > 0; retries--) { 119 mr = HREAD4(sc, LPSRTCMR); 120 lr = HREAD4(sc, LPSRTCLR); 121 srtc2 = (mr << 32) | lr; 122 if (srtc == srtc2) 123 break; 124 srtc = srtc2; 125 } 126 splx(s); 127 if (retries == 0) 128 return EIO; 129 130 tv->tv_sec = srtc / 32768; 131 tv->tv_usec = ((srtc % 32768) * 1000000U) / 32768U; 132 return 0; 133 } 134 135 int 136 imxrtc_settime(struct todr_chip_handle *handle, struct timeval *tv) 137 { 138 struct imxrtc_softc *sc = handle->cookie; 139 uint64_t srtc; 140 uint32_t cr; 141 int timeout; 142 143 /* Disable RTC. */ 144 cr = HREAD4(sc, LPCR); 145 cr &= ~LPCR_SRTC_ENV; 146 HWRITE4(sc, LPCR, cr); 147 for (timeout = 1000000; timeout > 0; timeout--) { 148 if ((HREAD4(sc, LPCR) & LPCR_SRTC_ENV) == 0) 149 break; 150 } 151 152 srtc = tv->tv_sec * 32768 + (tv->tv_usec * 32768U / 1000000U); 153 HWRITE4(sc, LPSRTCMR, srtc >> 32); 154 HWRITE4(sc, LPSRTCLR, srtc & 0xffffffff); 155 156 /* Enable RTC. */ 157 cr |= LPCR_SRTC_ENV; 158 HWRITE4(sc, LPCR, cr); 159 for (timeout = 1000000; timeout > 0; timeout--) { 160 if (HREAD4(sc, LPCR) & LPCR_SRTC_ENV) 161 break; 162 } 163 164 return 0; 165 } 166