xref: /openbsd-src/sys/arch/armv7/sunxi/sxitimer.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: sxitimer.c,v 1.6 2016/07/18 19:22:45 kettenis 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/types.h>
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/kernel.h>
24 #include <sys/time.h>
25 #include <sys/evcount.h>
26 #include <sys/device.h>
27 #include <sys/timetc.h>
28 #include <dev/clock_subr.h>
29 
30 #include <arm/cpufunc.h>
31 
32 #include <machine/bus.h>
33 #include <machine/intr.h>
34 
35 #include <armv7/armv7/armv7var.h>
36 #include <armv7/sunxi/sunxireg.h>
37 /* #include <armv7/sunxi/sxipiovar.h> */
38 
39 #define	TIMER_IER 		0x00
40 #define	TIMER_ISR 		0x04
41 #define	TIMER_IRQ(x)		(1 << (x))
42 
43 #define	TIMER_CTRL(x)		(0x10 + (0x10 * (x)))
44 #define	TIMER_INTV(x)		(0x14 + (0x10 * (x)))
45 #define	TIMER_CURR(x)		(0x18 + (0x10 * (x)))
46 
47 /* A1X counter */
48 #define	CNT64_CTRL		0xa0
49 #define	CNT64_LOW		0xa4
50 #define	CNT64_HIGH		0xa8
51 
52 #define	CNT64_CLR_EN		(1 << 0) /* clear enable */
53 #define	CNT64_RL_EN		(1 << 1) /* read latch enable */
54 
55 #define	LOSC_CTRL		0x100
56 #define	OSC32K_SRC_SEL		(1 << 0)
57 
58 #define	TIMER_ENABLE		(1 << 0)
59 #define	TIMER_RELOAD		(1 << 1)
60 #define	TIMER_CLK_SRC_MASK	(3 << 2)
61 #define	TIMER_LSOSC		(0 << 2)
62 #define	TIMER_OSC24M		(1 << 2)
63 #define	TIMER_PLL6_6		(2 << 2)
64 #define	TIMER_PRESC_1		(0 << 4)
65 #define	TIMER_PRESC_2		(1 << 4)
66 #define	TIMER_PRESC_4		(2 << 4)
67 #define	TIMER_PRESC_8		(3 << 4)
68 #define	TIMER_PRESC_16		(4 << 4)
69 #define	TIMER_PRESC_32		(5 << 4)
70 #define	TIMER_PRESC_64		(6 << 4)
71 #define	TIMER_PRESC_128		(7 << 4)
72 #define	TIMER_CONTINOUS		(0 << 7)
73 #define	TIMER_SINGLESHOT	(1 << 7)
74 
75 #define	TICKTIMER		0
76 #define	STATTIMER		1
77 #define	CNTRTIMER		2
78 
79 #define TIMER_SYNC		3
80 
81 void	sxitimer_attach(struct device *, struct device *, void *);
82 int	sxitimer_tickintr(void *);
83 int	sxitimer_statintr(void *);
84 void	sxitimer_cpu_initclocks(void);
85 void	sxitimer_setstatclockrate(int);
86 uint64_t	sxitimer_readcnt64(void);
87 uint32_t	sxitimer_readcnt32(void);
88 void	sxitimer_sync(void);
89 void	sxitimer_delay(u_int);
90 
91 u_int sxitimer_get_timecount(struct timecounter *);
92 
93 static struct timecounter sxitimer_timecounter = {
94 	sxitimer_get_timecount, NULL, 0xffffffff, 0, "sxitimer", 0, NULL
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), NULL, sxitimer_attach
125 };
126 
127 struct cfdriver sxitimer_cd = {
128 	NULL, "sxitimer", DV_DULL
129 };
130 
131 void
132 sxitimer_attach(struct device *parent, struct device *self, void *args)
133 {
134 	struct armv7_attach_args *aa = args;
135 	uint32_t freq, ival, now, cr;
136 	int unit = self->dv_unit;
137 
138 	if (unit != 0)
139 		goto skip_init;
140 
141 	sxitimer_iot = aa->aa_iot;
142 
143 	if (bus_space_map(sxitimer_iot, aa->aa_dev->mem[0].addr,
144 	    aa->aa_dev->mem[0].size, 0, &sxitimer_ioh))
145 		panic("sxitimer_attach: bus_space_map failed!");
146 
147 	/* clear counter, loop until ready */
148 	bus_space_write_4(sxitimer_iot, sxitimer_ioh, CNT64_CTRL,
149 	    CNT64_CLR_EN); /* XXX as a side-effect counter clk src=OSC24M */
150 	while (bus_space_read_4(sxitimer_iot, sxitimer_ioh, CNT64_CTRL)
151 	    & CNT64_CLR_EN)
152 		continue;
153 
154 	/* setup timers */
155 	cr = bus_space_read_4(sxitimer_iot, sxitimer_ioh, LOSC_CTRL);
156 	cr |= OSC32K_SRC_SEL; /* ext 32.768KHz OSC src */
157 	bus_space_write_4(sxitimer_iot, sxitimer_ioh, LOSC_CTRL, cr);
158 
159 skip_init:
160 	/* timers are down-counters, from interval to 0 */
161 	now = 0xffffffff; /* known big value */
162 	freq = sxitimer_freq[unit];
163 
164 	/* stop timer, and set clk src */
165 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
166 	    TIMER_CTRL(unit),
167 	    freq == 24000000 ? TIMER_OSC24M : TIMER_LSOSC);
168 
169 	switch (unit) { /* XXX more XXXXTIMER magic for less lines? */
170 	case TICKTIMER:
171 		ival = sxitimer_tick_tpi = freq / hz;
172 		sxitimer_tick_nextevt = now - ival;
173 
174 		sxitimer_ticks_err_cnt = freq % hz;
175 		sxitimer_ticks_err_sum = 0;
176 
177 		printf(": ticktimer %dhz @ %dKHz", hz, freq / 1000);
178 		break;
179 	case STATTIMER:
180 		/* 100/1000 or 128/1024 ? */
181 		stathz = 128;
182 		profhz = 1024;
183 		sxitimer_setstatclockrate(stathz);
184 
185 		ival = sxitimer_stat_tpi = freq / stathz;
186 		sxitimer_stat_nextevt = now - ival;
187 
188 		printf(": stattimer %dhz @ %dKHz", stathz, freq / 1000);
189 		break;
190 	case CNTRTIMER:
191 		ival = now;
192 
193 		sxitimer_timecounter.tc_frequency = freq;
194 		tc_init(&sxitimer_timecounter);
195 		arm_clock_register(sxitimer_cpu_initclocks, sxitimer_delay,
196 		    sxitimer_setstatclockrate, NULL);
197 
198 		printf(": cntrtimer @ %dKHz", freq / 1000);
199 		break;
200 	default:
201 		panic("sxitimer_attach: unit = %d", unit);
202 		break;
203 	}
204 
205 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
206 	    TIMER_INTV(unit), ival);
207 
208 	printf("\n");
209 }
210 
211 /*
212  * would be interesting to play with trigger mode while having one timer
213  * in 32KHz mode, and the other timer running in sysclk mode and use
214  * the high resolution speeds (matters more for delay than tick timer)
215  */
216 
217 void
218 sxitimer_cpu_initclocks(void)
219 {
220 	uint32_t isr, ier;
221 
222 	/* establish interrupts */
223 	arm_intr_establish(sxitimer_irq[TICKTIMER], IPL_CLOCK,
224 	    sxitimer_tickintr, NULL, "tick");
225 	arm_intr_establish(sxitimer_irq[STATTIMER], IPL_STATCLOCK,
226 	    sxitimer_statintr, NULL, "stattick");
227 
228 	/* clear timer interrupt pending bits */
229 	isr = bus_space_read_4(sxitimer_iot, sxitimer_ioh, TIMER_ISR);
230 	isr |= TIMER_IRQ(STATTIMER) | TIMER_IRQ(TICKTIMER);
231 	bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_ISR, isr);
232 
233 	/* enable timer IRQs */
234 	ier = bus_space_read_4(sxitimer_iot, sxitimer_ioh, TIMER_IER);
235 	ier |= TIMER_IRQ(STATTIMER) | TIMER_IRQ(TICKTIMER);
236 	bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_IER, ier);
237 
238 	/* enable timers */
239 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
240 	    TIMER_CTRL(CNTRTIMER),
241 	    TIMER_ENABLE | TIMER_RELOAD | TIMER_CONTINOUS);
242 
243 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
244 	    TIMER_CTRL(STATTIMER),
245 	    TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
246 
247 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
248 	    TIMER_CTRL(TICKTIMER),
249 	    TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
250 }
251 
252 /*
253  * See comment in arm/xscale/i80321_clock.c
254  *
255  * Counter is count up, but with autoreload timers it is not possible
256  * to detect how many interrupts passed while interrupts were blocked.
257  * Also it is not possible to atomically add to the register.
258  *
259  * To work around this two timers are used, one is used as a reference
260  * clock without reload, however we just disable the interrupt it
261  * could generate.
262  *
263  * Internally this keeps track of when the next timer should fire
264  * and based on that time and the current value of the reference
265  * clock a number is written into the timer count register to schedule
266  * the next event.
267  */
268 /* XXX update above comment */
269 int
270 sxitimer_tickintr(void *frame)
271 {
272 	uint32_t now, nextevent;
273 	uint32_t val;
274 	int rc = 0;
275 
276 	splassert(IPL_CLOCK);
277 
278 	/* clear timer pending interrupt bit */
279 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
280 	    TIMER_ISR, TIMER_IRQ(TICKTIMER));
281 
282 	now = sxitimer_readcnt32();
283 
284 	while ((int32_t)(now - sxitimer_tick_nextevt) < 0) {
285 		sxitimer_tick_nextevt -= sxitimer_tick_tpi;
286 		sxitimer_ticks_err_sum += sxitimer_ticks_err_cnt;
287 
288 		while (sxitimer_ticks_err_sum  > hz) {
289 			sxitimer_tick_nextevt += 1;
290 			sxitimer_ticks_err_sum -= hz;
291 		}
292 
293 		rc = 1;
294 		hardclock(frame);
295 	}
296 	nextevent = now - sxitimer_tick_nextevt;
297 	if (nextevent < 10 /* XXX */)
298 		nextevent = 10;
299 
300 	if (nextevent > sxitimer_tick_tpi) {
301 		/*
302 		 * If interrupts are blocked too long, like during
303 		 * the root prompt or ddb, the timer can roll over,
304 		 * this will allow the system to continue to run
305 		 * even if time is lost.
306 		 */
307 		nextevent = sxitimer_tick_tpi;
308 		sxitimer_tick_nextevt = now;
309 	}
310 
311 	val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
312 	    TIMER_CTRL(TICKTIMER));
313 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
314 	    TIMER_CTRL(TICKTIMER), val & ~TIMER_ENABLE);
315 
316 	sxitimer_sync();
317 
318 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
319 	    TIMER_INTV(TICKTIMER), nextevent);
320 
321 	val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
322 	    TIMER_CTRL(TICKTIMER));
323 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
324 	    TIMER_CTRL(TICKTIMER),
325 	    val | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
326 
327 	return rc;
328 }
329 
330 int
331 sxitimer_statintr(void *frame)
332 {
333 	uint32_t now, nextevent, r;
334 	uint32_t val;
335 	int rc = 0;
336 
337 	splassert(IPL_STATCLOCK);
338 
339 	/* clear timer pending interrupt bit */
340 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
341 	    TIMER_ISR, TIMER_IRQ(STATTIMER));
342 
343 	now = sxitimer_readcnt32();
344 	while ((int32_t)(now - sxitimer_stat_nextevt) < 0) {
345 		do {
346 			r = random() & (sxitimer_statvar -1);
347 		} while (r == 0); /* random == 0 not allowed */
348 		sxitimer_stat_nextevt -= sxitimer_statmin + r;
349 		rc = 1;
350 		statclock(frame);
351 	}
352 
353 	nextevent = now - sxitimer_stat_nextevt;
354 
355 	if (nextevent < 10 /* XXX */)
356 		nextevent = 10;
357 
358 	if (nextevent > sxitimer_stat_tpi) {
359 		/*
360 		 * If interrupts are blocked too long, like during
361 		 * the root prompt or ddb, the timer can roll over,
362 		 * this will allow the system to continue to run
363 		 * even if time is lost.
364 		 */
365 		nextevent = sxitimer_stat_tpi;
366 		sxitimer_stat_nextevt = now;
367 	}
368 
369 	val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
370 	    TIMER_CTRL(STATTIMER));
371 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
372 	    TIMER_CTRL(STATTIMER), val & ~TIMER_ENABLE);
373 
374 	sxitimer_sync();
375 
376 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
377 	    TIMER_INTV(STATTIMER), nextevent);
378 
379 	val = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
380 	    TIMER_CTRL(STATTIMER));
381 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
382 	    TIMER_CTRL(STATTIMER),
383 	    val | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
384 
385 	return rc;
386 }
387 
388 uint64_t
389 sxitimer_readcnt64(void)
390 {
391 	uint32_t low, high;
392 
393 	/* latch counter, loop until ready */
394 	bus_space_write_4(sxitimer_iot, sxitimer_ioh, CNT64_CTRL, CNT64_RL_EN);
395 	while (bus_space_read_4(sxitimer_iot, sxitimer_ioh, CNT64_CTRL)
396 	    & CNT64_RL_EN)
397 		continue;
398 
399 	/*
400 	 * A10 usermanual doesn't mention anything about order, but fwiw
401 	 * iirc. A20 manual mentions that low should be read first.
402 	 */
403 	/* XXX check above */
404 	low = bus_space_read_4(sxitimer_iot, sxitimer_ioh, CNT64_LOW);
405 	high = bus_space_read_4(sxitimer_iot, sxitimer_ioh, CNT64_HIGH);
406 	return (uint64_t)high << 32 | low;
407 }
408 
409 uint32_t
410 sxitimer_readcnt32(void)
411 {
412 	return bus_space_read_4(sxitimer_iot, sxitimer_ioh,
413 	    TIMER_CURR(CNTRTIMER));
414 }
415 
416 void
417 sxitimer_sync(void)
418 {
419 	uint32_t now = sxitimer_readcnt32();
420 
421 	while ((now - sxitimer_readcnt32()) < TIMER_SYNC)
422 		CPU_BUSY_CYCLE();
423 }
424 
425 void
426 sxitimer_delay(u_int usecs)
427 {
428 	uint64_t oclock, timeout;
429 
430 	oclock = sxitimer_readcnt64();
431 	timeout = oclock + (COUNTER_FREQUENCY / 1000000) * usecs;
432 
433 	while (oclock < timeout)
434 		oclock = sxitimer_readcnt64();
435 }
436 
437 void
438 sxitimer_setstatclockrate(int newhz)
439 {
440 	int minint, statint, s;
441 
442 	s = splstatclock();
443 
444 	statint = sxitimer_freq[STATTIMER] / newhz;
445 	/* calculate largest 2^n which is smaller than just over half statint */
446 	sxitimer_statvar = 0x40000000; /* really big power of two */
447 	minint = statint / 2 + 100;
448 	while (sxitimer_statvar > minint)
449 		sxitimer_statvar >>= 1;
450 
451 	sxitimer_statmin = statint - (sxitimer_statvar >> 1);
452 
453 	splx(s);
454 
455 	/*
456 	 * XXX this allows the next stat timer to occur then it switches
457 	 * to the new frequency. Rather than switching instantly.
458 	 */
459 }
460 
461 u_int
462 sxitimer_get_timecount(struct timecounter *tc)
463 {
464 	return (u_int)UINT_MAX - sxitimer_readcnt32();
465 }
466