1/*- 2 * Copyright (c) 2015 Semihalf. 3 * Copyright (c) 2015 Stormshield. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: releng/11.0/sys/arm/mv/armada38x/rtc.c 294434 2016-01-20 14:18:49Z zbb $"); 30 31#include <sys/param.h> 32#include <sys/bus.h> 33#include <sys/lock.h> 34#include <sys/time.h> 35#include <sys/proc.h> 36#include <sys/conf.h> 37#include <sys/rman.h> 38#include <sys/clock.h> 39#include <sys/systm.h> 40#include <sys/mutex.h> 41#include <sys/types.h> 42#include <sys/kernel.h> 43#include <sys/module.h> 44#include <sys/resource.h> 45 46#include <machine/bus.h> 47#include <machine/resource.h> 48 49#include <dev/ofw/ofw_bus.h> 50#include <dev/ofw/ofw_bus_subr.h> 51 52#include "clock_if.h" 53 54#define RTC_RES_US 1000000 55#define HALF_OF_SEC_NS 500000000 56 57#define RTC_STATUS 0x0 58#define RTC_TIME 0xC 59 60#define MV_RTC_LOCK(sc) mtx_lock(&(sc)->mutex) 61#define MV_RTC_UNLOCK(sc) mtx_unlock(&(sc)->mutex) 62 63static struct resource_spec res_spec[] = { 64 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 65 { -1, 0 } 66}; 67 68struct mv_rtc_softc { 69 device_t dev; 70 struct resource *res; 71 struct mtx mutex; 72}; 73 74static int mv_rtc_probe(device_t dev); 75static int mv_rtc_attach(device_t dev); 76static int mv_rtc_detach(device_t dev); 77 78static int mv_rtc_gettime(device_t dev, struct timespec *ts); 79static int mv_rtc_settime(device_t dev, struct timespec *ts); 80 81static uint32_t mv_rtc_reg_read(struct mv_rtc_softc *sc, bus_size_t off); 82static int mv_rtc_reg_write(struct mv_rtc_softc *sc, bus_size_t off, 83 uint32_t val); 84 85static device_method_t mv_rtc_methods[] = { 86 DEVMETHOD(device_probe, mv_rtc_probe), 87 DEVMETHOD(device_attach, mv_rtc_attach), 88 DEVMETHOD(device_detach, mv_rtc_detach), 89 90 DEVMETHOD(clock_gettime, mv_rtc_gettime), 91 DEVMETHOD(clock_settime, mv_rtc_settime), 92 93 { 0, 0 }, 94}; 95 96static driver_t mv_rtc_driver = { 97 "rtc", 98 mv_rtc_methods, 99 sizeof(struct mv_rtc_softc), 100}; 101 102static devclass_t mv_rtc_devclass; 103 104DRIVER_MODULE(mv_rtc, simplebus, mv_rtc_driver, mv_rtc_devclass, 0, 0); 105 106static int 107mv_rtc_probe(device_t dev) 108{ 109 110 if (!ofw_bus_status_okay(dev)) 111 return (ENXIO); 112 113 if (!ofw_bus_is_compatible(dev, "marvell,armada-380-rtc")) 114 return (ENXIO); 115 116 device_set_desc(dev, "Marvell Integrated RTC"); 117 118 return (BUS_PROBE_DEFAULT); 119} 120 121static int 122mv_rtc_attach(device_t dev) 123{ 124 struct mv_rtc_softc *sc; 125 int unit, ret; 126 127 unit = device_get_unit(dev); 128 129 sc = device_get_softc(dev); 130 sc->dev = dev; 131 132 clock_register(dev, RTC_RES_US); 133 134 mtx_init(&sc->mutex, device_get_nameunit(dev), NULL, MTX_DEF); 135 136 ret = bus_alloc_resources(dev, res_spec, &sc->res); 137 if (ret != 0) { 138 device_printf(dev, "could not allocate resources\n"); 139 mtx_destroy(&sc->mutex); 140 return (ENXIO); 141 } 142 143 return (0); 144} 145 146static int 147mv_rtc_detach(device_t dev) 148{ 149 struct mv_rtc_softc *sc; 150 151 sc = device_get_softc(dev); 152 153 mtx_destroy(&sc->mutex); 154 155 bus_release_resources(dev, res_spec, &sc->res); 156 157 return (0); 158} 159 160static int 161mv_rtc_gettime(device_t dev, struct timespec *ts) 162{ 163 struct mv_rtc_softc *sc; 164 uint32_t val, val_check; 165 166 sc = device_get_softc(dev); 167 168 MV_RTC_LOCK(sc); 169 /* 170 * According to HW Errata if more than one second between 171 * two time reads is detected, then read once again 172 */ 173 val = mv_rtc_reg_read(sc, RTC_TIME); 174 val_check = mv_rtc_reg_read(sc, RTC_TIME); 175 if (val_check - val > 1) 176 val_check = mv_rtc_reg_read(sc, RTC_TIME); 177 178 MV_RTC_UNLOCK(sc); 179 180 ts->tv_sec = val_check; 181 /* RTC resolution is 1 sec */ 182 ts->tv_nsec = 0; 183 184 return (0); 185} 186 187static int 188mv_rtc_settime(device_t dev, struct timespec *ts) 189{ 190 struct mv_rtc_softc *sc; 191 192 sc = device_get_softc(dev); 193 194 /* RTC resolution is 1 sec */ 195 if (ts->tv_nsec >= HALF_OF_SEC_NS) 196 ts->tv_sec++; 197 ts->tv_nsec = 0; 198 199 MV_RTC_LOCK(sc); 200 201 /* 202 * According to errata FE-3124064, Write to RTC TIME register 203 * may fail. As a workaround, before writing to RTC TIME register, 204 * issue a dummy write of 0x0 twice to RTC Status register. 205 */ 206 mv_rtc_reg_write(sc, RTC_STATUS, 0x0); 207 mv_rtc_reg_write(sc, RTC_STATUS, 0x0); 208 mv_rtc_reg_write(sc, RTC_TIME, ts->tv_sec); 209 210 MV_RTC_UNLOCK(sc); 211 212 return (0); 213} 214 215static uint32_t 216mv_rtc_reg_read(struct mv_rtc_softc *sc, bus_size_t off) 217{ 218 219 return (bus_read_4(sc->res, off)); 220} 221 222/* 223 * According to the datasheet, the OS should wait 5us after every 224 * register write to the RTC hard macro so that the required update 225 * can occur without holding off the system bus 226 */ 227static int 228mv_rtc_reg_write(struct mv_rtc_softc *sc, bus_size_t off, uint32_t val) 229{ 230 231 bus_write_4(sc->res, off, val); 232 DELAY(5); 233 234 return (0); 235} 236