initial commit, pull in sys/arch/armv7/omap
[bbb-pru.git] / gptimer.c
CommitLineData
cf3c20ae 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
100static struct evcount clk_count;
101static 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
107void gptimer_attach(struct device *parent, struct device *self, void *args);
108int gptimer_intr(void *frame);
109void gptimer_wait(int reg);
110void gptimer_cpu_initclocks(void);
111void gptimer_delay(u_int);
112void gptimer_setstatclockrate(int newhz);
113
114bus_space_tag_t gptimer_iot;
115bus_space_handle_t gptimer_ioh0, gptimer_ioh1;
116int gptimer_irq = 0;
117
118u_int gptimer_get_timecount(struct timecounter *);
119
120static struct timecounter gptimer_timecounter = {
121 gptimer_get_timecount, NULL, 0x7fffffff, 0, "gptimer", 0, NULL
122};
123
124volatile u_int32_t nexttickevent;
125volatile u_int32_t nextstatevent;
126u_int32_t ticks_per_second;
127u_int32_t ticks_per_intr;
128u_int32_t ticks_err_cnt;
129u_int32_t ticks_err_sum;
130u_int32_t statvar, statmin;
131
132struct cfattach gptimer_ca = {
133 sizeof (struct device), NULL, gptimer_attach
134};
135
136struct cfdriver gptimer_cd = {
137 NULL, "gptimer", DV_DULL
138};
139
140void
141gptimer_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
199int
200gptimer_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
282void
283gptimer_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
326void
327gptimer_wait(int reg)
328{
329 while (bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TWPS) & reg)
330 ;
331}
332
333#if 0
334void
335microtime(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
372void
373gptimer_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
411void
412gptimer_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
437u_int
438gptimer_get_timecount(struct timecounter *tc)
439{
440 return bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR);
441}