xref: /openbsd/sys/arch/armv7/sunxi/sxitimer.c (revision 0f9e9ec2)
1 /*	$OpenBSD: sxitimer.c,v 1.25 2024/05/13 01:15:50 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/clockintr.h>
24 #include <sys/device.h>
25 #include <sys/stdint.h>
26 #include <sys/timetc.h>
27 
28 #include <machine/bus.h>
29 #include <machine/fdt.h>
30 #include <machine/intr.h>
31 
32 #include <dev/fdt/sunxireg.h>
33 
34 #include <dev/ofw/openfirm.h>
35 #include <dev/ofw/fdt.h>
36 
37 #define	TIMER_IER 		0x00
38 #define	TIMER_ISR 		0x04
39 #define	TIMER_IRQ(x)		(1 << (x))
40 
41 #define	TIMER_CTRL(x)		(0x10 + (0x10 * (x)))
42 #define	TIMER_INTV(x)		(0x14 + (0x10 * (x)))
43 #define	TIMER_CURR(x)		(0x18 + (0x10 * (x)))
44 
45 /* A1X counter */
46 #define	CNT64_CTRL		0xa0
47 #define	CNT64_LOW		0xa4
48 #define	CNT64_HIGH		0xa8
49 
50 #define	CNT64_CLR_EN		(1 << 0) /* clear enable */
51 #define	CNT64_RL_EN		(1 << 1) /* read latch enable */
52 
53 #define	TIMER_ENABLE		(1 << 0)
54 #define	TIMER_RELOAD		(1 << 1)
55 #define	TIMER_CLK_SRC_MASK	(3 << 2)
56 #define	TIMER_OSC24M		(1 << 2)
57 #define	TIMER_PLL6_6		(2 << 2)
58 #define	TIMER_PRESC_1		(0 << 4)
59 #define	TIMER_PRESC_2		(1 << 4)
60 #define	TIMER_PRESC_4		(2 << 4)
61 #define	TIMER_PRESC_8		(3 << 4)
62 #define	TIMER_PRESC_16		(4 << 4)
63 #define	TIMER_PRESC_32		(5 << 4)
64 #define	TIMER_PRESC_64		(6 << 4)
65 #define	TIMER_PRESC_128		(7 << 4)
66 #define	TIMER_CONTINOUS		(0 << 7)
67 #define	TIMER_SINGLESHOT	(1 << 7)
68 
69 #define	TICKTIMER		0
70 #define	STATTIMER		1
71 #define	CNTRTIMER		2
72 
73 #define TIMER_SYNC		3
74 
75 int	sxitimer_match(struct device *, void *, void *);
76 void	sxitimer_attach(struct device *, struct device *, void *);
77 int	sxitimer_tickintr(void *);
78 void	sxitimer_cpu_initclocks(void);
79 void	sxitimer_cpu_startclock(void);
80 void	sxitimer_setstatclockrate(int);
81 uint64_t	sxitimer_readcnt64(void);
82 uint32_t	sxitimer_readcnt32(void);
83 void	sxitimer_sync(void);
84 void	sxitimer_delay(u_int);
85 
86 u_int sxitimer_get_timecount(struct timecounter *);
87 
88 static struct timecounter sxitimer_timecounter = {
89 	.tc_get_timecount = sxitimer_get_timecount,
90 	.tc_counter_mask = 0xffffffff,
91 	.tc_frequency = 0,
92 	.tc_name = "sxitimer",
93 	.tc_quality = 0,
94 	.tc_priv = NULL,
95 	.tc_user = 0,
96 };
97 
98 uint64_t sxitimer_nsec_cycle_ratio;
99 uint64_t sxitimer_nsec_max;
100 
101 void sxitimer_rearm(void *, uint64_t);
102 void sxitimer_trigger(void *);
103 
104 const struct intrclock sxitimer_intrclock = {
105 	.ic_rearm = sxitimer_rearm,
106 	.ic_trigger = sxitimer_trigger
107 };
108 
109 bus_space_tag_t		sxitimer_iot;
110 bus_space_handle_t	sxitimer_ioh;
111 
112 uint32_t sxitimer_freq[] = {
113 	TIMER0_FREQUENCY,
114 	TIMER1_FREQUENCY,
115 	TIMER2_FREQUENCY,
116 	0
117 };
118 
119 uint32_t sxitimer_irq[] = {
120 	TIMER0_IRQ,
121 	TIMER1_IRQ,
122 	TIMER2_IRQ,
123 	0
124 };
125 
126 struct sxitimer_softc {
127 	struct device		sc_dev;
128 };
129 
130 const struct cfattach sxitimer_ca = {
131 	sizeof (struct sxitimer_softc), sxitimer_match, sxitimer_attach
132 };
133 
134 struct cfdriver sxitimer_cd = {
135 	NULL, "sxitimer", DV_DULL
136 };
137 
138 int
sxitimer_match(struct device * parent,void * match,void * aux)139 sxitimer_match(struct device *parent, void *match, void *aux)
140 {
141 	struct fdt_attach_args *faa = aux;
142 	int node;
143 
144 	node = OF_finddevice("/");
145 	if (!OF_is_compatible(node, "allwinner,sun4i-a10") &&
146 	    !OF_is_compatible(node, "allwinner,sun5i-a10s") &&
147 	    !OF_is_compatible(node, "allwinner,sun5i-a13"))
148 		return 0;
149 
150 	return OF_is_compatible(faa->fa_node, "allwinner,sun4i-a10-timer");
151 }
152 
153 void
sxitimer_attach(struct device * parent,struct device * self,void * aux)154 sxitimer_attach(struct device *parent, struct device *self, void *aux)
155 {
156 	struct fdt_attach_args *faa = aux;
157 
158 	KASSERT(faa->fa_nreg > 0);
159 
160 	sxitimer_iot = faa->fa_iot;
161 	if (bus_space_map(sxitimer_iot, faa->fa_reg[0].addr,
162 	    faa->fa_reg[0].size, 0, &sxitimer_ioh))
163 		panic("%s: bus_space_map failed!", __func__);
164 
165 	/* clear counter, loop until ready */
166 	bus_space_write_4(sxitimer_iot, sxitimer_ioh, CNT64_CTRL,
167 	    CNT64_CLR_EN); /* XXX as a side-effect counter clk src=OSC24M */
168 	while (bus_space_read_4(sxitimer_iot, sxitimer_ioh, CNT64_CTRL)
169 	    & CNT64_CLR_EN)
170 		continue;
171 
172 	/* stop timer, and set clk src */
173 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
174 	    TIMER_CTRL(TICKTIMER), TIMER_OSC24M);
175 
176 	sxitimer_nsec_cycle_ratio =
177 	    sxitimer_freq[TICKTIMER] * (1ULL << 32) / 1000000000;
178 	sxitimer_nsec_max = UINT64_MAX / sxitimer_nsec_cycle_ratio;
179 
180 	stathz = hz;
181 	profhz = stathz * 10;
182 	statclock_is_randomized = 1;
183 
184 	/* stop timer, and set clk src */
185 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
186 	    TIMER_CTRL(CNTRTIMER), TIMER_OSC24M);
187 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
188 	    TIMER_INTV(CNTRTIMER), UINT32_MAX);
189 
190 	sxitimer_timecounter.tc_frequency = sxitimer_freq[CNTRTIMER];
191 	tc_init(&sxitimer_timecounter);
192 
193 	arm_clock_register(sxitimer_cpu_initclocks, sxitimer_delay,
194 	    sxitimer_setstatclockrate, sxitimer_cpu_startclock);
195 
196 	printf(": %d kHz", sxitimer_freq[CNTRTIMER] / 1000);
197 
198 	printf("\n");
199 }
200 
201 /*
202  * would be interesting to play with trigger mode while having one timer
203  * in 32kHz mode, and the other timer running in sysclk mode and use
204  * the high resolution speeds (matters more for delay than tick timer)
205  */
206 
207 void
sxitimer_cpu_initclocks(void)208 sxitimer_cpu_initclocks(void)
209 {
210 	uint32_t isr, ier, ctrl;
211 
212 	/* establish interrupt */
213 	arm_intr_establish(sxitimer_irq[TICKTIMER], IPL_CLOCK,
214 	    sxitimer_tickintr, NULL, "tick");
215 
216 	/* clear timer interrupt pending bits */
217 	isr = bus_space_read_4(sxitimer_iot, sxitimer_ioh, TIMER_ISR);
218 	isr |= TIMER_IRQ(TICKTIMER);
219 	bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_ISR, isr);
220 
221 	/* enable timer IRQ */
222 	ier = bus_space_read_4(sxitimer_iot, sxitimer_ioh, TIMER_IER);
223 	ier |= TIMER_IRQ(TICKTIMER);
224 	bus_space_write_4(sxitimer_iot, sxitimer_ioh, TIMER_IER, ier);
225 
226 	/* enable timers */
227 	ctrl = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
228 	    TIMER_CTRL(CNTRTIMER));
229 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
230 	    TIMER_CTRL(CNTRTIMER),
231 	    ctrl | TIMER_ENABLE | TIMER_RELOAD | TIMER_CONTINOUS);
232 }
233 
234 void
sxitimer_cpu_startclock(void)235 sxitimer_cpu_startclock(void)
236 {
237 	/* start clock interrupt cycle */
238 	clockintr_cpu_init(&sxitimer_intrclock);
239 	clockintr_trigger();
240 }
241 
242 int
sxitimer_tickintr(void * frame)243 sxitimer_tickintr(void *frame)
244 {
245 	splassert(IPL_CLOCK);
246 
247 	/* clear timer pending interrupt bit */
248 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
249 	    TIMER_ISR, TIMER_IRQ(TICKTIMER));
250 
251 	return clockintr_dispatch(frame);
252 }
253 
254 uint64_t
sxitimer_readcnt64(void)255 sxitimer_readcnt64(void)
256 {
257 	uint32_t low, high;
258 
259 	/* latch counter, loop until ready */
260 	bus_space_write_4(sxitimer_iot, sxitimer_ioh, CNT64_CTRL, CNT64_RL_EN);
261 	while (bus_space_read_4(sxitimer_iot, sxitimer_ioh, CNT64_CTRL)
262 	    & CNT64_RL_EN)
263 		continue;
264 
265 	/*
266 	 * A10 usermanual doesn't mention anything about order, but fwiw
267 	 * iirc. A20 manual mentions that low should be read first.
268 	 */
269 	/* XXX check above */
270 	low = bus_space_read_4(sxitimer_iot, sxitimer_ioh, CNT64_LOW);
271 	high = bus_space_read_4(sxitimer_iot, sxitimer_ioh, CNT64_HIGH);
272 	return (uint64_t)high << 32 | low;
273 }
274 
275 uint32_t
sxitimer_readcnt32(void)276 sxitimer_readcnt32(void)
277 {
278 	return bus_space_read_4(sxitimer_iot, sxitimer_ioh,
279 	    TIMER_CURR(CNTRTIMER));
280 }
281 
282 void
sxitimer_sync(void)283 sxitimer_sync(void)
284 {
285 	uint32_t now = sxitimer_readcnt32();
286 
287 	while ((now - sxitimer_readcnt32()) < TIMER_SYNC)
288 		CPU_BUSY_CYCLE();
289 }
290 
291 void
sxitimer_delay(u_int usecs)292 sxitimer_delay(u_int usecs)
293 {
294 	uint64_t oclock, timeout;
295 
296 	oclock = sxitimer_readcnt64();
297 	timeout = oclock + (COUNTER_FREQUENCY / 1000000) * usecs;
298 
299 	while (oclock < timeout)
300 		oclock = sxitimer_readcnt64();
301 }
302 
303 void
sxitimer_setstatclockrate(int newhz)304 sxitimer_setstatclockrate(int newhz)
305 {
306 }
307 
308 u_int
sxitimer_get_timecount(struct timecounter * tc)309 sxitimer_get_timecount(struct timecounter *tc)
310 {
311 	return (u_int)UINT_MAX - sxitimer_readcnt32();
312 }
313 
314 void
sxitimer_rearm(void * unused,uint64_t nsecs)315 sxitimer_rearm(void *unused, uint64_t nsecs)
316 {
317 	uint32_t ctrl, cycles;
318 
319 	if (nsecs > sxitimer_nsec_max)
320 		nsecs = sxitimer_nsec_max;
321 	cycles = (nsecs * sxitimer_nsec_cycle_ratio) >> 32;
322 	if (cycles < 10)
323 		cycles = 10;	/* XXX Why do we need to round up to 10? */
324 
325 	ctrl = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
326 	    TIMER_CTRL(TICKTIMER));
327 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
328 	    TIMER_CTRL(TICKTIMER), ctrl & ~TIMER_ENABLE);
329 
330 	sxitimer_sync();
331 
332 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
333 	    TIMER_INTV(TICKTIMER), cycles);
334 
335 	ctrl = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
336 	    TIMER_CTRL(TICKTIMER));
337 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
338 	    TIMER_CTRL(TICKTIMER),
339 	    ctrl | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
340 }
341 
342 void
sxitimer_trigger(void * unused)343 sxitimer_trigger(void *unused)
344 {
345 	uint32_t ctrl;
346 
347 	ctrl = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
348 	    TIMER_CTRL(TICKTIMER));
349 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
350 	    TIMER_CTRL(TICKTIMER), ctrl & ~TIMER_ENABLE);
351 
352 	sxitimer_sync();
353 
354 	/* XXX Why do we need to round up to 10? */
355 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
356 	    TIMER_INTV(TICKTIMER), 10);
357 
358 	ctrl = bus_space_read_4(sxitimer_iot, sxitimer_ioh,
359 	    TIMER_CTRL(TICKTIMER));
360 	bus_space_write_4(sxitimer_iot, sxitimer_ioh,
361 	    TIMER_CTRL(TICKTIMER),
362 	    ctrl | TIMER_ENABLE | TIMER_RELOAD | TIMER_SINGLESHOT);
363 }
364