generic_timer.c revision 269605
1252372Sray/*- 2252372Sray * Copyright (c) 2011 The FreeBSD Foundation 3252372Sray * Copyright (c) 2013 Ruslan Bukin <br@bsdpad.com> 4252372Sray * All rights reserved. 5252372Sray * 6252372Sray * Based on mpcore_timer.c developed by Ben Gray <ben.r.gray@gmail.com> 7252372Sray * 8252372Sray * Redistribution and use in source and binary forms, with or without 9252372Sray * modification, are permitted provided that the following conditions 10252372Sray * are met: 11252372Sray * 1. Redistributions of source code must retain the above copyright 12252372Sray * notice, this list of conditions and the following disclaimer. 13252372Sray * 2. Redistributions in binary form must reproduce the above copyright 14252372Sray * notice, this list of conditions and the following disclaimer in the 15252372Sray * documentation and/or other materials provided with the distribution. 16252372Sray * 3. The name of the company nor the name of the author may be used to 17252372Sray * endorse or promote products derived from this software without specific 18252372Sray * prior written permission. 19252372Sray * 20252372Sray * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21252372Sray * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22252372Sray * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23252372Sray * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24252372Sray * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25252372Sray * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26252372Sray * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27252372Sray * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28252372Sray * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29252372Sray * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30252372Sray * SUCH DAMAGE. 31252372Sray */ 32252372Sray 33252372Sray/** 34252372Sray * Cortex-A15 (and probably A7) Generic Timer 35252372Sray */ 36252372Sray 37252372Sray#include <sys/cdefs.h> 38252372Sray__FBSDID("$FreeBSD: head/sys/arm/arm/generic_timer.c 269605 2014-08-05 18:51:51Z ian $"); 39252372Sray 40252372Sray#include <sys/param.h> 41252372Sray#include <sys/systm.h> 42252372Sray#include <sys/bus.h> 43252372Sray#include <sys/kernel.h> 44252372Sray#include <sys/module.h> 45252372Sray#include <sys/malloc.h> 46252372Sray#include <sys/rman.h> 47252372Sray#include <sys/timeet.h> 48252372Sray#include <sys/timetc.h> 49252372Sray#include <sys/watchdog.h> 50252372Sray#include <machine/bus.h> 51252372Sray#include <machine/cpu.h> 52252372Sray#include <machine/intr.h> 53252372Sray 54252372Sray#include <dev/fdt/fdt_common.h> 55252372Sray#include <dev/ofw/openfirm.h> 56252372Sray#include <dev/ofw/ofw_bus.h> 57252372Sray#include <dev/ofw/ofw_bus_subr.h> 58252372Sray 59252372Sray#include <machine/bus.h> 60252372Sray#include <machine/fdt.h> 61252372Sray 62252780Sray#define GT_CTRL_ENABLE (1 << 0) 63252780Sray#define GT_CTRL_INT_MASK (1 << 1) 64252780Sray#define GT_CTRL_INT_STAT (1 << 2) 65252780Sray#define GT_REG_CTRL 0 66252780Sray#define GT_REG_TVAL 1 67252372Sray 68252780Sray#define GT_CNTKCTL_PL0PTEN (1 << 9) /* PL0 Physical timer reg access */ 69252780Sray#define GT_CNTKCTL_PL0VTEN (1 << 8) /* PL0 Virtual timer reg access */ 70252780Sray#define GT_CNTKCTL_EVNTI (1 << 4) /* Virtual counter event bits */ 71252780Sray#define GT_CNTKCTL_EVNTDIR (1 << 3) /* Virtual counter event transition */ 72252780Sray#define GT_CNTKCTL_EVNTEN (1 << 2) /* Enables virtual counter events */ 73252780Sray#define GT_CNTKCTL_PL0VCTEN (1 << 1) /* PL0 CNTVCT and CNTFRQ access */ 74252780Sray#define GT_CNTKCTL_PL0PCTEN (1 << 0) /* PL0 CNTPCT and CNTFRQ access */ 75252372Sray 76252372Sraystruct arm_tmr_softc { 77264065Sbr struct resource *res[4]; 78264065Sbr void *ihl[4]; 79252372Sray uint32_t clkfreq; 80252372Sray struct eventtimer et; 81252372Sray}; 82252372Sray 83252372Sraystatic struct arm_tmr_softc *arm_tmr_sc = NULL; 84252372Sray 85264065Sbrstatic struct resource_spec timer_spec[] = { 86264065Sbr { SYS_RES_IRQ, 0, RF_ACTIVE }, /* Secure */ 87264065Sbr { SYS_RES_IRQ, 1, RF_ACTIVE }, /* Non-secure */ 88264065Sbr { SYS_RES_IRQ, 2, RF_ACTIVE }, /* Virt */ 89264065Sbr { SYS_RES_IRQ, 3, RF_ACTIVE }, /* Hyp */ 90264065Sbr { -1, 0 } 91264065Sbr}; 92264065Sbr 93252372Sraystatic timecounter_get_t arm_tmr_get_timecount; 94252372Sray 95252372Sraystatic struct timecounter arm_tmr_timecount = { 96252372Sray .tc_name = "ARM MPCore Timecounter", 97252372Sray .tc_get_timecount = arm_tmr_get_timecount, 98252372Sray .tc_poll_pps = NULL, 99252372Sray .tc_counter_mask = ~0u, 100252372Sray .tc_frequency = 0, 101252372Sray .tc_quality = 1000, 102252372Sray}; 103252372Sray 104252372Sraystatic inline int 105252372Srayget_freq(void) 106252372Sray{ 107252372Sray uint32_t val; 108252372Sray 109252372Sray __asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (val)); 110252372Sray 111252372Sray return (val); 112252372Sray} 113252372Sray 114252372Sraystatic inline int 115252372Srayset_freq(uint32_t val) 116252372Sray{ 117252372Sray 118252372Sray __asm volatile("mcr p15, 0, %[val], c14, c0, 0" : : 119252372Sray [val] "r" (val)); 120252372Sray isb(); 121252372Sray 122252372Sray return (val); 123252372Sray} 124252372Sray 125252372Sray 126252372Sraystatic inline long 127252372Srayget_cntpct(void) 128252372Sray{ 129252372Sray uint64_t val; 130252372Sray 131252372Sray __asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (val)); 132252372Sray 133252372Sray return (val); 134252372Sray} 135252372Sray 136252372Sraystatic inline int 137252372Srayset_ctrl(uint32_t val) 138252372Sray{ 139252372Sray 140252372Sray __asm volatile("mcr p15, 0, %[val], c14, c2, 1" : : 141252372Sray [val] "r" (val)); 142252372Sray isb(); 143252372Sray 144252372Sray return (0); 145252372Sray} 146252372Sray 147252372Sraystatic inline int 148252372Srayset_tval(uint32_t val) 149252372Sray{ 150252372Sray 151252372Sray __asm volatile("mcr p15, 0, %[val], c14, c2, 0" : : 152252372Sray [val] "r" (val)); 153252372Sray isb(); 154252372Sray 155252372Sray return (0); 156252372Sray} 157252372Sray 158252372Sraystatic inline int 159252372Srayget_ctrl(void) 160252372Sray{ 161252372Sray uint32_t val; 162252372Sray 163252372Sray __asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val)); 164252372Sray 165252372Sray return (val); 166252372Sray} 167252372Sray 168252372Sraystatic inline int 169252372Srayget_tval(void) 170252372Sray{ 171252372Sray uint32_t val; 172252372Sray 173252372Sray __asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val)); 174252372Sray 175252372Sray return (val); 176252372Sray} 177252372Sray 178252372Sraystatic inline void 179252372Sraydisable_user_access(void) 180252372Sray{ 181252372Sray uint32_t cntkctl; 182252372Sray 183252372Sray __asm volatile("mrc p15, 0, %0, c14, c1, 0" : "=r" (cntkctl)); 184252780Sray cntkctl &= ~(GT_CNTKCTL_PL0PTEN | GT_CNTKCTL_PL0VTEN | 185252780Sray GT_CNTKCTL_EVNTEN | GT_CNTKCTL_PL0VCTEN | GT_CNTKCTL_PL0PCTEN); 186252372Sray __asm volatile("mcr p15, 0, %0, c14, c1, 0" : : "r" (cntkctl)); 187252372Sray isb(); 188252372Sray} 189252372Sray 190252372Sraystatic unsigned 191252372Srayarm_tmr_get_timecount(struct timecounter *tc) 192252372Sray{ 193252372Sray 194252372Sray return (get_cntpct()); 195252372Sray} 196252372Sray 197252372Sraystatic int 198252372Srayarm_tmr_start(struct eventtimer *et, sbintime_t first, sbintime_t period) 199252372Sray{ 200252372Sray struct arm_tmr_softc *sc; 201252372Sray int counts, ctrl; 202252372Sray 203252372Sray sc = (struct arm_tmr_softc *)et->et_priv; 204252372Sray 205252372Sray if (first != 0) { 206252372Sray counts = ((uint32_t)et->et_frequency * first) >> 32; 207252372Sray ctrl = get_ctrl(); 208252780Sray ctrl &= ~GT_CTRL_INT_MASK; 209252780Sray ctrl |= GT_CTRL_ENABLE; 210252372Sray set_tval(counts); 211252372Sray set_ctrl(ctrl); 212252372Sray return (0); 213252372Sray } 214252372Sray 215252372Sray return (EINVAL); 216252372Sray 217252372Sray} 218252372Sray 219252372Sraystatic int 220252372Srayarm_tmr_stop(struct eventtimer *et) 221252372Sray{ 222252372Sray int ctrl; 223252372Sray 224252372Sray ctrl = get_ctrl(); 225252780Sray ctrl &= GT_CTRL_ENABLE; 226252372Sray set_ctrl(ctrl); 227252372Sray 228252372Sray return (0); 229252372Sray} 230252372Sray 231252372Sraystatic int 232252372Srayarm_tmr_intr(void *arg) 233252372Sray{ 234252372Sray struct arm_tmr_softc *sc; 235252372Sray int ctrl; 236252372Sray 237252372Sray sc = (struct arm_tmr_softc *)arg; 238252372Sray ctrl = get_ctrl(); 239252780Sray if (ctrl & GT_CTRL_INT_STAT) { 240252780Sray ctrl |= GT_CTRL_INT_MASK; 241252372Sray set_ctrl(ctrl); 242252372Sray } 243252372Sray 244252372Sray if (sc->et.et_active) 245252372Sray sc->et.et_event_cb(&sc->et, sc->et.et_arg); 246252372Sray 247252372Sray return (FILTER_HANDLED); 248252372Sray} 249252372Sray 250252372Sraystatic int 251252372Srayarm_tmr_probe(device_t dev) 252252372Sray{ 253252372Sray 254261410Sian if (!ofw_bus_status_okay(dev)) 255261410Sian return (ENXIO); 256261410Sian 257252372Sray if (!ofw_bus_is_compatible(dev, "arm,armv7-timer")) 258252372Sray return (ENXIO); 259252372Sray 260252372Sray device_set_desc(dev, "ARMv7 Generic Timer"); 261252372Sray return (BUS_PROBE_DEFAULT); 262252372Sray} 263252372Sray 264252372Sray 265252372Sraystatic int 266252372Srayarm_tmr_attach(device_t dev) 267252372Sray{ 268252372Sray struct arm_tmr_softc *sc; 269252372Sray phandle_t node; 270252372Sray pcell_t clock; 271252372Sray int error; 272264065Sbr int i; 273252372Sray 274252372Sray sc = device_get_softc(dev); 275252372Sray if (arm_tmr_sc) 276252372Sray return (ENXIO); 277252372Sray 278252372Sray /* Get the base clock frequency */ 279252372Sray node = ofw_bus_get_node(dev); 280252372Sray error = OF_getprop(node, "clock-frequency", &clock, sizeof(clock)); 281264065Sbr if (error > 0) { 282264065Sbr sc->clkfreq = fdt32_to_cpu(clock); 283264065Sbr } 284264065Sbr 285264065Sbr if (sc->clkfreq == 0) { 286264065Sbr /* Try to get clock frequency from timer */ 287264065Sbr sc->clkfreq = get_freq(); 288264065Sbr } 289264065Sbr 290264065Sbr if (sc->clkfreq == 0) { 291264065Sbr device_printf(dev, "No clock frequency specified\n"); 292252372Sray return (ENXIO); 293252372Sray } 294252372Sray 295264065Sbr if (bus_alloc_resources(dev, timer_spec, sc->res)) { 296264065Sbr device_printf(dev, "could not allocate resources\n"); 297264065Sbr return (ENXIO); 298264065Sbr }; 299252372Sray 300252372Sray arm_tmr_sc = sc; 301252372Sray 302264065Sbr /* Setup secure and non-secure IRQs handler */ 303264065Sbr for (i = 0; i < 2; i++) { 304264065Sbr error = bus_setup_intr(dev, sc->res[i], INTR_TYPE_CLK, 305264065Sbr arm_tmr_intr, NULL, sc, &sc->ihl[i]); 306264065Sbr if (error) { 307264065Sbr device_printf(dev, "Unable to alloc int resource.\n"); 308264065Sbr return (ENXIO); 309264065Sbr } 310252372Sray } 311252372Sray 312252372Sray disable_user_access(); 313252372Sray 314252427Sray arm_tmr_timecount.tc_frequency = sc->clkfreq; 315252372Sray tc_init(&arm_tmr_timecount); 316252372Sray 317252372Sray sc->et.et_name = "ARM MPCore Eventtimer"; 318252372Sray sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; 319252372Sray sc->et.et_quality = 1000; 320252372Sray 321252372Sray sc->et.et_frequency = sc->clkfreq; 322252372Sray sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency; 323252372Sray sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; 324252372Sray sc->et.et_start = arm_tmr_start; 325252372Sray sc->et.et_stop = arm_tmr_stop; 326252372Sray sc->et.et_priv = sc; 327252372Sray et_register(&sc->et); 328252372Sray 329252372Sray return (0); 330252372Sray} 331252372Sray 332252372Sraystatic device_method_t arm_tmr_methods[] = { 333252372Sray DEVMETHOD(device_probe, arm_tmr_probe), 334252372Sray DEVMETHOD(device_attach, arm_tmr_attach), 335252372Sray { 0, 0 } 336252372Sray}; 337252372Sray 338252372Sraystatic driver_t arm_tmr_driver = { 339252372Sray "generic_timer", 340252372Sray arm_tmr_methods, 341252372Sray sizeof(struct arm_tmr_softc), 342252372Sray}; 343252372Sray 344252372Sraystatic devclass_t arm_tmr_devclass; 345252372Sray 346269605SianEARLY_DRIVER_MODULE(timer, simplebus, arm_tmr_driver, arm_tmr_devclass, 0, 0, 347269605Sian BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); 348252372Sray 349252372Srayvoid 350252372SrayDELAY(int usec) 351252372Sray{ 352252372Sray int32_t counts, counts_per_usec; 353252372Sray uint32_t first, last; 354252372Sray 355252372Sray /* 356252372Sray * Check the timers are setup, if not just 357252372Sray * use a for loop for the meantime 358252427Sray */ 359252372Sray if (arm_tmr_sc == NULL) { 360252372Sray for (; usec > 0; usec--) 361252372Sray for (counts = 200; counts > 0; counts--) 362252372Sray /* 363252372Sray * Prevent gcc from optimizing 364252372Sray * out the loop 365252372Sray */ 366252372Sray cpufunc_nullop(); 367252372Sray return; 368252372Sray } 369252372Sray 370252372Sray /* Get the number of times to count */ 371252427Sray counts_per_usec = ((arm_tmr_timecount.tc_frequency / 1000000) + 1); 372252372Sray 373252372Sray /* 374252372Sray * Clamp the timeout at a maximum value (about 32 seconds with 375252372Sray * a 66MHz clock). *Nobody* should be delay()ing for anywhere 376252372Sray * near that length of time and if they are, they should be hung 377252372Sray * out to dry. 378252372Sray */ 379252372Sray if (usec >= (0x80000000U / counts_per_usec)) 380252372Sray counts = (0x80000000U / counts_per_usec) - 1; 381252372Sray else 382252372Sray counts = usec * counts_per_usec; 383252372Sray 384252372Sray first = get_cntpct(); 385252372Sray 386252372Sray while (counts > 0) { 387252372Sray last = get_cntpct(); 388252372Sray counts -= (int32_t)(last - first); 389252372Sray first = last; 390252372Sray } 391252372Sray} 392