xref: /openbsd-src/sys/arch/arm/cortex/amptimer.c (revision 8e3880d25a2f65723f828571e27b9fa3eca1da3a)
1 /* $OpenBSD: amptimer.c,v 1.15 2023/01/17 02:47:55 cheloha 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/clockintr.h>
21 #include <sys/device.h>
22 #include <sys/kernel.h>
23 #include <sys/stdint.h>
24 #include <sys/timetc.h>
25 
26 #include <arm/cpufunc.h>
27 #include <machine/bus.h>
28 #include <machine/intr.h>
29 #include <arm/cortex/cortex.h>
30 
31 /* offset from periphbase */
32 #define GTIMER_ADDR	0x200
33 #define GTIMER_SIZE	0x100
34 
35 /* registers */
36 #define GTIMER_CNT_LOW		0x00
37 #define GTIMER_CNT_HIGH		0x04
38 #define GTIMER_CTRL		0x08
39 #define GTIMER_CTRL_AA		(1 << 3)
40 #define GTIMER_CTRL_IRQ		(1 << 2)
41 #define GTIMER_CTRL_COMP	(1 << 1)
42 #define GTIMER_CTRL_TIMER	(1 << 0)
43 #define GTIMER_STATUS		0x0c
44 #define GTIMER_STATUS_EVENT	(1 << 0)
45 #define GTIMER_CMP_LOW		0x10
46 #define GTIMER_CMP_HIGH		0x14
47 #define GTIMER_AUTOINC		0x18
48 
49 /* offset from periphbase */
50 #define PTIMER_ADDR		0x600
51 #define PTIMER_SIZE		0x100
52 
53 /* registers */
54 #define PTIMER_LOAD		0x0
55 #define PTIMER_CNT		0x4
56 #define PTIMER_CTRL		0x8
57 #define PTIMER_CTRL_ENABLE	(1<<0)
58 #define PTIMER_CTRL_AUTORELOAD	(1<<1)
59 #define PTIMER_CTRL_IRQEN	(1<<2)
60 #define PTIMER_STATUS		0xC
61 #define PTIMER_STATUS_EVENT	(1<<0)
62 
63 #define TIMER_FREQUENCY		396 * 1000 * 1000 /* ARM core clock */
64 int32_t amptimer_frequency = TIMER_FREQUENCY;
65 
66 u_int amptimer_get_timecount(struct timecounter *);
67 
68 static struct timecounter amptimer_timecounter = {
69 	.tc_get_timecount = amptimer_get_timecount,
70 	.tc_poll_pps = NULL,
71 	.tc_counter_mask = 0xffffffff,
72 	.tc_frequency = 0,
73 	.tc_name = "amptimer",
74 	.tc_quality = 0,
75 	.tc_priv = NULL,
76 	.tc_user = 0,
77 };
78 
79 void amptimer_rearm(void *, uint64_t);
80 void amptimer_trigger(void *);
81 
82 struct intrclock amptimer_intrclock = {
83 	.ic_rearm = amptimer_rearm,
84 	.ic_trigger = amptimer_trigger
85 };
86 
87 #define MAX_ARM_CPUS	8
88 
89 struct amptimer_softc {
90 	struct device		sc_dev;
91 	bus_space_tag_t		sc_iot;
92 	bus_space_handle_t	sc_ioh;
93 	bus_space_handle_t	sc_pioh;
94 
95 	u_int32_t		sc_ticks_per_second;
96 	u_int64_t		sc_nsec_cycle_ratio;
97 	u_int64_t		sc_nsec_max;
98 };
99 
100 int		amptimer_match(struct device *, void *, void *);
101 void		amptimer_attach(struct device *, struct device *, void *);
102 uint64_t	amptimer_readcnt64(struct amptimer_softc *sc);
103 int		amptimer_intr(void *);
104 void		amptimer_cpu_initclocks(void);
105 void		amptimer_delay(u_int);
106 void		amptimer_setstatclockrate(int stathz);
107 void		amptimer_set_clockrate(int32_t new_frequency);
108 void		amptimer_startclock(void);
109 
110 /* hack - XXXX
111  * gptimer connects directly to ampintc, not thru the generic
112  * interface because it uses an 'internal' interrupt
113  * not a peripheral interrupt.
114  */
115 void	*ampintc_intr_establish(int, int, int, struct cpu_info *,
116 	    int (*)(void *), void *, char *);
117 
118 
119 
120 const 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 	sc->sc_nsec_cycle_ratio =
172 	    sc->sc_ticks_per_second * (1ULL << 32) / 1000000000;
173 	sc->sc_nsec_max = UINT64_MAX / sc->sc_nsec_cycle_ratio;
174 	printf(": %d kHz\n", sc->sc_ticks_per_second / 1000);
175 
176 	sc->sc_ioh = ioh;
177 	sc->sc_pioh = pioh;
178 
179 	/* disable global timer */
180 	bus_space_write_4(sc->sc_iot, ioh, GTIMER_CTRL, 0);
181 
182 	/* XXX ??? reset counters to 0 - gives us uptime in the counter */
183 	bus_space_write_4(sc->sc_iot, ioh, GTIMER_CNT_LOW, 0);
184 	bus_space_write_4(sc->sc_iot, ioh, GTIMER_CNT_HIGH, 0);
185 
186 	/* enable global timer */
187 	bus_space_write_4(sc->sc_iot, ioh, GTIMER_CTRL, GTIMER_CTRL_TIMER);
188 
189 	/* Disable private timer, clear event flag. */
190 	bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL, 0);
191 	bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_STATUS,
192 	    PTIMER_STATUS_EVENT);
193 
194 	/*
195 	 * private timer and interrupts not enabled until
196 	 * timer configures
197 	 */
198 
199 	arm_clock_register(amptimer_cpu_initclocks, amptimer_delay,
200 	    amptimer_setstatclockrate, amptimer_startclock);
201 
202 	amptimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
203 	amptimer_timecounter.tc_priv = sc;
204 	tc_init(&amptimer_timecounter);
205 
206 	amptimer_intrclock.ic_cookie = sc;
207 }
208 
209 u_int
210 amptimer_get_timecount(struct timecounter *tc)
211 {
212 	struct amptimer_softc *sc = amptimer_timecounter.tc_priv;
213 	return bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CNT_LOW);
214 }
215 
216 void
217 amptimer_rearm(void *cookie, uint64_t nsecs)
218 {
219 	struct amptimer_softc *sc = cookie;
220 	uint32_t cycles, reg;
221 
222 	if (nsecs > sc->sc_nsec_max)
223 		nsecs = sc->sc_nsec_max;
224 	cycles = (nsecs * sc->sc_nsec_cycle_ratio) >> 32;
225 	if (cycles == 0)
226 		cycles = 1;
227 
228 	/* clear old status */
229 	bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_STATUS,
230 	    PTIMER_STATUS_EVENT);
231 
232 	/*
233 	 * Make sure the private timer counter and interrupts are enabled.
234 	 * XXX Why wouldn't they be?
235 	 */
236 	reg = bus_space_read_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL);
237 	if ((reg & (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN)) !=
238 	    (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN))
239 		bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL,
240 		    (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN));
241 
242 	/* Start the downcounter. */
243 	bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD, cycles);
244 }
245 
246 void
247 amptimer_trigger(void *cookie)
248 {
249 	struct amptimer_softc *sc = cookie;
250 
251 	/* Clear event flag, then arm counter to fire immediately. */
252 	bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_STATUS,
253 	    PTIMER_STATUS_EVENT);
254 	bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD, 1);
255 }
256 
257 int
258 amptimer_intr(void *frame)
259 {
260 	return clockintr_dispatch(frame);
261 }
262 
263 void
264 amptimer_set_clockrate(int32_t new_frequency)
265 {
266 	struct amptimer_softc	*sc = amptimer_cd.cd_devs[0];
267 
268 	amptimer_frequency = new_frequency;
269 
270 	if (sc == NULL)
271 		return;
272 
273 	sc->sc_ticks_per_second = amptimer_frequency;
274 	sc->sc_nsec_cycle_ratio =
275 	    sc->sc_ticks_per_second * (1ULL << 32) / 1000000000;
276 	sc->sc_nsec_max = UINT64_MAX / sc->sc_nsec_cycle_ratio;
277 
278 	amptimer_timecounter.tc_frequency = sc->sc_ticks_per_second;
279 
280 	printf("amptimer0: adjusting clock: new rate %d kHz\n",
281 	    sc->sc_ticks_per_second / 1000);
282 }
283 
284 void
285 amptimer_cpu_initclocks(void)
286 {
287 	struct amptimer_softc	*sc = amptimer_cd.cd_devs[0];
288 
289 	stathz = hz;
290 	profhz = hz * 10;
291 	clockintr_init(CL_RNDSTAT);
292 
293 	if (sc->sc_ticks_per_second != amptimer_frequency) {
294 		amptimer_set_clockrate(amptimer_frequency);
295 	}
296 
297 	/* establish interrupts */
298 	/* XXX - irq */
299 	ampintc_intr_establish(29, IST_EDGE_RISING, IPL_CLOCK,
300 	    NULL, amptimer_intr, NULL, "tick");
301 
302 	/* Enable private timer counter and interrupt. */
303 	bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL,
304 	    (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN));
305 
306 	/* Start the clock interrupt cycle. */
307 	clockintr_cpu_init(&amptimer_intrclock);
308 	clockintr_trigger();
309 }
310 
311 void
312 amptimer_delay(u_int usecs)
313 {
314 	struct amptimer_softc	*sc = amptimer_cd.cd_devs[0];
315 	u_int32_t		clock, oclock, delta, delaycnt;
316 	volatile int		j;
317 	int			csec, usec;
318 
319 	if (usecs > (0x80000000 / (sc->sc_ticks_per_second))) {
320 		csec = usecs / 10000;
321 		usec = usecs % 10000;
322 
323 		delaycnt = (sc->sc_ticks_per_second / 100) * csec +
324 		    (sc->sc_ticks_per_second / 100) * usec / 10000;
325 	} else {
326 		delaycnt = sc->sc_ticks_per_second * usecs / 1000000;
327 	}
328 	if (delaycnt <= 1)
329 		for (j = 100; j > 0; j--)
330 			;
331 
332 	oclock = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CNT_LOW);
333 	while (1) {
334 		for (j = 100; j > 0; j--)
335 			;
336 		clock = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
337 		    GTIMER_CNT_LOW);
338 		delta = clock - oclock;
339 		if (delta > delaycnt)
340 			break;
341 	}
342 }
343 
344 void
345 amptimer_setstatclockrate(int newhz)
346 {
347 	clockintr_setstatclockrate(newhz);
348 }
349 
350 void
351 amptimer_startclock(void)
352 {
353 	clockintr_cpu_init(&amptimer_intrclock);
354 	clockintr_trigger();
355 }
356