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