1 /* $OpenBSD: mvortc.c,v 1.1 2023/03/02 09:57:43 jmatthew Exp $ */ 2 /* 3 * Copyright (c) 2022 Jonathan Matthew <jmatthew@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 29 #include <dev/clock_subr.h> 30 31 extern todr_chip_handle_t todr_handle; 32 33 /* Registers. */ 34 #define RTC_STATUS 0x0000 35 #define RTC_TIME 0x000c 36 #define RTC_CONF_TEST 0x001c 37 38 #define RTC_TIMING_CTL 0x0000 39 #define RTC_PERIOD_SHIFT 0 40 #define RTC_PERIOD_MASK (0x3ff << RTC_PERIOD_SHIFT) 41 #define RTC_READ_DELAY_SHIFT 26 42 #define RTC_READ_DELAY_MASK (0x1f << RTC_READ_DELAY_SHIFT) 43 44 45 #define HREAD4(sc, reg) \ 46 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 47 #define HWRITE4(sc, reg, val) \ 48 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 49 50 struct mvortc_softc { 51 struct device sc_dev; 52 bus_space_tag_t sc_iot; 53 bus_space_handle_t sc_ioh; 54 bus_space_handle_t sc_soc_ioh; 55 56 struct todr_chip_handle sc_todr; 57 }; 58 59 int mvortc_match(struct device *, void *, void *); 60 void mvortc_attach(struct device *, struct device *, void *); 61 62 const struct cfattach mvortc_ca = { 63 sizeof (struct mvortc_softc), mvortc_match, mvortc_attach 64 }; 65 66 struct cfdriver mvortc_cd = { 67 NULL, "mvortc", DV_DULL 68 }; 69 70 int mvortc_gettime(struct todr_chip_handle *, struct timeval *); 71 int mvortc_settime(struct todr_chip_handle *, struct timeval *); 72 73 int 74 mvortc_match(struct device *parent, void *match, void *aux) 75 { 76 struct fdt_attach_args *faa = aux; 77 78 return OF_is_compatible(faa->fa_node, "marvell,armada-380-rtc"); 79 } 80 81 void 82 mvortc_attach(struct device *parent, struct device *self, void *aux) 83 { 84 struct mvortc_softc *sc = (struct mvortc_softc *)self; 85 struct fdt_attach_args *faa = aux; 86 uint32_t reg; 87 88 if (faa->fa_nreg < 2) { 89 printf(": no registers\n"); 90 return; 91 } 92 93 sc->sc_iot = faa->fa_iot; 94 95 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 96 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 97 printf(": can't map registers\n"); 98 return; 99 } 100 101 if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr, 102 faa->fa_reg[1].size, 0, &sc->sc_soc_ioh)) { 103 bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size); 104 printf(": can't map soc registers\n"); 105 return; 106 } 107 108 /* Magic to make bus access actually work. */ 109 reg = bus_space_read_4(sc->sc_iot, sc->sc_soc_ioh, RTC_TIMING_CTL); 110 reg &= ~RTC_PERIOD_MASK; 111 reg |= (0x3ff << RTC_PERIOD_SHIFT); 112 reg &= ~RTC_READ_DELAY_MASK; 113 reg |= (0x1f << RTC_READ_DELAY_SHIFT); 114 bus_space_write_4(sc->sc_iot, sc->sc_soc_ioh, RTC_TIMING_CTL, reg); 115 printf("\n"); 116 117 sc->sc_todr.cookie = sc; 118 sc->sc_todr.todr_gettime = mvortc_gettime; 119 sc->sc_todr.todr_settime = mvortc_settime; 120 todr_handle = &sc->sc_todr; 121 } 122 123 uint32_t 124 mvortc_read(struct mvortc_softc *sc, int reg) 125 { 126 uint32_t sample, mode; 127 uint32_t samples[100]; 128 int counts[100]; 129 int i, j, last; 130 131 memset(samples, 0, sizeof(samples)); 132 memset(counts, 0, sizeof(counts)); 133 last = 0; 134 for (i = 0; i < nitems(samples); i++) { 135 sample = HREAD4(sc, reg); 136 137 for (j = 0; j < last; j++) { 138 if (samples[j] == sample) 139 break; 140 } 141 142 if (j < last) { 143 counts[j]++; 144 } else { 145 samples[last] = sample; 146 counts[last] = 1; 147 last++; 148 } 149 } 150 151 j = 0; 152 mode = 0; 153 for (i = 0; i < last; i++) { 154 if (counts[i] > mode) { 155 mode = counts[i]; 156 j = i; 157 } 158 } 159 160 return samples[j]; 161 } 162 163 void 164 mvortc_write(struct mvortc_softc *sc, int reg, uint32_t val) 165 { 166 HWRITE4(sc, RTC_STATUS, 0); 167 HWRITE4(sc, RTC_STATUS, 0); 168 HWRITE4(sc, reg, val); 169 delay(5); 170 } 171 172 int 173 mvortc_gettime(struct todr_chip_handle *handle, struct timeval *tv) 174 { 175 struct mvortc_softc *sc = handle->cookie; 176 177 tv->tv_sec = mvortc_read(sc, RTC_TIME); 178 tv->tv_usec = 0; 179 return 0; 180 } 181 182 int 183 mvortc_settime(struct todr_chip_handle *handle, struct timeval *tv) 184 { 185 struct mvortc_softc *sc = handle->cookie; 186 uint32_t reg; 187 188 reg = mvortc_read(sc, RTC_CONF_TEST); 189 if (reg & 0xff) { 190 mvortc_write(sc, RTC_CONF_TEST, 0); 191 delay(500); 192 mvortc_write(sc, RTC_TIME, 0); 193 mvortc_write(sc, RTC_STATUS, 0x03); 194 } 195 196 mvortc_write(sc, RTC_TIME, tv->tv_sec); 197 return 0; 198 } 199