xref: /freebsd/sys/arm/allwinner/aw_timer.c (revision 9257fe124f0e640ca5cab77754117bd2e55f28d5)
1c4530dffSMitchell Horne /*-
2c4530dffSMitchell Horne  * Copyright (c) 2012 Ganbold Tsagaankhuu <ganbold@freebsd.org>
3c4530dffSMitchell Horne  * All rights reserved.
4c4530dffSMitchell Horne  *
5c4530dffSMitchell Horne  * Redistribution and use in source and binary forms, with or without
6c4530dffSMitchell Horne  * modification, are permitted provided that the following conditions
7c4530dffSMitchell Horne  * are met:
8c4530dffSMitchell Horne  * 1. Redistributions of source code must retain the above copyright
9c4530dffSMitchell Horne  *    notice, this list of conditions and the following disclaimer.
10c4530dffSMitchell Horne  * 2. Redistributions in binary form must reproduce the above copyright
11c4530dffSMitchell Horne  *    notice, this list of conditions and the following disclaimer in the
12c4530dffSMitchell Horne  *    documentation and/or other materials provided with the distribution.
13c4530dffSMitchell Horne  *
14c4530dffSMitchell Horne  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15c4530dffSMitchell Horne  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16c4530dffSMitchell Horne  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17c4530dffSMitchell Horne  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18c4530dffSMitchell Horne  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19c4530dffSMitchell Horne  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20c4530dffSMitchell Horne  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21c4530dffSMitchell Horne  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22c4530dffSMitchell Horne  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23c4530dffSMitchell Horne  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24c4530dffSMitchell Horne  * SUCH DAMAGE.
25c4530dffSMitchell Horne  */
26c4530dffSMitchell Horne 
27c4530dffSMitchell Horne #include <sys/param.h>
28c4530dffSMitchell Horne #include <sys/systm.h>
29c4530dffSMitchell Horne #include <sys/bus.h>
30c4530dffSMitchell Horne #include <sys/kernel.h>
31c4530dffSMitchell Horne #include <sys/malloc.h>
32c4530dffSMitchell Horne #include <sys/module.h>
33c4530dffSMitchell Horne #include <sys/rman.h>
34c4530dffSMitchell Horne #include <sys/timeet.h>
35c4530dffSMitchell Horne #include <sys/timetc.h>
36c4530dffSMitchell Horne #include <sys/watchdog.h>
37c4530dffSMitchell Horne 
38c4530dffSMitchell Horne #include <machine/bus.h>
39c4530dffSMitchell Horne #include <machine/intr.h>
40c4530dffSMitchell Horne #include <machine/machdep.h>
41c4530dffSMitchell Horne 
42c4530dffSMitchell Horne #include <dev/ofw/openfirm.h>
43c4530dffSMitchell Horne #include <dev/ofw/ofw_bus.h>
44c4530dffSMitchell Horne #include <dev/ofw/ofw_bus_subr.h>
45c4530dffSMitchell Horne 
46c4530dffSMitchell Horne #include <dev/clk/clk.h>
47c4530dffSMitchell Horne 
48*9257fe12SMitchell Horne #if defined(__aarch64__) || defined(__riscv)
49c4530dffSMitchell Horne #include "opt_soc.h"
50c4530dffSMitchell Horne #else
51c4530dffSMitchell Horne #include <arm/allwinner/aw_machdep.h>
52c4530dffSMitchell Horne #endif
53c4530dffSMitchell Horne 
54c4530dffSMitchell Horne /**
55c4530dffSMitchell Horne  * Timer registers addr
56c4530dffSMitchell Horne  *
57c4530dffSMitchell Horne  */
58c4530dffSMitchell Horne #define	TIMER_IRQ_EN_REG 	0x00
59c4530dffSMitchell Horne #define	 TIMER_IRQ_ENABLE(x)	(1 << x)
60c4530dffSMitchell Horne 
61c4530dffSMitchell Horne #define	TIMER_IRQ_STA_REG 	0x04
62c4530dffSMitchell Horne #define	 TIMER_IRQ_PENDING(x)	(1 << x)
63c4530dffSMitchell Horne 
64c4530dffSMitchell Horne /*
65c4530dffSMitchell Horne  * On A10, A13, A20 and A31/A31s 6 timers are available
66c4530dffSMitchell Horne  */
67c4530dffSMitchell Horne #define	TIMER_CTRL_REG(x)		(0x10 + 0x10 * x)
68c4530dffSMitchell Horne #define	 TIMER_CTRL_START		(1 << 0)
69c4530dffSMitchell Horne #define	 TIMER_CTRL_AUTORELOAD		(1 << 1)
70c4530dffSMitchell Horne #define	 TIMER_CTRL_CLKSRC_MASK		(3 << 2)
71c4530dffSMitchell Horne #define	 TIMER_CTRL_OSC24M		(1 << 2)
72c4530dffSMitchell Horne #define	 TIMER_CTRL_PRESCALAR_MASK	(0x7 << 4)
73c4530dffSMitchell Horne #define	 TIMER_CTRL_PRESCALAR(x)	((x - 1) << 4)
74c4530dffSMitchell Horne #define	 TIMER_CTRL_MODE_MASK		(1 << 7)
75c4530dffSMitchell Horne #define	 TIMER_CTRL_MODE_SINGLE		(1 << 7)
76c4530dffSMitchell Horne #define	 TIMER_CTRL_MODE_CONTINUOUS	(0 << 7)
77c4530dffSMitchell Horne #define	TIMER_INTV_REG(x)		(0x14 + 0x10 * x)
78c4530dffSMitchell Horne #define	TIMER_CURV_REG(x)		(0x18 + 0x10 * x)
79c4530dffSMitchell Horne 
80c4530dffSMitchell Horne /* 64 bit counter, available in A10 and A13 */
81c4530dffSMitchell Horne #define	CNT64_CTRL_REG		0xa0
82c4530dffSMitchell Horne #define	 CNT64_CTRL_RL_EN	0x02 /* read latch enable */
83c4530dffSMitchell Horne #define	CNT64_LO_REG		0xa4
84c4530dffSMitchell Horne #define	CNT64_HI_REG		0xa8
85c4530dffSMitchell Horne 
86c4530dffSMitchell Horne #define	SYS_TIMER_CLKSRC	24000000 /* clock source */
87c4530dffSMitchell Horne 
88c4530dffSMitchell Horne enum aw_timer_type {
89c4530dffSMitchell Horne 	A10_TIMER = 1,
90c4530dffSMitchell Horne 	A23_TIMER,
91*9257fe12SMitchell Horne 	D1_TIMER,
92c4530dffSMitchell Horne };
93c4530dffSMitchell Horne 
94c4530dffSMitchell Horne struct aw_timer_softc {
95c4530dffSMitchell Horne 	device_t 	sc_dev;
96c4530dffSMitchell Horne 	struct resource *res[2];
97c4530dffSMitchell Horne 	void 		*sc_ih;		/* interrupt handler */
98c4530dffSMitchell Horne 	uint32_t 	sc_period;
99c4530dffSMitchell Horne 	uint64_t 	timer0_freq;
100c4530dffSMitchell Horne 	struct eventtimer	et;
101c4530dffSMitchell Horne 	enum aw_timer_type	type;
102c4530dffSMitchell Horne };
103c4530dffSMitchell Horne 
104c4530dffSMitchell Horne #define timer_read_4(sc, reg)	\
105c4530dffSMitchell Horne 	bus_read_4(sc->res[AW_TIMER_MEMRES], reg)
106c4530dffSMitchell Horne #define timer_write_4(sc, reg, val)	\
107c4530dffSMitchell Horne 	bus_write_4(sc->res[AW_TIMER_MEMRES], reg, val)
108c4530dffSMitchell Horne 
109c4530dffSMitchell Horne #if defined(__arm__)
110c4530dffSMitchell Horne static u_int	a10_timer_get_timecount(struct timecounter *);
111c4530dffSMitchell Horne static uint64_t	a10_timer_read_counter64(struct aw_timer_softc *sc);
112c4530dffSMitchell Horne static void	a10_timer_timecounter_setup(struct aw_timer_softc *sc);
113*9257fe12SMitchell Horne #endif
114c4530dffSMitchell Horne 
115*9257fe12SMitchell Horne #if defined(__arm__) || defined(__riscv)
116*9257fe12SMitchell Horne #define	USE_EVENTTIMER
117c4530dffSMitchell Horne static void	aw_timer_eventtimer_setup(struct aw_timer_softc *sc);
118c4530dffSMitchell Horne static int	aw_timer_eventtimer_start(struct eventtimer *, sbintime_t first,
119c4530dffSMitchell Horne 		    sbintime_t period);
120c4530dffSMitchell Horne static int	aw_timer_eventtimer_stop(struct eventtimer *);
121c4530dffSMitchell Horne #endif
122c4530dffSMitchell Horne 
123c4530dffSMitchell Horne #if defined(__aarch64__)
124c4530dffSMitchell Horne static void a23_timer_timecounter_setup(struct aw_timer_softc *sc);
125c4530dffSMitchell Horne static u_int a23_timer_get_timecount(struct timecounter *tc);
126c4530dffSMitchell Horne #endif
127c4530dffSMitchell Horne 
128c4530dffSMitchell Horne static int aw_timer_irq(void *);
129c4530dffSMitchell Horne static int aw_timer_probe(device_t);
130c4530dffSMitchell Horne static int aw_timer_attach(device_t);
131c4530dffSMitchell Horne 
132c4530dffSMitchell Horne #if defined(__arm__)
133*9257fe12SMitchell Horne #define	AW_TIMER_QUALITY	1000
134*9257fe12SMitchell Horne 
135c4530dffSMitchell Horne static delay_func a10_timer_delay;
136c4530dffSMitchell Horne 
137c4530dffSMitchell Horne static struct timecounter a10_timer_timecounter = {
138c4530dffSMitchell Horne 	.tc_name           = "aw_timer timer0",
139c4530dffSMitchell Horne 	.tc_get_timecount  = a10_timer_get_timecount,
140c4530dffSMitchell Horne 	.tc_counter_mask   = ~0u,
141c4530dffSMitchell Horne 	.tc_frequency      = 0,
142*9257fe12SMitchell Horne 	.tc_quality        = AW_TIMER_QUALITY,
143c4530dffSMitchell Horne };
144c4530dffSMitchell Horne #endif
145c4530dffSMitchell Horne 
146c4530dffSMitchell Horne #if defined(__aarch64__)
147*9257fe12SMitchell Horne /* We want it to be selected over the arm generic timecounter */
148*9257fe12SMitchell Horne #define	AW_TIMER_QUALITY	2000
149*9257fe12SMitchell Horne 
150c4530dffSMitchell Horne static struct timecounter a23_timer_timecounter = {
151c4530dffSMitchell Horne 	.tc_name           = "aw_timer timer0",
152c4530dffSMitchell Horne 	.tc_get_timecount  = a23_timer_get_timecount,
153c4530dffSMitchell Horne 	.tc_counter_mask   = ~0u,
154c4530dffSMitchell Horne 	.tc_frequency      = 0,
155*9257fe12SMitchell Horne 	.tc_quality        = AW_TIMER_QUALITY,
156c4530dffSMitchell Horne };
157c4530dffSMitchell Horne #endif
158c4530dffSMitchell Horne 
159*9257fe12SMitchell Horne #if defined(__riscv)
160*9257fe12SMitchell Horne /* We want it to be selected over the generic RISC-V eventtimer */
161*9257fe12SMitchell Horne #define	AW_TIMER_QUALITY	2000
162*9257fe12SMitchell Horne #endif
163*9257fe12SMitchell Horne 
164c4530dffSMitchell Horne #define	AW_TIMER_MEMRES		0
165c4530dffSMitchell Horne #define	AW_TIMER_IRQRES		1
166c4530dffSMitchell Horne 
167c4530dffSMitchell Horne static struct resource_spec aw_timer_spec[] = {
168c4530dffSMitchell Horne 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
169c4530dffSMitchell Horne 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
170c4530dffSMitchell Horne 	{ -1, 0 }
171c4530dffSMitchell Horne };
172c4530dffSMitchell Horne 
173c4530dffSMitchell Horne static struct ofw_compat_data compat_data[] = {
174c4530dffSMitchell Horne 	{"allwinner,sun4i-a10-timer", A10_TIMER},
175c4530dffSMitchell Horne #if defined(__aarch64__)
176c4530dffSMitchell Horne 	{"allwinner,sun8i-a23-timer", A23_TIMER},
177*9257fe12SMitchell Horne #elif defined(__riscv)
178*9257fe12SMitchell Horne 	{"allwinner,sun20i-d1-timer", D1_TIMER},
179c4530dffSMitchell Horne #endif
180c4530dffSMitchell Horne 	{NULL, 0},
181c4530dffSMitchell Horne };
182c4530dffSMitchell Horne 
183c4530dffSMitchell Horne static int
184c4530dffSMitchell Horne aw_timer_probe(device_t dev)
185c4530dffSMitchell Horne {
186c4530dffSMitchell Horne 	if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
187c4530dffSMitchell Horne 		return (ENXIO);
188c4530dffSMitchell Horne 
189c4530dffSMitchell Horne #if defined(__arm__)
190c4530dffSMitchell Horne 	/* For SoC >= A10 we have the ARM Timecounter/Eventtimer */
191c4530dffSMitchell Horne 	u_int soc_family = allwinner_soc_family();
192c4530dffSMitchell Horne 	if (soc_family != ALLWINNERSOC_SUN4I &&
193c4530dffSMitchell Horne 	    soc_family != ALLWINNERSOC_SUN5I)
194c4530dffSMitchell Horne 		return (ENXIO);
195c4530dffSMitchell Horne #endif
196c4530dffSMitchell Horne 
197c4530dffSMitchell Horne 	device_set_desc(dev, "Allwinner timer");
198c4530dffSMitchell Horne 	return (BUS_PROBE_DEFAULT);
199c4530dffSMitchell Horne }
200c4530dffSMitchell Horne 
201c4530dffSMitchell Horne static int
202c4530dffSMitchell Horne aw_timer_attach(device_t dev)
203c4530dffSMitchell Horne {
204c4530dffSMitchell Horne 	struct aw_timer_softc *sc;
205c4530dffSMitchell Horne 	clk_t clk;
206c4530dffSMitchell Horne 	int err;
207c4530dffSMitchell Horne 
208c4530dffSMitchell Horne 	sc = device_get_softc(dev);
209c4530dffSMitchell Horne 	sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data;
210c4530dffSMitchell Horne 
211c4530dffSMitchell Horne 	if (bus_alloc_resources(dev, aw_timer_spec, sc->res)) {
212c4530dffSMitchell Horne 		device_printf(dev, "could not allocate resources\n");
213c4530dffSMitchell Horne 		return (ENXIO);
214c4530dffSMitchell Horne 	}
215c4530dffSMitchell Horne 
216c4530dffSMitchell Horne 	sc->sc_dev = dev;
217c4530dffSMitchell Horne 
218c4530dffSMitchell Horne 	/* Setup and enable the timer interrupt */
219c4530dffSMitchell Horne 	err = bus_setup_intr(dev, sc->res[AW_TIMER_IRQRES], INTR_TYPE_CLK,
220c4530dffSMitchell Horne 	    aw_timer_irq, NULL, sc, &sc->sc_ih);
221c4530dffSMitchell Horne 	if (err != 0) {
222c4530dffSMitchell Horne 		bus_release_resources(dev, aw_timer_spec, sc->res);
223c4530dffSMitchell Horne 		device_printf(dev, "Unable to setup the clock irq handler, "
224c4530dffSMitchell Horne 		    "err = %d\n", err);
225c4530dffSMitchell Horne 		return (ENXIO);
226c4530dffSMitchell Horne 	}
227c4530dffSMitchell Horne 
228c4530dffSMitchell Horne 	if (clk_get_by_ofw_index(dev, 0, 0, &clk) != 0) {
229c4530dffSMitchell Horne 		sc->timer0_freq = SYS_TIMER_CLKSRC;
230c4530dffSMitchell Horne 	} else {
231c4530dffSMitchell Horne 		if (clk_get_freq(clk, &sc->timer0_freq) != 0) {
232c4530dffSMitchell Horne 			device_printf(dev, "Cannot get clock source frequency\n");
233c4530dffSMitchell Horne 			return (ENXIO);
234c4530dffSMitchell Horne 		}
235c4530dffSMitchell Horne 	}
236c4530dffSMitchell Horne 
237c4530dffSMitchell Horne 	if (bootverbose) {
238c4530dffSMitchell Horne 		device_printf(sc->sc_dev, "clock: hz=%d stathz = %d\n", hz,
239c4530dffSMitchell Horne 		    stathz);
240c4530dffSMitchell Horne 	}
241c4530dffSMitchell Horne 
242*9257fe12SMitchell Horne 	/* Set up eventtimer (if applicable) */
243*9257fe12SMitchell Horne #if defined(USE_EVENTTIMER)
244c4530dffSMitchell Horne 	aw_timer_eventtimer_setup(sc);
245*9257fe12SMitchell Horne #endif
246*9257fe12SMitchell Horne 
247*9257fe12SMitchell Horne 	/* Set up timercounter (if applicable) */
248*9257fe12SMitchell Horne #if defined(__arm__)
249c4530dffSMitchell Horne 	a10_timer_timecounter_setup(sc);
250c4530dffSMitchell Horne #elif defined(__aarch64__)
251c4530dffSMitchell Horne 	a23_timer_timecounter_setup(sc);
252c4530dffSMitchell Horne #endif
253c4530dffSMitchell Horne 
254c4530dffSMitchell Horne 	return (0);
255c4530dffSMitchell Horne }
256c4530dffSMitchell Horne 
257c4530dffSMitchell Horne static int
258c4530dffSMitchell Horne aw_timer_irq(void *arg)
259c4530dffSMitchell Horne {
260c4530dffSMitchell Horne 	struct aw_timer_softc *sc;
261c4530dffSMitchell Horne 	uint32_t val;
262c4530dffSMitchell Horne 
263c4530dffSMitchell Horne 	sc = (struct aw_timer_softc *)arg;
264c4530dffSMitchell Horne 
265c4530dffSMitchell Horne 	/* Clear interrupt pending bit. */
266c4530dffSMitchell Horne 	timer_write_4(sc, TIMER_IRQ_STA_REG, TIMER_IRQ_PENDING(0));
267c4530dffSMitchell Horne 
268c4530dffSMitchell Horne 	val = timer_read_4(sc, TIMER_CTRL_REG(0));
269c4530dffSMitchell Horne 
270c4530dffSMitchell Horne 	/*
271c4530dffSMitchell Horne 	 * Disabled autoreload and sc_period > 0 means
272c4530dffSMitchell Horne 	 * timer_start was called with non NULL first value.
273c4530dffSMitchell Horne 	 * Now we will set periodic timer with the given period
274c4530dffSMitchell Horne 	 * value.
275c4530dffSMitchell Horne 	 */
276c4530dffSMitchell Horne 	if ((val & (1<<1)) == 0 && sc->sc_period > 0) {
277c4530dffSMitchell Horne 		/* Update timer */
278c4530dffSMitchell Horne 		timer_write_4(sc, TIMER_CURV_REG(0), sc->sc_period);
279c4530dffSMitchell Horne 
280c4530dffSMitchell Horne 		/* Make periodic and enable */
281c4530dffSMitchell Horne 		val |= TIMER_CTRL_AUTORELOAD | TIMER_CTRL_START;
282c4530dffSMitchell Horne 		timer_write_4(sc, TIMER_CTRL_REG(0), val);
283c4530dffSMitchell Horne 	}
284c4530dffSMitchell Horne 
285c4530dffSMitchell Horne 	if (sc->et.et_active)
286c4530dffSMitchell Horne 		sc->et.et_event_cb(&sc->et, sc->et.et_arg);
287c4530dffSMitchell Horne 
288c4530dffSMitchell Horne 	return (FILTER_HANDLED);
289c4530dffSMitchell Horne }
290c4530dffSMitchell Horne 
291c4530dffSMitchell Horne /*
292*9257fe12SMitchell Horne  * Event timer function for A10, A13, and D1.
293c4530dffSMitchell Horne  */
294*9257fe12SMitchell Horne #if defined(USE_EVENTTIMER)
295c4530dffSMitchell Horne static void
296c4530dffSMitchell Horne aw_timer_eventtimer_setup(struct aw_timer_softc *sc)
297c4530dffSMitchell Horne {
298c4530dffSMitchell Horne 	uint32_t val;
299c4530dffSMitchell Horne 
300c4530dffSMitchell Horne 	/* Set clock source to OSC24M, 1 pre-division, continuous mode */
301c4530dffSMitchell Horne 	val = timer_read_4(sc, TIMER_CTRL_REG(0));
302c4530dffSMitchell Horne 	val &= ~TIMER_CTRL_PRESCALAR_MASK | ~TIMER_CTRL_MODE_MASK | ~TIMER_CTRL_CLKSRC_MASK;
303c4530dffSMitchell Horne 	val |= TIMER_CTRL_PRESCALAR(1) | TIMER_CTRL_OSC24M;
304c4530dffSMitchell Horne 	timer_write_4(sc, TIMER_CTRL_REG(0), val);
305c4530dffSMitchell Horne 
306c4530dffSMitchell Horne 	/* Enable timer0 */
307c4530dffSMitchell Horne 	val = timer_read_4(sc, TIMER_IRQ_EN_REG);
308c4530dffSMitchell Horne 	val |= TIMER_IRQ_ENABLE(0);
309c4530dffSMitchell Horne 	timer_write_4(sc, TIMER_IRQ_EN_REG, val);
310c4530dffSMitchell Horne 
311c4530dffSMitchell Horne 	/* Set desired frequency in event timer and timecounter */
312c4530dffSMitchell Horne 	sc->et.et_frequency = sc->timer0_freq;
313c4530dffSMitchell Horne 	sc->et.et_name = "aw_timer Eventtimer";
314c4530dffSMitchell Horne 	sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC;
315*9257fe12SMitchell Horne 	sc->et.et_quality = AW_TIMER_QUALITY;
316c4530dffSMitchell Horne 	sc->et.et_min_period = (0x00000005LLU << 32) / sc->et.et_frequency;
317c4530dffSMitchell Horne 	sc->et.et_max_period = (0xfffffffeLLU << 32) / sc->et.et_frequency;
318c4530dffSMitchell Horne 	sc->et.et_start = aw_timer_eventtimer_start;
319c4530dffSMitchell Horne 	sc->et.et_stop = aw_timer_eventtimer_stop;
320c4530dffSMitchell Horne 	sc->et.et_priv = sc;
321c4530dffSMitchell Horne 	et_register(&sc->et);
322c4530dffSMitchell Horne 
323c4530dffSMitchell Horne 	if (bootverbose) {
324c4530dffSMitchell Horne 		device_printf(sc->sc_dev, "event timer clock frequency %ju\n",
325c4530dffSMitchell Horne 		    sc->timer0_freq);
326c4530dffSMitchell Horne 	}
327c4530dffSMitchell Horne }
328c4530dffSMitchell Horne 
329c4530dffSMitchell Horne static int
330c4530dffSMitchell Horne aw_timer_eventtimer_start(struct eventtimer *et, sbintime_t first,
331c4530dffSMitchell Horne     sbintime_t period)
332c4530dffSMitchell Horne {
333c4530dffSMitchell Horne 	struct aw_timer_softc *sc;
334c4530dffSMitchell Horne 	uint32_t count;
335c4530dffSMitchell Horne 	uint32_t val;
336c4530dffSMitchell Horne 
337c4530dffSMitchell Horne 	sc = (struct aw_timer_softc *)et->et_priv;
338c4530dffSMitchell Horne 
339c4530dffSMitchell Horne 	if (period != 0)
340c4530dffSMitchell Horne 		sc->sc_period = ((uint32_t)et->et_frequency * period) >> 32;
341c4530dffSMitchell Horne 	else
342c4530dffSMitchell Horne 		sc->sc_period = 0;
343c4530dffSMitchell Horne 	if (first != 0)
344c4530dffSMitchell Horne 		count = ((uint32_t)et->et_frequency * first) >> 32;
345c4530dffSMitchell Horne 	else
346c4530dffSMitchell Horne 		count = sc->sc_period;
347c4530dffSMitchell Horne 
348c4530dffSMitchell Horne 	/* Update timer values */
349c4530dffSMitchell Horne 	timer_write_4(sc, TIMER_INTV_REG(0), sc->sc_period);
350c4530dffSMitchell Horne 	timer_write_4(sc, TIMER_CURV_REG(0), count);
351c4530dffSMitchell Horne 
352c4530dffSMitchell Horne 	val = timer_read_4(sc, TIMER_CTRL_REG(0));
353c4530dffSMitchell Horne 	if (period != 0) {
354c4530dffSMitchell Horne 		/* periodic */
355c4530dffSMitchell Horne 		val |= TIMER_CTRL_AUTORELOAD;
356c4530dffSMitchell Horne 	} else {
357c4530dffSMitchell Horne 		/* oneshot */
358c4530dffSMitchell Horne 		val &= ~TIMER_CTRL_AUTORELOAD;
359c4530dffSMitchell Horne 	}
360c4530dffSMitchell Horne 	/* Enable timer0 */
361c4530dffSMitchell Horne 	val |= TIMER_IRQ_ENABLE(0);
362c4530dffSMitchell Horne 	timer_write_4(sc, TIMER_CTRL_REG(0), val);
363c4530dffSMitchell Horne 
364c4530dffSMitchell Horne 	return (0);
365c4530dffSMitchell Horne }
366c4530dffSMitchell Horne 
367c4530dffSMitchell Horne static int
368c4530dffSMitchell Horne aw_timer_eventtimer_stop(struct eventtimer *et)
369c4530dffSMitchell Horne {
370c4530dffSMitchell Horne 	struct aw_timer_softc *sc;
371c4530dffSMitchell Horne 	uint32_t val;
372c4530dffSMitchell Horne 
373c4530dffSMitchell Horne 	sc = (struct aw_timer_softc *)et->et_priv;
374c4530dffSMitchell Horne 
375c4530dffSMitchell Horne 	/* Disable timer0 */
376c4530dffSMitchell Horne 	val = timer_read_4(sc, TIMER_CTRL_REG(0));
377c4530dffSMitchell Horne 	val &= ~TIMER_CTRL_START;
378c4530dffSMitchell Horne 	timer_write_4(sc, TIMER_CTRL_REG(0), val);
379c4530dffSMitchell Horne 
380c4530dffSMitchell Horne 	sc->sc_period = 0;
381c4530dffSMitchell Horne 
382c4530dffSMitchell Horne 	return (0);
383c4530dffSMitchell Horne }
384*9257fe12SMitchell Horne #endif /* USE_EVENTTIMER */
385c4530dffSMitchell Horne 
386c4530dffSMitchell Horne /*
387c4530dffSMitchell Horne  * Timecounter functions for A23 and above
388c4530dffSMitchell Horne  */
389c4530dffSMitchell Horne 
390c4530dffSMitchell Horne #if defined(__aarch64__)
391c4530dffSMitchell Horne static void
392c4530dffSMitchell Horne a23_timer_timecounter_setup(struct aw_timer_softc *sc)
393c4530dffSMitchell Horne {
394c4530dffSMitchell Horne 	uint32_t val;
395c4530dffSMitchell Horne 
396c4530dffSMitchell Horne 	/* Set clock source to OSC24M, 1 pre-division, continuous mode */
397c4530dffSMitchell Horne 	val = timer_read_4(sc, TIMER_CTRL_REG(0));
398c4530dffSMitchell Horne 	val &= ~TIMER_CTRL_PRESCALAR_MASK | ~TIMER_CTRL_MODE_MASK | ~TIMER_CTRL_CLKSRC_MASK;
399c4530dffSMitchell Horne 	val |= TIMER_CTRL_PRESCALAR(1) | TIMER_CTRL_OSC24M;
400c4530dffSMitchell Horne 	timer_write_4(sc, TIMER_CTRL_REG(0), val);
401c4530dffSMitchell Horne 
402c4530dffSMitchell Horne 	/* Set reload value */
403c4530dffSMitchell Horne 	timer_write_4(sc, TIMER_INTV_REG(0), ~0);
404c4530dffSMitchell Horne 	val = timer_read_4(sc, TIMER_INTV_REG(0));
405c4530dffSMitchell Horne 
406c4530dffSMitchell Horne 	/* Enable timer0 */
407c4530dffSMitchell Horne 	val = timer_read_4(sc, TIMER_CTRL_REG(0));
408c4530dffSMitchell Horne 	val |= TIMER_CTRL_AUTORELOAD | TIMER_CTRL_START;
409c4530dffSMitchell Horne 	timer_write_4(sc, TIMER_CTRL_REG(0), val);
410c4530dffSMitchell Horne 
411c4530dffSMitchell Horne 	val = timer_read_4(sc, TIMER_CURV_REG(0));
412c4530dffSMitchell Horne 
413c4530dffSMitchell Horne 	a23_timer_timecounter.tc_priv = sc;
414c4530dffSMitchell Horne 	a23_timer_timecounter.tc_frequency = sc->timer0_freq;
415c4530dffSMitchell Horne 	tc_init(&a23_timer_timecounter);
416c4530dffSMitchell Horne 
417c4530dffSMitchell Horne 	if (bootverbose) {
418c4530dffSMitchell Horne 		device_printf(sc->sc_dev, "timecounter clock frequency %jd\n",
419c4530dffSMitchell Horne 		    a23_timer_timecounter.tc_frequency);
420c4530dffSMitchell Horne 	}
421c4530dffSMitchell Horne }
422c4530dffSMitchell Horne 
423c4530dffSMitchell Horne static u_int
424c4530dffSMitchell Horne a23_timer_get_timecount(struct timecounter *tc)
425c4530dffSMitchell Horne {
426c4530dffSMitchell Horne 	struct aw_timer_softc *sc;
427c4530dffSMitchell Horne 	uint32_t val;
428c4530dffSMitchell Horne 
429c4530dffSMitchell Horne 	sc = (struct aw_timer_softc *)tc->tc_priv;
430c4530dffSMitchell Horne 	if (sc == NULL)
431c4530dffSMitchell Horne 		return (0);
432c4530dffSMitchell Horne 
433c4530dffSMitchell Horne 	val = timer_read_4(sc, TIMER_CURV_REG(0));
434c4530dffSMitchell Horne 	/* Counter count backwards */
435c4530dffSMitchell Horne 	return (~0u - val);
436c4530dffSMitchell Horne }
437c4530dffSMitchell Horne #endif /* __aarch64__ */
438c4530dffSMitchell Horne 
439c4530dffSMitchell Horne /*
440c4530dffSMitchell Horne  * Timecounter functions for A10 and A13, using the 64 bits counter
441c4530dffSMitchell Horne  */
442c4530dffSMitchell Horne 
443c4530dffSMitchell Horne #if defined(__arm__)
444c4530dffSMitchell Horne static uint64_t
445c4530dffSMitchell Horne a10_timer_read_counter64(struct aw_timer_softc *sc)
446c4530dffSMitchell Horne {
447c4530dffSMitchell Horne 	uint32_t lo, hi;
448c4530dffSMitchell Horne 
449c4530dffSMitchell Horne 	/* Latch counter, wait for it to be ready to read. */
450c4530dffSMitchell Horne 	timer_write_4(sc, CNT64_CTRL_REG, CNT64_CTRL_RL_EN);
451c4530dffSMitchell Horne 	while (timer_read_4(sc, CNT64_CTRL_REG) & CNT64_CTRL_RL_EN)
452c4530dffSMitchell Horne 		continue;
453c4530dffSMitchell Horne 
454c4530dffSMitchell Horne 	hi = timer_read_4(sc, CNT64_HI_REG);
455c4530dffSMitchell Horne 	lo = timer_read_4(sc, CNT64_LO_REG);
456c4530dffSMitchell Horne 
457c4530dffSMitchell Horne 	return (((uint64_t)hi << 32) | lo);
458c4530dffSMitchell Horne }
459c4530dffSMitchell Horne 
460c4530dffSMitchell Horne static void
461c4530dffSMitchell Horne a10_timer_delay(int usec, void *arg)
462c4530dffSMitchell Horne {
463c4530dffSMitchell Horne 	struct aw_timer_softc *sc = arg;
464c4530dffSMitchell Horne 	uint64_t end, now;
465c4530dffSMitchell Horne 
466c4530dffSMitchell Horne 	now = a10_timer_read_counter64(sc);
467c4530dffSMitchell Horne 	end = now + (sc->timer0_freq / 1000000) * (usec + 1);
468c4530dffSMitchell Horne 
469c4530dffSMitchell Horne 	while (now < end)
470c4530dffSMitchell Horne 		now = a10_timer_read_counter64(sc);
471c4530dffSMitchell Horne }
472c4530dffSMitchell Horne 
473c4530dffSMitchell Horne static u_int
474c4530dffSMitchell Horne a10_timer_get_timecount(struct timecounter *tc)
475c4530dffSMitchell Horne {
476c4530dffSMitchell Horne 	if (tc->tc_priv == NULL)
477c4530dffSMitchell Horne 		return (0);
478c4530dffSMitchell Horne 
479c4530dffSMitchell Horne 	return ((u_int)a10_timer_read_counter64(tc->tc_priv));
480c4530dffSMitchell Horne }
481c4530dffSMitchell Horne 
482c4530dffSMitchell Horne static void
483c4530dffSMitchell Horne a10_timer_timecounter_setup(struct aw_timer_softc *sc)
484c4530dffSMitchell Horne {
485c4530dffSMitchell Horne 	arm_set_delay(a10_timer_delay, sc);
486c4530dffSMitchell Horne 	a10_timer_timecounter.tc_priv = sc;
487c4530dffSMitchell Horne 	a10_timer_timecounter.tc_frequency = sc->timer0_freq;
488c4530dffSMitchell Horne 	tc_init(&a10_timer_timecounter);
489c4530dffSMitchell Horne 
490c4530dffSMitchell Horne 	if (bootverbose) {
491c4530dffSMitchell Horne 		device_printf(sc->sc_dev, "timecounter clock frequency %jd\n",
492c4530dffSMitchell Horne 		    a10_timer_timecounter.tc_frequency);
493c4530dffSMitchell Horne 	}
494c4530dffSMitchell Horne }
495c4530dffSMitchell Horne #endif /* __arm__ */
496c4530dffSMitchell Horne 
497c4530dffSMitchell Horne static device_method_t aw_timer_methods[] = {
498c4530dffSMitchell Horne 	DEVMETHOD(device_probe,		aw_timer_probe),
499c4530dffSMitchell Horne 	DEVMETHOD(device_attach,	aw_timer_attach),
500c4530dffSMitchell Horne 
501c4530dffSMitchell Horne 	DEVMETHOD_END
502c4530dffSMitchell Horne };
503c4530dffSMitchell Horne 
504c4530dffSMitchell Horne static driver_t aw_timer_driver = {
505c4530dffSMitchell Horne 	"aw_timer",
506c4530dffSMitchell Horne 	aw_timer_methods,
507c4530dffSMitchell Horne 	sizeof(struct aw_timer_softc),
508c4530dffSMitchell Horne };
509c4530dffSMitchell Horne 
510c4530dffSMitchell Horne EARLY_DRIVER_MODULE(aw_timer, simplebus, aw_timer_driver, 0, 0,
511c4530dffSMitchell Horne     BUS_PASS_TIMER + BUS_PASS_ORDER_MIDDLE);
512