xref: /openbsd/sys/arch/armv7/sunxi/sxitimer.c (revision 771fbea0)
1 /*	$OpenBSD: sxitimer.c,v 1.17 2021/03/25 04:12:01 jsg Exp $	*/
2 /*
3  * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
4  * Copyright (c) 2013 Raphael Graf <r@undefined.ch>
5  * Copyright (c) 2013 Artturi Alm
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/param.h>
21 #include <sys/systm.h>
22 #include <sys/kernel.h>
23 #include <sys/device.h>
24 #include <sys/timetc.h>
25 
26 #include <machine/bus.h>
27 #include <machine/fdt.h>
28 #include <machine/intr.h>
29 
30 #include <dev/fdt/sunxireg.h>
31 
32 #include <dev/ofw/openfirm.h>
33 #include <dev/ofw/fdt.h>
34 
35 #define	TIMER_IER 		0x00
36 #define	TIMER_ISR 		0x04
37 #define	TIMER_IRQ(x)		(1 << (x))
38 
39 #define	TIMER_CTRL(x)		(0x10 + (0x10 * (x)))
40 #define	TIMER_INTV(x)		(0x14 + (0x10 * (x)))
41 #define	TIMER_CURR(x)		(0x18 + (0x10 * (x)))
42 
43 /* A1X counter */
44 #define	CNT64_CTRL		0xa0
45 #define	CNT64_LOW		0xa4
46 #define	CNT64_HIGH		0xa8
47 
48 #define	CNT64_CLR_EN		(1 << 0) /* clear enable */
49 #define	CNT64_RL_EN		(1 << 1) /* read latch enable */
50 
51 #define	TIMER_ENABLE		(1 << 0)
52 #define	TIMER_RELOAD		(1 << 1)
53 #define	TIMER_CLK_SRC_MASK	(3 << 2)
54 #define	TIMER_OSC24M		(1 << 2)
55 #define	TIMER_PLL6_6		(2 << 2)
56 #define	TIMER_PRESC_1		(0 << 4)
57 #define	TIMER_PRESC_2		(1 << 4)
58 #define	TIMER_PRESC_4		(2 << 4)
59 #define	TIMER_PRESC_8		(3 << 4)
60 #define	TIMER_PRESC_16		(4 << 4)
61 #define	TIMER_PRESC_32		(5 << 4)
62 #define	TIMER_PRESC_64		(6 << 4)
63 #define	TIMER_PRESC_128		(7 << 4)
64 #define	TIMER_CONTINOUS		(0 << 7)
65 #define	TIMER_SINGLESHOT	(1 << 7)
66 
67 #define	TICKTIMER		0
68 #define	STATTIMER		1
69 #define	CNTRTIMER		2
70 
71 #define TIMER_SYNC		3
72 
73 int	sxitimer_match(struct device *, void *, void *);
74 void	sxitimer_attach(struct device *, struct device *, void *);
75 int	sxitimer_tickintr(void *);
76 int	sxitimer_statintr(void *);
77 void	sxitimer_cpu_initclocks(void);
78 void	sxitimer_setstatclockrate(int);
79 uint64_t	sxitimer_readcnt64(void);
80 uint32_t	sxitimer_readcnt32(void);
81 void	sxitimer_sync(void);
82 void	sxitimer_delay(u_int);
83 
84 u_int sxitimer_get_timecount(struct timecounter *);
85 
86 static struct timecounter sxitimer_timecounter = {
87 	.tc_get_timecount = sxitimer_get_timecount,
88 	.tc_poll_pps = NULL,
89 	.tc_counter_mask = 0xffffffff,
90 	.tc_frequency = 0,
91 	.tc_name = "sxitimer",
92 	.tc_quality = 0,
93 	.tc_priv = NULL,
94 	.tc_user = 0,
95 };
96 
97 bus_space_tag_t		sxitimer_iot;
98 bus_space_handle_t	sxitimer_ioh;
99 
100 uint32_t sxitimer_freq[] = {
101 	TIMER0_FREQUENCY,
102 	TIMER1_FREQUENCY,
103 	TIMER2_FREQUENCY,
104 	0
105 };
106 
107 uint32_t sxitimer_irq[] = {
108 	TIMER0_IRQ,
109 	TIMER1_IRQ,
110 	TIMER2_IRQ,
111 	0
112 };
113 
114 uint32_t sxitimer_stat_tpi, sxitimer_tick_tpi;
115 uint32_t sxitimer_statvar, sxitimer_statmin;
116 uint32_t sxitimer_tick_nextevt, sxitimer_stat_nextevt;
117 uint32_t sxitimer_ticks_err_cnt, sxitimer_ticks_err_sum;
118 
119 struct sxitimer_softc {
120 	struct device		sc_dev;
121 };
122 
123 struct cfattach sxitimer_ca = {
124 	sizeof (struct sxitimer_softc), sxitimer_match, sxitimer_attach
125 };
126 
127 struct cfdriver sxitimer_cd = {
128 	NULL, "sxitimer", DV_DULL
129 };
130 
131 int
132 sxitimer_match(struct device *parent, void *match, void *aux)
133 {
134 	struct fdt_attach_args *faa = aux;
135 	int node;
136 
137 	node = OF_finddevice("/");
138 	if (!OF_is_compatible(node, "allwinner,sun4i-a10") &&
139 	    !OF_is_compatible(node, "allwinner,sun5i-a10s") &&
140 	    !OF_is_compatible(node, "allwinner,sun5i-a13"))
141 		return 0;
142 
143 	return OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-timer");
144 }
145 
146 void
147 sxitimer_attach(struct device *parent, struct device *self, void *aux)
148 {
149 	struct fdt_attach_args *faa = aux;
150 	uint32_t freq, ival, now;
151 
152 	KASSERT(faa->fa_nreg > 0);
153 
154 	sxitimer_iot = faa->fa_iot;
155 	if (bus_space_map(sxitimer_iot, faa->fa_reg[0].addr,
156 	    faa->fa_reg[0].size, 0, &sxitimer_ioh))
157 		panic("%s: bus_space_map failed!", __func__);
158 
159 	/* clear counter, loop until ready */
160 	bus_space_write_4(sxitimer_iot, sxitimer_ioh, CNT64_CTRL,
161 	    CNT64_CLR_EN); /* XXX as a side-effect counter clk src=OSC24M */
162 	while (bus_space_read_4(sxitimer_iot, sxitimer_ioh, CNT64_CTRL)
163 	    & CNT64_CLR_EN)
164 		continue;
165 
166 	/* timers are down-counters, from interval to 0 */
167 	now = 0xffffffff; /* known big value */
168 	freq = sxitimer_freq[TICKTIMER];
169 
170 	/* stop timer, and set clk src */
171 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
172 	    TIMER_CTRL(TICKTIMER), TIMER_OSC24M);
173 
174 	ival = sxitimer_tick_tpi = freq / hz;
175 	sxitimer_tick_nextevt = now - ival;
176 
177 	sxitimer_ticks_err_cnt = freq % hz;
178 	sxitimer_ticks_err_sum = 0;
179 
180 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
181 	    TIMER_INTV(TICKTIMER), ival);
182 
183 	/* timers are down-counters, from interval to 0 */
184 	now = 0xffffffff; /* known big value */
185 	freq = sxitimer_freq[STATTIMER];
186 
187 	/* stop timer, and set clk src */
188 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
189 	    TIMER_CTRL(STATTIMER), TIMER_OSC24M);
190 
191 	/* 100/1000 or 128/1024 ? */
192 	stathz = 128;
193 	profhz = 1024;
194 	sxitimer_setstatclockrate(stathz);
195 
196 	ival = sxitimer_stat_tpi = freq / stathz;
197 	sxitimer_stat_nextevt = now - ival;
198 
199 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
200 	    TIMER_INTV(STATTIMER), ival);
201 
202 	/* timers are down-counters, from interval to 0 */
203 	now = 0xffffffff; /* known big value */
204 	freq = sxitimer_freq[CNTRTIMER];
205 
206 	/* stop timer, and set clk src */
207 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
208 	    TIMER_CTRL(CNTRTIMER), TIMER_OSC24M);
209 
210 	ival = now;
211 
212 	sxitimer_timecounter.tc_frequency = freq;
213 	tc_init(&sxitimer_timecounter);
214 	arm_clock_register(sxitimer_cpu_initclocks, sxitimer_delay,
215 	    sxitimer_setstatclockrate, NULL);
216 
217 	printf(": %d kHz", freq / 1000);
218 
219 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
220 	    TIMER_INTV(CNTRTIMER), ival);
221 
222 	printf("\n");
223 }
224 
225 /*
226  * would be interesting to play with trigger mode while having one timer
227  * in 32kHz mode, and the other timer running in sysclk mode and use
228  * the high resolution speeds (matters more for delay than tick timer)
229  */
230 
231 void
232 sxitimer_cpu_initclocks(void)
233 {
234 	uint32_t isr, ier, ctrl;
235 
236 	/* establish interrupts */
237 	arm_intr_establish(sxitimer_irq[TICKTIMER], IPL_CLOCK,
238 	    sxitimer_tickintr, NULL, "tick");
239 	arm_intr_establish(sxitimer_irq[STATTIMER], IPL_STATCLOCK,
240 	    sxitimer_statintr, NULL, "stattick");
241 
242 	/* clear timer interrupt pending bits */
243 	isr = bus_space_read_4(sxitimer_iot, sxitimer_ioh, TIMER_ISR);
244 	isr |= TIMER_IRQ(STATTIMER) | TIMER_IRQ(TICKTIMER);
245 	bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_ISR, isr);
246 
247 	/* enable timer IRQs */
248 	ier = bus_space_read_4(sxitimer_iot, sxitimer_ioh, TIMER_IER);
249 	ier |= TIMER_IRQ(STATTIMER) | TIMER_IRQ(TICKTIMER);
250 	bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_IER, ier);
251 
252 	/* enable timers */
253 	ctrl = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
254 	    TIMER_CTRL(CNTRTIMER));
255 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
256 	    TIMER_CTRL(CNTRTIMER),
257 	    ctrl | TIMER_ENABLE | TIMER_RELOAD | TIMER_CONTINOUS);
258 
259 	ctrl = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
260 	    TIMER_CTRL(STATTIMER));
261 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
262 	    TIMER_CTRL(STATTIMER),
263 	    ctrl | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
264 
265 	ctrl = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
266 	    TIMER_CTRL(TICKTIMER));
267 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
268 	    TIMER_CTRL(TICKTIMER),
269 	    ctrl | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
270 }
271 
272 /*
273  * See comment in arm/xscale/i80321_clock.c
274  *
275  * Counter is count up, but with autoreload timers it is not possible
276  * to detect how many interrupts passed while interrupts were blocked.
277  * Also it is not possible to atomically add to the register.
278  *
279  * To work around this two timers are used, one is used as a reference
280  * clock without reload, however we just disable the interrupt it
281  * could generate.
282  *
283  * Internally this keeps track of when the next timer should fire
284  * and based on that time and the current value of the reference
285  * clock a number is written into the timer count register to schedule
286  * the next event.
287  */
288 /* XXX update above comment */
289 int
290 sxitimer_tickintr(void *frame)
291 {
292 	uint32_t now, nextevent;
293 	uint32_t val;
294 	int rc = 0;
295 
296 	splassert(IPL_CLOCK);
297 
298 	/* clear timer pending interrupt bit */
299 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
300 	    TIMER_ISR, TIMER_IRQ(TICKTIMER));
301 
302 	now = sxitimer_readcnt32();
303 
304 	while ((int32_t)(now - sxitimer_tick_nextevt) < 0) {
305 		sxitimer_tick_nextevt -= sxitimer_tick_tpi;
306 		sxitimer_ticks_err_sum += sxitimer_ticks_err_cnt;
307 
308 		while (sxitimer_ticks_err_sum  > hz) {
309 			sxitimer_tick_nextevt += 1;
310 			sxitimer_ticks_err_sum -= hz;
311 		}
312 
313 		rc = 1;
314 		hardclock(frame);
315 	}
316 	nextevent = now - sxitimer_tick_nextevt;
317 	if (nextevent < 10 /* XXX */)
318 		nextevent = 10;
319 
320 	if (nextevent > sxitimer_tick_tpi) {
321 		/*
322 		 * If interrupts are blocked too long, like during
323 		 * the root prompt or ddb, the timer can roll over,
324 		 * this will allow the system to continue to run
325 		 * even if time is lost.
326 		 */
327 		nextevent = sxitimer_tick_tpi;
328 		sxitimer_tick_nextevt = now;
329 	}
330 
331 	val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
332 	    TIMER_CTRL(TICKTIMER));
333 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
334 	    TIMER_CTRL(TICKTIMER), val & ~TIMER_ENABLE);
335 
336 	sxitimer_sync();
337 
338 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
339 	    TIMER_INTV(TICKTIMER), nextevent);
340 
341 	val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
342 	    TIMER_CTRL(TICKTIMER));
343 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
344 	    TIMER_CTRL(TICKTIMER),
345 	    val | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
346 
347 	return rc;
348 }
349 
350 int
351 sxitimer_statintr(void *frame)
352 {
353 	uint32_t now, nextevent, r;
354 	uint32_t val;
355 	int rc = 0;
356 
357 	splassert(IPL_STATCLOCK);
358 
359 	/* clear timer pending interrupt bit */
360 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
361 	    TIMER_ISR, TIMER_IRQ(STATTIMER));
362 
363 	now = sxitimer_readcnt32();
364 	while ((int32_t)(now - sxitimer_stat_nextevt) < 0) {
365 		do {
366 			r = random() & (sxitimer_statvar -1);
367 		} while (r == 0); /* random == 0 not allowed */
368 		sxitimer_stat_nextevt -= sxitimer_statmin + r;
369 		rc = 1;
370 		statclock(frame);
371 	}
372 
373 	nextevent = now - sxitimer_stat_nextevt;
374 
375 	if (nextevent < 10 /* XXX */)
376 		nextevent = 10;
377 
378 	if (nextevent > sxitimer_stat_tpi) {
379 		/*
380 		 * If interrupts are blocked too long, like during
381 		 * the root prompt or ddb, the timer can roll over,
382 		 * this will allow the system to continue to run
383 		 * even if time is lost.
384 		 */
385 		nextevent = sxitimer_stat_tpi;
386 		sxitimer_stat_nextevt = now;
387 	}
388 
389 	val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
390 	    TIMER_CTRL(STATTIMER));
391 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
392 	    TIMER_CTRL(STATTIMER), val & ~TIMER_ENABLE);
393 
394 	sxitimer_sync();
395 
396 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
397 	    TIMER_INTV(STATTIMER), nextevent);
398 
399 	val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
400 	    TIMER_CTRL(STATTIMER));
401 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
402 	    TIMER_CTRL(STATTIMER),
403 	    val | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
404 
405 	return rc;
406 }
407 
408 uint64_t
409 sxitimer_readcnt64(void)
410 {
411 	uint32_t low, high;
412 
413 	/* latch counter, loop until ready */
414 	bus_space_write_4(sxitimer_iot, sxitimer_ioh, CNT64_CTRL, CNT64_RL_EN);
415 	while (bus_space_read_4(sxitimer_iot, sxitimer_ioh, CNT64_CTRL)
416 	    & CNT64_RL_EN)
417 		continue;
418 
419 	/*
420 	 * A10 usermanual doesn't mention anything about order, but fwiw
421 	 * iirc. A20 manual mentions that low should be read first.
422 	 */
423 	/* XXX check above */
424 	low = bus_space_read_4(sxitimer_iot, sxitimer_ioh, CNT64_LOW);
425 	high = bus_space_read_4(sxitimer_iot, sxitimer_ioh, CNT64_HIGH);
426 	return (uint64_t)high << 32 | low;
427 }
428 
429 uint32_t
430 sxitimer_readcnt32(void)
431 {
432 	return bus_space_read_4(sxitimer_iot, sxitimer_ioh,
433 	    TIMER_CURR(CNTRTIMER));
434 }
435 
436 void
437 sxitimer_sync(void)
438 {
439 	uint32_t now = sxitimer_readcnt32();
440 
441 	while ((now - sxitimer_readcnt32()) < TIMER_SYNC)
442 		CPU_BUSY_CYCLE();
443 }
444 
445 void
446 sxitimer_delay(u_int usecs)
447 {
448 	uint64_t oclock, timeout;
449 
450 	oclock = sxitimer_readcnt64();
451 	timeout = oclock + (COUNTER_FREQUENCY / 1000000) * usecs;
452 
453 	while (oclock < timeout)
454 		oclock = sxitimer_readcnt64();
455 }
456 
457 void
458 sxitimer_setstatclockrate(int newhz)
459 {
460 	int minint, statint, s;
461 
462 	s = splstatclock();
463 
464 	statint = sxitimer_freq[STATTIMER] / newhz;
465 	/* calculate largest 2^n which is smaller than just over half statint */
466 	sxitimer_statvar = 0x40000000; /* really big power of two */
467 	minint = statint / 2 + 100;
468 	while (sxitimer_statvar > minint)
469 		sxitimer_statvar >>= 1;
470 
471 	sxitimer_statmin = statint - (sxitimer_statvar >> 1);
472 
473 	splx(s);
474 
475 	/*
476 	 * XXX this allows the next stat timer to occur then it switches
477 	 * to the new frequency. Rather than switching instantly.
478 	 */
479 }
480 
481 u_int
482 sxitimer_get_timecount(struct timecounter *tc)
483 {
484 	return (u_int)UINT_MAX - sxitimer_readcnt32();
485 }
486