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: stable/11/sys/arm/arm/generic_timer.c 346561 2019-04-22 15:23:06Z ian $"); 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> 52291937Skib#include <sys/smp.h> 53291937Skib#include <sys/vdso.h> 54252372Sray#include <sys/watchdog.h> 55252372Sray#include <machine/bus.h> 56252372Sray#include <machine/cpu.h> 57252372Sray#include <machine/intr.h> 58291937Skib#include <machine/md_var.h> 59252372Sray 60298854Sandrew#ifdef MULTIDELAY 61298854Sandrew#include <machine/machdep.h> /* For arm_set_delay */ 62298854Sandrew#endif 63298854Sandrew 64284273Sandrew#ifdef FDT 65252372Sray#include <dev/fdt/fdt_common.h> 66252372Sray#include <dev/ofw/openfirm.h> 67252372Sray#include <dev/ofw/ofw_bus.h> 68252372Sray#include <dev/ofw/ofw_bus_subr.h> 69284273Sandrew#endif 70252372Sray 71284273Sandrew#ifdef DEV_ACPI 72284273Sandrew#include <contrib/dev/acpica/include/acpi.h> 73284273Sandrew#include <dev/acpica/acpivar.h> 74284273Sandrew#endif 75252372Sray 76252780Sray#define GT_CTRL_ENABLE (1 << 0) 77252780Sray#define GT_CTRL_INT_MASK (1 << 1) 78252780Sray#define GT_CTRL_INT_STAT (1 << 2) 79252780Sray#define GT_REG_CTRL 0 80252780Sray#define GT_REG_TVAL 1 81252372Sray 82252780Sray#define GT_CNTKCTL_PL0PTEN (1 << 9) /* PL0 Physical timer reg access */ 83252780Sray#define GT_CNTKCTL_PL0VTEN (1 << 8) /* PL0 Virtual timer reg access */ 84271189Sandrew#define GT_CNTKCTL_EVNTI (0xf << 4) /* Virtual counter event bits */ 85252780Sray#define GT_CNTKCTL_EVNTDIR (1 << 3) /* Virtual counter event transition */ 86252780Sray#define GT_CNTKCTL_EVNTEN (1 << 2) /* Enables virtual counter events */ 87252780Sray#define GT_CNTKCTL_PL0VCTEN (1 << 1) /* PL0 CNTVCT and CNTFRQ access */ 88252780Sray#define GT_CNTKCTL_PL0PCTEN (1 << 0) /* PL0 CNTPCT and CNTFRQ access */ 89252372Sray 90252372Sraystruct arm_tmr_softc { 91264065Sbr struct resource *res[4]; 92264065Sbr void *ihl[4]; 93252372Sray uint32_t clkfreq; 94252372Sray struct eventtimer et; 95271189Sandrew bool physical; 96252372Sray}; 97252372Sray 98252372Sraystatic struct arm_tmr_softc *arm_tmr_sc = NULL; 99252372Sray 100264065Sbrstatic struct resource_spec timer_spec[] = { 101264065Sbr { SYS_RES_IRQ, 0, RF_ACTIVE }, /* Secure */ 102264065Sbr { SYS_RES_IRQ, 1, RF_ACTIVE }, /* Non-secure */ 103299072Sbz { SYS_RES_IRQ, 2, RF_ACTIVE | RF_OPTIONAL }, /* Virt */ 104275207Sandrew { SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL }, /* Hyp */ 105264065Sbr { -1, 0 } 106264065Sbr}; 107264065Sbr 108305866Skibstatic uint32_t arm_tmr_fill_vdso_timehands(struct vdso_timehands *vdso_th, 109305866Skib struct timecounter *tc); 110305866Skibstatic void arm_tmr_do_delay(int usec, void *); 111305866Skib 112252372Sraystatic timecounter_get_t arm_tmr_get_timecount; 113252372Sray 114252372Sraystatic struct timecounter arm_tmr_timecount = { 115252372Sray .tc_name = "ARM MPCore Timecounter", 116252372Sray .tc_get_timecount = arm_tmr_get_timecount, 117252372Sray .tc_poll_pps = NULL, 118252372Sray .tc_counter_mask = ~0u, 119252372Sray .tc_frequency = 0, 120252372Sray .tc_quality = 1000, 121305866Skib .tc_fill_vdso_timehands = arm_tmr_fill_vdso_timehands, 122252372Sray}; 123252372Sray 124281072Sandrew#ifdef __arm__ 125281072Sandrew#define get_el0(x) cp15_## x ##_get() 126281072Sandrew#define get_el1(x) cp15_## x ##_get() 127281072Sandrew#define set_el0(x, val) cp15_## x ##_set(val) 128281072Sandrew#define set_el1(x, val) cp15_## x ##_set(val) 129281072Sandrew#else /* __aarch64__ */ 130281072Sandrew#define get_el0(x) READ_SPECIALREG(x ##_el0) 131281072Sandrew#define get_el1(x) READ_SPECIALREG(x ##_el1) 132281072Sandrew#define set_el0(x, val) WRITE_SPECIALREG(x ##_el0, val) 133281072Sandrew#define set_el1(x, val) WRITE_SPECIALREG(x ##_el1, val) 134281072Sandrew#endif 135281072Sandrew 136271189Sandrewstatic int 137252372Srayget_freq(void) 138252372Sray{ 139281072Sandrew return (get_el0(cntfrq)); 140252372Sray} 141252372Sray 142271189Sandrewstatic long 143271189Sandrewget_cntxct(bool physical) 144252372Sray{ 145271189Sandrew uint64_t val; 146252372Sray 147252372Sray isb(); 148271189Sandrew if (physical) 149281072Sandrew val = get_el0(cntpct); 150271189Sandrew else 151281072Sandrew val = get_el0(cntvct); 152252372Sray 153252372Sray return (val); 154252372Sray} 155252372Sray 156271189Sandrewstatic int 157271189Sandrewset_ctrl(uint32_t val, bool physical) 158252372Sray{ 159252372Sray 160271189Sandrew if (physical) 161281072Sandrew set_el0(cntp_ctl, val); 162271189Sandrew else 163281072Sandrew set_el0(cntv_ctl, val); 164252372Sray isb(); 165252372Sray 166252372Sray return (0); 167252372Sray} 168252372Sray 169271189Sandrewstatic int 170271189Sandrewset_tval(uint32_t val, bool physical) 171252372Sray{ 172252372Sray 173271189Sandrew if (physical) 174281072Sandrew set_el0(cntp_tval, val); 175271189Sandrew else 176281072Sandrew set_el0(cntv_tval, val); 177252372Sray isb(); 178252372Sray 179252372Sray return (0); 180252372Sray} 181252372Sray 182271189Sandrewstatic int 183271189Sandrewget_ctrl(bool physical) 184252372Sray{ 185252372Sray uint32_t val; 186252372Sray 187271189Sandrew if (physical) 188281072Sandrew val = get_el0(cntp_ctl); 189271189Sandrew else 190281072Sandrew val = get_el0(cntv_ctl); 191252372Sray 192252372Sray return (val); 193252372Sray} 194252372Sray 195271189Sandrewstatic void 196291937Skibsetup_user_access(void *arg __unused) 197252372Sray{ 198252372Sray uint32_t cntkctl; 199252372Sray 200281072Sandrew cntkctl = get_el1(cntkctl); 201252780Sray cntkctl &= ~(GT_CNTKCTL_PL0PTEN | GT_CNTKCTL_PL0VTEN | 202291937Skib GT_CNTKCTL_EVNTEN); 203291937Skib if (arm_tmr_sc->physical) { 204291937Skib cntkctl |= GT_CNTKCTL_PL0PCTEN; 205291937Skib cntkctl &= ~GT_CNTKCTL_PL0VCTEN; 206291937Skib } else { 207291937Skib cntkctl |= GT_CNTKCTL_PL0VCTEN; 208291937Skib cntkctl &= ~GT_CNTKCTL_PL0PCTEN; 209291937Skib } 210281072Sandrew set_el1(cntkctl, cntkctl); 211252372Sray isb(); 212252372Sray} 213252372Sray 214291937Skibstatic void 215291937Skibtmr_setup_user_access(void *arg __unused) 216291937Skib{ 217291937Skib 218299851Smanu if (arm_tmr_sc != NULL) 219299851Smanu smp_rendezvous(NULL, setup_user_access, NULL, NULL); 220291937Skib} 221291937SkibSYSINIT(tmr_ua, SI_SUB_SMP, SI_ORDER_SECOND, tmr_setup_user_access, NULL); 222291937Skib 223252372Sraystatic unsigned 224252372Srayarm_tmr_get_timecount(struct timecounter *tc) 225252372Sray{ 226252372Sray 227271189Sandrew return (get_cntxct(arm_tmr_sc->physical)); 228252372Sray} 229252372Sray 230252372Sraystatic int 231298648Sbzarm_tmr_start(struct eventtimer *et, sbintime_t first, 232298648Sbz sbintime_t period __unused) 233252372Sray{ 234252372Sray struct arm_tmr_softc *sc; 235252372Sray int counts, ctrl; 236252372Sray 237252372Sray sc = (struct arm_tmr_softc *)et->et_priv; 238252372Sray 239252372Sray if (first != 0) { 240252372Sray counts = ((uint32_t)et->et_frequency * first) >> 32; 241271189Sandrew ctrl = get_ctrl(sc->physical); 242252780Sray ctrl &= ~GT_CTRL_INT_MASK; 243252780Sray ctrl |= GT_CTRL_ENABLE; 244271189Sandrew set_tval(counts, sc->physical); 245271189Sandrew set_ctrl(ctrl, sc->physical); 246252372Sray return (0); 247252372Sray } 248252372Sray 249252372Sray return (EINVAL); 250252372Sray 251252372Sray} 252252372Sray 253252372Sraystatic int 254252372Srayarm_tmr_stop(struct eventtimer *et) 255252372Sray{ 256271189Sandrew struct arm_tmr_softc *sc; 257252372Sray int ctrl; 258252372Sray 259271189Sandrew sc = (struct arm_tmr_softc *)et->et_priv; 260271189Sandrew 261271189Sandrew ctrl = get_ctrl(sc->physical); 262306907Sjmcneill ctrl &= ~GT_CTRL_ENABLE; 263271189Sandrew set_ctrl(ctrl, sc->physical); 264252372Sray 265252372Sray return (0); 266252372Sray} 267252372Sray 268252372Sraystatic int 269252372Srayarm_tmr_intr(void *arg) 270252372Sray{ 271252372Sray struct arm_tmr_softc *sc; 272252372Sray int ctrl; 273252372Sray 274252372Sray sc = (struct arm_tmr_softc *)arg; 275271189Sandrew ctrl = get_ctrl(sc->physical); 276252780Sray if (ctrl & GT_CTRL_INT_STAT) { 277252780Sray ctrl |= GT_CTRL_INT_MASK; 278271189Sandrew set_ctrl(ctrl, sc->physical); 279252372Sray } 280252372Sray 281252372Sray if (sc->et.et_active) 282252372Sray sc->et.et_event_cb(&sc->et, sc->et.et_arg); 283252372Sray 284252372Sray return (FILTER_HANDLED); 285252372Sray} 286252372Sray 287284273Sandrew#ifdef FDT 288252372Sraystatic int 289284273Sandrewarm_tmr_fdt_probe(device_t dev) 290252372Sray{ 291252372Sray 292261410Sian if (!ofw_bus_status_okay(dev)) 293261410Sian return (ENXIO); 294261410Sian 295281072Sandrew if (ofw_bus_is_compatible(dev, "arm,armv7-timer")) { 296281072Sandrew device_set_desc(dev, "ARMv7 Generic Timer"); 297281072Sandrew return (BUS_PROBE_DEFAULT); 298281072Sandrew } else if (ofw_bus_is_compatible(dev, "arm,armv8-timer")) { 299281072Sandrew device_set_desc(dev, "ARMv8 Generic Timer"); 300281072Sandrew return (BUS_PROBE_DEFAULT); 301281072Sandrew } 302252372Sray 303281072Sandrew return (ENXIO); 304252372Sray} 305284273Sandrew#endif 306252372Sray 307284273Sandrew#ifdef DEV_ACPI 308284273Sandrewstatic void 309284273Sandrewarm_tmr_acpi_identify(driver_t *driver, device_t parent) 310284273Sandrew{ 311284273Sandrew ACPI_TABLE_GTDT *gtdt; 312284273Sandrew vm_paddr_t physaddr; 313284273Sandrew device_t dev; 314252372Sray 315284273Sandrew physaddr = acpi_find_table(ACPI_SIG_GTDT); 316284273Sandrew if (physaddr == 0) 317284273Sandrew return; 318284273Sandrew 319284273Sandrew gtdt = acpi_map_table(physaddr, ACPI_SIG_GTDT); 320284273Sandrew if (gtdt == NULL) { 321284273Sandrew device_printf(parent, "gic: Unable to map the GTDT\n"); 322284273Sandrew return; 323284273Sandrew } 324284273Sandrew 325284273Sandrew dev = BUS_ADD_CHILD(parent, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE, 326284273Sandrew "generic_timer", -1); 327284273Sandrew if (dev == NULL) { 328284273Sandrew device_printf(parent, "add gic child failed\n"); 329284273Sandrew goto out; 330284273Sandrew } 331284273Sandrew 332284273Sandrew BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 0, 333284273Sandrew gtdt->SecureEl1Interrupt, 1); 334284273Sandrew BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 1, 335284273Sandrew gtdt->NonSecureEl1Interrupt, 1); 336284273Sandrew BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 2, 337284273Sandrew gtdt->VirtualTimerInterrupt, 1); 338284273Sandrew 339284273Sandrewout: 340284273Sandrew acpi_unmap_table(gtdt); 341284273Sandrew} 342284273Sandrew 343252372Sraystatic int 344284273Sandrewarm_tmr_acpi_probe(device_t dev) 345284273Sandrew{ 346284273Sandrew 347284273Sandrew device_set_desc(dev, "ARM Generic Timer"); 348284273Sandrew return (BUS_PROBE_NOWILDCARD); 349284273Sandrew} 350284273Sandrew#endif 351284273Sandrew 352284273Sandrew 353284273Sandrewstatic int 354252372Srayarm_tmr_attach(device_t dev) 355252372Sray{ 356252372Sray struct arm_tmr_softc *sc; 357284273Sandrew#ifdef FDT 358252372Sray phandle_t node; 359252372Sray pcell_t clock; 360284273Sandrew#endif 361252372Sray int error; 362346561Sian int i, first_timer, last_timer; 363252372Sray 364252372Sray sc = device_get_softc(dev); 365252372Sray if (arm_tmr_sc) 366252372Sray return (ENXIO); 367252372Sray 368284273Sandrew#ifdef FDT 369252372Sray /* Get the base clock frequency */ 370252372Sray node = ofw_bus_get_node(dev); 371284273Sandrew if (node > 0) { 372295470Sandrew error = OF_getencprop(node, "clock-frequency", &clock, 373284273Sandrew sizeof(clock)); 374295633Sandrew if (error > 0) 375295633Sandrew sc->clkfreq = clock; 376264065Sbr } 377284273Sandrew#endif 378264065Sbr 379264065Sbr if (sc->clkfreq == 0) { 380264065Sbr /* Try to get clock frequency from timer */ 381264065Sbr sc->clkfreq = get_freq(); 382264065Sbr } 383264065Sbr 384264065Sbr if (sc->clkfreq == 0) { 385264065Sbr device_printf(dev, "No clock frequency specified\n"); 386252372Sray return (ENXIO); 387252372Sray } 388252372Sray 389264065Sbr if (bus_alloc_resources(dev, timer_spec, sc->res)) { 390264065Sbr device_printf(dev, "could not allocate resources\n"); 391264065Sbr return (ENXIO); 392271189Sandrew } 393252372Sray 394346561Sian#ifdef __aarch64__ 395346561Sian /* Use the virtual timer if we have one. */ 396346561Sian if (sc->res[2] != NULL) { 397346561Sian sc->physical = false; 398346561Sian first_timer = 2; 399346561Sian last_timer = 2; 400346561Sian } else 401281072Sandrew#endif 402346561Sian /* Otherwise set up the secure and non-secure physical timers. */ 403346561Sian { 404346561Sian sc->physical = true; 405346561Sian first_timer = 0; 406346561Sian last_timer = 1; 407346561Sian } 408271189Sandrew 409252372Sray arm_tmr_sc = sc; 410252372Sray 411271189Sandrew /* Setup secure, non-secure and virtual IRQs handler */ 412346561Sian for (i = first_timer; i <= last_timer; i++) { 413299072Sbz /* If we do not have the interrupt, skip it. */ 414299072Sbz if (sc->res[i] == NULL) 415299072Sbz continue; 416264065Sbr error = bus_setup_intr(dev, sc->res[i], INTR_TYPE_CLK, 417264065Sbr arm_tmr_intr, NULL, sc, &sc->ihl[i]); 418264065Sbr if (error) { 419264065Sbr device_printf(dev, "Unable to alloc int resource.\n"); 420264065Sbr return (ENXIO); 421264065Sbr } 422252372Sray } 423252372Sray 424252427Sray arm_tmr_timecount.tc_frequency = sc->clkfreq; 425252372Sray tc_init(&arm_tmr_timecount); 426252372Sray 427252372Sray sc->et.et_name = "ARM MPCore Eventtimer"; 428252372Sray sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; 429252372Sray sc->et.et_quality = 1000; 430252372Sray 431252372Sray sc->et.et_frequency = sc->clkfreq; 432299071Sbz sc->et.et_min_period = (0x00000010LLU << 32) / sc->et.et_frequency; 433252372Sray sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; 434252372Sray sc->et.et_start = arm_tmr_start; 435252372Sray sc->et.et_stop = arm_tmr_stop; 436252372Sray sc->et.et_priv = sc; 437252372Sray et_register(&sc->et); 438252372Sray 439298854Sandrew#ifdef MULTIDELAY 440298854Sandrew arm_set_delay(arm_tmr_do_delay, sc); 441298854Sandrew#endif 442298854Sandrew 443252372Sray return (0); 444252372Sray} 445252372Sray 446284273Sandrew#ifdef FDT 447284273Sandrewstatic device_method_t arm_tmr_fdt_methods[] = { 448284273Sandrew DEVMETHOD(device_probe, arm_tmr_fdt_probe), 449252372Sray DEVMETHOD(device_attach, arm_tmr_attach), 450252372Sray { 0, 0 } 451252372Sray}; 452252372Sray 453284273Sandrewstatic driver_t arm_tmr_fdt_driver = { 454252372Sray "generic_timer", 455284273Sandrew arm_tmr_fdt_methods, 456252372Sray sizeof(struct arm_tmr_softc), 457252372Sray}; 458252372Sray 459284273Sandrewstatic devclass_t arm_tmr_fdt_devclass; 460252372Sray 461284273SandrewEARLY_DRIVER_MODULE(timer, simplebus, arm_tmr_fdt_driver, arm_tmr_fdt_devclass, 462284273Sandrew 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); 463284273SandrewEARLY_DRIVER_MODULE(timer, ofwbus, arm_tmr_fdt_driver, arm_tmr_fdt_devclass, 464284273Sandrew 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); 465284273Sandrew#endif 466252372Sray 467284273Sandrew#ifdef DEV_ACPI 468284273Sandrewstatic device_method_t arm_tmr_acpi_methods[] = { 469284273Sandrew DEVMETHOD(device_identify, arm_tmr_acpi_identify), 470284273Sandrew DEVMETHOD(device_probe, arm_tmr_acpi_probe), 471284273Sandrew DEVMETHOD(device_attach, arm_tmr_attach), 472284273Sandrew { 0, 0 } 473284273Sandrew}; 474284273Sandrew 475284273Sandrewstatic driver_t arm_tmr_acpi_driver = { 476284273Sandrew "generic_timer", 477284273Sandrew arm_tmr_acpi_methods, 478284273Sandrew sizeof(struct arm_tmr_softc), 479284273Sandrew}; 480284273Sandrew 481284273Sandrewstatic devclass_t arm_tmr_acpi_devclass; 482284273Sandrew 483284273SandrewEARLY_DRIVER_MODULE(timer, acpi, arm_tmr_acpi_driver, arm_tmr_acpi_devclass, 484284273Sandrew 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); 485284273Sandrew#endif 486284273Sandrew 487298854Sandrewstatic void 488298854Sandrewarm_tmr_do_delay(int usec, void *arg) 489252372Sray{ 490298854Sandrew struct arm_tmr_softc *sc = arg; 491252372Sray int32_t counts, counts_per_usec; 492252372Sray uint32_t first, last; 493252372Sray 494252372Sray /* Get the number of times to count */ 495252427Sray counts_per_usec = ((arm_tmr_timecount.tc_frequency / 1000000) + 1); 496252372Sray 497252372Sray /* 498252372Sray * Clamp the timeout at a maximum value (about 32 seconds with 499252372Sray * a 66MHz clock). *Nobody* should be delay()ing for anywhere 500252372Sray * near that length of time and if they are, they should be hung 501252372Sray * out to dry. 502252372Sray */ 503252372Sray if (usec >= (0x80000000U / counts_per_usec)) 504252372Sray counts = (0x80000000U / counts_per_usec) - 1; 505252372Sray else 506252372Sray counts = usec * counts_per_usec; 507252372Sray 508298854Sandrew first = get_cntxct(sc->physical); 509252372Sray 510252372Sray while (counts > 0) { 511298854Sandrew last = get_cntxct(sc->physical); 512252372Sray counts -= (int32_t)(last - first); 513252372Sray first = last; 514252372Sray } 515252372Sray} 516291937Skib 517298854Sandrew#ifndef MULTIDELAY 518298854Sandrewvoid 519298854SandrewDELAY(int usec) 520298854Sandrew{ 521298854Sandrew int32_t counts; 522298854Sandrew 523298854Sandrew /* 524298854Sandrew * Check the timers are setup, if not just 525298854Sandrew * use a for loop for the meantime 526298854Sandrew */ 527298854Sandrew if (arm_tmr_sc == NULL) { 528298854Sandrew for (; usec > 0; usec--) 529298854Sandrew for (counts = 200; counts > 0; counts--) 530298854Sandrew /* 531298854Sandrew * Prevent the compiler from optimizing 532298854Sandrew * out the loop 533298854Sandrew */ 534298854Sandrew cpufunc_nullop(); 535298854Sandrew } else 536298854Sandrew arm_tmr_do_delay(usec, arm_tmr_sc); 537298854Sandrew} 538298854Sandrew#endif 539298854Sandrew 540291937Skibstatic uint32_t 541291937Skibarm_tmr_fill_vdso_timehands(struct vdso_timehands *vdso_th, 542291937Skib struct timecounter *tc) 543291937Skib{ 544291937Skib 545305866Skib vdso_th->th_algo = VDSO_TH_ALGO_ARM_GENTIM; 546291937Skib vdso_th->th_physical = arm_tmr_sc->physical; 547291937Skib bzero(vdso_th->th_res, sizeof(vdso_th->th_res)); 548305866Skib return (1); 549291937Skib} 550