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 31extern 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 50struct 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 59int mvortc_match(struct device *, void *, void *); 60void mvortc_attach(struct device *, struct device *, void *); 61 62const struct cfattach mvortc_ca = { 63 sizeof (struct mvortc_softc), mvortc_match, mvortc_attach 64}; 65 66struct cfdriver mvortc_cd = { 67 NULL, "mvortc", DV_DULL 68}; 69 70int mvortc_gettime(struct todr_chip_handle *, struct timeval *); 71int mvortc_settime(struct todr_chip_handle *, struct timeval *); 72 73int 74mvortc_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 81void 82mvortc_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 123uint32_t 124mvortc_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 163void 164mvortc_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 172int 173mvortc_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 182int 183mvortc_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