1 /* $OpenBSD: dmtimer.c,v 1.6 2015/01/22 14:33:01 krw Exp $ */
3 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
4 * Copyright (c) 2013 Raphael Graf <r@undefined.ch>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * WARNING - this timer initializion has not been checked
21 * to see if it will do _ANYTHING_ sane if the omap enters
25 #include <sys/types.h>
26 #include <sys/param.h>
27 #include <sys/systm.h>
28 #include <sys/kernel.h>
30 #include <sys/evcount.h>
31 #include <sys/device.h>
32 #include <sys/timetc.h>
33 #include <dev/clock_subr.h>
34 #include <machine/bus.h>
35 #include <armv7/armv7/armv7var.h>
36 #include <armv7/omap/prcmvar.h>
38 #include <machine/intr.h>
39 #include <arm/cpufunc.h>
43 #define DM_TIDR_MAJOR 0x00000700
44 #define DM_TIDR_MINOR 0x0000003f
45 #define DM_TIOCP_CFG 0x010
46 #define DM_TIOCP_CFG_IDLEMODE (3<<2)
47 #define DM_TIOCP_CFG_EMUFREE (1<<1)
48 #define DM_TIOCP_CFG_SOFTRESET (1<<0)
50 #define DM_TISR_TCAR (1<<2)
51 #define DM_TISR_OVF (1<<1)
52 #define DM_TISR_MAT (1<<0)
54 #define DM_TIER_TCAR_EN (1<<2)
55 #define DM_TIER_OVF_EN (1<<1)
56 #define DM_TIER_MAT_EN (1<<0)
58 #define DM_TIECR_TCAR_EN (1<<2)
59 #define DM_TIECR_OVF_EN (1<<1)
60 #define DM_TIECR_MAT_EN (1<<0)
62 #define DM_TWER_TCAR_EN (1<<2)
63 #define DM_TWER_OVF_EN (1<<1)
64 #define DM_TWER_MAT_EN (1<<0)
66 #define DM_TCLR_GPO (1<<14)
67 #define DM_TCLR_CAPT (1<<13)
68 #define DM_TCLR_PT (1<<12)
69 #define DM_TCLR_TRG (3<<10)
70 #define DM_TCLR_TRG_O (1<<10)
71 #define DM_TCLR_TRG_OM (2<<10)
72 #define DM_TCLR_TCM (3<<8)
73 #define DM_TCLR_TCM_RISE (1<<8)
74 #define DM_TCLR_TCM_FALL (2<<8)
75 #define DM_TCLR_TCM_BOTH (3<<8)
76 #define DM_TCLR_SCPWM (1<<7)
77 #define DM_TCLR_CE (1<<6)
78 #define DM_TCLR_PRE (1<<5)
79 #define DM_TCLR_PTV (7<<2)
80 #define DM_TCLR_AR (1<<1)
81 #define DM_TCLR_ST (1<<0)
86 #define DM_TWPS_TMAR (1<<4)
87 #define DM_TWPS_TTGR (1<<3)
88 #define DM_TWPS_TLDR (1<<2)
89 #define DM_TWPS_TCLR (1<<0)
90 #define DM_TWPS_TCRR (1<<1)
91 #define DM_TWPS_ALL 0x1f
94 #define DM_TSICR 0x054
95 #define DM_TSICR_POSTED (1<<2)
96 #define DM_TSICR_SFT (1<<1)
97 #define DM_TCAR2 0x058
99 #define TIMER_FREQUENCY 32768 /* 32kHz is used, selectable */
102 static struct evcount clk_count
;
103 static struct evcount stat_count
;
105 void dmtimer_attach(struct device
*parent
, struct device
*self
, void *args
);
106 int dmtimer_intr(void *frame
);
107 void dmtimer_wait(int reg
);
108 void dmtimer_cpu_initclocks(void);
109 void dmtimer_delay(u_int
);
110 void dmtimer_setstatclockrate(int newhz
);
112 u_int
dmtimer_get_timecount(struct timecounter
*);
114 static struct timecounter dmtimer_timecounter
= {
115 dmtimer_get_timecount
, NULL
, 0xffffffff, 0, "dmtimer", 0, NULL
118 bus_space_handle_t dmtimer_ioh0
;
121 struct dmtimer_softc
{
122 struct device sc_dev
;
123 bus_space_tag_t sc_iot
;
124 bus_space_handle_t sc_ioh
[MAX_TIMERS
];
126 u_int32_t sc_ticks_per_second
;
127 u_int32_t sc_ticks_per_intr
;
128 u_int32_t sc_ticks_err_cnt
;
129 u_int32_t sc_ticks_err_sum
;
130 u_int32_t sc_statvar
;
131 u_int32_t sc_statmin
;
132 u_int32_t sc_nexttickevent
;
133 u_int32_t sc_nextstatevent
;
136 struct cfattach dmtimer_ca
= {
137 sizeof (struct dmtimer_softc
), NULL
, dmtimer_attach
140 struct cfdriver dmtimer_cd
= {
141 NULL
, "dmtimer", DV_DULL
145 dmtimer_attach(struct device
*parent
, struct device
*self
, void *args
)
147 struct dmtimer_softc
*sc
= (struct dmtimer_softc
*)self
;
148 struct armv7_attach_args
*aa
= args
;
149 bus_space_handle_t ioh
;
152 sc
->sc_iot
= aa
->aa_iot
;
154 if (bus_space_map(sc
->sc_iot
, aa
->aa_dev
->mem
[0].addr
,
155 aa
->aa_dev
->mem
[0].size
, 0, &ioh
))
156 panic("%s: bus_space_map failed!\n", __func__
);
159 prcm_setclock(1, PRCM_CLK_SPEED_32
);
160 prcm_setclock(2, PRCM_CLK_SPEED_32
);
161 prcm_enablemodule(PRCM_TIMER2
);
162 prcm_enablemodule(PRCM_TIMER3
);
165 bus_space_write_4(sc
->sc_iot
, ioh
, DM_TIOCP_CFG
,
166 DM_TIOCP_CFG_SOFTRESET
);
167 while (bus_space_read_4(sc
->sc_iot
, ioh
, DM_TIOCP_CFG
)
168 & DM_TIOCP_CFG_SOFTRESET
)
171 if (self
->dv_unit
== 0) {
173 dmtimer_irq
= aa
->aa_dev
->irq
[0];
174 /* enable write posted mode */
175 bus_space_write_4(sc
->sc_iot
, ioh
, DM_TSICR
, DM_TSICR_POSTED
);
177 bus_space_write_4(sc
->sc_iot
, ioh
, DM_TCLR
, 0);
178 } else if (self
->dv_unit
== 1) {
179 /* start timer because it is used in delay */
180 /* interrupts and posted mode are disabled */
181 sc
->sc_irq
= dmtimer_irq
;
182 sc
->sc_ioh
[0] = dmtimer_ioh0
;
185 bus_space_write_4(sc
->sc_iot
, ioh
, DM_TCRR
, 0);
186 bus_space_write_4(sc
->sc_iot
, ioh
, DM_TLDR
, 0);
187 bus_space_write_4(sc
->sc_iot
, ioh
, DM_TCLR
,
188 DM_TCLR_AR
| DM_TCLR_ST
);
190 dmtimer_timecounter
.tc_frequency
= TIMER_FREQUENCY
;
191 dmtimer_timecounter
.tc_priv
= sc
;
192 tc_init(&dmtimer_timecounter
);
193 arm_clock_register(dmtimer_cpu_initclocks
, dmtimer_delay
,
194 dmtimer_setstatclockrate
, NULL
);
197 panic("attaching too many dmtimers at 0x%lx",
198 aa
->aa_dev
->mem
[0].addr
);
200 /* set IDLEMODE to smart-idle */
201 cfg
= bus_space_read_4(sc
->sc_iot
, ioh
, DM_TIOCP_CFG
);
202 bus_space_write_4(sc
->sc_iot
, ioh
, DM_TIOCP_CFG
,
203 (cfg
& ~DM_TIOCP_CFG_IDLEMODE
) | 0x02);
205 rev
= bus_space_read_4(sc
->sc_iot
, ioh
, DM_TIDR
);
206 printf(" rev %d.%d\n", (rev
& DM_TIDR_MAJOR
) >> 8, rev
& DM_TIDR_MINOR
);
210 * See comment in arm/xscale/i80321_clock.c
212 * Counter is count up, but with autoreload timers it is not possible
213 * to detect how many interrupts passed while interrupts were blocked.
214 * Also it is not possible to atomically add to the register.
216 * To work around this two timers are used, one is used as a reference
217 * clock without reload, however we just disable the interrupt it
220 * Internally this keeps track of when the next timer should fire
221 * and based on that time and the current value of the reference
222 * clock a number is written into the timer count register to schedule
227 dmtimer_intr(void *frame
)
229 struct dmtimer_softc
*sc
= dmtimer_cd
.cd_devs
[1];
230 u_int32_t now
, r
, nextevent
;
233 now
= bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
[1], DM_TCRR
);
235 while ((int32_t) (sc
->sc_nexttickevent
- now
) <= 0) {
236 sc
->sc_nexttickevent
+= sc
->sc_ticks_per_intr
;
237 sc
->sc_ticks_err_sum
+= sc
->sc_ticks_err_cnt
;
239 while (sc
->sc_ticks_err_sum
> hz
) {
240 sc
->sc_nexttickevent
+= 1;
241 sc
->sc_ticks_err_sum
-= hz
;
244 clk_count
.ec_count
++;
248 while ((int32_t) (sc
->sc_nextstatevent
- now
) <= 0) {
250 r
= random() & (sc
->sc_statvar
- 1);
251 } while (r
== 0); /* random == 0 not allowed */
252 sc
->sc_nextstatevent
+= sc
->sc_statmin
+ r
;
253 stat_count
.ec_count
++;
256 if ((sc
->sc_nexttickevent
- now
) < (sc
->sc_nextstatevent
- now
))
257 nextevent
= sc
->sc_nexttickevent
;
259 nextevent
= sc
->sc_nextstatevent
;
261 duration
= nextevent
-
262 bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
[1], DM_TCRR
);
265 duration
= 1; /* trigger immediately. */
267 if (duration
> sc
->sc_ticks_per_intr
+ 1) {
268 printf("%s: time lost!\n", __func__
);
270 * If interrupts are blocked too long, like during
271 * the root prompt or ddb, the timer can roll over,
272 * this will allow the system to continue to run
273 * even if time is lost.
275 duration
= sc
->sc_ticks_per_intr
;
276 sc
->sc_nexttickevent
= now
;
277 sc
->sc_nextstatevent
= now
;
280 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
[0], DM_TISR
,
281 bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
[0], DM_TISR
));
282 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
[0], DM_TCRR
, -duration
);
283 dmtimer_wait(DM_TWPS_ALL
);
289 * would be interesting to play with trigger mode while having one timer
290 * in 32KHz mode, and the other timer running in sysclk mode and use
291 * the high resolution speeds (matters more for delay than tick timer
295 dmtimer_cpu_initclocks()
297 struct dmtimer_softc
*sc
= dmtimer_cd
.cd_devs
[1];
302 sc
->sc_ticks_per_second
= TIMER_FREQUENCY
; /* 32768 */
304 setstatclockrate(stathz
);
306 sc
->sc_ticks_per_intr
= sc
->sc_ticks_per_second
/ hz
;
307 sc
->sc_ticks_err_cnt
= sc
->sc_ticks_per_second
% hz
;
308 sc
->sc_ticks_err_sum
= 0;
310 /* establish interrupts */
311 arm_intr_establish(sc
->sc_irq
, IPL_CLOCK
, dmtimer_intr
,
316 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
[0], DM_TLDR
, 0);
318 sc
->sc_nexttickevent
= sc
->sc_nextstatevent
= bus_space_read_4(sc
->sc_iot
,
319 sc
->sc_ioh
[1], DM_TCRR
) + sc
->sc_ticks_per_intr
;
321 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
[0], DM_TIER
, DM_TIER_OVF_EN
);
322 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
[0], DM_TWER
, DM_TWER_OVF_EN
);
323 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
[0], DM_TISR
, /*clear interrupt flags */
324 bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
[0], DM_TISR
));
325 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
[0], DM_TCRR
, -sc
->sc_ticks_per_intr
);
326 dmtimer_wait(DM_TWPS_ALL
);
327 bus_space_write_4(sc
->sc_iot
, sc
->sc_ioh
[0], DM_TCLR
, /* autoreload and start */
328 DM_TCLR_AR
| DM_TCLR_ST
);
329 dmtimer_wait(DM_TWPS_ALL
);
333 dmtimer_wait(int reg
)
335 struct dmtimer_softc
*sc
= dmtimer_cd
.cd_devs
[1];
336 while (bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
[0], DM_TWPS
) & reg
)
341 dmtimer_delay(u_int usecs
)
343 struct dmtimer_softc
*sc
= dmtimer_cd
.cd_devs
[1];
344 u_int32_t clock
, oclock
, delta
, delaycnt
;
348 if (usecs
> (0x80000000 / (TIMER_FREQUENCY
))) {
349 csec
= usecs
/ 10000;
350 usec
= usecs
% 10000;
352 delaycnt
= (TIMER_FREQUENCY
/ 100) * csec
+
353 (TIMER_FREQUENCY
/ 100) * usec
/ 10000;
355 delaycnt
= TIMER_FREQUENCY
* usecs
/ 1000000;
358 for (j
= 100; j
> 0; j
--)
361 if (sc
->sc_ioh
[1] == 0) {
363 for (; usecs
> 0; usecs
--)
364 for (j
= 100; j
> 0; j
--)
368 oclock
= bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
[1], DM_TCRR
);
370 for (j
= 100; j
> 0; j
--)
372 clock
= bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
[1], DM_TCRR
);
373 delta
= clock
- oclock
;
374 if (delta
> delaycnt
)
381 dmtimer_setstatclockrate(int newhz
)
383 struct dmtimer_softc
*sc
= dmtimer_cd
.cd_devs
[1];
389 statint
= sc
->sc_ticks_per_second
/ newhz
;
390 /* calculate largest 2^n which is smaller than just over half statint */
391 sc
->sc_statvar
= 0x40000000; /* really big power of two */
392 minint
= statint
/ 2 + 100;
393 while (sc
->sc_statvar
> minint
)
394 sc
->sc_statvar
>>= 1;
396 sc
->sc_statmin
= statint
- (sc
->sc_statvar
>> 1);
401 * XXX this allows the next stat timer to occur then it switches
402 * to the new frequency. Rather than switching instantly.
408 dmtimer_get_timecount(struct timecounter
*tc
)
410 struct dmtimer_softc
*sc
= dmtimer_timecounter
.tc_priv
;
412 return bus_space_read_4(sc
->sc_iot
, sc
->sc_ioh
[1], DM_TCRR
);