generic_timer.c revision 299071
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 299071 2016-05-04 16:09:51Z bz $");
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 */
103264065Sbr	{ SYS_RES_IRQ,		2,	RF_ACTIVE },	/* Virt */
104275207Sandrew	{ SYS_RES_IRQ,		3,	RF_ACTIVE | RF_OPTIONAL	}, /* Hyp */
105264065Sbr	{ -1, 0 }
106264065Sbr};
107264065Sbr
108252372Sraystatic timecounter_get_t arm_tmr_get_timecount;
109252372Sray
110252372Sraystatic struct timecounter arm_tmr_timecount = {
111252372Sray	.tc_name           = "ARM MPCore Timecounter",
112252372Sray	.tc_get_timecount  = arm_tmr_get_timecount,
113252372Sray	.tc_poll_pps       = NULL,
114252372Sray	.tc_counter_mask   = ~0u,
115252372Sray	.tc_frequency      = 0,
116252372Sray	.tc_quality        = 1000,
117252372Sray};
118252372Sray
119281072Sandrew#ifdef __arm__
120281072Sandrew#define	get_el0(x)	cp15_## x ##_get()
121281072Sandrew#define	get_el1(x)	cp15_## x ##_get()
122281072Sandrew#define	set_el0(x, val)	cp15_## x ##_set(val)
123281072Sandrew#define	set_el1(x, val)	cp15_## x ##_set(val)
124281072Sandrew#else /* __aarch64__ */
125281072Sandrew#define	get_el0(x)	READ_SPECIALREG(x ##_el0)
126281072Sandrew#define	get_el1(x)	READ_SPECIALREG(x ##_el1)
127281072Sandrew#define	set_el0(x, val)	WRITE_SPECIALREG(x ##_el0, val)
128281072Sandrew#define	set_el1(x, val)	WRITE_SPECIALREG(x ##_el1, val)
129281072Sandrew#endif
130281072Sandrew
131291937Skibstatic uint32_t arm_tmr_fill_vdso_timehands(struct vdso_timehands *vdso_th,
132291937Skib    struct timecounter *tc);
133298854Sandrewstatic void arm_tmr_do_delay(int usec, void *);
134291937Skib
135271189Sandrewstatic int
136252372Srayget_freq(void)
137252372Sray{
138281072Sandrew	return (get_el0(cntfrq));
139252372Sray}
140252372Sray
141271189Sandrewstatic long
142271189Sandrewget_cntxct(bool physical)
143252372Sray{
144271189Sandrew	uint64_t val;
145252372Sray
146252372Sray	isb();
147271189Sandrew	if (physical)
148281072Sandrew		val = get_el0(cntpct);
149271189Sandrew	else
150281072Sandrew		val = get_el0(cntvct);
151252372Sray
152252372Sray	return (val);
153252372Sray}
154252372Sray
155271189Sandrewstatic int
156271189Sandrewset_ctrl(uint32_t val, bool physical)
157252372Sray{
158252372Sray
159271189Sandrew	if (physical)
160281072Sandrew		set_el0(cntp_ctl, val);
161271189Sandrew	else
162281072Sandrew		set_el0(cntv_ctl, val);
163252372Sray	isb();
164252372Sray
165252372Sray	return (0);
166252372Sray}
167252372Sray
168271189Sandrewstatic int
169271189Sandrewset_tval(uint32_t val, bool physical)
170252372Sray{
171252372Sray
172271189Sandrew	if (physical)
173281072Sandrew		set_el0(cntp_tval, val);
174271189Sandrew	else
175281072Sandrew		set_el0(cntv_tval, val);
176252372Sray	isb();
177252372Sray
178252372Sray	return (0);
179252372Sray}
180252372Sray
181271189Sandrewstatic int
182271189Sandrewget_ctrl(bool physical)
183252372Sray{
184252372Sray	uint32_t val;
185252372Sray
186271189Sandrew	if (physical)
187281072Sandrew		val = get_el0(cntp_ctl);
188271189Sandrew	else
189281072Sandrew		val = get_el0(cntv_ctl);
190252372Sray
191252372Sray	return (val);
192252372Sray}
193252372Sray
194271189Sandrewstatic void
195291937Skibsetup_user_access(void *arg __unused)
196252372Sray{
197252372Sray	uint32_t cntkctl;
198252372Sray
199281072Sandrew	cntkctl = get_el1(cntkctl);
200252780Sray	cntkctl &= ~(GT_CNTKCTL_PL0PTEN | GT_CNTKCTL_PL0VTEN |
201291937Skib	    GT_CNTKCTL_EVNTEN);
202291937Skib	if (arm_tmr_sc->physical) {
203291937Skib		cntkctl |= GT_CNTKCTL_PL0PCTEN;
204291937Skib		cntkctl &= ~GT_CNTKCTL_PL0VCTEN;
205291937Skib	} else {
206291937Skib		cntkctl |= GT_CNTKCTL_PL0VCTEN;
207291937Skib		cntkctl &= ~GT_CNTKCTL_PL0PCTEN;
208291937Skib	}
209281072Sandrew	set_el1(cntkctl, cntkctl);
210252372Sray	isb();
211252372Sray}
212252372Sray
213291937Skibstatic void
214291937Skibtmr_setup_user_access(void *arg __unused)
215291937Skib{
216291937Skib
217291937Skib	smp_rendezvous(NULL, setup_user_access, NULL, NULL);
218291937Skib}
219291937SkibSYSINIT(tmr_ua, SI_SUB_SMP, SI_ORDER_SECOND, tmr_setup_user_access, NULL);
220291937Skib
221252372Sraystatic unsigned
222252372Srayarm_tmr_get_timecount(struct timecounter *tc)
223252372Sray{
224252372Sray
225271189Sandrew	return (get_cntxct(arm_tmr_sc->physical));
226252372Sray}
227252372Sray
228252372Sraystatic int
229298648Sbzarm_tmr_start(struct eventtimer *et, sbintime_t first,
230298648Sbz    sbintime_t period __unused)
231252372Sray{
232252372Sray	struct arm_tmr_softc *sc;
233252372Sray	int counts, ctrl;
234252372Sray
235252372Sray	sc = (struct arm_tmr_softc *)et->et_priv;
236252372Sray
237252372Sray	if (first != 0) {
238252372Sray		counts = ((uint32_t)et->et_frequency * first) >> 32;
239271189Sandrew		ctrl = get_ctrl(sc->physical);
240252780Sray		ctrl &= ~GT_CTRL_INT_MASK;
241252780Sray		ctrl |= GT_CTRL_ENABLE;
242271189Sandrew		set_tval(counts, sc->physical);
243271189Sandrew		set_ctrl(ctrl, sc->physical);
244252372Sray		return (0);
245252372Sray	}
246252372Sray
247252372Sray	return (EINVAL);
248252372Sray
249252372Sray}
250252372Sray
251252372Sraystatic int
252252372Srayarm_tmr_stop(struct eventtimer *et)
253252372Sray{
254271189Sandrew	struct arm_tmr_softc *sc;
255252372Sray	int ctrl;
256252372Sray
257271189Sandrew	sc = (struct arm_tmr_softc *)et->et_priv;
258271189Sandrew
259271189Sandrew	ctrl = get_ctrl(sc->physical);
260252780Sray	ctrl &= GT_CTRL_ENABLE;
261271189Sandrew	set_ctrl(ctrl, sc->physical);
262252372Sray
263252372Sray	return (0);
264252372Sray}
265252372Sray
266252372Sraystatic int
267252372Srayarm_tmr_intr(void *arg)
268252372Sray{
269252372Sray	struct arm_tmr_softc *sc;
270252372Sray	int ctrl;
271252372Sray
272252372Sray	sc = (struct arm_tmr_softc *)arg;
273271189Sandrew	ctrl = get_ctrl(sc->physical);
274252780Sray	if (ctrl & GT_CTRL_INT_STAT) {
275252780Sray		ctrl |= GT_CTRL_INT_MASK;
276271189Sandrew		set_ctrl(ctrl, sc->physical);
277252372Sray	}
278252372Sray
279252372Sray	if (sc->et.et_active)
280252372Sray		sc->et.et_event_cb(&sc->et, sc->et.et_arg);
281252372Sray
282252372Sray	return (FILTER_HANDLED);
283252372Sray}
284252372Sray
285284273Sandrew#ifdef FDT
286252372Sraystatic int
287284273Sandrewarm_tmr_fdt_probe(device_t dev)
288252372Sray{
289252372Sray
290261410Sian	if (!ofw_bus_status_okay(dev))
291261410Sian		return (ENXIO);
292261410Sian
293281072Sandrew	if (ofw_bus_is_compatible(dev, "arm,armv7-timer")) {
294281072Sandrew		device_set_desc(dev, "ARMv7 Generic Timer");
295281072Sandrew		return (BUS_PROBE_DEFAULT);
296281072Sandrew	} else if (ofw_bus_is_compatible(dev, "arm,armv8-timer")) {
297281072Sandrew		device_set_desc(dev, "ARMv8 Generic Timer");
298281072Sandrew		return (BUS_PROBE_DEFAULT);
299281072Sandrew	}
300252372Sray
301281072Sandrew	return (ENXIO);
302252372Sray}
303284273Sandrew#endif
304252372Sray
305284273Sandrew#ifdef DEV_ACPI
306284273Sandrewstatic void
307284273Sandrewarm_tmr_acpi_identify(driver_t *driver, device_t parent)
308284273Sandrew{
309284273Sandrew	ACPI_TABLE_GTDT *gtdt;
310284273Sandrew	vm_paddr_t physaddr;
311284273Sandrew	device_t dev;
312252372Sray
313284273Sandrew	physaddr = acpi_find_table(ACPI_SIG_GTDT);
314284273Sandrew	if (physaddr == 0)
315284273Sandrew		return;
316284273Sandrew
317284273Sandrew	gtdt = acpi_map_table(physaddr, ACPI_SIG_GTDT);
318284273Sandrew	if (gtdt == NULL) {
319284273Sandrew		device_printf(parent, "gic: Unable to map the GTDT\n");
320284273Sandrew		return;
321284273Sandrew	}
322284273Sandrew
323284273Sandrew	dev = BUS_ADD_CHILD(parent, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE,
324284273Sandrew	    "generic_timer", -1);
325284273Sandrew	if (dev == NULL) {
326284273Sandrew		device_printf(parent, "add gic child failed\n");
327284273Sandrew		goto out;
328284273Sandrew	}
329284273Sandrew
330284273Sandrew	BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 0,
331284273Sandrew	    gtdt->SecureEl1Interrupt, 1);
332284273Sandrew	BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 1,
333284273Sandrew	    gtdt->NonSecureEl1Interrupt, 1);
334284273Sandrew	BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 2,
335284273Sandrew	    gtdt->VirtualTimerInterrupt, 1);
336284273Sandrew
337284273Sandrewout:
338284273Sandrew	acpi_unmap_table(gtdt);
339284273Sandrew}
340284273Sandrew
341252372Sraystatic int
342284273Sandrewarm_tmr_acpi_probe(device_t dev)
343284273Sandrew{
344284273Sandrew
345284273Sandrew	device_set_desc(dev, "ARM Generic Timer");
346284273Sandrew	return (BUS_PROBE_NOWILDCARD);
347284273Sandrew}
348284273Sandrew#endif
349284273Sandrew
350284273Sandrew
351284273Sandrewstatic int
352252372Srayarm_tmr_attach(device_t dev)
353252372Sray{
354252372Sray	struct arm_tmr_softc *sc;
355284273Sandrew#ifdef FDT
356252372Sray	phandle_t node;
357252372Sray	pcell_t clock;
358284273Sandrew#endif
359252372Sray	int error;
360264065Sbr	int i;
361252372Sray
362252372Sray	sc = device_get_softc(dev);
363252372Sray	if (arm_tmr_sc)
364252372Sray		return (ENXIO);
365252372Sray
366284273Sandrew#ifdef FDT
367252372Sray	/* Get the base clock frequency */
368252372Sray	node = ofw_bus_get_node(dev);
369284273Sandrew	if (node > 0) {
370295470Sandrew		error = OF_getencprop(node, "clock-frequency", &clock,
371284273Sandrew		    sizeof(clock));
372295633Sandrew		if (error > 0)
373295633Sandrew			sc->clkfreq = clock;
374264065Sbr	}
375284273Sandrew#endif
376264065Sbr
377264065Sbr	if (sc->clkfreq == 0) {
378264065Sbr		/* Try to get clock frequency from timer */
379264065Sbr		sc->clkfreq = get_freq();
380264065Sbr	}
381264065Sbr
382264065Sbr	if (sc->clkfreq == 0) {
383264065Sbr		device_printf(dev, "No clock frequency specified\n");
384252372Sray		return (ENXIO);
385252372Sray	}
386252372Sray
387264065Sbr	if (bus_alloc_resources(dev, timer_spec, sc->res)) {
388264065Sbr		device_printf(dev, "could not allocate resources\n");
389264065Sbr		return (ENXIO);
390271189Sandrew	}
391252372Sray
392281072Sandrew#ifdef __arm__
393271189Sandrew	sc->physical = true;
394281072Sandrew#else /* __aarch64__ */
395281072Sandrew	sc->physical = false;
396281072Sandrew#endif
397271189Sandrew
398252372Sray	arm_tmr_sc = sc;
399252372Sray
400271189Sandrew	/* Setup secure, non-secure and virtual IRQs handler */
401271189Sandrew	for (i = 0; i < 3; i++) {
402264065Sbr		error = bus_setup_intr(dev, sc->res[i], INTR_TYPE_CLK,
403264065Sbr		    arm_tmr_intr, NULL, sc, &sc->ihl[i]);
404264065Sbr		if (error) {
405264065Sbr			device_printf(dev, "Unable to alloc int resource.\n");
406264065Sbr			return (ENXIO);
407264065Sbr		}
408252372Sray	}
409252372Sray
410291937Skib	arm_cpu_fill_vdso_timehands = arm_tmr_fill_vdso_timehands;
411252372Sray
412252427Sray	arm_tmr_timecount.tc_frequency = sc->clkfreq;
413252372Sray	tc_init(&arm_tmr_timecount);
414252372Sray
415252372Sray	sc->et.et_name = "ARM MPCore Eventtimer";
416252372Sray	sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU;
417252372Sray	sc->et.et_quality = 1000;
418252372Sray
419252372Sray	sc->et.et_frequency = sc->clkfreq;
420299071Sbz	sc->et.et_min_period = (0x00000010LLU << 32) / sc->et.et_frequency;
421252372Sray	sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency;
422252372Sray	sc->et.et_start = arm_tmr_start;
423252372Sray	sc->et.et_stop = arm_tmr_stop;
424252372Sray	sc->et.et_priv = sc;
425252372Sray	et_register(&sc->et);
426252372Sray
427298854Sandrew#ifdef MULTIDELAY
428298854Sandrew	arm_set_delay(arm_tmr_do_delay, sc);
429298854Sandrew#endif
430298854Sandrew
431252372Sray	return (0);
432252372Sray}
433252372Sray
434284273Sandrew#ifdef FDT
435284273Sandrewstatic device_method_t arm_tmr_fdt_methods[] = {
436284273Sandrew	DEVMETHOD(device_probe,		arm_tmr_fdt_probe),
437252372Sray	DEVMETHOD(device_attach,	arm_tmr_attach),
438252372Sray	{ 0, 0 }
439252372Sray};
440252372Sray
441284273Sandrewstatic driver_t arm_tmr_fdt_driver = {
442252372Sray	"generic_timer",
443284273Sandrew	arm_tmr_fdt_methods,
444252372Sray	sizeof(struct arm_tmr_softc),
445252372Sray};
446252372Sray
447284273Sandrewstatic devclass_t arm_tmr_fdt_devclass;
448252372Sray
449284273SandrewEARLY_DRIVER_MODULE(timer, simplebus, arm_tmr_fdt_driver, arm_tmr_fdt_devclass,
450284273Sandrew    0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
451284273SandrewEARLY_DRIVER_MODULE(timer, ofwbus, arm_tmr_fdt_driver, arm_tmr_fdt_devclass,
452284273Sandrew    0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
453284273Sandrew#endif
454252372Sray
455284273Sandrew#ifdef DEV_ACPI
456284273Sandrewstatic device_method_t arm_tmr_acpi_methods[] = {
457284273Sandrew	DEVMETHOD(device_identify,	arm_tmr_acpi_identify),
458284273Sandrew	DEVMETHOD(device_probe,		arm_tmr_acpi_probe),
459284273Sandrew	DEVMETHOD(device_attach,	arm_tmr_attach),
460284273Sandrew	{ 0, 0 }
461284273Sandrew};
462284273Sandrew
463284273Sandrewstatic driver_t arm_tmr_acpi_driver = {
464284273Sandrew	"generic_timer",
465284273Sandrew	arm_tmr_acpi_methods,
466284273Sandrew	sizeof(struct arm_tmr_softc),
467284273Sandrew};
468284273Sandrew
469284273Sandrewstatic devclass_t arm_tmr_acpi_devclass;
470284273Sandrew
471284273SandrewEARLY_DRIVER_MODULE(timer, acpi, arm_tmr_acpi_driver, arm_tmr_acpi_devclass,
472284273Sandrew    0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
473284273Sandrew#endif
474284273Sandrew
475298854Sandrewstatic void
476298854Sandrewarm_tmr_do_delay(int usec, void *arg)
477252372Sray{
478298854Sandrew	struct arm_tmr_softc *sc = arg;
479252372Sray	int32_t counts, counts_per_usec;
480252372Sray	uint32_t first, last;
481252372Sray
482252372Sray	/* Get the number of times to count */
483252427Sray	counts_per_usec = ((arm_tmr_timecount.tc_frequency / 1000000) + 1);
484252372Sray
485252372Sray	/*
486252372Sray	 * Clamp the timeout at a maximum value (about 32 seconds with
487252372Sray	 * a 66MHz clock). *Nobody* should be delay()ing for anywhere
488252372Sray	 * near that length of time and if they are, they should be hung
489252372Sray	 * out to dry.
490252372Sray	 */
491252372Sray	if (usec >= (0x80000000U / counts_per_usec))
492252372Sray		counts = (0x80000000U / counts_per_usec) - 1;
493252372Sray	else
494252372Sray		counts = usec * counts_per_usec;
495252372Sray
496298854Sandrew	first = get_cntxct(sc->physical);
497252372Sray
498252372Sray	while (counts > 0) {
499298854Sandrew		last = get_cntxct(sc->physical);
500252372Sray		counts -= (int32_t)(last - first);
501252372Sray		first = last;
502252372Sray	}
503252372Sray}
504291937Skib
505298854Sandrew#ifndef MULTIDELAY
506298854Sandrewvoid
507298854SandrewDELAY(int usec)
508298854Sandrew{
509298854Sandrew	int32_t counts;
510298854Sandrew
511298854Sandrew	/*
512298854Sandrew	 * Check the timers are setup, if not just
513298854Sandrew	 * use a for loop for the meantime
514298854Sandrew	 */
515298854Sandrew	if (arm_tmr_sc == NULL) {
516298854Sandrew		for (; usec > 0; usec--)
517298854Sandrew			for (counts = 200; counts > 0; counts--)
518298854Sandrew				/*
519298854Sandrew				 * Prevent the compiler from optimizing
520298854Sandrew				 * out the loop
521298854Sandrew				 */
522298854Sandrew				cpufunc_nullop();
523298854Sandrew	} else
524298854Sandrew		arm_tmr_do_delay(usec, arm_tmr_sc);
525298854Sandrew}
526298854Sandrew#endif
527298854Sandrew
528291937Skibstatic uint32_t
529291937Skibarm_tmr_fill_vdso_timehands(struct vdso_timehands *vdso_th,
530291937Skib    struct timecounter *tc)
531291937Skib{
532291937Skib
533291937Skib	vdso_th->th_physical = arm_tmr_sc->physical;
534291937Skib	bzero(vdso_th->th_res, sizeof(vdso_th->th_res));
535291937Skib	return (tc == &arm_tmr_timecount);
536291937Skib}
537