xref: /openbsd/sys/arch/armv7/omap/gptimer.c (revision 097a140d)
1 /* $OpenBSD: gptimer.c,v 1.13 2021/03/25 04:12:01 jsg Exp $ */
2 /*
3  * Copyright (c) 2007,2009 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 /*
19  *	WARNING - this timer initializion has not been checked
20  *	to see if it will do _ANYTHING_ sane if the omap enters
21  *	low power mode.
22  */
23 
24 #include <sys/param.h>
25 #include <sys/systm.h>
26 #include <sys/kernel.h>
27 #include <sys/evcount.h>
28 #include <sys/device.h>
29 #include <sys/timetc.h>
30 #include <machine/bus.h>
31 #include <armv7/armv7/armv7var.h>
32 #include <armv7/omap/prcmvar.h>
33 
34 #include <machine/intr.h>
35 
36 /* registers */
37 #define	GP_TIDR		0x000
38 #define		GP_TIDR_REV	0xff
39 #define GP_TIOCP_CFG	0x010
40 #define 	GP_TIOCP_CFG_CLKA	0x000000300
41 #define 	GP_TIOCP_CFG_EMUFREE	0x000000020
42 #define 	GP_TIOCP_CFG_IDLEMODE	0x000000018
43 #define 	GP_TIOCP_CFG_ENAPWAKEUP	0x000000004
44 #define 	GP_TIOCP_CFG_SOFTRESET	0x000000002
45 #define 	GP_TIOCP_CFG_AUTOIDLE	0x000000001
46 #define	GP_TISTAT	0x014
47 #define 	GP_TISTAT_RESETDONE	0x000000001
48 #define	GP_TISR		0x018
49 #define		GP_TISTAT_TCAR		0x00000004
50 #define		GP_TISTAT_OVF		0x00000002
51 #define		GP_TISTAT_MATCH		0x00000001
52 #define GP_TIER		0x1c
53 #define		GP_TIER_TCAR_EN		0x4
54 #define		GP_TIER_OVF_EN		0x2
55 #define		GP_TIER_MAT_EN		0x1
56 #define	GP_TWER		0x020
57 #define		GP_TWER_TCAR_EN		0x00000004
58 #define		GP_TWER_OVF_EN		0x00000002
59 #define		GP_TWER_MAT_EN		0x00000001
60 #define	GP_TCLR		0x024
61 #define		GP_TCLR_GPO		(1<<14)
62 #define		GP_TCLR_CAPT		(1<<13)
63 #define		GP_TCLR_PT		(1<<12)
64 #define		GP_TCLR_TRG		(3<<10)
65 #define		GP_TCLR_TRG_O		(1<<10)
66 #define		GP_TCLR_TRG_OM		(2<<10)
67 #define		GP_TCLR_TCM		(3<<8)
68 #define		GP_TCLR_TCM_RISE	(1<<8)
69 #define		GP_TCLR_TCM_FALL	(2<<8)
70 #define		GP_TCLR_TCM_BOTH	(3<<8)
71 #define		GP_TCLR_SCPWM		(1<<7)
72 #define		GP_TCLR_CE		(1<<6)
73 #define		GP_TCLR_PRE		(1<<5)
74 #define		GP_TCLR_PTV		(7<<2)
75 #define		GP_TCLR_AR		(1<<1)
76 #define		GP_TCLR_ST		(1<<0)
77 #define	GP_TCRR		0x028				/* counter */
78 #define	GP_TLDR		0x02c				/* reload */
79 #define	GP_TTGR		0x030
80 #define	GP_TWPS		0x034
81 #define		GP_TWPS_TCLR	0x01
82 #define		GP_TWPS_TCRR	0x02
83 #define		GP_TWPS_TLDR	0x04
84 #define		GP_TWPS_TTGR	0x08
85 #define		GP_TWPS_TMAR	0x10
86 #define		GP_TWPS_ALL	0x1f
87 #define	GP_TMAR		0x038
88 #define	GP_TCAR		0x03C
89 #define	GP_TSICR	0x040
90 #define		GP_TSICR_POSTED		0x00000002
91 #define		GP_TSICR_SFT		0x00000001
92 #define	GP_TCAR2	0x044
93 
94 #define TIMER_FREQUENCY			32768	/* 32kHz is used, selectable */
95 
96 static struct evcount clk_count;
97 static struct evcount stat_count;
98 
99 void gptimer_attach(struct device *parent, struct device *self, void *args);
100 int gptimer_intr(void *frame);
101 void gptimer_wait(int reg);
102 void gptimer_cpu_initclocks(void);
103 void gptimer_delay(u_int);
104 void gptimer_setstatclockrate(int newhz);
105 
106 bus_space_tag_t gptimer_iot;
107 bus_space_handle_t gptimer_ioh0, gptimer_ioh1;
108 int gptimer_irq = 0;
109 
110 u_int gptimer_get_timecount(struct timecounter *);
111 
112 static struct timecounter gptimer_timecounter = {
113 	.tc_get_timecount = gptimer_get_timecount,
114 	.tc_poll_pps = NULL,
115 	.tc_counter_mask = 0xffffffff,
116 	.tc_frequency = 0,
117 	.tc_name = "gptimer",
118 	.tc_quality = 0,
119 	.tc_priv = NULL,
120 	.tc_user = 0,
121 };
122 
123 volatile u_int32_t nexttickevent;
124 volatile u_int32_t nextstatevent;
125 u_int32_t	ticks_per_second;
126 u_int32_t	ticks_per_intr;
127 u_int32_t	ticks_err_cnt;
128 u_int32_t	ticks_err_sum;
129 u_int32_t	statvar, statmin;
130 
131 struct cfattach	gptimer_ca = {
132 	sizeof (struct device), NULL, gptimer_attach
133 };
134 
135 struct cfdriver gptimer_cd = {
136 	NULL, "gptimer", DV_DULL
137 };
138 
139 void
140 gptimer_attach(struct device *parent, struct device *self, void *args)
141 {
142 	struct armv7_attach_args *aa = args;
143 	bus_space_handle_t ioh;
144 	u_int32_t rev;
145 
146 	gptimer_iot = aa->aa_iot;
147 	if (bus_space_map(gptimer_iot, aa->aa_dev->mem[0].addr,
148 	    aa->aa_dev->mem[0].size, 0, &ioh))
149 		panic("gptimer_attach: bus_space_map failed!");
150 
151 	rev = bus_space_read_4(gptimer_iot, ioh, GP_TIDR);
152 
153 	printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf);
154 	if (self->dv_unit == 0) {
155 		gptimer_ioh0 = ioh;
156 		gptimer_irq = aa->aa_dev->irq[0];
157 		bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, 0);
158 	} else if (self->dv_unit == 1) {
159 		/* start timer because it is used in delay */
160 		gptimer_ioh1 = ioh;
161 		bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TCRR, 0);
162 		gptimer_wait(GP_TWPS_ALL);
163 		bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TLDR, 0);
164 		gptimer_wait(GP_TWPS_ALL);
165 		bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TCLR,
166 		    GP_TCLR_AR | GP_TCLR_ST);
167 		gptimer_wait(GP_TWPS_ALL);
168 
169 		gptimer_timecounter.tc_frequency = TIMER_FREQUENCY;
170 		tc_init(&gptimer_timecounter);
171 	}
172 	else
173 		panic("attaching too many gptimers at 0x%lx",
174 		    aa->aa_dev->mem[0].addr);
175 
176 	arm_clock_register(gptimer_cpu_initclocks, gptimer_delay,
177 	    gptimer_setstatclockrate, NULL);
178 }
179 
180 /*
181  * See comment in arm/xscale/i80321_clock.c
182  *
183  * counter is count up, but with autoreload timers it is not possible
184  * to detect how many  interrupts passed while interrupts were blocked.
185  * also it is not possible to atomically add to the register
186  * get get it to precisely fire at a non-fixed interval.
187  *
188  * To work around this two timers are used, GPT1 is used as a reference
189  * clock without reload , however we just ignore the interrupt it
190  * would (may?) generate.
191  *
192  * Internally this keeps track of when the next timer should fire
193  * and based on that time and the current value of the reference
194  * clock a number is written into the timer count register to schedule
195  * the next event.
196  */
197 
198 int
199 gptimer_intr(void *frame)
200 {
201 	u_int32_t now, r;
202 	u_int32_t nextevent, duration;
203 
204 	/* clear interrupt */
205 	now = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
206 
207 	while ((int32_t) (nexttickevent - now) < 0) {
208 		nexttickevent += ticks_per_intr;
209 		ticks_err_sum += ticks_err_cnt;
210 #if 0
211 		if (ticks_err_sum  > hz) {
212 			u_int32_t match_error;
213 			match_error = ticks_err_sum / hz
214 			ticks_err_sum -= (match_error * hz);
215 		}
216 #else
217 		/* looping a few times is faster than divide */
218 		while (ticks_err_sum  > hz) {
219 			nexttickevent += 1;
220 			ticks_err_sum -= hz;
221 		}
222 #endif
223 		clk_count.ec_count++;
224 		hardclock(frame);
225 	}
226 	while ((int32_t) (nextstatevent - now) < 0) {
227 		do {
228 			r = random() & (statvar -1);
229 		} while (r == 0); /* random == 0 not allowed */
230 		nextstatevent += statmin + r;
231 		/* XXX - correct nextstatevent? */
232 		stat_count.ec_count++;
233 		statclock(frame);
234 	}
235 	if ((nexttickevent - now) < (nextstatevent - now))
236                 nextevent = nexttickevent;
237         else
238                 nextevent = nextstatevent;
239 
240 /* XXX */
241 	duration = nextevent -
242 	    bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
243 #if 0
244 	printf("duration 0x%x %x %x\n", nextevent -
245 	    bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR),
246 	    bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TCRR),
247 	    bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR));
248 #endif
249 
250 
251         if (duration <= 0)
252                 duration = 1; /* trigger immediately. */
253 
254         if (duration > ticks_per_intr) {
255                 /*
256                  * If interrupts are blocked too long, like during
257                  * the root prompt or ddb, the timer can roll over,
258                  * this will allow the system to continue to run
259                  * even if time is lost.
260                  */
261                 duration = ticks_per_intr;
262                 nexttickevent = now;
263                 nextstatevent = now;
264         }
265 
266 	gptimer_wait(GP_TWPS_ALL);
267 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TISR,
268 		bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TISR));
269 	gptimer_wait(GP_TWPS_ALL);
270         bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, -duration);
271 
272 	return 1;
273 }
274 
275 /*
276  * would be interesting to play with trigger mode while having one timer
277  * in 32kHz mode, and the other timer running in sysclk mode and use
278  * the high resolution speeds (matters more for delay than tick timer
279  */
280 
281 void
282 gptimer_cpu_initclocks()
283 {
284 	stathz = 128;
285 	profhz = 1024;
286 
287 	ticks_per_second = TIMER_FREQUENCY;
288 
289 	setstatclockrate(stathz);
290 
291 	ticks_per_intr = ticks_per_second / hz;
292 	ticks_err_cnt = ticks_per_second % hz;
293 	ticks_err_sum = 0;
294 
295 	prcm_setclock(1, PRCM_CLK_SPEED_32);
296 	prcm_setclock(2, PRCM_CLK_SPEED_32);
297 	/* establish interrupts */
298 	arm_intr_establish(gptimer_irq, IPL_CLOCK, gptimer_intr,
299 	    NULL, "tick");
300 
301 	/* setup timer 0 (hardware timer 2) */
302 	/* reset? - XXX */
303 
304         bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TLDR, 0);
305 
306 	nexttickevent = nextstatevent = bus_space_read_4(gptimer_iot,
307 	    gptimer_ioh1, GP_TCRR) + ticks_per_intr;
308 
309 	gptimer_wait(GP_TWPS_ALL);
310 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TIER, GP_TIER_OVF_EN);
311 	gptimer_wait(GP_TWPS_ALL);
312 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TWER, GP_TWER_OVF_EN);
313 	gptimer_wait(GP_TWPS_ALL);
314 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR,
315 	    GP_TCLR_AR | GP_TCLR_ST);
316 	gptimer_wait(GP_TWPS_ALL);
317 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TISR,
318 		bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TISR));
319 	gptimer_wait(GP_TWPS_ALL);
320 	bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, -ticks_per_intr);
321 	gptimer_wait(GP_TWPS_ALL);
322 }
323 
324 void
325 gptimer_wait(int reg)
326 {
327 	while (bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TWPS) & reg)
328 		;
329 }
330 
331 #if 0
332 void
333 microtime(struct timeval *tvp)
334 {
335 	int s;
336 	int deltacnt;
337 	u_int32_t counter, expected;
338 	s = splhigh();
339 
340 	if (1) {	/* not inited */
341 		tvp->tv_sec = 0;
342 		tvp->tv_usec = 0;
343 		return;
344 	}
345 	s = splhigh();
346 	counter = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
347 	expected = nexttickevent;
348 
349 	*tvp = time;
350 	splx(s);
351 
352 	deltacnt = counter - expected + ticks_per_intr;
353 
354 #if 1
355 	/* low frequency timer algorithm */
356 	tvp->tv_usec += deltacnt * 1000000ULL / TIMER_FREQUENCY;
357 #else
358 	/* high frequency timer algorithm - XXX */
359 	tvp->tv_usec += deltacnt / (TIMER_FREQUENCY / 1000000ULL);
360 #endif
361 
362 	while (tvp->tv_usec >= 1000000) {
363 		tvp->tv_sec++;
364 		tvp->tv_usec -= 1000000;
365 	}
366 
367 }
368 #endif
369 
370 void
371 gptimer_delay(u_int usecs)
372 {
373 	u_int32_t clock, oclock, delta, delaycnt;
374 	volatile int j;
375 	int csec, usec;
376 
377 	if (usecs > (0x80000000 / (TIMER_FREQUENCY))) {
378 		csec = usecs / 10000;
379 		usec = usecs % 10000;
380 
381 		delaycnt = (TIMER_FREQUENCY / 100) * csec +
382 		    (TIMER_FREQUENCY / 100) * usec / 10000;
383 	} else {
384 		delaycnt = TIMER_FREQUENCY * usecs / 1000000;
385 	}
386 	if (delaycnt <= 1)
387 		for (j = 100; j > 0; j--)
388 			;
389 
390 	if (gptimer_ioh1 == 0) {
391 		/* BAH */
392 		for (; usecs > 0; usecs--)
393 			for (j = 100; j > 0; j--)
394 				;
395 		return;
396 	}
397 	oclock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
398 	while (1) {
399 		for (j = 100; j > 0; j--)
400 			;
401 		clock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
402 		delta = clock - oclock;
403 		if (delta > delaycnt)
404 			break;
405 	}
406 
407 }
408 
409 void
410 gptimer_setstatclockrate(int newhz)
411 {
412 	int minint, statint;
413 	int s;
414 
415 	s = splclock();
416 
417 	statint = ticks_per_second / newhz;
418 	/* calculate largest 2^n which is smaller that just over half statint */
419 	statvar = 0x40000000; /* really big power of two */
420 	minint = statint / 2 + 100;
421 	while (statvar > minint)
422 		statvar >>= 1;
423 
424 	statmin = statint - (statvar >> 1);
425 
426 	splx(s);
427 
428 	/*
429 	 * XXX this allows the next stat timer to occur then it switches
430 	 * to the new frequency. Rather than switching instantly.
431 	 */
432 }
433 
434 
435 u_int
436 gptimer_get_timecount(struct timecounter *tc)
437 {
438 	return bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
439 }
440