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