generic_timer.c revision 284273
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/** 34282483Sandrew * Cortex-A7, Cortex-A15, ARMv8 and later Generic Timer 35252372Sray */ 36252372Sray 37284273Sandrew#include "opt_acpi.h" 38284273Sandrew#include "opt_platform.h" 39284273Sandrew 40252372Sray#include <sys/cdefs.h> 41252372Sray__FBSDID("$FreeBSD: head/sys/arm/arm/generic_timer.c 284273 2015-06-11 15:45:33Z andrew $"); 42252372Sray 43252372Sray#include <sys/param.h> 44252372Sray#include <sys/systm.h> 45252372Sray#include <sys/bus.h> 46252372Sray#include <sys/kernel.h> 47252372Sray#include <sys/module.h> 48252372Sray#include <sys/malloc.h> 49252372Sray#include <sys/rman.h> 50252372Sray#include <sys/timeet.h> 51252372Sray#include <sys/timetc.h> 52252372Sray#include <sys/watchdog.h> 53252372Sray#include <machine/bus.h> 54252372Sray#include <machine/cpu.h> 55252372Sray#include <machine/intr.h> 56252372Sray 57284273Sandrew#ifdef FDT 58252372Sray#include <dev/fdt/fdt_common.h> 59252372Sray#include <dev/ofw/openfirm.h> 60252372Sray#include <dev/ofw/ofw_bus.h> 61252372Sray#include <dev/ofw/ofw_bus_subr.h> 62284273Sandrew#endif 63252372Sray 64284273Sandrew#ifdef DEV_ACPI 65284273Sandrew#include <contrib/dev/acpica/include/acpi.h> 66284273Sandrew#include <dev/acpica/acpivar.h> 67284273Sandrew#endif 68252372Sray 69252780Sray#define GT_CTRL_ENABLE (1 << 0) 70252780Sray#define GT_CTRL_INT_MASK (1 << 1) 71252780Sray#define GT_CTRL_INT_STAT (1 << 2) 72252780Sray#define GT_REG_CTRL 0 73252780Sray#define GT_REG_TVAL 1 74252372Sray 75252780Sray#define GT_CNTKCTL_PL0PTEN (1 << 9) /* PL0 Physical timer reg access */ 76252780Sray#define GT_CNTKCTL_PL0VTEN (1 << 8) /* PL0 Virtual timer reg access */ 77271189Sandrew#define GT_CNTKCTL_EVNTI (0xf << 4) /* Virtual counter event bits */ 78252780Sray#define GT_CNTKCTL_EVNTDIR (1 << 3) /* Virtual counter event transition */ 79252780Sray#define GT_CNTKCTL_EVNTEN (1 << 2) /* Enables virtual counter events */ 80252780Sray#define GT_CNTKCTL_PL0VCTEN (1 << 1) /* PL0 CNTVCT and CNTFRQ access */ 81252780Sray#define GT_CNTKCTL_PL0PCTEN (1 << 0) /* PL0 CNTPCT and CNTFRQ access */ 82252372Sray 83252372Sraystruct arm_tmr_softc { 84264065Sbr struct resource *res[4]; 85264065Sbr void *ihl[4]; 86252372Sray uint32_t clkfreq; 87252372Sray struct eventtimer et; 88271189Sandrew bool physical; 89252372Sray}; 90252372Sray 91252372Sraystatic struct arm_tmr_softc *arm_tmr_sc = NULL; 92252372Sray 93264065Sbrstatic struct resource_spec timer_spec[] = { 94264065Sbr { SYS_RES_IRQ, 0, RF_ACTIVE }, /* Secure */ 95264065Sbr { SYS_RES_IRQ, 1, RF_ACTIVE }, /* Non-secure */ 96264065Sbr { SYS_RES_IRQ, 2, RF_ACTIVE }, /* Virt */ 97275207Sandrew { SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL }, /* Hyp */ 98264065Sbr { -1, 0 } 99264065Sbr}; 100264065Sbr 101252372Sraystatic timecounter_get_t arm_tmr_get_timecount; 102252372Sray 103252372Sraystatic struct timecounter arm_tmr_timecount = { 104252372Sray .tc_name = "ARM MPCore Timecounter", 105252372Sray .tc_get_timecount = arm_tmr_get_timecount, 106252372Sray .tc_poll_pps = NULL, 107252372Sray .tc_counter_mask = ~0u, 108252372Sray .tc_frequency = 0, 109252372Sray .tc_quality = 1000, 110252372Sray}; 111252372Sray 112281072Sandrew#ifdef __arm__ 113281072Sandrew#define get_el0(x) cp15_## x ##_get() 114281072Sandrew#define get_el1(x) cp15_## x ##_get() 115281072Sandrew#define set_el0(x, val) cp15_## x ##_set(val) 116281072Sandrew#define set_el1(x, val) cp15_## x ##_set(val) 117281072Sandrew#else /* __aarch64__ */ 118281072Sandrew#define get_el0(x) READ_SPECIALREG(x ##_el0) 119281072Sandrew#define get_el1(x) READ_SPECIALREG(x ##_el1) 120281072Sandrew#define set_el0(x, val) WRITE_SPECIALREG(x ##_el0, val) 121281072Sandrew#define set_el1(x, val) WRITE_SPECIALREG(x ##_el1, val) 122281072Sandrew#endif 123281072Sandrew 124271189Sandrewstatic int 125252372Srayget_freq(void) 126252372Sray{ 127281072Sandrew return (get_el0(cntfrq)); 128252372Sray} 129252372Sray 130271189Sandrewstatic long 131271189Sandrewget_cntxct(bool physical) 132252372Sray{ 133271189Sandrew uint64_t val; 134252372Sray 135252372Sray isb(); 136271189Sandrew if (physical) 137281072Sandrew val = get_el0(cntpct); 138271189Sandrew else 139281072Sandrew val = get_el0(cntvct); 140252372Sray 141252372Sray return (val); 142252372Sray} 143252372Sray 144271189Sandrewstatic int 145271189Sandrewset_ctrl(uint32_t val, bool physical) 146252372Sray{ 147252372Sray 148271189Sandrew if (physical) 149281072Sandrew set_el0(cntp_ctl, val); 150271189Sandrew else 151281072Sandrew set_el0(cntv_ctl, val); 152252372Sray isb(); 153252372Sray 154252372Sray return (0); 155252372Sray} 156252372Sray 157271189Sandrewstatic int 158271189Sandrewset_tval(uint32_t val, bool physical) 159252372Sray{ 160252372Sray 161271189Sandrew if (physical) 162281072Sandrew set_el0(cntp_tval, val); 163271189Sandrew else 164281072Sandrew set_el0(cntv_tval, val); 165252372Sray isb(); 166252372Sray 167252372Sray return (0); 168252372Sray} 169252372Sray 170271189Sandrewstatic int 171271189Sandrewget_ctrl(bool physical) 172252372Sray{ 173252372Sray uint32_t val; 174252372Sray 175271189Sandrew if (physical) 176281072Sandrew val = get_el0(cntp_ctl); 177271189Sandrew else 178281072Sandrew val = get_el0(cntv_ctl); 179252372Sray 180252372Sray return (val); 181252372Sray} 182252372Sray 183271189Sandrewstatic void 184252372Sraydisable_user_access(void) 185252372Sray{ 186252372Sray uint32_t cntkctl; 187252372Sray 188281072Sandrew cntkctl = get_el1(cntkctl); 189252780Sray cntkctl &= ~(GT_CNTKCTL_PL0PTEN | GT_CNTKCTL_PL0VTEN | 190252780Sray GT_CNTKCTL_EVNTEN | GT_CNTKCTL_PL0VCTEN | GT_CNTKCTL_PL0PCTEN); 191281072Sandrew set_el1(cntkctl, cntkctl); 192252372Sray isb(); 193252372Sray} 194252372Sray 195252372Sraystatic unsigned 196252372Srayarm_tmr_get_timecount(struct timecounter *tc) 197252372Sray{ 198252372Sray 199271189Sandrew return (get_cntxct(arm_tmr_sc->physical)); 200252372Sray} 201252372Sray 202252372Sraystatic int 203252372Srayarm_tmr_start(struct eventtimer *et, sbintime_t first, sbintime_t period) 204252372Sray{ 205252372Sray struct arm_tmr_softc *sc; 206252372Sray int counts, ctrl; 207252372Sray 208252372Sray sc = (struct arm_tmr_softc *)et->et_priv; 209252372Sray 210252372Sray if (first != 0) { 211252372Sray counts = ((uint32_t)et->et_frequency * first) >> 32; 212271189Sandrew ctrl = get_ctrl(sc->physical); 213252780Sray ctrl &= ~GT_CTRL_INT_MASK; 214252780Sray ctrl |= GT_CTRL_ENABLE; 215271189Sandrew set_tval(counts, sc->physical); 216271189Sandrew set_ctrl(ctrl, sc->physical); 217252372Sray return (0); 218252372Sray } 219252372Sray 220252372Sray return (EINVAL); 221252372Sray 222252372Sray} 223252372Sray 224252372Sraystatic int 225252372Srayarm_tmr_stop(struct eventtimer *et) 226252372Sray{ 227271189Sandrew struct arm_tmr_softc *sc; 228252372Sray int ctrl; 229252372Sray 230271189Sandrew sc = (struct arm_tmr_softc *)et->et_priv; 231271189Sandrew 232271189Sandrew ctrl = get_ctrl(sc->physical); 233252780Sray ctrl &= GT_CTRL_ENABLE; 234271189Sandrew set_ctrl(ctrl, sc->physical); 235252372Sray 236252372Sray return (0); 237252372Sray} 238252372Sray 239252372Sraystatic int 240252372Srayarm_tmr_intr(void *arg) 241252372Sray{ 242252372Sray struct arm_tmr_softc *sc; 243252372Sray int ctrl; 244252372Sray 245252372Sray sc = (struct arm_tmr_softc *)arg; 246271189Sandrew ctrl = get_ctrl(sc->physical); 247252780Sray if (ctrl & GT_CTRL_INT_STAT) { 248252780Sray ctrl |= GT_CTRL_INT_MASK; 249271189Sandrew set_ctrl(ctrl, sc->physical); 250252372Sray } 251252372Sray 252252372Sray if (sc->et.et_active) 253252372Sray sc->et.et_event_cb(&sc->et, sc->et.et_arg); 254252372Sray 255252372Sray return (FILTER_HANDLED); 256252372Sray} 257252372Sray 258284273Sandrew#ifdef FDT 259252372Sraystatic int 260284273Sandrewarm_tmr_fdt_probe(device_t dev) 261252372Sray{ 262252372Sray 263261410Sian if (!ofw_bus_status_okay(dev)) 264261410Sian return (ENXIO); 265261410Sian 266281072Sandrew if (ofw_bus_is_compatible(dev, "arm,armv7-timer")) { 267281072Sandrew device_set_desc(dev, "ARMv7 Generic Timer"); 268281072Sandrew return (BUS_PROBE_DEFAULT); 269281072Sandrew } else if (ofw_bus_is_compatible(dev, "arm,armv8-timer")) { 270281072Sandrew device_set_desc(dev, "ARMv8 Generic Timer"); 271281072Sandrew return (BUS_PROBE_DEFAULT); 272281072Sandrew } 273252372Sray 274281072Sandrew return (ENXIO); 275252372Sray} 276284273Sandrew#endif 277252372Sray 278284273Sandrew#ifdef DEV_ACPI 279284273Sandrewstatic void 280284273Sandrewarm_tmr_acpi_identify(driver_t *driver, device_t parent) 281284273Sandrew{ 282284273Sandrew ACPI_TABLE_GTDT *gtdt; 283284273Sandrew vm_paddr_t physaddr; 284284273Sandrew device_t dev; 285252372Sray 286284273Sandrew physaddr = acpi_find_table(ACPI_SIG_GTDT); 287284273Sandrew if (physaddr == 0) 288284273Sandrew return; 289284273Sandrew 290284273Sandrew gtdt = acpi_map_table(physaddr, ACPI_SIG_GTDT); 291284273Sandrew if (gtdt == NULL) { 292284273Sandrew device_printf(parent, "gic: Unable to map the GTDT\n"); 293284273Sandrew return; 294284273Sandrew } 295284273Sandrew 296284273Sandrew dev = BUS_ADD_CHILD(parent, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE, 297284273Sandrew "generic_timer", -1); 298284273Sandrew if (dev == NULL) { 299284273Sandrew device_printf(parent, "add gic child failed\n"); 300284273Sandrew goto out; 301284273Sandrew } 302284273Sandrew 303284273Sandrew BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 0, 304284273Sandrew gtdt->SecureEl1Interrupt, 1); 305284273Sandrew BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 1, 306284273Sandrew gtdt->NonSecureEl1Interrupt, 1); 307284273Sandrew BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 2, 308284273Sandrew gtdt->VirtualTimerInterrupt, 1); 309284273Sandrew 310284273Sandrewout: 311284273Sandrew acpi_unmap_table(gtdt); 312284273Sandrew} 313284273Sandrew 314252372Sraystatic int 315284273Sandrewarm_tmr_acpi_probe(device_t dev) 316284273Sandrew{ 317284273Sandrew 318284273Sandrew device_set_desc(dev, "ARM Generic Timer"); 319284273Sandrew return (BUS_PROBE_NOWILDCARD); 320284273Sandrew} 321284273Sandrew#endif 322284273Sandrew 323284273Sandrew 324284273Sandrewstatic int 325252372Srayarm_tmr_attach(device_t dev) 326252372Sray{ 327252372Sray struct arm_tmr_softc *sc; 328284273Sandrew#ifdef FDT 329252372Sray phandle_t node; 330252372Sray pcell_t clock; 331284273Sandrew#endif 332252372Sray int error; 333264065Sbr int i; 334252372Sray 335252372Sray sc = device_get_softc(dev); 336252372Sray if (arm_tmr_sc) 337252372Sray return (ENXIO); 338252372Sray 339284273Sandrew#ifdef FDT 340252372Sray /* Get the base clock frequency */ 341252372Sray node = ofw_bus_get_node(dev); 342284273Sandrew if (node > 0) { 343284273Sandrew error = OF_getprop(node, "clock-frequency", &clock, 344284273Sandrew sizeof(clock)); 345284273Sandrew if (error > 0) { 346284273Sandrew sc->clkfreq = fdt32_to_cpu(clock); 347284273Sandrew } 348264065Sbr } 349284273Sandrew#endif 350264065Sbr 351264065Sbr if (sc->clkfreq == 0) { 352264065Sbr /* Try to get clock frequency from timer */ 353264065Sbr sc->clkfreq = get_freq(); 354264065Sbr } 355264065Sbr 356264065Sbr if (sc->clkfreq == 0) { 357264065Sbr device_printf(dev, "No clock frequency specified\n"); 358252372Sray return (ENXIO); 359252372Sray } 360252372Sray 361264065Sbr if (bus_alloc_resources(dev, timer_spec, sc->res)) { 362264065Sbr device_printf(dev, "could not allocate resources\n"); 363264065Sbr return (ENXIO); 364271189Sandrew } 365252372Sray 366281072Sandrew#ifdef __arm__ 367271189Sandrew sc->physical = true; 368281072Sandrew#else /* __aarch64__ */ 369281072Sandrew sc->physical = false; 370281072Sandrew#endif 371271189Sandrew 372252372Sray arm_tmr_sc = sc; 373252372Sray 374271189Sandrew /* Setup secure, non-secure and virtual IRQs handler */ 375271189Sandrew for (i = 0; i < 3; i++) { 376264065Sbr error = bus_setup_intr(dev, sc->res[i], INTR_TYPE_CLK, 377264065Sbr arm_tmr_intr, NULL, sc, &sc->ihl[i]); 378264065Sbr if (error) { 379264065Sbr device_printf(dev, "Unable to alloc int resource.\n"); 380264065Sbr return (ENXIO); 381264065Sbr } 382252372Sray } 383252372Sray 384252372Sray disable_user_access(); 385252372Sray 386252427Sray arm_tmr_timecount.tc_frequency = sc->clkfreq; 387252372Sray tc_init(&arm_tmr_timecount); 388252372Sray 389252372Sray sc->et.et_name = "ARM MPCore Eventtimer"; 390252372Sray sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; 391252372Sray sc->et.et_quality = 1000; 392252372Sray 393252372Sray sc->et.et_frequency = sc->clkfreq; 394252372Sray sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency; 395252372Sray sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; 396252372Sray sc->et.et_start = arm_tmr_start; 397252372Sray sc->et.et_stop = arm_tmr_stop; 398252372Sray sc->et.et_priv = sc; 399252372Sray et_register(&sc->et); 400252372Sray 401252372Sray return (0); 402252372Sray} 403252372Sray 404284273Sandrew#ifdef FDT 405284273Sandrewstatic device_method_t arm_tmr_fdt_methods[] = { 406284273Sandrew DEVMETHOD(device_probe, arm_tmr_fdt_probe), 407252372Sray DEVMETHOD(device_attach, arm_tmr_attach), 408252372Sray { 0, 0 } 409252372Sray}; 410252372Sray 411284273Sandrewstatic driver_t arm_tmr_fdt_driver = { 412252372Sray "generic_timer", 413284273Sandrew arm_tmr_fdt_methods, 414252372Sray sizeof(struct arm_tmr_softc), 415252372Sray}; 416252372Sray 417284273Sandrewstatic devclass_t arm_tmr_fdt_devclass; 418252372Sray 419284273SandrewEARLY_DRIVER_MODULE(timer, simplebus, arm_tmr_fdt_driver, arm_tmr_fdt_devclass, 420284273Sandrew 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); 421284273SandrewEARLY_DRIVER_MODULE(timer, ofwbus, arm_tmr_fdt_driver, arm_tmr_fdt_devclass, 422284273Sandrew 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); 423284273Sandrew#endif 424252372Sray 425284273Sandrew#ifdef DEV_ACPI 426284273Sandrewstatic device_method_t arm_tmr_acpi_methods[] = { 427284273Sandrew DEVMETHOD(device_identify, arm_tmr_acpi_identify), 428284273Sandrew DEVMETHOD(device_probe, arm_tmr_acpi_probe), 429284273Sandrew DEVMETHOD(device_attach, arm_tmr_attach), 430284273Sandrew { 0, 0 } 431284273Sandrew}; 432284273Sandrew 433284273Sandrewstatic driver_t arm_tmr_acpi_driver = { 434284273Sandrew "generic_timer", 435284273Sandrew arm_tmr_acpi_methods, 436284273Sandrew sizeof(struct arm_tmr_softc), 437284273Sandrew}; 438284273Sandrew 439284273Sandrewstatic devclass_t arm_tmr_acpi_devclass; 440284273Sandrew 441284273SandrewEARLY_DRIVER_MODULE(timer, acpi, arm_tmr_acpi_driver, arm_tmr_acpi_devclass, 442284273Sandrew 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); 443284273Sandrew#endif 444284273Sandrew 445252372Srayvoid 446252372SrayDELAY(int usec) 447252372Sray{ 448252372Sray int32_t counts, counts_per_usec; 449252372Sray uint32_t first, last; 450252372Sray 451252372Sray /* 452252372Sray * Check the timers are setup, if not just 453252372Sray * use a for loop for the meantime 454252427Sray */ 455252372Sray if (arm_tmr_sc == NULL) { 456252372Sray for (; usec > 0; usec--) 457252372Sray for (counts = 200; counts > 0; counts--) 458252372Sray /* 459280986Sandrew * Prevent the compiler from optimizing 460252372Sray * out the loop 461252372Sray */ 462252372Sray cpufunc_nullop(); 463252372Sray return; 464252372Sray } 465252372Sray 466252372Sray /* Get the number of times to count */ 467252427Sray counts_per_usec = ((arm_tmr_timecount.tc_frequency / 1000000) + 1); 468252372Sray 469252372Sray /* 470252372Sray * Clamp the timeout at a maximum value (about 32 seconds with 471252372Sray * a 66MHz clock). *Nobody* should be delay()ing for anywhere 472252372Sray * near that length of time and if they are, they should be hung 473252372Sray * out to dry. 474252372Sray */ 475252372Sray if (usec >= (0x80000000U / counts_per_usec)) 476252372Sray counts = (0x80000000U / counts_per_usec) - 1; 477252372Sray else 478252372Sray counts = usec * counts_per_usec; 479252372Sray 480271189Sandrew first = get_cntxct(arm_tmr_sc->physical); 481252372Sray 482252372Sray while (counts > 0) { 483271189Sandrew last = get_cntxct(arm_tmr_sc->physical); 484252372Sray counts -= (int32_t)(last - first); 485252372Sray first = last; 486252372Sray } 487252372Sray} 488