Path: blob/main/sys/arm/mv/armada38x/armada38x_rtc.c
39537 views
/*-1* Copyright (c) 2015 Semihalf.2* Copyright (c) 2015 Stormshield.3* All rights reserved.4*5* Redistribution and use in source and binary forms, with or without6* modification, are permitted provided that the following conditions7* are met:8* 1. Redistributions of source code must retain the above copyright9* notice, this list of conditions and the following disclaimer.10* 2. Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND15* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE16* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE17* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE18* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL19* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS20* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)21* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT22* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY23* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF24* SUCH DAMAGE.25*/2627#include <sys/param.h>28#include <sys/bus.h>29#include <sys/lock.h>30#include <sys/time.h>31#include <sys/proc.h>32#include <sys/conf.h>33#include <sys/rman.h>34#include <sys/clock.h>35#include <sys/systm.h>36#include <sys/mutex.h>37#include <sys/types.h>38#include <sys/kernel.h>39#include <sys/module.h>40#include <sys/resource.h>4142#include <machine/bus.h>43#include <machine/resource.h>4445#include <dev/ofw/ofw_bus.h>46#include <dev/ofw/ofw_bus_subr.h>4748#include "clock_if.h"4950#define RTC_RES_US 100000051#define HALF_OF_SEC_NS 5000000005253#define RTC_STATUS 0x054#define RTC_TIME 0xC55#define RTC_TEST_CONFIG 0x1C56#define RTC_IRQ_1_CONFIG 0x457#define RTC_IRQ_2_CONFIG 0x858#define RTC_ALARM_1 0x1059#define RTC_ALARM_2 0x1460#define RTC_CLOCK_CORR 0x186162#define RTC_NOMINAL_TIMING 0x200063#define RTC_NOMINAL_TIMING_MASK 0x7fff6465#define RTC_STATUS_ALARM1_MASK 0x166#define RTC_STATUS_ALARM2_MASK 0x26768#define MV_RTC_LOCK(sc) mtx_lock_spin(&(sc)->mutex)69#define MV_RTC_UNLOCK(sc) mtx_unlock_spin(&(sc)->mutex)7071#define A38X_RTC_BRIDGE_TIMING_CTRL 0x072#define A38X_RTC_WRCLK_PERIOD_SHIFT 073#define A38X_RTC_WRCLK_PERIOD_MASK 0x00000003FF74#define A38X_RTC_WRCLK_PERIOD_MAX 0x3FF75#define A38X_RTC_READ_OUTPUT_DELAY_SHIFT 2676#define A38X_RTC_READ_OUTPUT_DELAY_MASK 0x007C00000077#define A38X_RTC_READ_OUTPUT_DELAY_MAX 0x1F7879#define A8K_RTC_BRIDGE_TIMING_CTRL0 0x080#define A8K_RTC_WRCLK_PERIOD_SHIFT 081#define A8K_RTC_WRCLK_PERIOD_MASK 0x000000FFFF82#define A8K_RTC_WRCLK_PERIOD_VAL 0x3FF83#define A8K_RTC_WRCLK_SETUP_SHIFT 1684#define A8K_RTC_WRCLK_SETUP_MASK 0x00FFFF000085#define A8K_RTC_WRCLK_SETUP_VAL 2986#define A8K_RTC_BRIDGE_TIMING_CTRL1 0x487#define A8K_RTC_READ_OUTPUT_DELAY_SHIFT 088#define A8K_RTC_READ_OUTPUT_DELAY_MASK 0x000000FFFF89#define A8K_RTC_READ_OUTPUT_DELAY_VAL 0x3F9091#define RTC_RES 092#define RTC_SOC_RES 19394static struct resource_spec res_spec[] = {95{ SYS_RES_MEMORY, 0, RF_ACTIVE },96{ SYS_RES_MEMORY, 1, RF_ACTIVE },97{ -1, 0 }98};99100struct mv_rtc_softc {101device_t dev;102struct resource *res[2];103struct mtx mutex;104int rtc_type;105};106107static int mv_rtc_probe(device_t dev);108static int mv_rtc_attach(device_t dev);109static int mv_rtc_detach(device_t dev);110111static int mv_rtc_gettime(device_t dev, struct timespec *ts);112static int mv_rtc_settime(device_t dev, struct timespec *ts);113114static inline uint32_t mv_rtc_reg_read(struct mv_rtc_softc *sc,115bus_size_t off);116static inline int mv_rtc_reg_write(struct mv_rtc_softc *sc, bus_size_t off,117uint32_t val);118static inline void mv_rtc_configure_bus_a38x(struct mv_rtc_softc *sc);119static inline void mv_rtc_configure_bus_a8k(struct mv_rtc_softc *sc);120121static device_method_t mv_rtc_methods[] = {122DEVMETHOD(device_probe, mv_rtc_probe),123DEVMETHOD(device_attach, mv_rtc_attach),124DEVMETHOD(device_detach, mv_rtc_detach),125126DEVMETHOD(clock_gettime, mv_rtc_gettime),127DEVMETHOD(clock_settime, mv_rtc_settime),128129{ 0, 0 },130};131132static driver_t mv_rtc_driver = {133"rtc",134mv_rtc_methods,135sizeof(struct mv_rtc_softc),136};137138#define RTC_A38X 1139#define RTC_A8K 2140141static struct ofw_compat_data mv_rtc_compat[] = {142{"marvell,armada-380-rtc", RTC_A38X},143{"marvell,armada-8k-rtc", RTC_A8K},144{NULL, 0},145};146147DRIVER_MODULE(a38x_rtc, simplebus, mv_rtc_driver, 0, 0);148149static void150mv_rtc_reset(device_t dev)151{152struct mv_rtc_softc *sc;153154sc = device_get_softc(dev);155156/* Reset Test register */157mv_rtc_reg_write(sc, RTC_TEST_CONFIG, 0);158DELAY(500000);159160/* Reset Time register */161mv_rtc_reg_write(sc, RTC_TIME, 0);162DELAY(62);163164/* Reset Status register */165mv_rtc_reg_write(sc, RTC_STATUS, (RTC_STATUS_ALARM1_MASK | RTC_STATUS_ALARM2_MASK));166DELAY(62);167168/* Turn off Int1 and Int2 sources & clear the Alarm count */169mv_rtc_reg_write(sc, RTC_IRQ_1_CONFIG, 0);170mv_rtc_reg_write(sc, RTC_IRQ_2_CONFIG, 0);171mv_rtc_reg_write(sc, RTC_ALARM_1, 0);172mv_rtc_reg_write(sc, RTC_ALARM_2, 0);173174/* Setup nominal register access timing */175mv_rtc_reg_write(sc, RTC_CLOCK_CORR, RTC_NOMINAL_TIMING);176177/* Reset Time register */178mv_rtc_reg_write(sc, RTC_TIME, 0);179DELAY(10);180181/* Reset Status register */182mv_rtc_reg_write(sc, RTC_STATUS, (RTC_STATUS_ALARM1_MASK | RTC_STATUS_ALARM2_MASK));183DELAY(50);184}185186static int187mv_rtc_probe(device_t dev)188{189190if (!ofw_bus_status_okay(dev))191return (ENXIO);192193if (!ofw_bus_search_compatible(dev, mv_rtc_compat)->ocd_data)194return (ENXIO);195196device_set_desc(dev, "Marvell Integrated RTC");197198return (BUS_PROBE_DEFAULT);199}200201static int202mv_rtc_attach(device_t dev)203{204struct mv_rtc_softc *sc;205int ret;206207sc = device_get_softc(dev);208sc->dev = dev;209sc->rtc_type = ofw_bus_search_compatible(dev, mv_rtc_compat)->ocd_data;210211mtx_init(&sc->mutex, device_get_nameunit(dev), NULL, MTX_SPIN);212213ret = bus_alloc_resources(dev, res_spec, sc->res);214if (ret != 0) {215device_printf(dev, "could not allocate resources\n");216mtx_destroy(&sc->mutex);217return (ENXIO);218}219220switch (sc->rtc_type) {221case RTC_A38X:222mv_rtc_configure_bus_a38x(sc);223break;224case RTC_A8K:225mv_rtc_configure_bus_a8k(sc);226break;227default:228panic("Unknown RTC type: %d", sc->rtc_type);229}230clock_register(dev, RTC_RES_US);231232return (0);233}234235static int236mv_rtc_detach(device_t dev)237{238struct mv_rtc_softc *sc;239240sc = device_get_softc(dev);241242mtx_destroy(&sc->mutex);243244bus_release_resources(dev, res_spec, sc->res);245246return (0);247}248249static int250mv_rtc_gettime(device_t dev, struct timespec *ts)251{252struct mv_rtc_softc *sc;253uint32_t val, val_check;254255sc = device_get_softc(dev);256257MV_RTC_LOCK(sc);258/*259* According to HW Errata, if more than one second is detected260* between two time reads, then at least one of the reads gave261* an invalid value.262*/263do {264val = mv_rtc_reg_read(sc, RTC_TIME);265DELAY(100);266val_check = mv_rtc_reg_read(sc, RTC_TIME);267} while ((val_check - val) > 1);268269MV_RTC_UNLOCK(sc);270271ts->tv_sec = val_check;272/* RTC resolution is 1 sec */273ts->tv_nsec = 0;274275return (0);276}277278static int279mv_rtc_settime(device_t dev, struct timespec *ts)280{281struct mv_rtc_softc *sc;282283sc = device_get_softc(dev);284285/* RTC resolution is 1 sec */286if (ts->tv_nsec >= HALF_OF_SEC_NS)287ts->tv_sec++;288ts->tv_nsec = 0;289290MV_RTC_LOCK(sc);291292if ((mv_rtc_reg_read(sc, RTC_CLOCK_CORR) & RTC_NOMINAL_TIMING_MASK) !=293RTC_NOMINAL_TIMING) {294/* RTC was not resetted yet */295mv_rtc_reset(dev);296}297298/*299* According to errata FE-3124064, Write to RTC TIME register300* may fail. As a workaround, before writing to RTC TIME register,301* issue a dummy write of 0x0 twice to RTC Status register.302*/303mv_rtc_reg_write(sc, RTC_STATUS, 0x0);304mv_rtc_reg_write(sc, RTC_STATUS, 0x0);305mv_rtc_reg_write(sc, RTC_TIME, ts->tv_sec);306MV_RTC_UNLOCK(sc);307308return (0);309}310311static inline uint32_t312mv_rtc_reg_read(struct mv_rtc_softc *sc, bus_size_t off)313{314315return (bus_read_4(sc->res[RTC_RES], off));316}317318/*319* According to the datasheet, the OS should wait 5us after every320* register write to the RTC hard macro so that the required update321* can occur without holding off the system bus322*/323static inline int324mv_rtc_reg_write(struct mv_rtc_softc *sc, bus_size_t off, uint32_t val)325{326327bus_write_4(sc->res[RTC_RES], off, val);328DELAY(5);329330return (0);331}332333static inline void334mv_rtc_configure_bus_a38x(struct mv_rtc_softc *sc)335{336int val;337338val = bus_read_4(sc->res[RTC_SOC_RES], A38X_RTC_BRIDGE_TIMING_CTRL);339val &= ~(A38X_RTC_WRCLK_PERIOD_MASK | A38X_RTC_READ_OUTPUT_DELAY_MASK);340val |= A38X_RTC_WRCLK_PERIOD_MAX << A38X_RTC_WRCLK_PERIOD_SHIFT;341val |= A38X_RTC_READ_OUTPUT_DELAY_MAX << A38X_RTC_READ_OUTPUT_DELAY_SHIFT;342bus_write_4(sc->res[RTC_SOC_RES], A38X_RTC_BRIDGE_TIMING_CTRL, val);343}344345static inline void346mv_rtc_configure_bus_a8k(struct mv_rtc_softc *sc)347{348int val;349350val = bus_read_4(sc->res[RTC_SOC_RES], A8K_RTC_BRIDGE_TIMING_CTRL0);351val &= ~(A8K_RTC_WRCLK_PERIOD_MASK | A8K_RTC_WRCLK_SETUP_MASK);352val |= A8K_RTC_WRCLK_PERIOD_VAL << A8K_RTC_WRCLK_PERIOD_SHIFT;353val |= A8K_RTC_WRCLK_SETUP_VAL << A8K_RTC_WRCLK_SETUP_SHIFT;354bus_write_4(sc->res[RTC_SOC_RES], A8K_RTC_BRIDGE_TIMING_CTRL1, val);355356val = bus_read_4(sc->res[RTC_SOC_RES], A8K_RTC_BRIDGE_TIMING_CTRL0);357val &= ~A8K_RTC_READ_OUTPUT_DELAY_MASK;358val |= A8K_RTC_READ_OUTPUT_DELAY_VAL << A8K_RTC_READ_OUTPUT_DELAY_SHIFT;359bus_write_4(sc->res[RTC_SOC_RES], A8K_RTC_BRIDGE_TIMING_CTRL1, val);360}361362363