1 /* $OpenBSD: mvrtc.c,v 1.1 2018/03/29 18:20:52 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 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 37 #define RTC_TIMING_CTL0 0x0000 38 #define RTC_TIMING_CTL0_WRCLK_PERIOD_MASK (0xffff << 0) 39 #define RTC_TIMING_CTL0_WRCLK_PERIOD_SHIFT 0 40 #define RTC_TIMING_CTL0_WRCLK_SETUP_MASK (0xffff << 16) 41 #define RTC_TIMING_CTL0_WRCLK_SETUP_SHIFT 16 42 #define RTC_TIMING_CTL1 0x0004 43 #define RTC_TIMING_CTL1_READ_DELAY_MASK (0xffff << 0) 44 #define RTC_TIMING_CTL1_READ_DELAY_SHIFT 0 45 46 #define HREAD4(sc, reg) \ 47 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 48 #define HWRITE4(sc, reg, val) \ 49 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 50 51 struct mvrtc_softc { 52 struct device sc_dev; 53 bus_space_tag_t sc_iot; 54 bus_space_handle_t sc_ioh; 55 bus_space_handle_t sc_soc_ioh; 56 57 struct todr_chip_handle sc_todr; 58 }; 59 60 int mvrtc_match(struct device *, void *, void *); 61 void mvrtc_attach(struct device *, struct device *, void *); 62 63 struct cfattach mvrtc_ca = { 64 sizeof (struct mvrtc_softc), mvrtc_match, mvrtc_attach 65 }; 66 67 struct cfdriver mvrtc_cd = { 68 NULL, "mvrtc", DV_DULL 69 }; 70 71 int mvrtc_gettime(struct todr_chip_handle *, struct timeval *); 72 int mvrtc_settime(struct todr_chip_handle *, struct timeval *); 73 74 int 75 mvrtc_match(struct device *parent, void *match, void *aux) 76 { 77 struct fdt_attach_args *faa = aux; 78 79 return OF_is_compatible(faa->fa_node, "marvell,armada-8k-rtc"); 80 } 81 82 void 83 mvrtc_attach(struct device *parent, struct device *self, void *aux) 84 { 85 struct mvrtc_softc *sc = (struct mvrtc_softc *)self; 86 struct fdt_attach_args *faa = aux; 87 uint32_t reg; 88 89 if (faa->fa_nreg < 2) { 90 printf(": no registers\n"); 91 return; 92 } 93 94 sc->sc_iot = faa->fa_iot; 95 96 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 97 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 98 printf(": can't map registers\n"); 99 return; 100 } 101 102 if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr, 103 faa->fa_reg[1].size, 0, &sc->sc_soc_ioh)) { 104 bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size); 105 printf(": can't map soc registers\n"); 106 return; 107 } 108 109 /* Magic to make bus access actually work. */ 110 reg = bus_space_read_4(sc->sc_iot, sc->sc_soc_ioh, RTC_TIMING_CTL0); 111 reg &= ~RTC_TIMING_CTL0_WRCLK_PERIOD_MASK; 112 reg |= (0x3ff << RTC_TIMING_CTL0_WRCLK_PERIOD_SHIFT); 113 reg &= ~RTC_TIMING_CTL0_WRCLK_SETUP_MASK; 114 reg |= (0x29 << RTC_TIMING_CTL0_WRCLK_SETUP_SHIFT); 115 bus_space_write_4(sc->sc_iot, sc->sc_soc_ioh, RTC_TIMING_CTL0, reg); 116 reg = bus_space_read_4(sc->sc_iot, sc->sc_soc_ioh, RTC_TIMING_CTL1); 117 reg &= ~RTC_TIMING_CTL1_READ_DELAY_MASK; 118 reg |= (0x3f << RTC_TIMING_CTL1_READ_DELAY_SHIFT); 119 bus_space_write_4(sc->sc_iot, sc->sc_soc_ioh, RTC_TIMING_CTL1, reg); 120 121 printf("\n"); 122 123 sc->sc_todr.cookie = sc; 124 sc->sc_todr.todr_gettime = mvrtc_gettime; 125 sc->sc_todr.todr_settime = mvrtc_settime; 126 todr_handle = &sc->sc_todr; 127 } 128 129 int 130 mvrtc_gettime(struct todr_chip_handle *handle, struct timeval *tv) 131 { 132 struct mvrtc_softc *sc = handle->cookie; 133 134 tv->tv_sec = HREAD4(sc, RTC_TIME); 135 tv->tv_usec = 0; 136 return 0; 137 } 138 139 int 140 mvrtc_settime(struct todr_chip_handle *handle, struct timeval *tv) 141 { 142 struct mvrtc_softc *sc = handle->cookie; 143 144 HWRITE4(sc, RTC_STATUS, 0); 145 HWRITE4(sc, RTC_STATUS, 0); 146 HWRITE4(sc, RTC_TIME, tv->tv_sec); 147 delay(10); 148 return 0; 149 } 150