timer.c revision 245453
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 17245450Sganbold * 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 245453 2013-01-15 09:31:13Z 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 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 65245450Sganbold#define SYS_TIMER_SCAL 16 /* timer clock source pre-divsion */ 66245450Sganbold#define SYS_TIMER_CLKSRC 24000000 /* timer clock source */ 67245450Sganbold#define TMR_INTER_VAL SYS_TIMER_CLKSRC/(SYS_TIMER_SCAL * 1000) 68245450Sganbold 69245450Sganbold#define CLOCK_TICK_RATE TMR_INTER_VAL 70245450Sganbold#define INITIAL_TIMECOUNTER (0xffffffff) 71245450Sganbold 72245450Sganboldstruct a10_timer_softc { 73245450Sganbold device_t sc_dev; 74245450Sganbold struct resource *res[2]; 75245450Sganbold bus_space_tag_t sc_bst; 76245450Sganbold bus_space_handle_t sc_bsh; 77245450Sganbold void *sc_ih; /* interrupt handler */ 78245450Sganbold uint32_t sc_period; 79245450Sganbold uint32_t clkfreq; 80245450Sganbold struct eventtimer et; 81245450Sganbold}; 82245450Sganbold 83245450Sganboldint a10_timer_get_timerfreq(struct a10_timer_softc *); 84245450Sganbold 85245450Sganbold#define timer_read_4(sc, reg) \ 86245450Sganbold bus_space_read_4(sc->sc_bst, sc->sc_bsh, reg) 87245450Sganbold#define timer_write_4(sc, reg, val) \ 88245450Sganbold bus_space_write_4(sc->sc_bst, sc->sc_bsh, reg, val) 89245450Sganbold 90245450Sganboldstatic u_int a10_timer_get_timecount(struct timecounter *); 91245450Sganboldstatic int a10_timer_timer_start(struct eventtimer *, 92245450Sganbold struct bintime *, struct bintime *); 93245450Sganboldstatic int a10_timer_timer_stop(struct eventtimer *); 94245450Sganbold 95245450Sganboldstatic int a10_timer_initialized = 0; 96245450Sganboldstatic int a10_timer_intr(void *); 97245450Sganboldstatic int a10_timer_probe(device_t); 98245450Sganboldstatic int a10_timer_attach(device_t); 99245450Sganbold 100245450Sganboldstatic struct timecounter a10_timer_timecounter = { 101245450Sganbold .tc_name = "a10_timer timer0", 102245450Sganbold .tc_get_timecount = a10_timer_get_timecount, 103245450Sganbold .tc_counter_mask = ~0u, 104245450Sganbold .tc_frequency = 0, 105245450Sganbold .tc_quality = 1000, 106245450Sganbold}; 107245450Sganbold 108245450Sganboldstruct a10_timer_softc *a10_timer_sc = NULL; 109245450Sganbold 110245450Sganboldstatic struct resource_spec a10_timer_spec[] = { 111245450Sganbold { SYS_RES_MEMORY, 0, RF_ACTIVE }, 112245450Sganbold { SYS_RES_IRQ, 0, RF_ACTIVE }, 113245450Sganbold { -1, 0 } 114245450Sganbold}; 115245450Sganbold 116245450Sganboldstatic int 117245450Sganbolda10_timer_probe(device_t dev) 118245450Sganbold{ 119245450Sganbold 120245450Sganbold if (!ofw_bus_is_compatible(dev, "a10,timers")) 121245450Sganbold return (ENXIO); 122245450Sganbold 123245450Sganbold device_set_desc(dev, "Allwinner A10 timer"); 124245450Sganbold return (BUS_PROBE_DEFAULT); 125245450Sganbold} 126245450Sganbold 127245450Sganboldstatic int 128245450Sganbolda10_timer_attach(device_t dev) 129245450Sganbold{ 130245450Sganbold struct a10_timer_softc *sc; 131245450Sganbold int err; 132245450Sganbold uint32_t val; 133245450Sganbold uint32_t freq; 134245450Sganbold 135245450Sganbold sc = device_get_softc(dev); 136245450Sganbold 137245450Sganbold if (bus_alloc_resources(dev, a10_timer_spec, sc->res)) { 138245450Sganbold device_printf(dev, "could not allocate resources\n"); 139245450Sganbold return (ENXIO); 140245450Sganbold } 141245450Sganbold 142245450Sganbold sc->sc_dev = dev; 143245450Sganbold sc->sc_bst = rman_get_bustag(sc->res[0]); 144245450Sganbold sc->sc_bsh = rman_get_bushandle(sc->res[0]); 145245450Sganbold 146245450Sganbold /* set interval */ 147245450Sganbold timer_write_4(sc, SW_TIMER0_INT_VALUE_REG, TMR_INTER_VAL); 148245450Sganbold 149245450Sganbold /* set clock source to HOSC, 16 pre-division */ 150245450Sganbold val = timer_read_4(sc, SW_TIMER0_CTRL_REG); 151245450Sganbold val &= ~(0x07<<4); 152245450Sganbold val &= ~(0x03<<2); 153245450Sganbold val |= (4<<4) | (1<<2); 154245450Sganbold timer_write_4(sc, SW_TIMER0_CTRL_REG, val); 155245450Sganbold 156245450Sganbold /* set mode to auto reload */ 157245450Sganbold val = timer_read_4(sc, SW_TIMER0_CTRL_REG); 158245450Sganbold val |= (1<<1); 159245450Sganbold timer_write_4(sc, SW_TIMER0_CTRL_REG, val); 160245450Sganbold 161245450Sganbold /* Enable timer0 */ 162245450Sganbold val = timer_read_4(sc, SW_TIMER_IRQ_EN_REG); 163245450Sganbold val |= (1<<0); 164245450Sganbold timer_write_4(sc, SW_TIMER_IRQ_EN_REG, val); 165245450Sganbold 166245450Sganbold /* Setup and enable the timer interrupt */ 167245450Sganbold err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_CLK, a10_timer_intr, 168245450Sganbold NULL, sc, &sc->sc_ih); 169245450Sganbold if (err != 0) { 170245450Sganbold bus_release_resources(dev, a10_timer_spec, sc->res); 171245450Sganbold device_printf(dev, "Unable to setup the clock irq handler, " 172245450Sganbold "err = %d\n", err); 173245450Sganbold return (ENXIO); 174245450Sganbold } 175245450Sganbold freq = SYS_TIMER_CLKSRC; 176245450Sganbold 177245450Sganbold /* Set desired frequency in event timer and timecounter */ 178245450Sganbold sc->et.et_frequency = (uint64_t)freq; 179245450Sganbold sc->clkfreq = (uint64_t)freq; 180245450Sganbold sc->et.et_name = "a10_timer Eventtimer"; 181245450Sganbold sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC; 182245450Sganbold sc->et.et_quality = 1000; 183245450Sganbold sc->et.et_min_period.sec = 0; 184245450Sganbold sc->et.et_min_period.frac = 185245450Sganbold ((0x00000002LLU << 32) / sc->et.et_frequency) << 32; 186245450Sganbold sc->et.et_max_period.sec = 0xfffffff0U / sc->et.et_frequency; 187245450Sganbold sc->et.et_max_period.frac = 188245450Sganbold ((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32; 189245450Sganbold sc->et.et_start = a10_timer_timer_start; 190245450Sganbold sc->et.et_stop = a10_timer_timer_stop; 191245450Sganbold sc->et.et_priv = sc; 192245450Sganbold et_register(&sc->et); 193245450Sganbold 194245450Sganbold if (device_get_unit(dev) == 0) 195245450Sganbold a10_timer_sc = sc; 196245450Sganbold 197245450Sganbold a10_timer_timecounter.tc_frequency = (uint64_t)freq; 198245450Sganbold tc_init(&a10_timer_timecounter); 199245450Sganbold 200245450Sganbold printf("clock: hz=%d stathz = %d\n", hz, stathz); 201245450Sganbold 202245450Sganbold device_printf(sc->sc_dev, "timer clock frequency %d\n", sc->clkfreq); 203245450Sganbold 204245450Sganbold a10_timer_initialized = 1; 205245450Sganbold 206245450Sganbold return (0); 207245450Sganbold} 208245450Sganbold 209245450Sganboldstatic int 210245450Sganbolda10_timer_timer_start(struct eventtimer *et, struct bintime *first, 211245450Sganbold struct bintime *period) 212245450Sganbold{ 213245450Sganbold struct a10_timer_softc *sc; 214245450Sganbold uint32_t clo, count; 215245450Sganbold 216245450Sganbold sc = (struct a10_timer_softc *)et->et_priv; 217245450Sganbold 218245450Sganbold if (first != NULL) { 219245450Sganbold count = (sc->et.et_frequency * (first->frac >> 32)) >> 32; 220245450Sganbold if (first->sec != 0) 221245450Sganbold count += sc->et.et_frequency * first->sec; 222245450Sganbold 223245450Sganbold /* clear */ 224245450Sganbold timer_write_4(sc, SW_TIMER0_CUR_VALUE_REG, 0); 225245450Sganbold clo = timer_read_4(sc, SW_TIMER0_CUR_VALUE_REG); 226245450Sganbold clo += count; 227245450Sganbold timer_write_4(sc, SW_TIMER0_CUR_VALUE_REG, clo); 228245450Sganbold 229245450Sganbold return (0); 230245450Sganbold } 231245450Sganbold 232245450Sganbold return (EINVAL); 233245450Sganbold} 234245450Sganbold 235245450Sganboldstatic int 236245450Sganbolda10_timer_timer_stop(struct eventtimer *et) 237245450Sganbold{ 238245450Sganbold struct a10_timer_softc *sc; 239245450Sganbold uint32_t val; 240245450Sganbold 241245450Sganbold sc = (struct a10_timer_softc *)et->et_priv; 242245450Sganbold 243245450Sganbold /* clear */ 244245450Sganbold timer_write_4(sc, SW_TIMER0_CUR_VALUE_REG, 0); 245245450Sganbold 246245450Sganbold /* disable */ 247245450Sganbold val = timer_read_4(sc, SW_TIMER0_CTRL_REG); 248245450Sganbold val &= ~(1<<0); /* Disable timer0 */ 249245450Sganbold timer_write_4(sc, SW_TIMER0_CTRL_REG, val); 250245450Sganbold 251245450Sganbold sc->sc_period = 0; 252245450Sganbold 253245450Sganbold return (0); 254245450Sganbold} 255245450Sganbold 256245450Sganboldint 257245450Sganbolda10_timer_get_timerfreq(struct a10_timer_softc *sc) 258245450Sganbold{ 259245450Sganbold 260245450Sganbold return (sc->clkfreq); 261245450Sganbold} 262245450Sganbold 263245450Sganboldvoid 264245450Sganboldcpu_initclocks(void) 265245450Sganbold{ 266245450Sganbold cpu_initclocks_bsp(); 267245450Sganbold} 268245450Sganbold 269245450Sganboldstatic int 270245450Sganbolda10_timer_intr(void *arg) 271245450Sganbold{ 272245450Sganbold struct a10_timer_softc *sc; 273245450Sganbold 274245450Sganbold sc = (struct a10_timer_softc *)arg; 275245450Sganbold 276245450Sganbold if (sc->et.et_active) 277245450Sganbold sc->et.et_event_cb(&sc->et, sc->et.et_arg); 278245450Sganbold 279245450Sganbold /* pending */ 280245450Sganbold timer_write_4(sc, SW_TIMER_IRQ_STA_REG, 0x1); 281245450Sganbold 282245450Sganbold return (FILTER_HANDLED); 283245450Sganbold} 284245450Sganbold 285245450Sganboldu_int 286245450Sganbolda10_timer_get_timecount(struct timecounter *tc) 287245450Sganbold{ 288245450Sganbold 289245450Sganbold if (a10_timer_sc == NULL) 290245450Sganbold return (0); 291245450Sganbold 292245450Sganbold return (timer_read_4(a10_timer_sc, SW_TIMER0_CUR_VALUE_REG)); 293245450Sganbold} 294245450Sganbold 295245450Sganboldstatic device_method_t a10_timer_methods[] = { 296245450Sganbold DEVMETHOD(device_probe, a10_timer_probe), 297245450Sganbold DEVMETHOD(device_attach, a10_timer_attach), 298245450Sganbold 299245450Sganbold DEVMETHOD_END 300245450Sganbold}; 301245450Sganbold 302245450Sganboldstatic driver_t a10_timer_driver = { 303245450Sganbold "a10_timer", 304245450Sganbold a10_timer_methods, 305245450Sganbold sizeof(struct a10_timer_softc), 306245450Sganbold}; 307245450Sganbold 308245450Sganboldstatic devclass_t a10_timer_devclass; 309245450Sganbold 310245450SganboldDRIVER_MODULE(a10_timer, simplebus, a10_timer_driver, a10_timer_devclass, 0, 0); 311245450Sganbold 312245450Sganboldvoid 313245450SganboldDELAY(int usec) 314245450Sganbold{ 315245450Sganbold uint32_t counter; 316245450Sganbold uint32_t val, val_temp; 317245450Sganbold int32_t nticks; 318245450Sganbold 319245450Sganbold /* Timer is not initialized yet */ 320245450Sganbold if (!a10_timer_initialized) { 321245450Sganbold for (; usec > 0; usec--) 322245450Sganbold for (counter = 200; counter > 0; counter--) 323245450Sganbold /* Prevent optimizing out the loop */ 324245450Sganbold cpufunc_nullop(); 325245450Sganbold return; 326245450Sganbold } 327245450Sganbold 328245450Sganbold val = timer_read_4(a10_timer_sc, SW_TIMER0_CUR_VALUE_REG); 329245450Sganbold nticks = ((a10_timer_sc->clkfreq / 1000000 + 1) * usec); 330245450Sganbold 331245450Sganbold while (nticks > 0) { 332245450Sganbold val_temp = timer_read_4(a10_timer_sc, SW_TIMER0_CUR_VALUE_REG); 333245450Sganbold if (val > val_temp) 334245450Sganbold nticks -= (val - val_temp); 335245450Sganbold else 336245450Sganbold nticks -= (val + (INITIAL_TIMECOUNTER - val_temp)); 337245450Sganbold 338245450Sganbold val = val_temp; 339245450Sganbold } 340245450Sganbold} 341245450Sganbold 342