2 * TI OMAP2 general purpose timers emulation.
4 * Copyright (C) 2007-2008 Nokia Corporation
5 * Written by Andrzej Zaborowski <andrew@openedhand.com>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 or
10 * (at your option) any later version of the License.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
23 #include "qemu/timer.h"
24 #include "hw/arm/omap.h"
27 struct omap_gp_timer_s
{
36 struct omap_target_agent_s
*ta
;
42 int64_t ticks_per_sec
;
53 gpt_trigger_none
, gpt_trigger_overflow
, gpt_trigger_both
56 gpt_capture_none
, gpt_capture_rising
,
57 gpt_capture_falling
, gpt_capture_both
68 uint32_t capture_val
[2];
72 uint16_t writeh
; /* LSB */
73 uint16_t readh
; /* MSB */
76 #define GPT_TCAR_IT (1 << 2)
77 #define GPT_OVF_IT (1 << 1)
78 #define GPT_MAT_IT (1 << 0)
80 static inline void omap_gp_timer_intr(struct omap_gp_timer_s
*timer
, int it
)
82 if (timer
->it_ena
& it
) {
84 qemu_irq_raise(timer
->irq
);
87 /* Or are the status bits set even when masked?
88 * i.e. is masking applied before or after the status register? */
91 if (timer
->wu_ena
& it
)
92 qemu_irq_pulse(timer
->wkup
);
95 static inline void omap_gp_timer_out(struct omap_gp_timer_s
*timer
, int level
)
97 if (!timer
->inout
&& timer
->out_val
!= level
) {
98 timer
->out_val
= level
;
99 qemu_set_irq(timer
->out
, level
);
103 static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s
*timer
)
107 if (timer
->st
&& timer
->rate
) {
108 distance
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
) - timer
->time
;
109 distance
= muldiv64(distance
, timer
->rate
, timer
->ticks_per_sec
);
111 if (distance
>= 0xffffffff - timer
->val
)
114 return timer
->val
+ distance
;
119 static inline void omap_gp_timer_sync(struct omap_gp_timer_s
*timer
)
122 timer
->val
= omap_gp_timer_read(timer
);
123 timer
->time
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
127 static inline void omap_gp_timer_update(struct omap_gp_timer_s
*timer
)
129 int64_t expires
, matches
;
131 if (timer
->st
&& timer
->rate
) {
132 expires
= muldiv64(0x100000000ll
- timer
->val
,
133 timer
->ticks_per_sec
, timer
->rate
);
134 timer_mod(timer
->timer
, timer
->time
+ expires
);
136 if (timer
->ce
&& timer
->match_val
>= timer
->val
) {
137 matches
= muldiv64(timer
->ticks_per_sec
,
138 timer
->match_val
- timer
->val
, timer
->rate
);
139 timer_mod(timer
->match
, timer
->time
+ matches
);
141 timer_del(timer
->match
);
143 timer_del(timer
->timer
);
144 timer_del(timer
->match
);
145 omap_gp_timer_out(timer
, timer
->scpwm
);
149 static inline void omap_gp_timer_trigger(struct omap_gp_timer_s
*timer
)
152 /* TODO in overflow-and-match mode if the first event to
153 * occur is the match, don't toggle. */
154 omap_gp_timer_out(timer
, !timer
->out_val
);
156 /* TODO inverted pulse on timer->out_val == 1? */
157 qemu_irq_pulse(timer
->out
);
160 static void omap_gp_timer_tick(void *opaque
)
162 struct omap_gp_timer_s
*timer
= (struct omap_gp_timer_s
*) opaque
;
168 timer
->val
= timer
->load_val
;
169 timer
->time
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
172 if (timer
->trigger
== gpt_trigger_overflow
||
173 timer
->trigger
== gpt_trigger_both
)
174 omap_gp_timer_trigger(timer
);
176 omap_gp_timer_intr(timer
, GPT_OVF_IT
);
177 omap_gp_timer_update(timer
);
180 static void omap_gp_timer_match(void *opaque
)
182 struct omap_gp_timer_s
*timer
= (struct omap_gp_timer_s
*) opaque
;
184 if (timer
->trigger
== gpt_trigger_both
)
185 omap_gp_timer_trigger(timer
);
187 omap_gp_timer_intr(timer
, GPT_MAT_IT
);
190 static void omap_gp_timer_input(void *opaque
, int line
, int on
)
192 struct omap_gp_timer_s
*s
= (struct omap_gp_timer_s
*) opaque
;
195 switch (s
->capture
) {
197 case gpt_capture_none
:
200 case gpt_capture_rising
:
201 trigger
= !s
->in_val
&& on
;
203 case gpt_capture_falling
:
204 trigger
= s
->in_val
&& !on
;
206 case gpt_capture_both
:
207 trigger
= (s
->in_val
== !on
);
212 if (s
->inout
&& trigger
&& s
->capt_num
< 2) {
213 s
->capture_val
[s
->capt_num
] = omap_gp_timer_read(s
);
215 if (s
->capt2
== s
->capt_num
++)
216 omap_gp_timer_intr(s
, GPT_TCAR_IT
);
220 static void omap_gp_timer_clk_update(void *opaque
, int line
, int on
)
222 struct omap_gp_timer_s
*timer
= (struct omap_gp_timer_s
*) opaque
;
224 omap_gp_timer_sync(timer
);
225 timer
->rate
= on
? omap_clk_getrate(timer
->clk
) : 0;
226 omap_gp_timer_update(timer
);
229 static void omap_gp_timer_clk_setup(struct omap_gp_timer_s
*timer
)
231 omap_clk_adduser(timer
->clk
,
232 qemu_allocate_irq(omap_gp_timer_clk_update
, timer
, 0));
233 timer
->rate
= omap_clk_getrate(timer
->clk
);
236 void omap_gp_timer_reset(struct omap_gp_timer_s
*s
)
246 s
->trigger
= gpt_trigger_none
;
247 s
->capture
= gpt_capture_none
;
256 s
->load_val
= 0x00000000;
257 s
->capture_val
[0] = 0x00000000;
258 s
->capture_val
[1] = 0x00000000;
259 s
->match_val
= 0x00000000;
260 omap_gp_timer_update(s
);
263 static uint32_t omap_gp_timer_readw(void *opaque
, hwaddr addr
)
265 struct omap_gp_timer_s
*s
= (struct omap_gp_timer_s
*) opaque
;
268 case 0x00: /* TIDR */
271 case 0x10: /* TIOCP_CFG */
274 case 0x14: /* TISTAT */
275 /* ??? When's this bit reset? */
276 return 1; /* RESETDONE */
278 case 0x18: /* TISR */
281 case 0x1c: /* TIER */
284 case 0x20: /* TWER */
287 case 0x24: /* TCLR */
288 return (s
->inout
<< 14) |
300 case 0x28: /* TCRR */
301 return omap_gp_timer_read(s
);
303 case 0x2c: /* TLDR */
306 case 0x30: /* TTGR */
309 case 0x34: /* TWPS */
310 return 0x00000000; /* No posted writes pending. */
312 case 0x38: /* TMAR */
315 case 0x3c: /* TCAR1 */
316 return s
->capture_val
[0];
318 case 0x40: /* TSICR */
319 return s
->posted
<< 2;
321 case 0x44: /* TCAR2 */
322 return s
->capture_val
[1];
329 static uint32_t omap_gp_timer_readh(void *opaque
, hwaddr addr
)
331 struct omap_gp_timer_s
*s
= (struct omap_gp_timer_s
*) opaque
;
337 ret
= omap_gp_timer_readw(opaque
, addr
);
338 s
->readh
= ret
>> 16;
343 static void omap_gp_timer_write(void *opaque
, hwaddr addr
,
346 struct omap_gp_timer_s
*s
= (struct omap_gp_timer_s
*) opaque
;
349 case 0x00: /* TIDR */
350 case 0x14: /* TISTAT */
351 case 0x34: /* TWPS */
352 case 0x3c: /* TCAR1 */
353 case 0x44: /* TCAR2 */
357 case 0x10: /* TIOCP_CFG */
358 s
->config
= value
& 0x33d;
359 if (((value
>> 3) & 3) == 3) /* IDLEMODE */
360 fprintf(stderr
, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
362 if (value
& 2) /* SOFTRESET */
363 omap_gp_timer_reset(s
);
366 case 0x18: /* TISR */
367 if (value
& GPT_TCAR_IT
)
369 if (s
->status
&& !(s
->status
&= ~value
))
370 qemu_irq_lower(s
->irq
);
373 case 0x1c: /* TIER */
374 s
->it_ena
= value
& 7;
377 case 0x20: /* TWER */
378 s
->wu_ena
= value
& 7;
381 case 0x24: /* TCLR */
382 omap_gp_timer_sync(s
);
383 s
->inout
= (value
>> 14) & 1;
384 s
->capt2
= (value
>> 13) & 1;
385 s
->pt
= (value
>> 12) & 1;
386 s
->trigger
= (value
>> 10) & 3;
387 if (s
->capture
== gpt_capture_none
&&
388 ((value
>> 8) & 3) != gpt_capture_none
)
390 s
->capture
= (value
>> 8) & 3;
391 s
->scpwm
= (value
>> 7) & 1;
392 s
->ce
= (value
>> 6) & 1;
393 s
->pre
= (value
>> 5) & 1;
394 s
->ptv
= (value
>> 2) & 7;
395 s
->ar
= (value
>> 1) & 1;
396 s
->st
= (value
>> 0) & 1;
397 if (s
->inout
&& s
->trigger
!= gpt_trigger_none
)
398 fprintf(stderr
, "%s: GP timer pin must be an output "
399 "for this trigger mode\n", __func__
);
400 if (!s
->inout
&& s
->capture
!= gpt_capture_none
)
401 fprintf(stderr
, "%s: GP timer pin must be an input "
402 "for this capture mode\n", __func__
);
403 if (s
->trigger
== gpt_trigger_none
)
404 omap_gp_timer_out(s
, s
->scpwm
);
405 /* TODO: make sure this doesn't overflow 32-bits */
406 s
->ticks_per_sec
= NANOSECONDS_PER_SECOND
<< (s
->pre
? s
->ptv
+ 1 : 0);
407 omap_gp_timer_update(s
);
410 case 0x28: /* TCRR */
411 s
->time
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
413 omap_gp_timer_update(s
);
416 case 0x2c: /* TLDR */
420 case 0x30: /* TTGR */
421 s
->time
= qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL
);
422 s
->val
= s
->load_val
;
423 omap_gp_timer_update(s
);
426 case 0x38: /* TMAR */
427 omap_gp_timer_sync(s
);
428 s
->match_val
= value
;
429 omap_gp_timer_update(s
);
432 case 0x40: /* TSICR */
433 s
->posted
= (value
>> 2) & 1;
434 if (value
& 2) /* How much exactly are we supposed to reset? */
435 omap_gp_timer_reset(s
);
443 static void omap_gp_timer_writeh(void *opaque
, hwaddr addr
,
446 struct omap_gp_timer_s
*s
= (struct omap_gp_timer_s
*) opaque
;
449 omap_gp_timer_write(opaque
, addr
, (value
<< 16) | s
->writeh
);
451 s
->writeh
= (uint16_t) value
;
454 static uint64_t omap_gp_timer_readfn(void *opaque
, hwaddr addr
,
459 return omap_badwidth_read32(opaque
, addr
);
461 return omap_gp_timer_readh(opaque
, addr
);
463 return omap_gp_timer_readw(opaque
, addr
);
465 g_assert_not_reached();
469 static void omap_gp_timer_writefn(void *opaque
, hwaddr addr
,
470 uint64_t value
, unsigned size
)
474 omap_badwidth_write32(opaque
, addr
, value
);
477 omap_gp_timer_writeh(opaque
, addr
, value
);
480 omap_gp_timer_write(opaque
, addr
, value
);
483 g_assert_not_reached();
487 static const MemoryRegionOps omap_gp_timer_ops
= {
488 .read
= omap_gp_timer_readfn
,
489 .write
= omap_gp_timer_writefn
,
490 .valid
.min_access_size
= 1,
491 .valid
.max_access_size
= 4,
492 .endianness
= DEVICE_NATIVE_ENDIAN
,
495 struct omap_gp_timer_s
*omap_gp_timer_init(struct omap_target_agent_s
*ta
,
496 qemu_irq irq
, omap_clk fclk
, omap_clk iclk
)
498 struct omap_gp_timer_s
*s
= g_new0(struct omap_gp_timer_s
, 1);
503 s
->timer
= timer_new_ns(QEMU_CLOCK_VIRTUAL
, omap_gp_timer_tick
, s
);
504 s
->match
= timer_new_ns(QEMU_CLOCK_VIRTUAL
, omap_gp_timer_match
, s
);
505 s
->in
= qemu_allocate_irq(omap_gp_timer_input
, s
, 0);
506 omap_gp_timer_reset(s
);
507 omap_gp_timer_clk_setup(s
);
509 memory_region_init_io(&s
->iomem
, NULL
, &omap_gp_timer_ops
, s
, "omap.gptimer",
510 omap_l4_region_size(ta
, 0));
511 omap_l4_attach(ta
, 0, &s
->iomem
);