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