xref: /openbsd-src/sys/arch/arm64/dev/agtimer.c (revision 0ed1bf01ac7e45759b65902d0ab711deb359316d)
1 /* $OpenBSD: agtimer.c,v 1.28 2023/09/17 14:50:51 cheloha Exp $ */
2 /*
3  * Copyright (c) 2011 Dale Rahn <drahn@openbsd.org>
4  * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/clockintr.h>
22 #include <sys/queue.h>
23 #include <sys/malloc.h>
24 #include <sys/device.h>
25 #include <sys/kernel.h>
26 #include <sys/stdint.h>
27 #include <sys/timetc.h>
28 #include <sys/evcount.h>
29 
30 #include <machine/intr.h>
31 #include <machine/bus.h>
32 #include <machine/fdt.h>
33 
34 #include <dev/ofw/fdt.h>
35 #include <dev/ofw/openfirm.h>
36 
37 /* registers */
38 #define GTIMER_CNTV_CTL_ENABLE		(1 << 0)
39 #define GTIMER_CNTV_CTL_IMASK		(1 << 1)
40 #define GTIMER_CNTV_CTL_ISTATUS		(1 << 2)
41 
42 #define TIMER_FREQUENCY		24 * 1000 * 1000 /* ARM core clock */
43 int32_t agtimer_frequency = TIMER_FREQUENCY;
44 
45 u_int agtimer_get_timecount_default(struct timecounter *);
46 u_int agtimer_get_timecount_sun50i(struct timecounter *);
47 
48 static struct timecounter agtimer_timecounter = {
49 	.tc_get_timecount = agtimer_get_timecount_default,
50 	.tc_counter_mask = 0xffffffff,
51 	.tc_frequency = 0,
52 	.tc_name = "agtimer",
53 	.tc_quality = 0,
54 	.tc_priv = NULL,
55 	.tc_user = TC_AGTIMER,
56 };
57 
58 struct agtimer_softc {
59 	struct device		sc_dev;
60 	int			sc_node;
61 
62 	u_int32_t		sc_ticks_per_second;
63 	uint64_t		sc_nsec_cycle_ratio;
64 	uint64_t		sc_nsec_max;
65 	void			*sc_ih;
66 };
67 
68 int		agtimer_match(struct device *, void *, void *);
69 void		agtimer_attach(struct device *, struct device *, void *);
70 int		agtimer_intr(void *);
71 void		agtimer_cpu_initclocks(void);
72 void		agtimer_delay(u_int);
73 void		agtimer_rearm(void *, uint64_t);
74 void		agtimer_setstatclockrate(int stathz);
75 void		agtimer_set_clockrate(int32_t new_frequency);
76 void		agtimer_startclock(void);
77 void		agtimer_trigger(void *);
78 
79 const struct cfattach agtimer_ca = {
80 	sizeof (struct agtimer_softc), agtimer_match, agtimer_attach
81 };
82 
83 struct cfdriver agtimer_cd = {
84 	NULL, "agtimer", DV_DULL
85 };
86 
87 struct intrclock agtimer_intrclock = {
88 	.ic_rearm = agtimer_rearm,
89 	.ic_trigger = agtimer_trigger
90 };
91 
92 uint64_t
agtimer_readcnt64_default(void)93 agtimer_readcnt64_default(void)
94 {
95 	uint64_t val0, val1;
96 
97 	/*
98 	 * Work around Cortex-A73 errata 858921, where there is a
99 	 * one-cycle window where the read might return the old value
100 	 * for the low 32 bits and the new value for the high 32 bits
101 	 * upon roll-over of the low 32 bits.
102 	 */
103 	__asm volatile("isb" ::: "memory");
104 	__asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val0));
105 	__asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val1));
106 	return ((val0 ^ val1) & 0x100000000ULL) ? val0 : val1;
107 }
108 
109 uint64_t
agtimer_readcnt64_sun50i(void)110 agtimer_readcnt64_sun50i(void)
111 {
112 	uint64_t val;
113 	int retry;
114 
115 	__asm volatile("isb" ::: "memory");
116 	for (retry = 0; retry < 150; retry++) {
117 		__asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val));
118 
119 		if (((val + 1) & 0x1ff) > 1)
120 			break;
121 	}
122 	KASSERT(retry < 150);
123 
124 	return val;
125 }
126 
127 uint64_t (*agtimer_readcnt64)(void) = agtimer_readcnt64_default;
128 
129 static inline uint64_t
agtimer_get_freq(void)130 agtimer_get_freq(void)
131 {
132 	uint64_t val;
133 
134 	__asm volatile("mrs %x0, CNTFRQ_EL0" : "=r" (val));
135 
136 	return (val);
137 }
138 
139 static inline int
agtimer_get_ctrl(void)140 agtimer_get_ctrl(void)
141 {
142 	uint32_t val;
143 
144 	__asm volatile("mrs %x0, CNTV_CTL_EL0" : "=r" (val));
145 
146 	return (val);
147 }
148 
149 static inline int
agtimer_set_ctrl(uint32_t val)150 agtimer_set_ctrl(uint32_t val)
151 {
152 	__asm volatile("msr CNTV_CTL_EL0, %x0" :: "r" (val));
153 	__asm volatile("isb" ::: "memory");
154 
155 	return (0);
156 }
157 
158 static inline int
agtimer_set_tval(uint32_t val)159 agtimer_set_tval(uint32_t val)
160 {
161 	__asm volatile("msr CNTV_TVAL_EL0, %x0" :: "r" (val));
162 	__asm volatile("isb" ::: "memory");
163 
164 	return (0);
165 }
166 
167 int
agtimer_match(struct device * parent,void * cfdata,void * aux)168 agtimer_match(struct device *parent, void *cfdata, void *aux)
169 {
170 	struct fdt_attach_args *faa = (struct fdt_attach_args *)aux;
171 
172 	return (OF_is_compatible(faa->fa_node, "arm,armv7-timer") ||
173 	    OF_is_compatible(faa->fa_node, "arm,armv8-timer"));
174 }
175 
176 void
agtimer_attach(struct device * parent,struct device * self,void * aux)177 agtimer_attach(struct device *parent, struct device *self, void *aux)
178 {
179 	struct agtimer_softc *sc = (struct agtimer_softc *)self;
180 	struct fdt_attach_args *faa = aux;
181 
182 	sc->sc_node = faa->fa_node;
183 
184 	if (agtimer_get_freq() != 0)
185 		agtimer_frequency = agtimer_get_freq();
186 	agtimer_frequency =
187 	    OF_getpropint(sc->sc_node, "clock-frequency", agtimer_frequency);
188 	sc->sc_ticks_per_second = agtimer_frequency;
189 	sc->sc_nsec_cycle_ratio =
190 	    sc->sc_ticks_per_second * (1ULL << 32) / 1000000000;
191 	sc->sc_nsec_max = UINT64_MAX / sc->sc_nsec_cycle_ratio;
192 
193 	printf(": %u kHz\n", sc->sc_ticks_per_second / 1000);
194 
195 	/*
196 	 * The Allwinner A64 has an erratum where the bottom 9 bits of
197 	 * the counter register can't be trusted if any of the higher
198 	 * bits are rolling over.
199 	 */
200 	if (OF_getpropbool(sc->sc_node, "allwinner,erratum-unknown1")) {
201 		agtimer_readcnt64 = agtimer_readcnt64_sun50i;
202 		agtimer_timecounter.tc_get_timecount =
203 		    agtimer_get_timecount_sun50i;
204 		agtimer_timecounter.tc_user = TC_AGTIMER_SUN50I;
205 	}
206 
207 	/*
208 	 * private timer and interrupts not enabled until
209 	 * timer configures
210 	 */
211 
212 	arm_clock_register(agtimer_cpu_initclocks, agtimer_delay,
213 	    agtimer_setstatclockrate, agtimer_startclock);
214 
215 	agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
216 	agtimer_timecounter.tc_priv = sc;
217 	tc_init(&agtimer_timecounter);
218 
219 	agtimer_intrclock.ic_cookie = sc;
220 }
221 
222 u_int
agtimer_get_timecount_default(struct timecounter * tc)223 agtimer_get_timecount_default(struct timecounter *tc)
224 {
225 	uint64_t val;
226 
227 	/*
228 	 * No need to work around Cortex-A73 errata 858921 since we
229 	 * only look at the low 32 bits here.
230 	 */
231 	__asm volatile("isb" ::: "memory");
232 	__asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val));
233 	return (val & 0xffffffff);
234 }
235 
236 u_int
agtimer_get_timecount_sun50i(struct timecounter * tc)237 agtimer_get_timecount_sun50i(struct timecounter *tc)
238 {
239 	return agtimer_readcnt64_sun50i();
240 }
241 
242 void
agtimer_rearm(void * cookie,uint64_t nsecs)243 agtimer_rearm(void *cookie, uint64_t nsecs)
244 {
245 	struct agtimer_softc *sc = cookie;
246 	uint32_t cycles;
247 
248 	if (nsecs > sc->sc_nsec_max)
249 		nsecs = sc->sc_nsec_max;
250 	cycles = (nsecs * sc->sc_nsec_cycle_ratio) >> 32;
251 	if (cycles > INT32_MAX)
252 		cycles = INT32_MAX;
253 	agtimer_set_tval(cycles);
254 }
255 
256 void
agtimer_trigger(void * unused)257 agtimer_trigger(void *unused)
258 {
259 	agtimer_set_tval(0);
260 }
261 
262 int
agtimer_intr(void * frame)263 agtimer_intr(void *frame)
264 {
265 	return clockintr_dispatch(frame);
266 }
267 
268 void
agtimer_set_clockrate(int32_t new_frequency)269 agtimer_set_clockrate(int32_t new_frequency)
270 {
271 	struct agtimer_softc	*sc = agtimer_cd.cd_devs[0];
272 
273 	agtimer_frequency = new_frequency;
274 
275 	if (sc == NULL)
276 		return;
277 
278 	sc->sc_ticks_per_second = agtimer_frequency;
279 	sc->sc_nsec_cycle_ratio =
280 	    sc->sc_ticks_per_second * (1ULL << 32) / 1000000000;
281 	sc->sc_nsec_max = UINT64_MAX / sc->sc_nsec_cycle_ratio;
282 
283 	agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
284 
285 	printf("agtimer0: adjusting clock: new tick rate %u kHz\n",
286 	    sc->sc_ticks_per_second / 1000);
287 }
288 
289 void
agtimer_cpu_initclocks(void)290 agtimer_cpu_initclocks(void)
291 {
292 	struct agtimer_softc	*sc = agtimer_cd.cd_devs[0];
293 
294 	stathz = hz;
295 	profhz = stathz * 10;
296 	statclock_is_randomized = 1;
297 
298 	if (sc->sc_ticks_per_second != agtimer_frequency) {
299 		agtimer_set_clockrate(agtimer_frequency);
300 	}
301 
302 	/* configure virtual timer interrupt */
303 	sc->sc_ih = arm_intr_establish_fdt_idx(sc->sc_node, 2,
304 	    IPL_CLOCK|IPL_MPSAFE, agtimer_intr, NULL, "tick");
305 }
306 
307 void
agtimer_delay(u_int usecs)308 agtimer_delay(u_int usecs)
309 {
310 	uint64_t cycles, start;
311 
312 	start = agtimer_readcnt64();
313 	cycles = (uint64_t)usecs * agtimer_frequency / 1000000;
314 	while (agtimer_readcnt64() - start < cycles)
315 		CPU_BUSY_CYCLE();
316 }
317 
318 void
agtimer_setstatclockrate(int newhz)319 agtimer_setstatclockrate(int newhz)
320 {
321 }
322 
323 void
agtimer_startclock(void)324 agtimer_startclock(void)
325 {
326 	struct agtimer_softc	*sc = agtimer_cd.cd_devs[0];
327 	uint64_t kctl;
328 	uint32_t reg;
329 
330 	if (!CPU_IS_PRIMARY(curcpu()))
331 		arm_intr_route(sc->sc_ih, 1, curcpu());
332 
333 	clockintr_cpu_init(&agtimer_intrclock);
334 
335 	reg = agtimer_get_ctrl();
336 	reg &= ~GTIMER_CNTV_CTL_IMASK;
337 	reg |= GTIMER_CNTV_CTL_ENABLE;
338 	agtimer_set_tval(INT32_MAX);
339 	agtimer_set_ctrl(reg);
340 
341 	clockintr_trigger();
342 
343 	/* enable userland access to virtual counter */
344 	kctl = READ_SPECIALREG(CNTKCTL_EL1);
345 	WRITE_SPECIALREG(CNTKCTL_EL1, kctl | CNTKCTL_EL0VCTEN);
346 }
347 
348 void
agtimer_init(void)349 agtimer_init(void)
350 {
351 	uint64_t cntfrq = 0;
352 
353 	/* XXX: Check for Generic Timer support. */
354 	cntfrq = agtimer_get_freq();
355 
356 	if (cntfrq != 0) {
357 		agtimer_frequency = cntfrq;
358 		arm_clock_register(NULL, agtimer_delay, NULL, NULL);
359 	}
360 }
361