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