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