generic_timer.c revision 295633
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 295633 2016-02-15 19:14:24Z 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> 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 60284273Sandrew#ifdef FDT 61252372Sray#include <dev/fdt/fdt_common.h> 62252372Sray#include <dev/ofw/openfirm.h> 63252372Sray#include <dev/ofw/ofw_bus.h> 64252372Sray#include <dev/ofw/ofw_bus_subr.h> 65284273Sandrew#endif 66252372Sray 67284273Sandrew#ifdef DEV_ACPI 68284273Sandrew#include <contrib/dev/acpica/include/acpi.h> 69284273Sandrew#include <dev/acpica/acpivar.h> 70284273Sandrew#endif 71252372Sray 72252780Sray#define GT_CTRL_ENABLE (1 << 0) 73252780Sray#define GT_CTRL_INT_MASK (1 << 1) 74252780Sray#define GT_CTRL_INT_STAT (1 << 2) 75252780Sray#define GT_REG_CTRL 0 76252780Sray#define GT_REG_TVAL 1 77252372Sray 78252780Sray#define GT_CNTKCTL_PL0PTEN (1 << 9) /* PL0 Physical timer reg access */ 79252780Sray#define GT_CNTKCTL_PL0VTEN (1 << 8) /* PL0 Virtual timer reg access */ 80271189Sandrew#define GT_CNTKCTL_EVNTI (0xf << 4) /* Virtual counter event bits */ 81252780Sray#define GT_CNTKCTL_EVNTDIR (1 << 3) /* Virtual counter event transition */ 82252780Sray#define GT_CNTKCTL_EVNTEN (1 << 2) /* Enables virtual counter events */ 83252780Sray#define GT_CNTKCTL_PL0VCTEN (1 << 1) /* PL0 CNTVCT and CNTFRQ access */ 84252780Sray#define GT_CNTKCTL_PL0PCTEN (1 << 0) /* PL0 CNTPCT and CNTFRQ access */ 85252372Sray 86252372Sraystruct arm_tmr_softc { 87264065Sbr struct resource *res[4]; 88264065Sbr void *ihl[4]; 89252372Sray uint32_t clkfreq; 90252372Sray struct eventtimer et; 91271189Sandrew bool physical; 92252372Sray}; 93252372Sray 94252372Sraystatic struct arm_tmr_softc *arm_tmr_sc = NULL; 95252372Sray 96264065Sbrstatic struct resource_spec timer_spec[] = { 97264065Sbr { SYS_RES_IRQ, 0, RF_ACTIVE }, /* Secure */ 98264065Sbr { SYS_RES_IRQ, 1, RF_ACTIVE }, /* Non-secure */ 99264065Sbr { SYS_RES_IRQ, 2, RF_ACTIVE }, /* Virt */ 100275207Sandrew { SYS_RES_IRQ, 3, RF_ACTIVE | RF_OPTIONAL }, /* Hyp */ 101264065Sbr { -1, 0 } 102264065Sbr}; 103264065Sbr 104252372Sraystatic timecounter_get_t arm_tmr_get_timecount; 105252372Sray 106252372Sraystatic struct timecounter arm_tmr_timecount = { 107252372Sray .tc_name = "ARM MPCore Timecounter", 108252372Sray .tc_get_timecount = arm_tmr_get_timecount, 109252372Sray .tc_poll_pps = NULL, 110252372Sray .tc_counter_mask = ~0u, 111252372Sray .tc_frequency = 0, 112252372Sray .tc_quality = 1000, 113252372Sray}; 114252372Sray 115281072Sandrew#ifdef __arm__ 116281072Sandrew#define get_el0(x) cp15_## x ##_get() 117281072Sandrew#define get_el1(x) cp15_## x ##_get() 118281072Sandrew#define set_el0(x, val) cp15_## x ##_set(val) 119281072Sandrew#define set_el1(x, val) cp15_## x ##_set(val) 120281072Sandrew#else /* __aarch64__ */ 121281072Sandrew#define get_el0(x) READ_SPECIALREG(x ##_el0) 122281072Sandrew#define get_el1(x) READ_SPECIALREG(x ##_el1) 123281072Sandrew#define set_el0(x, val) WRITE_SPECIALREG(x ##_el0, val) 124281072Sandrew#define set_el1(x, val) WRITE_SPECIALREG(x ##_el1, val) 125281072Sandrew#endif 126281072Sandrew 127291937Skibstatic uint32_t arm_tmr_fill_vdso_timehands(struct vdso_timehands *vdso_th, 128291937Skib struct timecounter *tc); 129291937Skib 130271189Sandrewstatic int 131252372Srayget_freq(void) 132252372Sray{ 133281072Sandrew return (get_el0(cntfrq)); 134252372Sray} 135252372Sray 136271189Sandrewstatic long 137271189Sandrewget_cntxct(bool physical) 138252372Sray{ 139271189Sandrew uint64_t val; 140252372Sray 141252372Sray isb(); 142271189Sandrew if (physical) 143281072Sandrew val = get_el0(cntpct); 144271189Sandrew else 145281072Sandrew val = get_el0(cntvct); 146252372Sray 147252372Sray return (val); 148252372Sray} 149252372Sray 150271189Sandrewstatic int 151271189Sandrewset_ctrl(uint32_t val, bool physical) 152252372Sray{ 153252372Sray 154271189Sandrew if (physical) 155281072Sandrew set_el0(cntp_ctl, val); 156271189Sandrew else 157281072Sandrew set_el0(cntv_ctl, val); 158252372Sray isb(); 159252372Sray 160252372Sray return (0); 161252372Sray} 162252372Sray 163271189Sandrewstatic int 164271189Sandrewset_tval(uint32_t val, bool physical) 165252372Sray{ 166252372Sray 167271189Sandrew if (physical) 168281072Sandrew set_el0(cntp_tval, val); 169271189Sandrew else 170281072Sandrew set_el0(cntv_tval, val); 171252372Sray isb(); 172252372Sray 173252372Sray return (0); 174252372Sray} 175252372Sray 176271189Sandrewstatic int 177271189Sandrewget_ctrl(bool physical) 178252372Sray{ 179252372Sray uint32_t val; 180252372Sray 181271189Sandrew if (physical) 182281072Sandrew val = get_el0(cntp_ctl); 183271189Sandrew else 184281072Sandrew val = get_el0(cntv_ctl); 185252372Sray 186252372Sray return (val); 187252372Sray} 188252372Sray 189271189Sandrewstatic void 190291937Skibsetup_user_access(void *arg __unused) 191252372Sray{ 192252372Sray uint32_t cntkctl; 193252372Sray 194281072Sandrew cntkctl = get_el1(cntkctl); 195252780Sray cntkctl &= ~(GT_CNTKCTL_PL0PTEN | GT_CNTKCTL_PL0VTEN | 196291937Skib GT_CNTKCTL_EVNTEN); 197291937Skib if (arm_tmr_sc->physical) { 198291937Skib cntkctl |= GT_CNTKCTL_PL0PCTEN; 199291937Skib cntkctl &= ~GT_CNTKCTL_PL0VCTEN; 200291937Skib } else { 201291937Skib cntkctl |= GT_CNTKCTL_PL0VCTEN; 202291937Skib cntkctl &= ~GT_CNTKCTL_PL0PCTEN; 203291937Skib } 204281072Sandrew set_el1(cntkctl, cntkctl); 205252372Sray isb(); 206252372Sray} 207252372Sray 208291937Skibstatic void 209291937Skibtmr_setup_user_access(void *arg __unused) 210291937Skib{ 211291937Skib 212291937Skib smp_rendezvous(NULL, setup_user_access, NULL, NULL); 213291937Skib} 214291937SkibSYSINIT(tmr_ua, SI_SUB_SMP, SI_ORDER_SECOND, tmr_setup_user_access, NULL); 215291937Skib 216252372Sraystatic unsigned 217252372Srayarm_tmr_get_timecount(struct timecounter *tc) 218252372Sray{ 219252372Sray 220271189Sandrew return (get_cntxct(arm_tmr_sc->physical)); 221252372Sray} 222252372Sray 223252372Sraystatic int 224252372Srayarm_tmr_start(struct eventtimer *et, sbintime_t first, sbintime_t period) 225252372Sray{ 226252372Sray struct arm_tmr_softc *sc; 227252372Sray int counts, ctrl; 228252372Sray 229252372Sray sc = (struct arm_tmr_softc *)et->et_priv; 230252372Sray 231252372Sray if (first != 0) { 232252372Sray counts = ((uint32_t)et->et_frequency * first) >> 32; 233271189Sandrew ctrl = get_ctrl(sc->physical); 234252780Sray ctrl &= ~GT_CTRL_INT_MASK; 235252780Sray ctrl |= GT_CTRL_ENABLE; 236271189Sandrew set_tval(counts, sc->physical); 237271189Sandrew set_ctrl(ctrl, sc->physical); 238252372Sray return (0); 239252372Sray } 240252372Sray 241252372Sray return (EINVAL); 242252372Sray 243252372Sray} 244252372Sray 245252372Sraystatic int 246252372Srayarm_tmr_stop(struct eventtimer *et) 247252372Sray{ 248271189Sandrew struct arm_tmr_softc *sc; 249252372Sray int ctrl; 250252372Sray 251271189Sandrew sc = (struct arm_tmr_softc *)et->et_priv; 252271189Sandrew 253271189Sandrew ctrl = get_ctrl(sc->physical); 254252780Sray ctrl &= GT_CTRL_ENABLE; 255271189Sandrew set_ctrl(ctrl, sc->physical); 256252372Sray 257252372Sray return (0); 258252372Sray} 259252372Sray 260252372Sraystatic int 261252372Srayarm_tmr_intr(void *arg) 262252372Sray{ 263252372Sray struct arm_tmr_softc *sc; 264252372Sray int ctrl; 265252372Sray 266252372Sray sc = (struct arm_tmr_softc *)arg; 267271189Sandrew ctrl = get_ctrl(sc->physical); 268252780Sray if (ctrl & GT_CTRL_INT_STAT) { 269252780Sray ctrl |= GT_CTRL_INT_MASK; 270271189Sandrew set_ctrl(ctrl, sc->physical); 271252372Sray } 272252372Sray 273252372Sray if (sc->et.et_active) 274252372Sray sc->et.et_event_cb(&sc->et, sc->et.et_arg); 275252372Sray 276252372Sray return (FILTER_HANDLED); 277252372Sray} 278252372Sray 279284273Sandrew#ifdef FDT 280252372Sraystatic int 281284273Sandrewarm_tmr_fdt_probe(device_t dev) 282252372Sray{ 283252372Sray 284261410Sian if (!ofw_bus_status_okay(dev)) 285261410Sian return (ENXIO); 286261410Sian 287281072Sandrew if (ofw_bus_is_compatible(dev, "arm,armv7-timer")) { 288281072Sandrew device_set_desc(dev, "ARMv7 Generic Timer"); 289281072Sandrew return (BUS_PROBE_DEFAULT); 290281072Sandrew } else if (ofw_bus_is_compatible(dev, "arm,armv8-timer")) { 291281072Sandrew device_set_desc(dev, "ARMv8 Generic Timer"); 292281072Sandrew return (BUS_PROBE_DEFAULT); 293281072Sandrew } 294252372Sray 295281072Sandrew return (ENXIO); 296252372Sray} 297284273Sandrew#endif 298252372Sray 299284273Sandrew#ifdef DEV_ACPI 300284273Sandrewstatic void 301284273Sandrewarm_tmr_acpi_identify(driver_t *driver, device_t parent) 302284273Sandrew{ 303284273Sandrew ACPI_TABLE_GTDT *gtdt; 304284273Sandrew vm_paddr_t physaddr; 305284273Sandrew device_t dev; 306252372Sray 307284273Sandrew physaddr = acpi_find_table(ACPI_SIG_GTDT); 308284273Sandrew if (physaddr == 0) 309284273Sandrew return; 310284273Sandrew 311284273Sandrew gtdt = acpi_map_table(physaddr, ACPI_SIG_GTDT); 312284273Sandrew if (gtdt == NULL) { 313284273Sandrew device_printf(parent, "gic: Unable to map the GTDT\n"); 314284273Sandrew return; 315284273Sandrew } 316284273Sandrew 317284273Sandrew dev = BUS_ADD_CHILD(parent, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE, 318284273Sandrew "generic_timer", -1); 319284273Sandrew if (dev == NULL) { 320284273Sandrew device_printf(parent, "add gic child failed\n"); 321284273Sandrew goto out; 322284273Sandrew } 323284273Sandrew 324284273Sandrew BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 0, 325284273Sandrew gtdt->SecureEl1Interrupt, 1); 326284273Sandrew BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 1, 327284273Sandrew gtdt->NonSecureEl1Interrupt, 1); 328284273Sandrew BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 2, 329284273Sandrew gtdt->VirtualTimerInterrupt, 1); 330284273Sandrew 331284273Sandrewout: 332284273Sandrew acpi_unmap_table(gtdt); 333284273Sandrew} 334284273Sandrew 335252372Sraystatic int 336284273Sandrewarm_tmr_acpi_probe(device_t dev) 337284273Sandrew{ 338284273Sandrew 339284273Sandrew device_set_desc(dev, "ARM Generic Timer"); 340284273Sandrew return (BUS_PROBE_NOWILDCARD); 341284273Sandrew} 342284273Sandrew#endif 343284273Sandrew 344284273Sandrew 345284273Sandrewstatic int 346252372Srayarm_tmr_attach(device_t dev) 347252372Sray{ 348252372Sray struct arm_tmr_softc *sc; 349284273Sandrew#ifdef FDT 350252372Sray phandle_t node; 351252372Sray pcell_t clock; 352284273Sandrew#endif 353252372Sray int error; 354264065Sbr int i; 355252372Sray 356252372Sray sc = device_get_softc(dev); 357252372Sray if (arm_tmr_sc) 358252372Sray return (ENXIO); 359252372Sray 360284273Sandrew#ifdef FDT 361252372Sray /* Get the base clock frequency */ 362252372Sray node = ofw_bus_get_node(dev); 363284273Sandrew if (node > 0) { 364295470Sandrew error = OF_getencprop(node, "clock-frequency", &clock, 365284273Sandrew sizeof(clock)); 366295633Sandrew if (error > 0) 367295633Sandrew sc->clkfreq = clock; 368264065Sbr } 369284273Sandrew#endif 370264065Sbr 371264065Sbr if (sc->clkfreq == 0) { 372264065Sbr /* Try to get clock frequency from timer */ 373264065Sbr sc->clkfreq = get_freq(); 374264065Sbr } 375264065Sbr 376264065Sbr if (sc->clkfreq == 0) { 377264065Sbr device_printf(dev, "No clock frequency specified\n"); 378252372Sray return (ENXIO); 379252372Sray } 380252372Sray 381264065Sbr if (bus_alloc_resources(dev, timer_spec, sc->res)) { 382264065Sbr device_printf(dev, "could not allocate resources\n"); 383264065Sbr return (ENXIO); 384271189Sandrew } 385252372Sray 386281072Sandrew#ifdef __arm__ 387271189Sandrew sc->physical = true; 388281072Sandrew#else /* __aarch64__ */ 389281072Sandrew sc->physical = false; 390281072Sandrew#endif 391271189Sandrew 392252372Sray arm_tmr_sc = sc; 393252372Sray 394271189Sandrew /* Setup secure, non-secure and virtual IRQs handler */ 395271189Sandrew for (i = 0; i < 3; i++) { 396264065Sbr error = bus_setup_intr(dev, sc->res[i], INTR_TYPE_CLK, 397264065Sbr arm_tmr_intr, NULL, sc, &sc->ihl[i]); 398264065Sbr if (error) { 399264065Sbr device_printf(dev, "Unable to alloc int resource.\n"); 400264065Sbr return (ENXIO); 401264065Sbr } 402252372Sray } 403252372Sray 404291937Skib arm_cpu_fill_vdso_timehands = arm_tmr_fill_vdso_timehands; 405252372Sray 406252427Sray arm_tmr_timecount.tc_frequency = sc->clkfreq; 407252372Sray tc_init(&arm_tmr_timecount); 408252372Sray 409252372Sray sc->et.et_name = "ARM MPCore Eventtimer"; 410252372Sray sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU; 411252372Sray sc->et.et_quality = 1000; 412252372Sray 413252372Sray sc->et.et_frequency = sc->clkfreq; 414252372Sray sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency; 415252372Sray sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency; 416252372Sray sc->et.et_start = arm_tmr_start; 417252372Sray sc->et.et_stop = arm_tmr_stop; 418252372Sray sc->et.et_priv = sc; 419252372Sray et_register(&sc->et); 420252372Sray 421252372Sray return (0); 422252372Sray} 423252372Sray 424284273Sandrew#ifdef FDT 425284273Sandrewstatic device_method_t arm_tmr_fdt_methods[] = { 426284273Sandrew DEVMETHOD(device_probe, arm_tmr_fdt_probe), 427252372Sray DEVMETHOD(device_attach, arm_tmr_attach), 428252372Sray { 0, 0 } 429252372Sray}; 430252372Sray 431284273Sandrewstatic driver_t arm_tmr_fdt_driver = { 432252372Sray "generic_timer", 433284273Sandrew arm_tmr_fdt_methods, 434252372Sray sizeof(struct arm_tmr_softc), 435252372Sray}; 436252372Sray 437284273Sandrewstatic devclass_t arm_tmr_fdt_devclass; 438252372Sray 439284273SandrewEARLY_DRIVER_MODULE(timer, simplebus, arm_tmr_fdt_driver, arm_tmr_fdt_devclass, 440284273Sandrew 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); 441284273SandrewEARLY_DRIVER_MODULE(timer, ofwbus, arm_tmr_fdt_driver, arm_tmr_fdt_devclass, 442284273Sandrew 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); 443284273Sandrew#endif 444252372Sray 445284273Sandrew#ifdef DEV_ACPI 446284273Sandrewstatic device_method_t arm_tmr_acpi_methods[] = { 447284273Sandrew DEVMETHOD(device_identify, arm_tmr_acpi_identify), 448284273Sandrew DEVMETHOD(device_probe, arm_tmr_acpi_probe), 449284273Sandrew DEVMETHOD(device_attach, arm_tmr_attach), 450284273Sandrew { 0, 0 } 451284273Sandrew}; 452284273Sandrew 453284273Sandrewstatic driver_t arm_tmr_acpi_driver = { 454284273Sandrew "generic_timer", 455284273Sandrew arm_tmr_acpi_methods, 456284273Sandrew sizeof(struct arm_tmr_softc), 457284273Sandrew}; 458284273Sandrew 459284273Sandrewstatic devclass_t arm_tmr_acpi_devclass; 460284273Sandrew 461284273SandrewEARLY_DRIVER_MODULE(timer, acpi, arm_tmr_acpi_driver, arm_tmr_acpi_devclass, 462284273Sandrew 0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE); 463284273Sandrew#endif 464284273Sandrew 465252372Srayvoid 466252372SrayDELAY(int usec) 467252372Sray{ 468252372Sray int32_t counts, counts_per_usec; 469252372Sray uint32_t first, last; 470252372Sray 471252372Sray /* 472252372Sray * Check the timers are setup, if not just 473252372Sray * use a for loop for the meantime 474252427Sray */ 475252372Sray if (arm_tmr_sc == NULL) { 476252372Sray for (; usec > 0; usec--) 477252372Sray for (counts = 200; counts > 0; counts--) 478252372Sray /* 479280986Sandrew * Prevent the compiler from optimizing 480252372Sray * out the loop 481252372Sray */ 482252372Sray cpufunc_nullop(); 483252372Sray return; 484252372Sray } 485252372Sray 486252372Sray /* Get the number of times to count */ 487252427Sray counts_per_usec = ((arm_tmr_timecount.tc_frequency / 1000000) + 1); 488252372Sray 489252372Sray /* 490252372Sray * Clamp the timeout at a maximum value (about 32 seconds with 491252372Sray * a 66MHz clock). *Nobody* should be delay()ing for anywhere 492252372Sray * near that length of time and if they are, they should be hung 493252372Sray * out to dry. 494252372Sray */ 495252372Sray if (usec >= (0x80000000U / counts_per_usec)) 496252372Sray counts = (0x80000000U / counts_per_usec) - 1; 497252372Sray else 498252372Sray counts = usec * counts_per_usec; 499252372Sray 500271189Sandrew first = get_cntxct(arm_tmr_sc->physical); 501252372Sray 502252372Sray while (counts > 0) { 503271189Sandrew last = get_cntxct(arm_tmr_sc->physical); 504252372Sray counts -= (int32_t)(last - first); 505252372Sray first = last; 506252372Sray } 507252372Sray} 508291937Skib 509291937Skibstatic uint32_t 510291937Skibarm_tmr_fill_vdso_timehands(struct vdso_timehands *vdso_th, 511291937Skib struct timecounter *tc) 512291937Skib{ 513291937Skib 514291937Skib vdso_th->th_physical = arm_tmr_sc->physical; 515291937Skib bzero(vdso_th->th_res, sizeof(vdso_th->th_res)); 516291937Skib return (tc == &arm_tmr_timecount); 517291937Skib} 518