1373bbe25SRafal Jaworowski /*- 2*51369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3*51369649SPedro F. Giffuni * 4373bbe25SRafal Jaworowski * Copyright (C) 2008 MARVELL INTERNATIONAL LTD. 5373bbe25SRafal Jaworowski * All rights reserved. 6373bbe25SRafal Jaworowski * 7373bbe25SRafal Jaworowski * Developed by Semihalf. 8373bbe25SRafal Jaworowski * 9373bbe25SRafal Jaworowski * Redistribution and use in source and binary forms, with or without 10373bbe25SRafal Jaworowski * modification, are permitted provided that the following conditions 11373bbe25SRafal Jaworowski * are met: 12373bbe25SRafal Jaworowski * 1. Redistributions of source code must retain the above copyright 13373bbe25SRafal Jaworowski * notice, this list of conditions and the following disclaimer. 14373bbe25SRafal Jaworowski * 2. Redistributions in binary form must reproduce the above copyright 15373bbe25SRafal Jaworowski * notice, this list of conditions and the following disclaimer in the 16373bbe25SRafal Jaworowski * documentation and/or other materials provided with the distribution. 17373bbe25SRafal Jaworowski * 3. Neither the name of MARVELL nor the names of contributors 18373bbe25SRafal Jaworowski * may be used to endorse or promote products derived from this software 19373bbe25SRafal Jaworowski * without specific prior written permission. 20373bbe25SRafal Jaworowski * 21373bbe25SRafal Jaworowski * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22373bbe25SRafal Jaworowski * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23373bbe25SRafal Jaworowski * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24373bbe25SRafal Jaworowski * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 25373bbe25SRafal Jaworowski * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26373bbe25SRafal Jaworowski * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27373bbe25SRafal Jaworowski * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28373bbe25SRafal Jaworowski * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29373bbe25SRafal Jaworowski * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30373bbe25SRafal Jaworowski * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31373bbe25SRafal Jaworowski * SUCH DAMAGE. 32373bbe25SRafal Jaworowski */ 33373bbe25SRafal Jaworowski 34373bbe25SRafal Jaworowski #include <sys/cdefs.h> 35373bbe25SRafal Jaworowski __FBSDID("$FreeBSD$"); 36373bbe25SRafal Jaworowski #include <sys/param.h> 37373bbe25SRafal Jaworowski #include <sys/bus.h> 38373bbe25SRafal Jaworowski #include <sys/lock.h> 39373bbe25SRafal Jaworowski #include <sys/time.h> 40373bbe25SRafal Jaworowski #include <sys/clock.h> 41373bbe25SRafal Jaworowski #include <sys/resource.h> 42373bbe25SRafal Jaworowski #include <sys/systm.h> 43373bbe25SRafal Jaworowski #include <sys/rman.h> 44373bbe25SRafal Jaworowski #include <sys/kernel.h> 45373bbe25SRafal Jaworowski #include <sys/module.h> 46373bbe25SRafal Jaworowski 47373bbe25SRafal Jaworowski #include <machine/bus.h> 48373bbe25SRafal Jaworowski #include <machine/resource.h> 49373bbe25SRafal Jaworowski 50db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus.h> 51db5ef4fcSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h> 52db5ef4fcSRafal Jaworowski 53373bbe25SRafal Jaworowski #include "clock_if.h" 54373bbe25SRafal Jaworowski 55373bbe25SRafal Jaworowski #define MV_RTC_TIME_REG 0x00 56373bbe25SRafal Jaworowski #define MV_RTC_DATE_REG 0x04 57373bbe25SRafal Jaworowski #define YEAR_BASE 2000 58373bbe25SRafal Jaworowski 59373bbe25SRafal Jaworowski struct mv_rtc_softc { 60373bbe25SRafal Jaworowski device_t dev; 61373bbe25SRafal Jaworowski struct resource *res[1]; 62373bbe25SRafal Jaworowski }; 63373bbe25SRafal Jaworowski 64373bbe25SRafal Jaworowski static struct resource_spec res_spec[] = { 65373bbe25SRafal Jaworowski { SYS_RES_MEMORY, 0, RF_ACTIVE }, 66373bbe25SRafal Jaworowski { -1, 0 } 67373bbe25SRafal Jaworowski }; 68373bbe25SRafal Jaworowski 69373bbe25SRafal Jaworowski static int mv_rtc_probe(device_t dev); 70373bbe25SRafal Jaworowski static int mv_rtc_attach(device_t dev); 71373bbe25SRafal Jaworowski 72373bbe25SRafal Jaworowski static int mv_rtc_gettime(device_t dev, struct timespec *ts); 73373bbe25SRafal Jaworowski static int mv_rtc_settime(device_t dev, struct timespec *ts); 74373bbe25SRafal Jaworowski 75373bbe25SRafal Jaworowski static uint32_t mv_rtc_reg_read(struct mv_rtc_softc *sc, bus_size_t off); 76373bbe25SRafal Jaworowski static int mv_rtc_reg_write(struct mv_rtc_softc *sc, bus_size_t off, 77373bbe25SRafal Jaworowski uint32_t val); 78373bbe25SRafal Jaworowski 79373bbe25SRafal Jaworowski static device_method_t mv_rtc_methods[] = { 80373bbe25SRafal Jaworowski DEVMETHOD(device_probe, mv_rtc_probe), 81373bbe25SRafal Jaworowski DEVMETHOD(device_attach, mv_rtc_attach), 82373bbe25SRafal Jaworowski 83373bbe25SRafal Jaworowski DEVMETHOD(clock_gettime, mv_rtc_gettime), 84373bbe25SRafal Jaworowski DEVMETHOD(clock_settime, mv_rtc_settime), 85373bbe25SRafal Jaworowski 86373bbe25SRafal Jaworowski { 0, 0 }, 87373bbe25SRafal Jaworowski }; 88373bbe25SRafal Jaworowski 89373bbe25SRafal Jaworowski static driver_t mv_rtc_driver = { 90373bbe25SRafal Jaworowski "rtc", 91373bbe25SRafal Jaworowski mv_rtc_methods, 92373bbe25SRafal Jaworowski sizeof(struct mv_rtc_softc), 93373bbe25SRafal Jaworowski }; 94373bbe25SRafal Jaworowski static devclass_t mv_rtc_devclass; 95373bbe25SRafal Jaworowski 96db5ef4fcSRafal Jaworowski DRIVER_MODULE(mv_rtc, simplebus, mv_rtc_driver, mv_rtc_devclass, 0, 0); 97373bbe25SRafal Jaworowski 98373bbe25SRafal Jaworowski static int 99373bbe25SRafal Jaworowski mv_rtc_probe(device_t dev) 100373bbe25SRafal Jaworowski { 101373bbe25SRafal Jaworowski 102add35ed5SIan Lepore if (!ofw_bus_status_okay(dev)) 103add35ed5SIan Lepore return (ENXIO); 104add35ed5SIan Lepore 105db5ef4fcSRafal Jaworowski if (!ofw_bus_is_compatible(dev, "mrvl,rtc")) 106db5ef4fcSRafal Jaworowski return (ENXIO); 107db5ef4fcSRafal Jaworowski 108373bbe25SRafal Jaworowski device_set_desc(dev, "Marvell Integrated RTC"); 109db5ef4fcSRafal Jaworowski return (BUS_PROBE_DEFAULT); 110373bbe25SRafal Jaworowski } 111373bbe25SRafal Jaworowski 112373bbe25SRafal Jaworowski static int 113373bbe25SRafal Jaworowski mv_rtc_attach(device_t dev) 114373bbe25SRafal Jaworowski { 115373bbe25SRafal Jaworowski struct mv_rtc_softc *sc; 116373bbe25SRafal Jaworowski 117373bbe25SRafal Jaworowski sc = device_get_softc(dev); 118373bbe25SRafal Jaworowski sc->dev = dev; 119373bbe25SRafal Jaworowski 120373bbe25SRafal Jaworowski clock_register(dev, 1000000); 121373bbe25SRafal Jaworowski 122373bbe25SRafal Jaworowski if (bus_alloc_resources(dev, res_spec, sc->res)) { 123373bbe25SRafal Jaworowski device_printf(dev, "could not allocate resources\n"); 124373bbe25SRafal Jaworowski return (ENXIO); 125373bbe25SRafal Jaworowski } 126373bbe25SRafal Jaworowski 127373bbe25SRafal Jaworowski return (0); 128373bbe25SRafal Jaworowski } 129373bbe25SRafal Jaworowski 130373bbe25SRafal Jaworowski static int 131373bbe25SRafal Jaworowski mv_rtc_gettime(device_t dev, struct timespec *ts) 132373bbe25SRafal Jaworowski { 133373bbe25SRafal Jaworowski struct clocktime ct; 134373bbe25SRafal Jaworowski struct mv_rtc_softc *sc; 135373bbe25SRafal Jaworowski uint32_t val; 136373bbe25SRafal Jaworowski 137373bbe25SRafal Jaworowski sc = device_get_softc(dev); 138373bbe25SRafal Jaworowski 139373bbe25SRafal Jaworowski val = mv_rtc_reg_read(sc, MV_RTC_TIME_REG); 140373bbe25SRafal Jaworowski 141373bbe25SRafal Jaworowski ct.nsec = 0; 142373bbe25SRafal Jaworowski ct.sec = FROMBCD(val & 0x7f); 143373bbe25SRafal Jaworowski ct.min = FROMBCD((val & 0x7f00) >> 8); 144373bbe25SRafal Jaworowski ct.hour = FROMBCD((val & 0x3f0000) >> 16); 145373bbe25SRafal Jaworowski ct.dow = FROMBCD((val & 0x7000000) >> 24) - 1; 146373bbe25SRafal Jaworowski 147373bbe25SRafal Jaworowski val = mv_rtc_reg_read(sc, MV_RTC_DATE_REG); 148373bbe25SRafal Jaworowski 149373bbe25SRafal Jaworowski ct.day = FROMBCD(val & 0x7f); 150373bbe25SRafal Jaworowski ct.mon = FROMBCD((val & 0x1f00) >> 8); 151373bbe25SRafal Jaworowski ct.year = YEAR_BASE + FROMBCD((val & 0xff0000) >> 16); 152373bbe25SRafal Jaworowski 153373bbe25SRafal Jaworowski return (clock_ct_to_ts(&ct, ts)); 154373bbe25SRafal Jaworowski } 155373bbe25SRafal Jaworowski 156373bbe25SRafal Jaworowski static int 157373bbe25SRafal Jaworowski mv_rtc_settime(device_t dev, struct timespec *ts) 158373bbe25SRafal Jaworowski { 159373bbe25SRafal Jaworowski struct clocktime ct; 160373bbe25SRafal Jaworowski struct mv_rtc_softc *sc; 161373bbe25SRafal Jaworowski uint32_t val; 162373bbe25SRafal Jaworowski 163373bbe25SRafal Jaworowski sc = device_get_softc(dev); 164373bbe25SRafal Jaworowski 165373bbe25SRafal Jaworowski /* Resolution: 1 sec */ 166373bbe25SRafal Jaworowski if (ts->tv_nsec >= 500000000) 167373bbe25SRafal Jaworowski ts->tv_sec++; 168373bbe25SRafal Jaworowski ts->tv_nsec = 0; 169373bbe25SRafal Jaworowski clock_ts_to_ct(ts, &ct); 170373bbe25SRafal Jaworowski 171373bbe25SRafal Jaworowski val = TOBCD(ct.sec) | (TOBCD(ct.min) << 8) | 172373bbe25SRafal Jaworowski (TOBCD(ct.hour) << 16) | (TOBCD( ct.dow + 1) << 24); 173373bbe25SRafal Jaworowski mv_rtc_reg_write(sc, MV_RTC_TIME_REG, val); 174373bbe25SRafal Jaworowski 175373bbe25SRafal Jaworowski val = TOBCD(ct.day) | (TOBCD(ct.mon) << 8) | 176373bbe25SRafal Jaworowski (TOBCD(ct.year - YEAR_BASE) << 16); 177373bbe25SRafal Jaworowski mv_rtc_reg_write(sc, MV_RTC_DATE_REG, val); 178373bbe25SRafal Jaworowski 179373bbe25SRafal Jaworowski return (0); 180373bbe25SRafal Jaworowski } 181373bbe25SRafal Jaworowski 182373bbe25SRafal Jaworowski static uint32_t 183373bbe25SRafal Jaworowski mv_rtc_reg_read(struct mv_rtc_softc *sc, bus_size_t off) 184373bbe25SRafal Jaworowski { 185373bbe25SRafal Jaworowski 186373bbe25SRafal Jaworowski return (bus_read_4(sc->res[0], off)); 187373bbe25SRafal Jaworowski } 188373bbe25SRafal Jaworowski 189373bbe25SRafal Jaworowski static int 190373bbe25SRafal Jaworowski mv_rtc_reg_write(struct mv_rtc_softc *sc, bus_size_t off, uint32_t val) 191373bbe25SRafal Jaworowski { 192373bbe25SRafal Jaworowski 193373bbe25SRafal Jaworowski bus_write_4(sc->res[0], off, val); 194373bbe25SRafal Jaworowski return (0); 195373bbe25SRafal Jaworowski } 196