generic_timer.c revision 284273
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 284273 2015-06-11 15:45:33Z 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>
52252372Sray#include <sys/watchdog.h>
53252372Sray#include <machine/bus.h>
54252372Sray#include <machine/cpu.h>
55252372Sray#include <machine/intr.h>
56252372Sray
57284273Sandrew#ifdef FDT
58252372Sray#include <dev/fdt/fdt_common.h>
59252372Sray#include <dev/ofw/openfirm.h>
60252372Sray#include <dev/ofw/ofw_bus.h>
61252372Sray#include <dev/ofw/ofw_bus_subr.h>
62284273Sandrew#endif
63252372Sray
64284273Sandrew#ifdef DEV_ACPI
65284273Sandrew#include <contrib/dev/acpica/include/acpi.h>
66284273Sandrew#include <dev/acpica/acpivar.h>
67284273Sandrew#endif
68252372Sray
69252780Sray#define	GT_CTRL_ENABLE		(1 << 0)
70252780Sray#define	GT_CTRL_INT_MASK	(1 << 1)
71252780Sray#define	GT_CTRL_INT_STAT	(1 << 2)
72252780Sray#define	GT_REG_CTRL		0
73252780Sray#define	GT_REG_TVAL		1
74252372Sray
75252780Sray#define	GT_CNTKCTL_PL0PTEN	(1 << 9) /* PL0 Physical timer reg access */
76252780Sray#define	GT_CNTKCTL_PL0VTEN	(1 << 8) /* PL0 Virtual timer reg access */
77271189Sandrew#define	GT_CNTKCTL_EVNTI	(0xf << 4) /* Virtual counter event bits */
78252780Sray#define	GT_CNTKCTL_EVNTDIR	(1 << 3) /* Virtual counter event transition */
79252780Sray#define	GT_CNTKCTL_EVNTEN	(1 << 2) /* Enables virtual counter events */
80252780Sray#define	GT_CNTKCTL_PL0VCTEN	(1 << 1) /* PL0 CNTVCT and CNTFRQ access */
81252780Sray#define	GT_CNTKCTL_PL0PCTEN	(1 << 0) /* PL0 CNTPCT and CNTFRQ access */
82252372Sray
83252372Sraystruct arm_tmr_softc {
84264065Sbr	struct resource		*res[4];
85264065Sbr	void			*ihl[4];
86252372Sray	uint32_t		clkfreq;
87252372Sray	struct eventtimer	et;
88271189Sandrew	bool			physical;
89252372Sray};
90252372Sray
91252372Sraystatic struct arm_tmr_softc *arm_tmr_sc = NULL;
92252372Sray
93264065Sbrstatic struct resource_spec timer_spec[] = {
94264065Sbr	{ SYS_RES_IRQ,		0,	RF_ACTIVE },	/* Secure */
95264065Sbr	{ SYS_RES_IRQ,		1,	RF_ACTIVE },	/* Non-secure */
96264065Sbr	{ SYS_RES_IRQ,		2,	RF_ACTIVE },	/* Virt */
97275207Sandrew	{ SYS_RES_IRQ,		3,	RF_ACTIVE | RF_OPTIONAL	}, /* Hyp */
98264065Sbr	{ -1, 0 }
99264065Sbr};
100264065Sbr
101252372Sraystatic timecounter_get_t arm_tmr_get_timecount;
102252372Sray
103252372Sraystatic struct timecounter arm_tmr_timecount = {
104252372Sray	.tc_name           = "ARM MPCore Timecounter",
105252372Sray	.tc_get_timecount  = arm_tmr_get_timecount,
106252372Sray	.tc_poll_pps       = NULL,
107252372Sray	.tc_counter_mask   = ~0u,
108252372Sray	.tc_frequency      = 0,
109252372Sray	.tc_quality        = 1000,
110252372Sray};
111252372Sray
112281072Sandrew#ifdef __arm__
113281072Sandrew#define	get_el0(x)	cp15_## x ##_get()
114281072Sandrew#define	get_el1(x)	cp15_## x ##_get()
115281072Sandrew#define	set_el0(x, val)	cp15_## x ##_set(val)
116281072Sandrew#define	set_el1(x, val)	cp15_## x ##_set(val)
117281072Sandrew#else /* __aarch64__ */
118281072Sandrew#define	get_el0(x)	READ_SPECIALREG(x ##_el0)
119281072Sandrew#define	get_el1(x)	READ_SPECIALREG(x ##_el1)
120281072Sandrew#define	set_el0(x, val)	WRITE_SPECIALREG(x ##_el0, val)
121281072Sandrew#define	set_el1(x, val)	WRITE_SPECIALREG(x ##_el1, val)
122281072Sandrew#endif
123281072Sandrew
124271189Sandrewstatic int
125252372Srayget_freq(void)
126252372Sray{
127281072Sandrew	return (get_el0(cntfrq));
128252372Sray}
129252372Sray
130271189Sandrewstatic long
131271189Sandrewget_cntxct(bool physical)
132252372Sray{
133271189Sandrew	uint64_t val;
134252372Sray
135252372Sray	isb();
136271189Sandrew	if (physical)
137281072Sandrew		val = get_el0(cntpct);
138271189Sandrew	else
139281072Sandrew		val = get_el0(cntvct);
140252372Sray
141252372Sray	return (val);
142252372Sray}
143252372Sray
144271189Sandrewstatic int
145271189Sandrewset_ctrl(uint32_t val, bool physical)
146252372Sray{
147252372Sray
148271189Sandrew	if (physical)
149281072Sandrew		set_el0(cntp_ctl, val);
150271189Sandrew	else
151281072Sandrew		set_el0(cntv_ctl, val);
152252372Sray	isb();
153252372Sray
154252372Sray	return (0);
155252372Sray}
156252372Sray
157271189Sandrewstatic int
158271189Sandrewset_tval(uint32_t val, bool physical)
159252372Sray{
160252372Sray
161271189Sandrew	if (physical)
162281072Sandrew		set_el0(cntp_tval, val);
163271189Sandrew	else
164281072Sandrew		set_el0(cntv_tval, val);
165252372Sray	isb();
166252372Sray
167252372Sray	return (0);
168252372Sray}
169252372Sray
170271189Sandrewstatic int
171271189Sandrewget_ctrl(bool physical)
172252372Sray{
173252372Sray	uint32_t val;
174252372Sray
175271189Sandrew	if (physical)
176281072Sandrew		val = get_el0(cntp_ctl);
177271189Sandrew	else
178281072Sandrew		val = get_el0(cntv_ctl);
179252372Sray
180252372Sray	return (val);
181252372Sray}
182252372Sray
183271189Sandrewstatic void
184252372Sraydisable_user_access(void)
185252372Sray{
186252372Sray	uint32_t cntkctl;
187252372Sray
188281072Sandrew	cntkctl = get_el1(cntkctl);
189252780Sray	cntkctl &= ~(GT_CNTKCTL_PL0PTEN | GT_CNTKCTL_PL0VTEN |
190252780Sray	    GT_CNTKCTL_EVNTEN | GT_CNTKCTL_PL0VCTEN | GT_CNTKCTL_PL0PCTEN);
191281072Sandrew	set_el1(cntkctl, cntkctl);
192252372Sray	isb();
193252372Sray}
194252372Sray
195252372Sraystatic unsigned
196252372Srayarm_tmr_get_timecount(struct timecounter *tc)
197252372Sray{
198252372Sray
199271189Sandrew	return (get_cntxct(arm_tmr_sc->physical));
200252372Sray}
201252372Sray
202252372Sraystatic int
203252372Srayarm_tmr_start(struct eventtimer *et, sbintime_t first, sbintime_t period)
204252372Sray{
205252372Sray	struct arm_tmr_softc *sc;
206252372Sray	int counts, ctrl;
207252372Sray
208252372Sray	sc = (struct arm_tmr_softc *)et->et_priv;
209252372Sray
210252372Sray	if (first != 0) {
211252372Sray		counts = ((uint32_t)et->et_frequency * first) >> 32;
212271189Sandrew		ctrl = get_ctrl(sc->physical);
213252780Sray		ctrl &= ~GT_CTRL_INT_MASK;
214252780Sray		ctrl |= GT_CTRL_ENABLE;
215271189Sandrew		set_tval(counts, sc->physical);
216271189Sandrew		set_ctrl(ctrl, sc->physical);
217252372Sray		return (0);
218252372Sray	}
219252372Sray
220252372Sray	return (EINVAL);
221252372Sray
222252372Sray}
223252372Sray
224252372Sraystatic int
225252372Srayarm_tmr_stop(struct eventtimer *et)
226252372Sray{
227271189Sandrew	struct arm_tmr_softc *sc;
228252372Sray	int ctrl;
229252372Sray
230271189Sandrew	sc = (struct arm_tmr_softc *)et->et_priv;
231271189Sandrew
232271189Sandrew	ctrl = get_ctrl(sc->physical);
233252780Sray	ctrl &= GT_CTRL_ENABLE;
234271189Sandrew	set_ctrl(ctrl, sc->physical);
235252372Sray
236252372Sray	return (0);
237252372Sray}
238252372Sray
239252372Sraystatic int
240252372Srayarm_tmr_intr(void *arg)
241252372Sray{
242252372Sray	struct arm_tmr_softc *sc;
243252372Sray	int ctrl;
244252372Sray
245252372Sray	sc = (struct arm_tmr_softc *)arg;
246271189Sandrew	ctrl = get_ctrl(sc->physical);
247252780Sray	if (ctrl & GT_CTRL_INT_STAT) {
248252780Sray		ctrl |= GT_CTRL_INT_MASK;
249271189Sandrew		set_ctrl(ctrl, sc->physical);
250252372Sray	}
251252372Sray
252252372Sray	if (sc->et.et_active)
253252372Sray		sc->et.et_event_cb(&sc->et, sc->et.et_arg);
254252372Sray
255252372Sray	return (FILTER_HANDLED);
256252372Sray}
257252372Sray
258284273Sandrew#ifdef FDT
259252372Sraystatic int
260284273Sandrewarm_tmr_fdt_probe(device_t dev)
261252372Sray{
262252372Sray
263261410Sian	if (!ofw_bus_status_okay(dev))
264261410Sian		return (ENXIO);
265261410Sian
266281072Sandrew	if (ofw_bus_is_compatible(dev, "arm,armv7-timer")) {
267281072Sandrew		device_set_desc(dev, "ARMv7 Generic Timer");
268281072Sandrew		return (BUS_PROBE_DEFAULT);
269281072Sandrew	} else if (ofw_bus_is_compatible(dev, "arm,armv8-timer")) {
270281072Sandrew		device_set_desc(dev, "ARMv8 Generic Timer");
271281072Sandrew		return (BUS_PROBE_DEFAULT);
272281072Sandrew	}
273252372Sray
274281072Sandrew	return (ENXIO);
275252372Sray}
276284273Sandrew#endif
277252372Sray
278284273Sandrew#ifdef DEV_ACPI
279284273Sandrewstatic void
280284273Sandrewarm_tmr_acpi_identify(driver_t *driver, device_t parent)
281284273Sandrew{
282284273Sandrew	ACPI_TABLE_GTDT *gtdt;
283284273Sandrew	vm_paddr_t physaddr;
284284273Sandrew	device_t dev;
285252372Sray
286284273Sandrew	physaddr = acpi_find_table(ACPI_SIG_GTDT);
287284273Sandrew	if (physaddr == 0)
288284273Sandrew		return;
289284273Sandrew
290284273Sandrew	gtdt = acpi_map_table(physaddr, ACPI_SIG_GTDT);
291284273Sandrew	if (gtdt == NULL) {
292284273Sandrew		device_printf(parent, "gic: Unable to map the GTDT\n");
293284273Sandrew		return;
294284273Sandrew	}
295284273Sandrew
296284273Sandrew	dev = BUS_ADD_CHILD(parent, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE,
297284273Sandrew	    "generic_timer", -1);
298284273Sandrew	if (dev == NULL) {
299284273Sandrew		device_printf(parent, "add gic child failed\n");
300284273Sandrew		goto out;
301284273Sandrew	}
302284273Sandrew
303284273Sandrew	BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 0,
304284273Sandrew	    gtdt->SecureEl1Interrupt, 1);
305284273Sandrew	BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 1,
306284273Sandrew	    gtdt->NonSecureEl1Interrupt, 1);
307284273Sandrew	BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 2,
308284273Sandrew	    gtdt->VirtualTimerInterrupt, 1);
309284273Sandrew
310284273Sandrewout:
311284273Sandrew	acpi_unmap_table(gtdt);
312284273Sandrew}
313284273Sandrew
314252372Sraystatic int
315284273Sandrewarm_tmr_acpi_probe(device_t dev)
316284273Sandrew{
317284273Sandrew
318284273Sandrew	device_set_desc(dev, "ARM Generic Timer");
319284273Sandrew	return (BUS_PROBE_NOWILDCARD);
320284273Sandrew}
321284273Sandrew#endif
322284273Sandrew
323284273Sandrew
324284273Sandrewstatic int
325252372Srayarm_tmr_attach(device_t dev)
326252372Sray{
327252372Sray	struct arm_tmr_softc *sc;
328284273Sandrew#ifdef FDT
329252372Sray	phandle_t node;
330252372Sray	pcell_t clock;
331284273Sandrew#endif
332252372Sray	int error;
333264065Sbr	int i;
334252372Sray
335252372Sray	sc = device_get_softc(dev);
336252372Sray	if (arm_tmr_sc)
337252372Sray		return (ENXIO);
338252372Sray
339284273Sandrew#ifdef FDT
340252372Sray	/* Get the base clock frequency */
341252372Sray	node = ofw_bus_get_node(dev);
342284273Sandrew	if (node > 0) {
343284273Sandrew		error = OF_getprop(node, "clock-frequency", &clock,
344284273Sandrew		    sizeof(clock));
345284273Sandrew		if (error > 0) {
346284273Sandrew			sc->clkfreq = fdt32_to_cpu(clock);
347284273Sandrew		}
348264065Sbr	}
349284273Sandrew#endif
350264065Sbr
351264065Sbr	if (sc->clkfreq == 0) {
352264065Sbr		/* Try to get clock frequency from timer */
353264065Sbr		sc->clkfreq = get_freq();
354264065Sbr	}
355264065Sbr
356264065Sbr	if (sc->clkfreq == 0) {
357264065Sbr		device_printf(dev, "No clock frequency specified\n");
358252372Sray		return (ENXIO);
359252372Sray	}
360252372Sray
361264065Sbr	if (bus_alloc_resources(dev, timer_spec, sc->res)) {
362264065Sbr		device_printf(dev, "could not allocate resources\n");
363264065Sbr		return (ENXIO);
364271189Sandrew	}
365252372Sray
366281072Sandrew#ifdef __arm__
367271189Sandrew	sc->physical = true;
368281072Sandrew#else /* __aarch64__ */
369281072Sandrew	sc->physical = false;
370281072Sandrew#endif
371271189Sandrew
372252372Sray	arm_tmr_sc = sc;
373252372Sray
374271189Sandrew	/* Setup secure, non-secure and virtual IRQs handler */
375271189Sandrew	for (i = 0; i < 3; i++) {
376264065Sbr		error = bus_setup_intr(dev, sc->res[i], INTR_TYPE_CLK,
377264065Sbr		    arm_tmr_intr, NULL, sc, &sc->ihl[i]);
378264065Sbr		if (error) {
379264065Sbr			device_printf(dev, "Unable to alloc int resource.\n");
380264065Sbr			return (ENXIO);
381264065Sbr		}
382252372Sray	}
383252372Sray
384252372Sray	disable_user_access();
385252372Sray
386252427Sray	arm_tmr_timecount.tc_frequency = sc->clkfreq;
387252372Sray	tc_init(&arm_tmr_timecount);
388252372Sray
389252372Sray	sc->et.et_name = "ARM MPCore Eventtimer";
390252372Sray	sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERCPU;
391252372Sray	sc->et.et_quality = 1000;
392252372Sray
393252372Sray	sc->et.et_frequency = sc->clkfreq;
394252372Sray	sc->et.et_min_period = (0x00000002LLU << 32) / sc->et.et_frequency;
395252372Sray	sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency;
396252372Sray	sc->et.et_start = arm_tmr_start;
397252372Sray	sc->et.et_stop = arm_tmr_stop;
398252372Sray	sc->et.et_priv = sc;
399252372Sray	et_register(&sc->et);
400252372Sray
401252372Sray	return (0);
402252372Sray}
403252372Sray
404284273Sandrew#ifdef FDT
405284273Sandrewstatic device_method_t arm_tmr_fdt_methods[] = {
406284273Sandrew	DEVMETHOD(device_probe,		arm_tmr_fdt_probe),
407252372Sray	DEVMETHOD(device_attach,	arm_tmr_attach),
408252372Sray	{ 0, 0 }
409252372Sray};
410252372Sray
411284273Sandrewstatic driver_t arm_tmr_fdt_driver = {
412252372Sray	"generic_timer",
413284273Sandrew	arm_tmr_fdt_methods,
414252372Sray	sizeof(struct arm_tmr_softc),
415252372Sray};
416252372Sray
417284273Sandrewstatic devclass_t arm_tmr_fdt_devclass;
418252372Sray
419284273SandrewEARLY_DRIVER_MODULE(timer, simplebus, arm_tmr_fdt_driver, arm_tmr_fdt_devclass,
420284273Sandrew    0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
421284273SandrewEARLY_DRIVER_MODULE(timer, ofwbus, arm_tmr_fdt_driver, arm_tmr_fdt_devclass,
422284273Sandrew    0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
423284273Sandrew#endif
424252372Sray
425284273Sandrew#ifdef DEV_ACPI
426284273Sandrewstatic device_method_t arm_tmr_acpi_methods[] = {
427284273Sandrew	DEVMETHOD(device_identify,	arm_tmr_acpi_identify),
428284273Sandrew	DEVMETHOD(device_probe,		arm_tmr_acpi_probe),
429284273Sandrew	DEVMETHOD(device_attach,	arm_tmr_attach),
430284273Sandrew	{ 0, 0 }
431284273Sandrew};
432284273Sandrew
433284273Sandrewstatic driver_t arm_tmr_acpi_driver = {
434284273Sandrew	"generic_timer",
435284273Sandrew	arm_tmr_acpi_methods,
436284273Sandrew	sizeof(struct arm_tmr_softc),
437284273Sandrew};
438284273Sandrew
439284273Sandrewstatic devclass_t arm_tmr_acpi_devclass;
440284273Sandrew
441284273SandrewEARLY_DRIVER_MODULE(timer, acpi, arm_tmr_acpi_driver, arm_tmr_acpi_devclass,
442284273Sandrew    0, 0, BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
443284273Sandrew#endif
444284273Sandrew
445252372Srayvoid
446252372SrayDELAY(int usec)
447252372Sray{
448252372Sray	int32_t counts, counts_per_usec;
449252372Sray	uint32_t first, last;
450252372Sray
451252372Sray	/*
452252372Sray	 * Check the timers are setup, if not just
453252372Sray	 * use a for loop for the meantime
454252427Sray	 */
455252372Sray	if (arm_tmr_sc == NULL) {
456252372Sray		for (; usec > 0; usec--)
457252372Sray			for (counts = 200; counts > 0; counts--)
458252372Sray				/*
459280986Sandrew				 * Prevent the compiler from optimizing
460252372Sray				 * out the loop
461252372Sray				 */
462252372Sray				cpufunc_nullop();
463252372Sray		return;
464252372Sray	}
465252372Sray
466252372Sray	/* Get the number of times to count */
467252427Sray	counts_per_usec = ((arm_tmr_timecount.tc_frequency / 1000000) + 1);
468252372Sray
469252372Sray	/*
470252372Sray	 * Clamp the timeout at a maximum value (about 32 seconds with
471252372Sray	 * a 66MHz clock). *Nobody* should be delay()ing for anywhere
472252372Sray	 * near that length of time and if they are, they should be hung
473252372Sray	 * out to dry.
474252372Sray	 */
475252372Sray	if (usec >= (0x80000000U / counts_per_usec))
476252372Sray		counts = (0x80000000U / counts_per_usec) - 1;
477252372Sray	else
478252372Sray		counts = usec * counts_per_usec;
479252372Sray
480271189Sandrew	first = get_cntxct(arm_tmr_sc->physical);
481252372Sray
482252372Sray	while (counts > 0) {
483271189Sandrew		last = get_cntxct(arm_tmr_sc->physical);
484252372Sray		counts -= (int32_t)(last - first);
485252372Sray		first = last;
486252372Sray	}
487252372Sray}
488