1 /* $OpenBSD: gptimer.c,v 1.4 2014/06/20 14:08:11 rapha Exp $ */
3 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
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.
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.
19 * WARNING - this timer initializion has not been checked
20 * to see if it will do _ANYTHING_ sane if the omap enters
24 #include <sys/types.h>
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 #include <sys/kernel.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>
37 #include <machine/intr.h>
38 #include <arm/cpufunc.h>
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
53 #define GP_TISTAT_TCAR 0x00000004
54 #define GP_TISTAT_OVF 0x00000002
55 #define GP_TISTAT_MATCH 0x00000001
57 #define GP_TIER_TCAR_EN 0x4
58 #define GP_TIER_OVF_EN 0x2
59 #define GP_TIER_MAT_EN 0x1
61 #define GP_TWER_TCAR_EN 0x00000004
62 #define GP_TWER_OVF_EN 0x00000002
63 #define GP_TWER_MAT_EN 0x00000001
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 */
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
93 #define GP_TSICR 0x040
94 #define GP_TSICR_POSTED 0x00000002
95 #define GP_TSICR_SFT 0x00000001
96 #define GP_TCAR2 0x044
98 #define TIMER_FREQUENCY 32768 /* 32kHz is used, selectable */
100 static struct evcount clk_count
;
101 static struct evcount stat_count
;
103 #define GPTIMER0_IRQ 38
105 //static int clk_irq = GPT1_IRQ; /* XXX 37 */
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
);
114 bus_space_tag_t gptimer_iot
;
115 bus_space_handle_t gptimer_ioh0
, gptimer_ioh1
;
118 u_int
gptimer_get_timecount(struct timecounter
*);
120 static struct timecounter gptimer_timecounter
= {
121 gptimer_get_timecount
, NULL
, 0x7fffffff, 0, "gptimer", 0, NULL
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
;
132 struct cfattach gptimer_ca
= {
133 sizeof (struct device
), NULL
, gptimer_attach
136 struct cfdriver gptimer_cd
= {
137 NULL
, "gptimer", DV_DULL
141 gptimer_attach(struct device
*parent
, struct device
*self
, void *args
)
143 struct armv7_attach_args
*aa
= args
;
144 bus_space_handle_t ioh
;
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!");
152 rev
= bus_space_read_4(gptimer_iot
, ioh
, GP_TIDR
);
154 printf(" rev %d.%d\n", rev
>> 4 & 0xf, rev
& 0xf);
155 if (self
->dv_unit
== 0) {
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 */
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
);
170 gptimer_timecounter
.tc_frequency
= TIMER_FREQUENCY
;
171 tc_init(&gptimer_timecounter
);
174 panic("attaching too many gptimers at 0x%lx",
175 aa
->aa_dev
->mem
[0].addr
);
177 arm_clock_register(gptimer_cpu_initclocks
, gptimer_delay
,
178 gptimer_setstatclockrate
, NULL
);
182 * See comment in arm/xscale/i80321_clock.c
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.
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.
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
200 gptimer_intr(void *frame
)
203 u_int32_t nextevent
, duration
;
205 /* clear interrupt */
206 now
= bus_space_read_4(gptimer_iot
, gptimer_ioh1
, GP_TCRR
);
208 while ((int32_t) (nexttickevent
- now
) < 0) {
209 nexttickevent
+= ticks_per_intr
;
210 ticks_err_sum
+= ticks_err_cnt
;
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
);
218 /* looping a few times is faster than divide */
219 while (ticks_err_sum
> hz
) {
224 clk_count
.ec_count
++;
227 while ((int32_t) (nextstatevent
- now
) < 0) {
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
++;
236 if ((nexttickevent
- now
) < (nextstatevent
- now
))
237 nextevent
= nexttickevent
;
239 nextevent
= nextstatevent
;
242 duration
= nextevent
-
243 bus_space_read_4(gptimer_iot
, gptimer_ioh1
, GP_TCRR
);
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
));
253 duration
= 1; /* trigger immediately. */
255 if (duration
> ticks_per_intr
) {
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.
262 duration
= ticks_per_intr
;
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
);
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
283 gptimer_cpu_initclocks()
289 ticks_per_second
= TIMER_FREQUENCY
;
291 setstatclockrate(stathz
);
293 ticks_per_intr
= ticks_per_second
/ hz
;
294 ticks_err_cnt
= ticks_per_second
% hz
;
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
,
303 /* setup timer 0 (hardware timer 2) */
306 bus_space_write_4(gptimer_iot
, gptimer_ioh0
, GP_TLDR
, 0);
308 nexttickevent
= nextstatevent
= bus_space_read_4(gptimer_iot
,
309 gptimer_ioh1
, GP_TCRR
) + ticks_per_intr
;
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
);
327 gptimer_wait(int reg
)
329 while (bus_space_read_4(gptimer_iot
, gptimer_ioh0
, GP_TWPS
) & reg
)
335 microtime(struct timeval
*tvp
)
339 u_int32_t counter
, expected
;
342 if (1) { /* not inited */
348 counter
= bus_space_read_4(gptimer_iot
, gptimer_ioh1
, GP_TCRR
);
349 expected
= nexttickevent
;
354 deltacnt
= counter
- expected
+ ticks_per_intr
;
357 /* low frequency timer algorithm */
358 tvp
->tv_usec
+= deltacnt
* 1000000ULL / TIMER_FREQUENCY
;
360 /* high frequency timer algorithm - XXX */
361 tvp
->tv_usec
+= deltacnt
/ (TIMER_FREQUENCY
/ 1000000ULL);
364 while (tvp
->tv_usec
>= 1000000) {
366 tvp
->tv_usec
-= 1000000;
373 gptimer_delay(u_int usecs
)
375 u_int32_t clock
, oclock
, delta
, delaycnt
;
379 if (usecs
> (0x80000000 / (TIMER_FREQUENCY
))) {
380 csec
= usecs
/ 10000;
381 usec
= usecs
% 10000;
383 delaycnt
= (TIMER_FREQUENCY
/ 100) * csec
+
384 (TIMER_FREQUENCY
/ 100) * usec
/ 10000;
386 delaycnt
= TIMER_FREQUENCY
* usecs
/ 1000000;
389 for (j
= 100; j
> 0; j
--)
392 if (gptimer_ioh1
== 0) {
394 for (; usecs
> 0; usecs
--)
395 for (j
= 100; j
> 0; j
--)
399 oclock
= bus_space_read_4(gptimer_iot
, gptimer_ioh1
, GP_TCRR
);
401 for (j
= 100; j
> 0; j
--)
403 clock
= bus_space_read_4(gptimer_iot
, gptimer_ioh1
, GP_TCRR
);
404 delta
= clock
- oclock
;
405 if (delta
> delaycnt
)
412 gptimer_setstatclockrate(int newhz
)
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
)
426 statmin
= statint
- (statvar
>> 1);
431 * XXX this allows the next stat timer to occur then it switches
432 * to the new frequency. Rather than switching instantly.
438 gptimer_get_timecount(struct timecounter
*tc
)
440 return bus_space_read_4(gptimer_iot
, gptimer_ioh1
, GP_TCRR
);