timer.c revision 254056
1245450Sganbold/*- 2245450Sganbold * Copyright (c) 2012 Ganbold Tsagaankhuu <ganbold@gmail.com> 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 254056 2013-08-07 11:07:56Z ganbold $"); 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/frame.h> 43245450Sganbold#include <machine/intr.h> 44245450Sganbold 45245450Sganbold#include <dev/fdt/fdt_common.h> 46245450Sganbold#include <dev/ofw/openfirm.h> 47245450Sganbold#include <dev/ofw/ofw_bus.h> 48245450Sganbold#include <dev/ofw/ofw_bus_subr.h> 49245450Sganbold 50245450Sganbold#include <machine/bus.h> 51245450Sganbold#include <machine/fdt.h> 52245450Sganbold 53245450Sganbold#include <sys/kdb.h> 54245450Sganbold 55254056Sganbold#include "a20/a20_cpu_cfg.h" 56254056Sganbold 57245450Sganbold/** 58245450Sganbold * Timer registers addr 59245450Sganbold * 60245450Sganbold */ 61245450Sganbold#define SW_TIMER_IRQ_EN_REG 0x00 62245450Sganbold#define SW_TIMER_IRQ_STA_REG 0x04 63245450Sganbold#define SW_TIMER0_CTRL_REG 0x10 64245450Sganbold#define SW_TIMER0_INT_VALUE_REG 0x14 65245450Sganbold#define SW_TIMER0_CUR_VALUE_REG 0x18 66245450Sganbold 67245876Sganbold#define SW_COUNTER64LO_REG 0xa4 68245876Sganbold#define SW_COUNTER64HI_REG 0xa8 69245876Sganbold#define CNT64_CTRL_REG 0xa0 70245450Sganbold 71245876Sganbold#define CNT64_RL_EN 0x02 /* read latch enable */ 72245450Sganbold 73245876Sganbold#define TIMER_ENABLE (1<<0) 74245876Sganbold#define TIMER_AUTORELOAD (1<<1) 75245876Sganbold#define TIMER_OSC24M (1<<2) /* oscillator = 24mhz */ 76245876Sganbold#define TIMER_PRESCALAR (4<<4) /* prescalar = 16 */ 77245876Sganbold 78245876Sganbold#define SYS_TIMER_CLKSRC 24000000 /* clock source */ 79245876Sganbold 80245450Sganboldstruct a10_timer_softc { 81245450Sganbold device_t sc_dev; 82245450Sganbold struct resource *res[2]; 83245450Sganbold bus_space_tag_t sc_bst; 84245450Sganbold bus_space_handle_t sc_bsh; 85245450Sganbold void *sc_ih; /* interrupt handler */ 86245450Sganbold uint32_t sc_period; 87245876Sganbold uint32_t timer0_freq; 88245450Sganbold struct eventtimer et; 89254056Sganbold uint8_t sc_timer_type; /* 0 for A10, 1 for A20 */ 90245450Sganbold}; 91245450Sganbold 92245450Sganboldint a10_timer_get_timerfreq(struct a10_timer_softc *); 93245450Sganbold 94245450Sganbold#define timer_read_4(sc, reg) \ 95245450Sganbold bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg) 96245450Sganbold#define timer_write_4(sc, reg, val) \ 97245450Sganbold bus_space_write_4(sc->sc_bst, sc->sc_bsh, reg, val) 98245450Sganbold 99245450Sganboldstatic u_int a10_timer_get_timecount(struct timecounter *); 100245450Sganboldstatic int a10_timer_timer_start(struct eventtimer *, 101247463Smav sbintime_t first, sbintime_t period); 102245450Sganboldstatic int a10_timer_timer_stop(struct eventtimer *); 103245450Sganbold 104245876Sganboldstatic uint64_t timer_read_counter64(void); 105245876Sganbold 106245450Sganboldstatic int a10_timer_initialized = 0; 107245876Sganboldstatic int a10_timer_hardclock(void *); 108245450Sganboldstatic int a10_timer_probe(device_t); 109245450Sganboldstatic int a10_timer_attach(device_t); 110245450Sganbold 111245450Sganboldstatic struct timecounter a10_timer_timecounter = { 112245450Sganbold .tc_name = "a10_timer timer0", 113245450Sganbold .tc_get_timecount = a10_timer_get_timecount, 114245450Sganbold .tc_counter_mask = ~0u, 115245450Sganbold .tc_frequency = 0, 116245450Sganbold .tc_quality = 1000, 117245450Sganbold}; 118245450Sganbold 119245450Sganboldstruct a10_timer_softc *a10_timer_sc = NULL; 120245450Sganbold 121245450Sganboldstatic struct resource_spec a10_timer_spec[] = { 122245450Sganbold { SYS_RES_MEMORY, 0, RF_ACTIVE }, 123245450Sganbold { SYS_RES_IRQ, 0, RF_ACTIVE }, 124245450Sganbold { -1, 0 } 125245450Sganbold}; 126245450Sganbold 127245876Sganboldstatic uint64_t 128245876Sganboldtimer_read_counter64(void) 129245876Sganbold{ 130245876Sganbold uint32_t lo, hi; 131245876Sganbold 132254056Sganbold /* In case of A20 get appropriate counter info */ 133254056Sganbold if (a10_timer_sc->sc_timer_type) 134254056Sganbold return (a20_read_counter64()); 135254056Sganbold 136245876Sganbold /* Latch counter, wait for it to be ready to read. */ 137245876Sganbold timer_write_4(a10_timer_sc, CNT64_CTRL_REG, CNT64_RL_EN); 138245876Sganbold while (timer_read_4(a10_timer_sc, CNT64_CTRL_REG) & CNT64_RL_EN) 139245876Sganbold continue; 140245876Sganbold 141245876Sganbold hi = timer_read_4(a10_timer_sc, SW_COUNTER64HI_REG); 142245876Sganbold lo = timer_read_4(a10_timer_sc, SW_COUNTER64LO_REG); 143245876Sganbold 144245876Sganbold return (((uint64_t)hi << 32) | lo); 145245876Sganbold} 146245876Sganbold 147245450Sganboldstatic int 148245450Sganbolda10_timer_probe(device_t dev) 149245450Sganbold{ 150254056Sganbold struct a10_timer_softc *sc; 151245450Sganbold 152254056Sganbold sc = device_get_softc(dev); 153254056Sganbold 154254056Sganbold if (ofw_bus_is_compatible(dev, "allwinner,sun4i-timer")) 155254056Sganbold sc->sc_timer_type = 0; 156254056Sganbold else if (ofw_bus_is_compatible(dev, "allwinner,sun7i-timer")) 157254056Sganbold sc->sc_timer_type = 1; 158254056Sganbold else 159245450Sganbold return (ENXIO); 160245450Sganbold 161254056Sganbold device_set_desc(dev, "Allwinner A10/A20 timer"); 162245450Sganbold return (BUS_PROBE_DEFAULT); 163245450Sganbold} 164245450Sganbold 165245450Sganboldstatic int 166245450Sganbolda10_timer_attach(device_t dev) 167245450Sganbold{ 168245450Sganbold struct a10_timer_softc *sc; 169245450Sganbold int err; 170245450Sganbold uint32_t val; 171245450Sganbold 172245450Sganbold sc = device_get_softc(dev); 173245450Sganbold 174245450Sganbold if (bus_alloc_resources(dev, a10_timer_spec, sc->res)) { 175245450Sganbold device_printf(dev, "could not allocate resources\n"); 176245450Sganbold return (ENXIO); 177245450Sganbold } 178245450Sganbold 179245450Sganbold sc->sc_dev = dev; 180245450Sganbold sc->sc_bst = rman_get_bustag(sc->res[0]); 181245450Sganbold sc->sc_bsh = rman_get_bushandle(sc->res[0]); 182245450Sganbold 183245450Sganbold /* Setup and enable the timer interrupt */ 184245876Sganbold err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_CLK, a10_timer_hardclock, 185245450Sganbold NULL, sc, &sc->sc_ih); 186245450Sganbold if (err != 0) { 187245450Sganbold bus_release_resources(dev, a10_timer_spec, sc->res); 188245450Sganbold device_printf(dev, "Unable to setup the clock irq handler, " 189245450Sganbold "err = %d\n", err); 190245450Sganbold return (ENXIO); 191245450Sganbold } 192245450Sganbold 193245876Sganbold /* Set clock source to OSC24M, 16 pre-division */ 194245876Sganbold val = timer_read_4(sc, SW_TIMER0_CTRL_REG); 195245876Sganbold val |= TIMER_PRESCALAR | TIMER_OSC24M; 196245876Sganbold timer_write_4(sc, SW_TIMER0_CTRL_REG, val); 197245876Sganbold 198245876Sganbold /* Enable timer0 */ 199245876Sganbold val = timer_read_4(sc, SW_TIMER_IRQ_EN_REG); 200245876Sganbold val |= TIMER_ENABLE; 201245876Sganbold timer_write_4(sc, SW_TIMER_IRQ_EN_REG, val); 202245876Sganbold 203245876Sganbold sc->timer0_freq = SYS_TIMER_CLKSRC; 204245876Sganbold 205245876Sganbold /* Set desired frequency in event timer and timecounter */ 206245876Sganbold sc->et.et_frequency = sc->timer0_freq; 207245450Sganbold sc->et.et_name = "a10_timer Eventtimer"; 208245450Sganbold sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC; 209245450Sganbold sc->et.et_quality = 1000; 210247463Smav sc->et.et_min_period = (0x00000005LLU << 32) / sc->et.et_frequency; 211247463Smav sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; 212245450Sganbold sc->et.et_start = a10_timer_timer_start; 213245450Sganbold sc->et.et_stop = a10_timer_timer_stop; 214245450Sganbold sc->et.et_priv = sc; 215245450Sganbold et_register(&sc->et); 216245450Sganbold 217245450Sganbold if (device_get_unit(dev) == 0) 218245450Sganbold a10_timer_sc = sc; 219245450Sganbold 220245876Sganbold a10_timer_timecounter.tc_frequency = sc->timer0_freq; 221245450Sganbold tc_init(&a10_timer_timecounter); 222245450Sganbold 223245876Sganbold if (bootverbose) { 224245876Sganbold device_printf(sc->sc_dev, "clock: hz=%d stathz = %d\n", hz, stathz); 225245450Sganbold 226245876Sganbold device_printf(sc->sc_dev, "event timer clock frequency %u\n", 227245876Sganbold sc->timer0_freq); 228245876Sganbold device_printf(sc->sc_dev, "timecounter clock frequency %lld\n", 229245876Sganbold a10_timer_timecounter.tc_frequency); 230245876Sganbold } 231245450Sganbold 232245450Sganbold a10_timer_initialized = 1; 233245876Sganbold 234245450Sganbold return (0); 235245450Sganbold} 236245450Sganbold 237245450Sganboldstatic int 238247463Smava10_timer_timer_start(struct eventtimer *et, sbintime_t first, 239247463Smav sbintime_t period) 240245450Sganbold{ 241245450Sganbold struct a10_timer_softc *sc; 242245876Sganbold uint32_t count; 243245876Sganbold uint32_t val; 244245450Sganbold 245245450Sganbold sc = (struct a10_timer_softc *)et->et_priv; 246245450Sganbold 247247463Smav if (period != 0) 248247463Smav sc->sc_period = ((uint32_t)et->et_frequency * period) >> 32; 249247463Smav else 250247463Smav sc->sc_period = 0; 251247463Smav if (first != 0) 252247463Smav count = ((uint32_t)et->et_frequency * first) >> 32; 253247463Smav else 254245876Sganbold count = sc->sc_period; 255245450Sganbold 256245876Sganbold /* Update timer values */ 257245876Sganbold timer_write_4(sc, SW_TIMER0_INT_VALUE_REG, sc->sc_period); 258245876Sganbold timer_write_4(sc, SW_TIMER0_CUR_VALUE_REG, count); 259245450Sganbold 260245876Sganbold val = timer_read_4(sc, SW_TIMER0_CTRL_REG); 261247463Smav if (period != 0) { 262245876Sganbold /* periodic */ 263245876Sganbold val |= TIMER_AUTORELOAD; 264245876Sganbold } else { 265245876Sganbold /* oneshot */ 266245876Sganbold val &= ~TIMER_AUTORELOAD; 267245450Sganbold } 268245876Sganbold /* Enable timer0 */ 269245876Sganbold val |= TIMER_ENABLE; 270245876Sganbold timer_write_4(sc, SW_TIMER0_CTRL_REG, val); 271245450Sganbold 272245876Sganbold return (0); 273245450Sganbold} 274245450Sganbold 275245450Sganboldstatic int 276245450Sganbolda10_timer_timer_stop(struct eventtimer *et) 277245450Sganbold{ 278245450Sganbold struct a10_timer_softc *sc; 279245450Sganbold uint32_t val; 280245450Sganbold 281245450Sganbold sc = (struct a10_timer_softc *)et->et_priv; 282245450Sganbold 283245876Sganbold /* Disable timer0 */ 284245450Sganbold val = timer_read_4(sc, SW_TIMER0_CTRL_REG); 285245876Sganbold val &= ~TIMER_ENABLE; 286245450Sganbold timer_write_4(sc, SW_TIMER0_CTRL_REG, val); 287245450Sganbold 288245450Sganbold sc->sc_period = 0; 289245450Sganbold 290245450Sganbold return (0); 291245450Sganbold} 292245450Sganbold 293245450Sganboldint 294245450Sganbolda10_timer_get_timerfreq(struct a10_timer_softc *sc) 295245450Sganbold{ 296245876Sganbold return (sc->timer0_freq); 297245450Sganbold} 298245450Sganbold 299245450Sganboldvoid 300245450Sganboldcpu_initclocks(void) 301245450Sganbold{ 302245450Sganbold cpu_initclocks_bsp(); 303245450Sganbold} 304245450Sganbold 305245450Sganboldstatic int 306245876Sganbolda10_timer_hardclock(void *arg) 307245450Sganbold{ 308245450Sganbold struct a10_timer_softc *sc; 309245876Sganbold uint32_t val; 310245450Sganbold 311245450Sganbold sc = (struct a10_timer_softc *)arg; 312245450Sganbold 313245876Sganbold /* Clear interrupt pending bit. */ 314245876Sganbold timer_write_4(sc, SW_TIMER_IRQ_STA_REG, 0x1); 315245876Sganbold 316245876Sganbold val = timer_read_4(sc, SW_TIMER0_CTRL_REG); 317245876Sganbold /* 318245876Sganbold * Disabled autoreload and sc_period > 0 means 319245876Sganbold * timer_start was called with non NULL first value. 320245876Sganbold * Now we will set periodic timer with the given period 321245876Sganbold * value. 322245876Sganbold */ 323245876Sganbold if ((val & (1<<1)) == 0 && sc->sc_period > 0) { 324245876Sganbold /* Update timer */ 325245876Sganbold timer_write_4(sc, SW_TIMER0_CUR_VALUE_REG, sc->sc_period); 326245876Sganbold 327245876Sganbold /* Make periodic and enable */ 328245876Sganbold val |= TIMER_AUTORELOAD | TIMER_ENABLE; 329245876Sganbold timer_write_4(sc, SW_TIMER0_CTRL_REG, val); 330245876Sganbold } 331245876Sganbold 332245450Sganbold if (sc->et.et_active) 333245450Sganbold sc->et.et_event_cb(&sc->et, sc->et.et_arg); 334245450Sganbold 335245450Sganbold return (FILTER_HANDLED); 336245450Sganbold} 337245450Sganbold 338245450Sganboldu_int 339245450Sganbolda10_timer_get_timecount(struct timecounter *tc) 340245450Sganbold{ 341245450Sganbold 342245450Sganbold if (a10_timer_sc == NULL) 343245450Sganbold return (0); 344245450Sganbold 345245876Sganbold return ((u_int)timer_read_counter64()); 346245450Sganbold} 347245450Sganbold 348245450Sganboldstatic device_method_t a10_timer_methods[] = { 349245450Sganbold DEVMETHOD(device_probe, a10_timer_probe), 350245450Sganbold DEVMETHOD(device_attach, a10_timer_attach), 351245450Sganbold 352245450Sganbold DEVMETHOD_END 353245450Sganbold}; 354245450Sganbold 355245450Sganboldstatic driver_t a10_timer_driver = { 356245450Sganbold "a10_timer", 357245450Sganbold a10_timer_methods, 358245450Sganbold sizeof(struct a10_timer_softc), 359245450Sganbold}; 360245450Sganbold 361245450Sganboldstatic devclass_t a10_timer_devclass; 362245450Sganbold 363245450SganboldDRIVER_MODULE(a10_timer, simplebus, a10_timer_driver, a10_timer_devclass, 0, 0); 364245450Sganbold 365245450Sganboldvoid 366245450SganboldDELAY(int usec) 367245450Sganbold{ 368245450Sganbold uint32_t counter; 369245876Sganbold uint64_t end, now; 370245450Sganbold 371245450Sganbold if (!a10_timer_initialized) { 372245450Sganbold for (; usec > 0; usec--) 373245876Sganbold for (counter = 50; counter > 0; counter--) 374245450Sganbold cpufunc_nullop(); 375245450Sganbold return; 376245450Sganbold } 377245450Sganbold 378245876Sganbold now = timer_read_counter64(); 379245876Sganbold end = now + (a10_timer_sc->timer0_freq / 1000000) * (usec + 1); 380245450Sganbold 381245876Sganbold while (now < end) 382245876Sganbold now = timer_read_counter64(); 383245450Sganbold} 384245450Sganbold 385