timer.c revision 295464
1245450Sganbold/*- 2263711Sganbold * Copyright (c) 2012 Ganbold Tsagaankhuu <ganbold@freebsd.org> 3245450Sganbold * All rights reserved. 4245450Sganbold * 5245450Sganbold * Redistribution and use in source and binary forms, with or without 6245450Sganbold * modification, are permitted provided that the following conditions 7245450Sganbold * are met: 8245453Sganbold * 1. Redistributions of source code must retain the above copyright 9245453Sganbold * notice, this list of conditions and the following disclaimer. 10245453Sganbold * 2. Redistributions in binary form must reproduce the above copyright 11245453Sganbold * notice, this list of conditions and the following disclaimer in the 12245453Sganbold * documentation and/or other materials provided with the distribution. 13245450Sganbold * 14245450Sganbold * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15245450Sganbold * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16245450Sganbold * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17245454Sganbold * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18245450Sganbold * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19245450Sganbold * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20245450Sganbold * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21245450Sganbold * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22245450Sganbold * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23245450Sganbold * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24245450Sganbold * SUCH DAMAGE. 25245450Sganbold */ 26245450Sganbold 27245450Sganbold#include <sys/cdefs.h> 28245450Sganbold__FBSDID("$FreeBSD: head/sys/arm/allwinner/timer.c 295464 2016-02-10 09:19:29Z andrew $"); 29245450Sganbold 30245450Sganbold#include <sys/param.h> 31245450Sganbold#include <sys/systm.h> 32245450Sganbold#include <sys/bus.h> 33245450Sganbold#include <sys/kernel.h> 34245450Sganbold#include <sys/module.h> 35245450Sganbold#include <sys/malloc.h> 36245450Sganbold#include <sys/rman.h> 37245450Sganbold#include <sys/timeet.h> 38245450Sganbold#include <sys/timetc.h> 39245450Sganbold#include <sys/watchdog.h> 40245450Sganbold#include <machine/bus.h> 41245450Sganbold#include <machine/cpu.h> 42245450Sganbold#include <machine/intr.h> 43245450Sganbold 44245450Sganbold#include <dev/fdt/fdt_common.h> 45245450Sganbold#include <dev/ofw/openfirm.h> 46245450Sganbold#include <dev/ofw/ofw_bus.h> 47245450Sganbold#include <dev/ofw/ofw_bus_subr.h> 48245450Sganbold 49245450Sganbold#include <machine/bus.h> 50245450Sganbold 51245450Sganbold#include <sys/kdb.h> 52245450Sganbold 53295464Sandrew#include <arm/allwinner/allwinner_machdep.h> 54254056Sganbold 55245450Sganbold/** 56245450Sganbold * Timer registers addr 57245450Sganbold * 58245450Sganbold */ 59245450Sganbold#define SW_TIMER_IRQ_EN_REG 0x00 60245450Sganbold#define SW_TIMER_IRQ_STA_REG 0x04 61245450Sganbold#define SW_TIMER0_CTRL_REG 0x10 62245450Sganbold#define SW_TIMER0_INT_VALUE_REG 0x14 63245450Sganbold#define SW_TIMER0_CUR_VALUE_REG 0x18 64245450Sganbold 65245876Sganbold#define SW_COUNTER64LO_REG 0xa4 66245876Sganbold#define SW_COUNTER64HI_REG 0xa8 67245876Sganbold#define CNT64_CTRL_REG 0xa0 68245450Sganbold 69245876Sganbold#define CNT64_RL_EN 0x02 /* read latch enable */ 70245450Sganbold 71245876Sganbold#define TIMER_ENABLE (1<<0) 72245876Sganbold#define TIMER_AUTORELOAD (1<<1) 73245876Sganbold#define TIMER_OSC24M (1<<2) /* oscillator = 24mhz */ 74272397Sganbold#define TIMER_PRESCALAR (0<<4) /* prescalar = 1 */ 75245876Sganbold 76245876Sganbold#define SYS_TIMER_CLKSRC 24000000 /* clock source */ 77245876Sganbold 78245450Sganboldstruct a10_timer_softc { 79245450Sganbold device_t sc_dev; 80245450Sganbold struct resource *res[2]; 81245450Sganbold bus_space_tag_t sc_bst; 82245450Sganbold bus_space_handle_t sc_bsh; 83245450Sganbold void *sc_ih; /* interrupt handler */ 84245450Sganbold uint32_t sc_period; 85245876Sganbold uint32_t timer0_freq; 86245450Sganbold struct eventtimer et; 87245450Sganbold}; 88245450Sganbold 89245450Sganboldint a10_timer_get_timerfreq(struct a10_timer_softc *); 90245450Sganbold 91245450Sganbold#define timer_read_4(sc, reg) \ 92245450Sganbold bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg) 93245450Sganbold#define timer_write_4(sc, reg, val) \ 94245450Sganbold bus_space_write_4(sc->sc_bst, sc->sc_bsh, reg, val) 95245450Sganbold 96245450Sganboldstatic u_int a10_timer_get_timecount(struct timecounter *); 97245450Sganboldstatic int a10_timer_timer_start(struct eventtimer *, 98247463Smav sbintime_t first, sbintime_t period); 99245450Sganboldstatic int a10_timer_timer_stop(struct eventtimer *); 100245450Sganbold 101245876Sganboldstatic uint64_t timer_read_counter64(void); 102245876Sganbold 103245450Sganboldstatic int a10_timer_initialized = 0; 104245876Sganboldstatic int a10_timer_hardclock(void *); 105245450Sganboldstatic int a10_timer_probe(device_t); 106245450Sganboldstatic int a10_timer_attach(device_t); 107245450Sganbold 108245450Sganboldstatic struct timecounter a10_timer_timecounter = { 109245450Sganbold .tc_name = "a10_timer timer0", 110245450Sganbold .tc_get_timecount = a10_timer_get_timecount, 111245450Sganbold .tc_counter_mask = ~0u, 112245450Sganbold .tc_frequency = 0, 113245450Sganbold .tc_quality = 1000, 114245450Sganbold}; 115245450Sganbold 116245450Sganboldstruct a10_timer_softc *a10_timer_sc = NULL; 117245450Sganbold 118245450Sganboldstatic struct resource_spec a10_timer_spec[] = { 119245450Sganbold { SYS_RES_MEMORY, 0, RF_ACTIVE }, 120245450Sganbold { SYS_RES_IRQ, 0, RF_ACTIVE }, 121245450Sganbold { -1, 0 } 122245450Sganbold}; 123245450Sganbold 124245876Sganboldstatic uint64_t 125245876Sganboldtimer_read_counter64(void) 126245876Sganbold{ 127245876Sganbold uint32_t lo, hi; 128245876Sganbold 129245876Sganbold /* Latch counter, wait for it to be ready to read. */ 130245876Sganbold timer_write_4(a10_timer_sc, CNT64_CTRL_REG, CNT64_RL_EN); 131245876Sganbold while (timer_read_4(a10_timer_sc, CNT64_CTRL_REG) & CNT64_RL_EN) 132245876Sganbold continue; 133245876Sganbold 134245876Sganbold hi = timer_read_4(a10_timer_sc, SW_COUNTER64HI_REG); 135245876Sganbold lo = timer_read_4(a10_timer_sc, SW_COUNTER64LO_REG); 136245876Sganbold 137245876Sganbold return (((uint64_t)hi << 32) | lo); 138245876Sganbold} 139245876Sganbold 140245450Sganboldstatic int 141245450Sganbolda10_timer_probe(device_t dev) 142245450Sganbold{ 143254056Sganbold struct a10_timer_softc *sc; 144295464Sandrew u_int soc_family; 145245450Sganbold 146254056Sganbold sc = device_get_softc(dev); 147254056Sganbold 148295464Sandrew if (!ofw_bus_is_compatible(dev, "allwinner,sun4i-a10-timer")) 149245450Sganbold return (ENXIO); 150245450Sganbold 151295464Sandrew soc_family = allwinner_soc_family(); 152295464Sandrew if (soc_family != ALLWINNERSOC_SUN4I && 153295464Sandrew soc_family != ALLWINNERSOC_SUN5I) 154295464Sandrew return (ENXIO); 155295464Sandrew 156254056Sganbold device_set_desc(dev, "Allwinner A10/A20 timer"); 157245450Sganbold return (BUS_PROBE_DEFAULT); 158245450Sganbold} 159245450Sganbold 160245450Sganboldstatic int 161245450Sganbolda10_timer_attach(device_t dev) 162245450Sganbold{ 163245450Sganbold struct a10_timer_softc *sc; 164245450Sganbold int err; 165245450Sganbold uint32_t val; 166245450Sganbold 167245450Sganbold sc = device_get_softc(dev); 168245450Sganbold 169245450Sganbold if (bus_alloc_resources(dev, a10_timer_spec, sc->res)) { 170245450Sganbold device_printf(dev, "could not allocate resources\n"); 171245450Sganbold return (ENXIO); 172245450Sganbold } 173245450Sganbold 174245450Sganbold sc->sc_dev = dev; 175245450Sganbold sc->sc_bst = rman_get_bustag(sc->res[0]); 176245450Sganbold sc->sc_bsh = rman_get_bushandle(sc->res[0]); 177245450Sganbold 178245450Sganbold /* Setup and enable the timer interrupt */ 179245876Sganbold err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_CLK, a10_timer_hardclock, 180245450Sganbold NULL, sc, &sc->sc_ih); 181245450Sganbold if (err != 0) { 182245450Sganbold bus_release_resources(dev, a10_timer_spec, sc->res); 183245450Sganbold device_printf(dev, "Unable to setup the clock irq handler, " 184245450Sganbold "err = %d\n", err); 185245450Sganbold return (ENXIO); 186245450Sganbold } 187245450Sganbold 188245876Sganbold /* Set clock source to OSC24M, 16 pre-division */ 189245876Sganbold val = timer_read_4(sc, SW_TIMER0_CTRL_REG); 190245876Sganbold val |= TIMER_PRESCALAR | TIMER_OSC24M; 191245876Sganbold timer_write_4(sc, SW_TIMER0_CTRL_REG, val); 192245876Sganbold 193245876Sganbold /* Enable timer0 */ 194245876Sganbold val = timer_read_4(sc, SW_TIMER_IRQ_EN_REG); 195245876Sganbold val |= TIMER_ENABLE; 196245876Sganbold timer_write_4(sc, SW_TIMER_IRQ_EN_REG, val); 197245876Sganbold 198245876Sganbold sc->timer0_freq = SYS_TIMER_CLKSRC; 199245876Sganbold 200245876Sganbold /* Set desired frequency in event timer and timecounter */ 201245876Sganbold sc->et.et_frequency = sc->timer0_freq; 202245450Sganbold sc->et.et_name = "a10_timer Eventtimer"; 203245450Sganbold sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC; 204245450Sganbold sc->et.et_quality = 1000; 205247463Smav sc->et.et_min_period = (0x00000005LLU << 32) / sc->et.et_frequency; 206247463Smav sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; 207245450Sganbold sc->et.et_start = a10_timer_timer_start; 208245450Sganbold sc->et.et_stop = a10_timer_timer_stop; 209245450Sganbold sc->et.et_priv = sc; 210245450Sganbold et_register(&sc->et); 211245450Sganbold 212245450Sganbold if (device_get_unit(dev) == 0) 213245450Sganbold a10_timer_sc = sc; 214245450Sganbold 215245876Sganbold a10_timer_timecounter.tc_frequency = sc->timer0_freq; 216245450Sganbold tc_init(&a10_timer_timecounter); 217245450Sganbold 218245876Sganbold if (bootverbose) { 219245876Sganbold device_printf(sc->sc_dev, "clock: hz=%d stathz = %d\n", hz, stathz); 220245450Sganbold 221245876Sganbold device_printf(sc->sc_dev, "event timer clock frequency %u\n", 222245876Sganbold sc->timer0_freq); 223245876Sganbold device_printf(sc->sc_dev, "timecounter clock frequency %lld\n", 224245876Sganbold a10_timer_timecounter.tc_frequency); 225245876Sganbold } 226245450Sganbold 227245450Sganbold a10_timer_initialized = 1; 228245876Sganbold 229245450Sganbold return (0); 230245450Sganbold} 231245450Sganbold 232245450Sganboldstatic int 233247463Smava10_timer_timer_start(struct eventtimer *et, sbintime_t first, 234247463Smav sbintime_t period) 235245450Sganbold{ 236245450Sganbold struct a10_timer_softc *sc; 237245876Sganbold uint32_t count; 238245876Sganbold uint32_t val; 239245450Sganbold 240245450Sganbold sc = (struct a10_timer_softc *)et->et_priv; 241245450Sganbold 242247463Smav if (period != 0) 243247463Smav sc->sc_period = ((uint32_t)et->et_frequency * period) >> 32; 244247463Smav else 245247463Smav sc->sc_period = 0; 246247463Smav if (first != 0) 247247463Smav count = ((uint32_t)et->et_frequency * first) >> 32; 248247463Smav else 249245876Sganbold count = sc->sc_period; 250245450Sganbold 251245876Sganbold /* Update timer values */ 252245876Sganbold timer_write_4(sc, SW_TIMER0_INT_VALUE_REG, sc->sc_period); 253245876Sganbold timer_write_4(sc, SW_TIMER0_CUR_VALUE_REG, count); 254245450Sganbold 255245876Sganbold val = timer_read_4(sc, SW_TIMER0_CTRL_REG); 256247463Smav if (period != 0) { 257245876Sganbold /* periodic */ 258245876Sganbold val |= TIMER_AUTORELOAD; 259245876Sganbold } else { 260245876Sganbold /* oneshot */ 261245876Sganbold val &= ~TIMER_AUTORELOAD; 262245450Sganbold } 263245876Sganbold /* Enable timer0 */ 264245876Sganbold val |= TIMER_ENABLE; 265245876Sganbold timer_write_4(sc, SW_TIMER0_CTRL_REG, val); 266245450Sganbold 267245876Sganbold return (0); 268245450Sganbold} 269245450Sganbold 270245450Sganboldstatic int 271245450Sganbolda10_timer_timer_stop(struct eventtimer *et) 272245450Sganbold{ 273245450Sganbold struct a10_timer_softc *sc; 274245450Sganbold uint32_t val; 275245450Sganbold 276245450Sganbold sc = (struct a10_timer_softc *)et->et_priv; 277245450Sganbold 278245876Sganbold /* Disable timer0 */ 279245450Sganbold val = timer_read_4(sc, SW_TIMER0_CTRL_REG); 280245876Sganbold val &= ~TIMER_ENABLE; 281245450Sganbold timer_write_4(sc, SW_TIMER0_CTRL_REG, val); 282245450Sganbold 283245450Sganbold sc->sc_period = 0; 284245450Sganbold 285245450Sganbold return (0); 286245450Sganbold} 287245450Sganbold 288245450Sganboldint 289245450Sganbolda10_timer_get_timerfreq(struct a10_timer_softc *sc) 290245450Sganbold{ 291245876Sganbold return (sc->timer0_freq); 292245450Sganbold} 293245450Sganbold 294245450Sganboldstatic int 295245876Sganbolda10_timer_hardclock(void *arg) 296245450Sganbold{ 297245450Sganbold struct a10_timer_softc *sc; 298245876Sganbold uint32_t val; 299245450Sganbold 300245450Sganbold sc = (struct a10_timer_softc *)arg; 301245450Sganbold 302245876Sganbold /* Clear interrupt pending bit. */ 303245876Sganbold timer_write_4(sc, SW_TIMER_IRQ_STA_REG, 0x1); 304245876Sganbold 305245876Sganbold val = timer_read_4(sc, SW_TIMER0_CTRL_REG); 306245876Sganbold /* 307245876Sganbold * Disabled autoreload and sc_period > 0 means 308245876Sganbold * timer_start was called with non NULL first value. 309245876Sganbold * Now we will set periodic timer with the given period 310245876Sganbold * value. 311245876Sganbold */ 312245876Sganbold if ((val & (1<<1)) == 0 && sc->sc_period > 0) { 313245876Sganbold /* Update timer */ 314245876Sganbold timer_write_4(sc, SW_TIMER0_CUR_VALUE_REG, sc->sc_period); 315245876Sganbold 316245876Sganbold /* Make periodic and enable */ 317245876Sganbold val |= TIMER_AUTORELOAD | TIMER_ENABLE; 318245876Sganbold timer_write_4(sc, SW_TIMER0_CTRL_REG, val); 319245876Sganbold } 320245876Sganbold 321245450Sganbold if (sc->et.et_active) 322245450Sganbold sc->et.et_event_cb(&sc->et, sc->et.et_arg); 323245450Sganbold 324245450Sganbold return (FILTER_HANDLED); 325245450Sganbold} 326245450Sganbold 327245450Sganboldu_int 328245450Sganbolda10_timer_get_timecount(struct timecounter *tc) 329245450Sganbold{ 330245450Sganbold 331245450Sganbold if (a10_timer_sc == NULL) 332245450Sganbold return (0); 333245450Sganbold 334245876Sganbold return ((u_int)timer_read_counter64()); 335245450Sganbold} 336245450Sganbold 337245450Sganboldstatic device_method_t a10_timer_methods[] = { 338245450Sganbold DEVMETHOD(device_probe, a10_timer_probe), 339245450Sganbold DEVMETHOD(device_attach, a10_timer_attach), 340245450Sganbold 341245450Sganbold DEVMETHOD_END 342245450Sganbold}; 343245450Sganbold 344245450Sganboldstatic driver_t a10_timer_driver = { 345245450Sganbold "a10_timer", 346245450Sganbold a10_timer_methods, 347245450Sganbold sizeof(struct a10_timer_softc), 348245450Sganbold}; 349245450Sganbold 350245450Sganboldstatic devclass_t a10_timer_devclass; 351245450Sganbold 352295464SandrewEARLY_DRIVER_MODULE(a10_timer, simplebus, a10_timer_driver, a10_timer_devclass, 0, 0, 353295464Sandrew BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); 354245450Sganbold 355245450Sganboldvoid 356245450SganboldDELAY(int usec) 357245450Sganbold{ 358245450Sganbold uint32_t counter; 359245876Sganbold uint64_t end, now; 360245450Sganbold 361245450Sganbold if (!a10_timer_initialized) { 362245450Sganbold for (; usec > 0; usec--) 363245876Sganbold for (counter = 50; counter > 0; counter--) 364245450Sganbold cpufunc_nullop(); 365245450Sganbold return; 366245450Sganbold } 367245450Sganbold 368245876Sganbold now = timer_read_counter64(); 369245876Sganbold end = now + (a10_timer_sc->timer0_freq / 1000000) * (usec + 1); 370245450Sganbold 371245876Sganbold while (now < end) 372245876Sganbold now = timer_read_counter64(); 373245450Sganbold} 374245450Sganbold 375