xref: /openbsd-src/sys/arch/arm/cortex/agtimer.c (revision 1a8dbaac879b9f3335ad7fb25429ce63ac1d6bac)
1 /* $OpenBSD: agtimer.c,v 1.10 2020/07/12 20:36:37 naddy 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/queue.h>
22 #include <sys/malloc.h>
23 #include <sys/device.h>
24 #include <sys/kernel.h>
25 #include <sys/timetc.h>
26 #include <sys/evcount.h>
27 
28 #include <machine/intr.h>
29 #include <machine/bus.h>
30 #include <machine/fdt.h>
31 
32 #include <arm/cpufunc.h>
33 #include <arm/cortex/cortex.h>
34 
35 #include <dev/ofw/fdt.h>
36 #include <dev/ofw/openfirm.h>
37 
38 /* registers */
39 #define GTIMER_CNTP_CTL_ENABLE		(1 << 0)
40 #define GTIMER_CNTP_CTL_IMASK		(1 << 1)
41 #define GTIMER_CNTP_CTL_ISTATUS		(1 << 2)
42 
43 #define TIMER_FREQUENCY		24 * 1000 * 1000 /* ARM core clock */
44 int32_t agtimer_frequency = TIMER_FREQUENCY;
45 
46 u_int agtimer_get_timecount(struct timecounter *);
47 
48 static struct timecounter agtimer_timecounter = {
49 	agtimer_get_timecount, NULL, 0xffffffff, 0, "agtimer", 0, NULL
50 };
51 
52 struct agtimer_pcpu_softc {
53 	uint64_t 		pc_nexttickevent;
54 	uint64_t 		pc_nextstatevent;
55 	u_int32_t		pc_ticks_err_sum;
56 };
57 
58 struct agtimer_softc {
59 	struct device		sc_dev;
60 	int			sc_node;
61 
62 	struct agtimer_pcpu_softc sc_pstat[MAXCPUS];
63 
64 	u_int32_t		sc_ticks_err_cnt;
65 	u_int32_t		sc_ticks_per_second;
66 	u_int32_t		sc_ticks_per_intr;
67 	u_int32_t		sc_statvar;
68 	u_int32_t		sc_statmin;
69 
70 #ifdef AMPTIMER_DEBUG
71 	struct evcount		sc_clk_count;
72 	struct evcount		sc_stat_count;
73 #endif
74 };
75 
76 int		agtimer_match(struct device *, void *, void *);
77 void		agtimer_attach(struct device *, struct device *, void *);
78 uint64_t	agtimer_readcnt64(void);
79 int		agtimer_intr(void *);
80 void		agtimer_cpu_initclocks(void);
81 void		agtimer_delay(u_int);
82 void		agtimer_setstatclockrate(int stathz);
83 void		agtimer_set_clockrate(int32_t new_frequency);
84 void		agtimer_startclock(void);
85 
86 struct cfattach agtimer_ca = {
87 	sizeof (struct agtimer_softc), agtimer_match, agtimer_attach
88 };
89 
90 struct cfdriver agtimer_cd = {
91 	NULL, "agtimer", DV_DULL
92 };
93 
94 uint64_t
95 agtimer_readcnt64(void)
96 {
97 	uint64_t val;
98 
99 	__asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (val));
100 
101 	return (val);
102 }
103 
104 static inline int
105 agtimer_get_ctrl(void)
106 {
107 	uint32_t val;
108 
109 	__asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
110 
111 	return (val);
112 }
113 
114 static inline int
115 agtimer_set_ctrl(uint32_t val)
116 {
117 	__asm volatile("mcr p15, 0, %[val], c14, c2, 1" : :
118 	    [val] "r" (val));
119 
120 	cpu_drain_writebuf();
121 	//isb();
122 
123 	return (0);
124 }
125 
126 static inline int
127 agtimer_set_tval(uint32_t val)
128 {
129 	__asm volatile("mcr p15, 0, %[val], c14, c2, 0" : :
130 	    [val] "r" (val));
131 	cpu_drain_writebuf();
132 	//isb();
133 
134 	return (0);
135 }
136 
137 int
138 agtimer_match(struct device *parent, void *cfdata, void *aux)
139 {
140 	struct fdt_attach_args *faa = (struct fdt_attach_args *)aux;
141 
142 	return OF_is_compatible(faa->fa_node, "arm,armv7-timer");
143 }
144 
145 void
146 agtimer_attach(struct device *parent, struct device *self, void *aux)
147 {
148 	struct agtimer_softc *sc = (struct agtimer_softc *)self;
149 	struct fdt_attach_args *faa = aux;
150 
151 	sc->sc_node = faa->fa_node;
152 
153 	agtimer_frequency =
154 	    OF_getpropint(sc->sc_node, "clock-frequency", agtimer_frequency);
155 	sc->sc_ticks_per_second = agtimer_frequency;
156 
157 	printf(": tick rate %d KHz\n", sc->sc_ticks_per_second /1000);
158 
159 	/* XXX: disable user access */
160 
161 #ifdef AMPTIMER_DEBUG
162 	evcount_attach(&sc->sc_clk_count, "clock", NULL);
163 	evcount_attach(&sc->sc_stat_count, "stat", NULL);
164 #endif
165 
166 	/*
167 	 * private timer and interrupts not enabled until
168 	 * timer configures
169 	 */
170 
171 	arm_clock_register(agtimer_cpu_initclocks, agtimer_delay,
172 	    agtimer_setstatclockrate, agtimer_startclock);
173 
174 	agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
175 	agtimer_timecounter.tc_priv = sc;
176 
177 	tc_init(&agtimer_timecounter);
178 }
179 
180 u_int
181 agtimer_get_timecount(struct timecounter *tc)
182 {
183 	return agtimer_readcnt64();
184 }
185 
186 int
187 agtimer_intr(void *frame)
188 {
189 	struct agtimer_softc	*sc = agtimer_cd.cd_devs[0];
190 	struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
191 	uint64_t		 now;
192 	uint64_t		 nextevent;
193 	uint32_t		 r;
194 #if defined(USE_GTIMER_CMP)
195 	int			 skip = 1;
196 #else
197 	int64_t			 delay;
198 #endif
199 	int			 rc = 0;
200 
201 	/*
202 	 * DSR - I know that the tick timer is 64 bits, but the following
203 	 * code deals with rollover, so there is no point in dealing
204 	 * with the 64 bit math, just let the 32 bit rollover
205 	 * do the right thing
206 	 */
207 
208 	now = agtimer_readcnt64();
209 
210 	while (pc->pc_nexttickevent <= now) {
211 		pc->pc_nexttickevent += sc->sc_ticks_per_intr;
212 		pc->pc_ticks_err_sum += sc->sc_ticks_err_cnt;
213 
214 		/* looping a few times is faster than divide */
215 		while (pc->pc_ticks_err_sum > hz) {
216 			pc->pc_nexttickevent += 1;
217 			pc->pc_ticks_err_sum -= hz;
218 		}
219 
220 #ifdef AMPTIMER_DEBUG
221 		sc->sc_clk_count.ec_count++;
222 #endif
223 		rc = 1;
224 		hardclock(frame);
225 	}
226 	while (pc->pc_nextstatevent <= now) {
227 		do {
228 			r = random() & (sc->sc_statvar -1);
229 		} while (r == 0); /* random == 0 not allowed */
230 		pc->pc_nextstatevent += sc->sc_statmin + r;
231 
232 		/* XXX - correct nextstatevent? */
233 #ifdef AMPTIMER_DEBUG
234 		sc->sc_stat_count.ec_count++;
235 #endif
236 		rc = 1;
237 		statclock(frame);
238 	}
239 
240 	if (pc->pc_nexttickevent < pc->pc_nextstatevent)
241 		nextevent = pc->pc_nexttickevent;
242 	else
243 		nextevent = pc->pc_nextstatevent;
244 
245 	delay = nextevent - now;
246 	if (delay < 0)
247 		delay = 1;
248 
249 	agtimer_set_tval(delay);
250 
251 	return (rc);
252 }
253 
254 void
255 agtimer_set_clockrate(int32_t new_frequency)
256 {
257 	struct agtimer_softc	*sc = agtimer_cd.cd_devs[0];
258 
259 	agtimer_frequency = new_frequency;
260 
261 	if (sc == NULL)
262 		return;
263 
264 	sc->sc_ticks_per_second = agtimer_frequency;
265 	agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
266 	printf("agtimer0: adjusting clock: new tick rate %d KHz\n",
267 	    sc->sc_ticks_per_second /1000);
268 }
269 
270 void
271 agtimer_cpu_initclocks()
272 {
273 	struct agtimer_softc	*sc = agtimer_cd.cd_devs[0];
274 	struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
275 	uint32_t		 reg;
276 	uint64_t		 next;
277 
278 	stathz = hz;
279 	profhz = hz * 10;
280 
281 	if (sc->sc_ticks_per_second != agtimer_frequency) {
282 		agtimer_set_clockrate(agtimer_frequency);
283 	}
284 
285 	agtimer_setstatclockrate(stathz);
286 
287 	sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz;
288 	sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz;
289 	pc->pc_ticks_err_sum = 0;
290 
291 	/* Setup secure and non-secure timer IRQs. */
292 	arm_intr_establish_fdt_idx(sc->sc_node, 0, IPL_CLOCK,
293 	    agtimer_intr, NULL, "tick");
294 	arm_intr_establish_fdt_idx(sc->sc_node, 1, IPL_CLOCK,
295 	    agtimer_intr, NULL, "tick");
296 
297 	next = agtimer_readcnt64() + sc->sc_ticks_per_intr;
298 	pc->pc_nexttickevent = pc->pc_nextstatevent = next;
299 
300 	reg = agtimer_get_ctrl();
301 	reg &= ~GTIMER_CNTP_CTL_IMASK;
302 	reg |= GTIMER_CNTP_CTL_ENABLE;
303 	agtimer_set_tval(sc->sc_ticks_per_second);
304 	agtimer_set_ctrl(reg);
305 }
306 
307 void
308 agtimer_delay(u_int usecs)
309 {
310 	u_int32_t		clock, oclock, delta, delaycnt;
311 	volatile int		j;
312 	int			csec, usec;
313 
314 	if (usecs > (0x80000000 / agtimer_frequency)) {
315 		csec = usecs / 10000;
316 		usec = usecs % 10000;
317 
318 		delaycnt = (agtimer_frequency / 100) * csec +
319 		    (agtimer_frequency / 100) * usec / 10000;
320 	} else {
321 		delaycnt = agtimer_frequency * usecs / 1000000;
322 	}
323 	if (delaycnt <= 1)
324 		for (j = 100; j > 0; j--)
325 			;
326 
327 	oclock = agtimer_readcnt64();
328 	while (1) {
329 		for (j = 100; j > 0; j--)
330 			;
331 		clock = agtimer_readcnt64();
332 		delta = clock - oclock;
333 		if (delta > delaycnt)
334 			break;
335 	}
336 }
337 
338 void
339 agtimer_setstatclockrate(int newhz)
340 {
341 	struct agtimer_softc	*sc = agtimer_cd.cd_devs[0];
342 	int			 minint, statint;
343 	int			 s;
344 
345 	s = splclock();
346 
347 	statint = sc->sc_ticks_per_second / newhz;
348 	/* calculate largest 2^n which is smaller that just over half statint */
349 	sc->sc_statvar = 0x40000000; /* really big power of two */
350 	minint = statint / 2 + 100;
351 	while (sc->sc_statvar > minint)
352 		sc->sc_statvar >>= 1;
353 
354 	sc->sc_statmin = statint - (sc->sc_statvar >> 1);
355 
356 	splx(s);
357 
358 	/*
359 	 * XXX this allows the next stat timer to occur then it switches
360 	 * to the new frequency. Rather than switching instantly.
361 	 */
362 }
363 
364 void
365 agtimer_startclock(void)
366 {
367 	struct agtimer_softc	*sc = agtimer_cd.cd_devs[0];
368 	struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
369 	uint64_t nextevent;
370 	uint32_t reg;
371 
372 	nextevent = agtimer_readcnt64() + sc->sc_ticks_per_intr;
373 	pc->pc_nexttickevent = pc->pc_nextstatevent = nextevent;
374 
375 	reg = agtimer_get_ctrl();
376 	reg &= ~GTIMER_CNTP_CTL_IMASK;
377 	reg |= GTIMER_CNTP_CTL_ENABLE;
378 	agtimer_set_tval(sc->sc_ticks_per_second);
379 	agtimer_set_ctrl(reg);
380 }
381 
382 void
383 agtimer_init(void)
384 {
385 	uint32_t id_pfr1, cntfrq = 0;
386 
387 	/* Check for Generic Timer support. */
388 	__asm volatile("mrc p15, 0, %0, c0, c1, 1" : "=r"(id_pfr1));
389 	if ((id_pfr1 & 0x000f0000) == 0x00010000)
390 		__asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (cntfrq));
391 
392 	if (cntfrq != 0) {
393 		agtimer_frequency = cntfrq;
394 		arm_clock_register(NULL, agtimer_delay, NULL, NULL);
395 	}
396 }
397