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