xref: /openbsd-src/sys/arch/arm/cortex/agtimer.c (revision c83094e173ffac247866812b0651d91f19006af2)
1 /* $OpenBSD: agtimer.c,v 1.2 2015/05/29 02:35:43 jsg 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 <arm/cpufunc.h>
29 #include <machine/bus.h>
30 #include <machine/intr.h>
31 #include <arm/cortex/cortex.h>
32 
33 /* registers */
34 #define GTIMER_CNTP_CTL_ENABLE		(1 << 0)
35 #define GTIMER_CNTP_CTL_IMASK		(1 << 1)
36 #define GTIMER_CNTP_CTL_ISTATUS		(1 << 2)
37 
38 #define TIMER_FREQUENCY		24 * 1000 * 1000 /* ARM core clock */
39 int32_t agtimer_frequency = TIMER_FREQUENCY;
40 
41 u_int agtimer_get_timecount(struct timecounter *);
42 
43 static struct timecounter agtimer_timecounter = {
44 	agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL
45 };
46 
47 #define MAX_ARM_CPUS	8
48 
49 struct agtimer_pcpu_softc {
50 	uint64_t 		pc_nexttickevent;
51 	uint64_t 		pc_nextstatevent;
52 	u_int32_t		pc_ticks_err_sum;
53 };
54 
55 struct agtimer_softc {
56 	struct device		sc_dev;
57 
58 	struct agtimer_pcpu_softc sc_pstat[MAX_ARM_CPUS];
59 
60 	u_int32_t		sc_ticks_err_cnt;
61 	u_int32_t		sc_ticks_per_second;
62 	u_int32_t		sc_ticks_per_intr;
63 	u_int32_t		sc_statvar;
64 	u_int32_t		sc_statmin;
65 
66 #ifdef AMPTIMER_DEBUG
67 	struct evcount		sc_clk_count;
68 	struct evcount		sc_stat_count;
69 #endif
70 };
71 
72 int		agtimer_match(struct device *, void *, void *);
73 void		agtimer_attach(struct device *, struct device *, void *);
74 uint64_t	agtimer_readcnt64(struct agtimer_softc *sc);
75 int		agtimer_intr(void *);
76 void		agtimer_cpu_initclocks(void);
77 void		agtimer_delay(u_int);
78 void		agtimer_setstatclockrate(int stathz);
79 void		agtimer_set_clockrate(int32_t new_frequency);
80 void		agtimer_startclock(void);
81 
82 /* hack - XXXX
83  * agtimer connects directly to ampintc, not thru the generic
84  * inteface because it uses an 'internal' interupt
85  * not a peripheral interrupt.
86  */
87 void	*ampintc_intr_establish(int, int, int (*)(void *), void *, char *);
88 
89 
90 
91 struct cfattach agtimer_ca = {
92 	sizeof (struct agtimer_softc), agtimer_match, agtimer_attach
93 };
94 
95 struct cfdriver agtimer_cd = {
96 	NULL, "agtimer", DV_DULL
97 };
98 
99 uint64_t
100 agtimer_readcnt64(struct agtimer_softc *sc)
101 {
102 	uint64_t val;
103 
104 	__asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (val));
105 
106 	return (val);
107 }
108 
109 static inline int
110 agtimer_get_ctrl(void)
111 {
112 	uint32_t val;
113 
114 	__asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val));
115 
116 	return (val);
117 }
118 
119 static inline int
120 agtimer_set_ctrl(uint32_t val)
121 {
122 	__asm volatile("mcr p15, 0, %[val], c14, c2, 1" : :
123 	    [val] "r" (val));
124 
125 	cpu_drain_writebuf();
126 	//isb();
127 
128 	return (0);
129 }
130 
131 static inline int
132 agtimer_get_tval(void)
133 {
134 	uint32_t val;
135 
136 	__asm volatile("mrc p15, 0, %0, c14, c2, 0" : "=r" (val));
137 
138 	return (val);
139 }
140 
141 static inline int
142 agtimer_set_tval(uint32_t val)
143 {
144 	__asm volatile("mcr p15, 0, %[val], c14, c2, 0" : :
145 	    [val] "r" (val));
146 	cpu_drain_writebuf();
147 	//isb();
148 
149 	return (0);
150 }
151 
152 int
153 agtimer_match(struct device *parent, void *cfdata, void *aux)
154 {
155 	if ((cpufunc_id() & CPU_ID_CORTEX_A7_MASK) == CPU_ID_CORTEX_A7 ||
156 	    (cpufunc_id() & CPU_ID_CORTEX_A15_MASK) == CPU_ID_CORTEX_A15)
157 		return (1);
158 
159 	return 0;
160 }
161 
162 void
163 agtimer_attach(struct device *parent, struct device *self, void *args)
164 {
165 	struct agtimer_softc *sc = (struct agtimer_softc *)self;
166 
167 	sc->sc_ticks_per_second = agtimer_frequency;
168 	printf(": tick rate %d KHz\n", sc->sc_ticks_per_second /1000);
169 
170 	/* XXX: disable user access */
171 
172 #ifdef AMPTIMER_DEBUG
173 	evcount_attach(&sc->sc_clk_count, "clock", NULL);
174 	evcount_attach(&sc->sc_stat_count, "stat", NULL);
175 #endif
176 
177 	/*
178 	 * private timer and interrupts not enabled until
179 	 * timer configures
180 	 */
181 
182 	arm_clock_register(agtimer_cpu_initclocks, agtimer_delay,
183 	    agtimer_setstatclockrate, agtimer_startclock);
184 
185 	agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
186 	agtimer_timecounter.tc_priv = sc;
187 
188 	tc_init(&agtimer_timecounter);
189 }
190 
191 u_int
192 agtimer_get_timecount(struct timecounter *tc)
193 {
194 	struct agtimer_softc *sc = agtimer_timecounter.tc_priv;
195 	return agtimer_readcnt64(sc);
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, reg;
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(sc);
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 	reg = agtimer_get_ctrl();
264 	if (reg & GTIMER_CNTP_CTL_ISTATUS) {
265 		reg |= GTIMER_CNTP_CTL_IMASK;
266 		agtimer_set_ctrl(reg);
267 	}
268 
269 	return (rc);
270 }
271 
272 void
273 agtimer_set_clockrate(int32_t new_frequency)
274 {
275 	struct agtimer_softc	*sc = agtimer_cd.cd_devs[0];
276 
277 	agtimer_frequency = new_frequency;
278 
279 	if (sc == NULL)
280 		return;
281 
282 	sc->sc_ticks_per_second = agtimer_frequency;
283 	agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
284 	printf("agtimer0: adjusting clock: new tick rate %d KHz\n",
285 	    sc->sc_ticks_per_second /1000);
286 }
287 
288 void
289 agtimer_cpu_initclocks()
290 {
291 	struct agtimer_softc	*sc = agtimer_cd.cd_devs[0];
292 	struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
293 	uint32_t		 reg;
294 	uint64_t		 next;
295 
296 	stathz = hz;
297 	profhz = hz * 10;
298 
299 	if (sc->sc_ticks_per_second != agtimer_frequency) {
300 		agtimer_set_clockrate(agtimer_frequency);
301 	}
302 
303 	agtimer_setstatclockrate(stathz);
304 
305 	sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz;
306 	sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz;
307 	pc->pc_ticks_err_sum = 0;
308 
309 	/* establish interrupts */
310 	/* XXX - irq */
311 	ampintc_intr_establish(29, IPL_CLOCK, agtimer_intr,
312 	    NULL, "tick");
313 
314 	next = agtimer_readcnt64(sc) + sc->sc_ticks_per_intr;
315 	pc->pc_nexttickevent = pc->pc_nextstatevent = next;
316 
317 	reg = agtimer_get_ctrl();
318 	reg &= GTIMER_CNTP_CTL_IMASK;
319 	reg |= GTIMER_CNTP_CTL_ENABLE;
320 	agtimer_set_tval(sc->sc_ticks_per_second);
321 	agtimer_set_ctrl(reg);
322 }
323 
324 void
325 agtimer_delay(u_int usecs)
326 {
327 	struct agtimer_softc	*sc = agtimer_cd.cd_devs[0];
328 	u_int32_t		clock, oclock, delta, delaycnt;
329 	volatile int		j;
330 	int			csec, usec;
331 
332 	if (usecs > (0x80000000 / (sc->sc_ticks_per_second))) {
333 		csec = usecs / 10000;
334 		usec = usecs % 10000;
335 
336 		delaycnt = (sc->sc_ticks_per_second / 100) * csec +
337 		    (sc->sc_ticks_per_second / 100) * usec / 10000;
338 	} else {
339 		delaycnt = sc->sc_ticks_per_second * usecs / 1000000;
340 	}
341 	if (delaycnt <= 1)
342 		for (j = 100; j > 0; j--)
343 			;
344 
345 	oclock = agtimer_readcnt64(sc);
346 	while (1) {
347 		for (j = 100; j > 0; j--)
348 			;
349 		clock = agtimer_readcnt64(sc);
350 		delta = clock - oclock;
351 		if (delta > delaycnt)
352 			break;
353 	}
354 }
355 
356 void
357 agtimer_setstatclockrate(int newhz)
358 {
359 	struct agtimer_softc	*sc = agtimer_cd.cd_devs[0];
360 	int			 minint, statint;
361 	int			 s;
362 
363 	s = splclock();
364 
365 	statint = sc->sc_ticks_per_second / newhz;
366 	/* calculate largest 2^n which is smaller that just over half statint */
367 	sc->sc_statvar = 0x40000000; /* really big power of two */
368 	minint = statint / 2 + 100;
369 	while (sc->sc_statvar > minint)
370 		sc->sc_statvar >>= 1;
371 
372 	sc->sc_statmin = statint - (sc->sc_statvar >> 1);
373 
374 	splx(s);
375 
376 	/*
377 	 * XXX this allows the next stat timer to occur then it switches
378 	 * to the new frequency. Rather than switching instantly.
379 	 */
380 }
381 
382 void
383 agtimer_startclock(void)
384 {
385 	struct agtimer_softc	*sc = agtimer_cd.cd_devs[0];
386 	struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
387 	uint64_t nextevent;
388 	uint32_t reg;
389 
390 	nextevent = agtimer_readcnt64(sc) + sc->sc_ticks_per_intr;
391 	pc->pc_nexttickevent = pc->pc_nextstatevent = nextevent;
392 
393 	reg = agtimer_get_ctrl();
394 	reg &= GTIMER_CNTP_CTL_IMASK;
395 	reg |= GTIMER_CNTP_CTL_ENABLE;
396 	agtimer_set_tval(sc->sc_ticks_per_second);
397 	agtimer_set_ctrl(reg);
398 }
399