xref: /openbsd-src/sys/arch/arm/cortex/amptimer.c (revision 4e1ee0786f11cc571bd0be17d38e46f635c719fc)
1 /* $OpenBSD: amptimer.c,v 1.13 2021/05/16 03:39:27 jsg Exp $ */
2 /*
3  * Copyright (c) 2011 Dale Rahn <drahn@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/device.h>
21 #include <sys/kernel.h>
22 #include <sys/timetc.h>
23 
24 #include <arm/cpufunc.h>
25 #include <machine/bus.h>
26 #include <machine/intr.h>
27 #include <arm/cortex/cortex.h>
28 
29 /* offset from periphbase */
30 #define GTIMER_ADDR	0x200
31 #define GTIMER_SIZE	0x100
32 
33 /* registers */
34 #define GTIMER_CNT_LOW		0x00
35 #define GTIMER_CNT_HIGH		0x04
36 #define GTIMER_CTRL		0x08
37 #define GTIMER_CTRL_AA		(1 << 3)
38 #define GTIMER_CTRL_IRQ		(1 << 2)
39 #define GTIMER_CTRL_COMP	(1 << 1)
40 #define GTIMER_CTRL_TIMER	(1 << 0)
41 #define GTIMER_STATUS		0x0c
42 #define GTIMER_STATUS_EVENT	(1 << 0)
43 #define GTIMER_CMP_LOW		0x10
44 #define GTIMER_CMP_HIGH		0x14
45 #define GTIMER_AUTOINC		0x18
46 
47 /* offset from periphbase */
48 #define PTIMER_ADDR		0x600
49 #define PTIMER_SIZE		0x100
50 
51 /* registers */
52 #define PTIMER_LOAD		0x0
53 #define PTIMER_CNT		0x4
54 #define PTIMER_CTRL		0x8
55 #define PTIMER_CTRL_ENABLE	(1<<0)
56 #define PTIMER_CTRL_AUTORELOAD	(1<<1)
57 #define PTIMER_CTRL_IRQEN	(1<<2)
58 #define PTIMER_STATUS		0xC
59 #define PTIMER_STATUS_EVENT	(1<<0)
60 
61 #define TIMER_FREQUENCY		396 * 1000 * 1000 /* ARM core clock */
62 int32_t amptimer_frequency = TIMER_FREQUENCY;
63 
64 u_int amptimer_get_timecount(struct timecounter *);
65 
66 static struct timecounter amptimer_timecounter = {
67 	.tc_get_timecount = amptimer_get_timecount,
68 	.tc_poll_pps = NULL,
69 	.tc_counter_mask = 0xffffffff,
70 	.tc_frequency = 0,
71 	.tc_name = "amptimer",
72 	.tc_quality = 0,
73 	.tc_priv = NULL,
74 	.tc_user = 0,
75 };
76 
77 #define MAX_ARM_CPUS	8
78 
79 struct amptimer_pcpu_softc {
80 	uint64_t 		pc_nexttickevent;
81 	uint64_t 		pc_nextstatevent;
82 	u_int32_t		pc_ticks_err_sum;
83 };
84 
85 struct amptimer_softc {
86 	struct device		sc_dev;
87 	bus_space_tag_t		sc_iot;
88 	bus_space_handle_t	sc_ioh;
89 	bus_space_handle_t	sc_pioh;
90 
91 	struct amptimer_pcpu_softc sc_pstat[MAX_ARM_CPUS];
92 
93 	u_int32_t		sc_ticks_err_cnt;
94 	u_int32_t		sc_ticks_per_second;
95 	u_int32_t		sc_ticks_per_intr;
96 	u_int32_t		sc_statvar;
97 	u_int32_t		sc_statmin;
98 
99 #ifdef AMPTIMER_DEBUG
100 	struct evcount		sc_clk_count;
101 	struct evcount		sc_stat_count;
102 #endif
103 };
104 
105 int		amptimer_match(struct device *, void *, void *);
106 void		amptimer_attach(struct device *, struct device *, void *);
107 uint64_t	amptimer_readcnt64(struct amptimer_softc *sc);
108 int		amptimer_intr(void *);
109 void		amptimer_cpu_initclocks(void);
110 void		amptimer_delay(u_int);
111 void		amptimer_setstatclockrate(int stathz);
112 void		amptimer_set_clockrate(int32_t new_frequency);
113 void		amptimer_startclock(void);
114 
115 /* hack - XXXX
116  * gptimer connects directly to ampintc, not thru the generic
117  * interface because it uses an 'internal' interrupt
118  * not a peripheral interrupt.
119  */
120 void	*ampintc_intr_establish(int, int, int, struct cpu_info *,
121 	    int (*)(void *), void *, char *);
122 
123 
124 
125 struct cfattach amptimer_ca = {
126 	sizeof (struct amptimer_softc), amptimer_match, amptimer_attach
127 };
128 
129 struct cfdriver amptimer_cd = {
130 	NULL, "amptimer", DV_DULL
131 };
132 
133 uint64_t
134 amptimer_readcnt64(struct amptimer_softc *sc)
135 {
136 	uint32_t high0, high1, low;
137 	bus_space_tag_t iot = sc->sc_iot;
138 	bus_space_handle_t ioh = sc->sc_ioh;
139 
140 	do {
141 		high0 = bus_space_read_4(iot, ioh, GTIMER_CNT_HIGH);
142 		low = bus_space_read_4(iot, ioh, GTIMER_CNT_LOW);
143 		high1 = bus_space_read_4(iot, ioh, GTIMER_CNT_HIGH);
144 	} while (high0 != high1);
145 
146 	return ((((uint64_t)high1) << 32) | low);
147 }
148 
149 int
150 amptimer_match(struct device *parent, void *cfdata, void *aux)
151 {
152 	if ((cpufunc_id() & CPU_ID_CORTEX_A9_MASK) == CPU_ID_CORTEX_A9)
153 		return (1);
154 
155 	return 0;
156 }
157 
158 void
159 amptimer_attach(struct device *parent, struct device *self, void *args)
160 {
161 	struct amptimer_softc *sc = (struct amptimer_softc *)self;
162 	struct cortex_attach_args *ia = args;
163 	bus_space_handle_t ioh, pioh;
164 
165 	sc->sc_iot = ia->ca_iot;
166 
167 	if (bus_space_map(sc->sc_iot, ia->ca_periphbase + GTIMER_ADDR,
168 	    GTIMER_SIZE, 0, &ioh))
169 		panic("amptimer_attach: bus_space_map global timer failed!");
170 
171 	if (bus_space_map(sc->sc_iot, ia->ca_periphbase + PTIMER_ADDR,
172 	    PTIMER_SIZE, 0, &pioh))
173 		panic("amptimer_attach: bus_space_map priv timer failed!");
174 
175 	sc->sc_ticks_per_second = amptimer_frequency;
176 	printf(": %d kHz\n", sc->sc_ticks_per_second / 1000);
177 
178 	sc->sc_ioh = ioh;
179 	sc->sc_pioh = pioh;
180 
181 	/* disable global timer */
182 	bus_space_write_4(sc->sc_iot, ioh, GTIMER_CTRL, 0);
183 
184 	/* XXX ??? reset counters to 0 - gives us uptime in the counter */
185 	bus_space_write_4(sc->sc_iot, ioh, GTIMER_CNT_LOW, 0);
186 	bus_space_write_4(sc->sc_iot, ioh, GTIMER_CNT_HIGH, 0);
187 
188 	/* enable global timer */
189 	bus_space_write_4(sc->sc_iot, ioh, GTIMER_CTRL, GTIMER_CTRL_TIMER);
190 
191 #if defined(USE_GTIMER_CMP)
192 
193 	/* clear event */
194 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_STATUS, 1);
195 #else
196 	bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL, 0);
197 	bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_STATUS,
198 	    PTIMER_STATUS_EVENT);
199 #endif
200 
201 
202 #ifdef AMPTIMER_DEBUG
203 	evcount_attach(&sc->sc_clk_count, "clock", NULL);
204 	evcount_attach(&sc->sc_stat_count, "stat", NULL);
205 #endif
206 
207 	/*
208 	 * private timer and interrupts not enabled until
209 	 * timer configures
210 	 */
211 
212 	arm_clock_register(amptimer_cpu_initclocks, amptimer_delay,
213 	    amptimer_setstatclockrate, amptimer_startclock);
214 
215 	amptimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
216 	amptimer_timecounter.tc_priv = sc;
217 
218 	tc_init(&amptimer_timecounter);
219 }
220 
221 u_int
222 amptimer_get_timecount(struct timecounter *tc)
223 {
224 	struct amptimer_softc *sc = amptimer_timecounter.tc_priv;
225 	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CNT_LOW);
226 }
227 
228 int
229 amptimer_intr(void *frame)
230 {
231 	struct amptimer_softc	*sc = amptimer_cd.cd_devs[0];
232 	struct amptimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
233 	uint64_t		 now;
234 	uint64_t		 nextevent;
235 	uint32_t		 r, reg;
236 #if defined(USE_GTIMER_CMP)
237 	int			 skip = 1;
238 #else
239 	int64_t			 delay;
240 #endif
241 	int			 rc = 0;
242 
243 	/*
244 	 * DSR - I know that the tick timer is 64 bits, but the following
245 	 * code deals with rollover, so there is no point in dealing
246 	 * with the 64 bit math, just let the 32 bit rollover
247 	 * do the right thing
248 	 */
249 
250 	now = amptimer_readcnt64(sc);
251 
252 	while (pc->pc_nexttickevent <= now) {
253 		pc->pc_nexttickevent += sc->sc_ticks_per_intr;
254 		pc->pc_ticks_err_sum += sc->sc_ticks_err_cnt;
255 
256 		/* looping a few times is faster than divide */
257 		while (pc->pc_ticks_err_sum  > hz) {
258 			pc->pc_nexttickevent += 1;
259 			pc->pc_ticks_err_sum -= hz;
260 		}
261 
262 #ifdef AMPTIMER_DEBUG
263 		sc->sc_clk_count.ec_count++;
264 #endif
265 		rc = 1;
266 		hardclock(frame);
267 	}
268 	while (pc->pc_nextstatevent <= now) {
269 		do {
270 			r = random() & (sc->sc_statvar -1);
271 		} while (r == 0); /* random == 0 not allowed */
272 		pc->pc_nextstatevent += sc->sc_statmin + r;
273 
274 		/* XXX - correct nextstatevent? */
275 #ifdef AMPTIMER_DEBUG
276 		sc->sc_stat_count.ec_count++;
277 #endif
278 		rc = 1;
279 		statclock(frame);
280 	}
281 
282 	if (pc->pc_nexttickevent < pc->pc_nextstatevent)
283 		nextevent = pc->pc_nexttickevent;
284 	else
285 		nextevent = pc->pc_nextstatevent;
286 
287 #if defined(USE_GTIMER_CMP)
288 again:
289 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL);
290 	reg &= ~GTIMER_CTRL_COMP;
291 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg);
292 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_LOW,
293 	    nextevent & 0xffffffff);
294 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_HIGH,
295 	    nextevent >> 32);
296 	reg |= GTIMER_CTRL_COMP;
297 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg);
298 
299 	now = amptimer_readcnt64(sc);
300 	if (now >= nextevent) {
301 		nextevent = now + skip;
302 		skip += 1;
303 		goto again;
304 	}
305 #else
306 	/* clear old status */
307 	bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_STATUS,
308 	    PTIMER_STATUS_EVENT);
309 
310 	delay = nextevent - now;
311 	if (delay < 0)
312 		delay = 1;
313 
314 	reg = bus_space_read_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL);
315 	if ((reg & (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN)) !=
316 	    (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN))
317 		bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL,
318 		    (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN));
319 
320 	bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD, delay);
321 #endif
322 
323 	return (rc);
324 }
325 
326 void
327 amptimer_set_clockrate(int32_t new_frequency)
328 {
329 	struct amptimer_softc	*sc = amptimer_cd.cd_devs[0];
330 
331 	amptimer_frequency = new_frequency;
332 
333 	if (sc == NULL)
334 		return;
335 
336 	sc->sc_ticks_per_second = amptimer_frequency;
337 	amptimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
338 	printf("amptimer0: adjusting clock: new rate %d kHz\n",
339 	    sc->sc_ticks_per_second / 1000);
340 }
341 
342 void
343 amptimer_cpu_initclocks(void)
344 {
345 	struct amptimer_softc	*sc = amptimer_cd.cd_devs[0];
346 	struct amptimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
347 	uint64_t		 next;
348 #if defined(USE_GTIMER_CMP)
349 	uint32_t		 reg;
350 #endif
351 
352 	stathz = hz;
353 	profhz = hz * 10;
354 
355 	if (sc->sc_ticks_per_second != amptimer_frequency) {
356 		amptimer_set_clockrate(amptimer_frequency);
357 	}
358 
359 	amptimer_setstatclockrate(stathz);
360 
361 	sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz;
362 	sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz;
363 	pc->pc_ticks_err_sum = 0;
364 
365 	/* establish interrupts */
366 	/* XXX - irq */
367 #if defined(USE_GTIMER_CMP)
368 	ampintc_intr_establish(27, IST_EDGE_RISING, IPL_CLOCK,
369 	    NULL, amptimer_intr, NULL, "tick");
370 #else
371 	ampintc_intr_establish(29, IST_EDGE_RISING, IPL_CLOCK,
372 	    NULL, amptimer_intr, NULL, "tick");
373 #endif
374 
375 	next = amptimer_readcnt64(sc) + sc->sc_ticks_per_intr;
376 	pc->pc_nexttickevent = pc->pc_nextstatevent = next;
377 
378 #if defined(USE_GTIMER_CMP)
379 	reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL);
380 	reg &= ~GTIMER_CTRL_COMP;
381 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg);
382 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_LOW,
383 	    next & 0xffffffff);
384 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_HIGH,
385 	    next >> 32);
386 	reg |= GTIMER_CTRL_COMP | GTIMER_CTRL_IRQ;
387 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg);
388 #else
389 	bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL,
390 	    (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN));
391 	bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD,
392 	    sc->sc_ticks_per_intr);
393 #endif
394 }
395 
396 void
397 amptimer_delay(u_int usecs)
398 {
399 	struct amptimer_softc	*sc = amptimer_cd.cd_devs[0];
400 	u_int32_t		clock, oclock, delta, delaycnt;
401 	volatile int		j;
402 	int			csec, usec;
403 
404 	if (usecs > (0x80000000 / (sc->sc_ticks_per_second))) {
405 		csec = usecs / 10000;
406 		usec = usecs % 10000;
407 
408 		delaycnt = (sc->sc_ticks_per_second / 100) * csec +
409 		    (sc->sc_ticks_per_second / 100) * usec / 10000;
410 	} else {
411 		delaycnt = sc->sc_ticks_per_second * usecs / 1000000;
412 	}
413 	if (delaycnt <= 1)
414 		for (j = 100; j > 0; j--)
415 			;
416 
417 	oclock = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CNT_LOW);
418 	while (1) {
419 		for (j = 100; j > 0; j--)
420 			;
421 		clock = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
422 		    GTIMER_CNT_LOW);
423 		delta = clock - oclock;
424 		if (delta > delaycnt)
425 			break;
426 	}
427 }
428 
429 void
430 amptimer_setstatclockrate(int newhz)
431 {
432 	struct amptimer_softc	*sc = amptimer_cd.cd_devs[0];
433 	int			 minint, statint;
434 	int			 s;
435 
436 	s = splclock();
437 
438 	statint = sc->sc_ticks_per_second / newhz;
439 	/* calculate largest 2^n which is smaller that just over half statint */
440 	sc->sc_statvar = 0x40000000; /* really big power of two */
441 	minint = statint / 2 + 100;
442 	while (sc->sc_statvar > minint)
443 		sc->sc_statvar >>= 1;
444 
445 	sc->sc_statmin = statint - (sc->sc_statvar >> 1);
446 
447 	splx(s);
448 
449 	/*
450 	 * XXX this allows the next stat timer to occur then it switches
451 	 * to the new frequency. Rather than switching instantly.
452 	 */
453 }
454 
455 void
456 amptimer_startclock(void)
457 {
458 	struct amptimer_softc	*sc = amptimer_cd.cd_devs[0];
459 	struct amptimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())];
460 	uint64_t nextevent;
461 
462 	nextevent = amptimer_readcnt64(sc) + sc->sc_ticks_per_intr;
463 	pc->pc_nexttickevent = pc->pc_nextstatevent = nextevent;
464 
465 	bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD,
466 		sc->sc_ticks_per_intr);
467 }
468