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-timer.h"
25
struct omap_gp_timer_s {
33
struct omap_target_agent_s *ta;
39
int64_t ticks_per_sec;
50
gpt_trigger_none, gpt_trigger_overflow, gpt_trigger_both
53
gpt_capture_none, gpt_capture_rising,
54
gpt_capture_falling, gpt_capture_both
65
uint32_t capture_val[2];
69
uint16_t writeh; /* LSB */
70
uint16_t readh; /* MSB */
73
#define GPT_TCAR_IT (1 << 2)
74
#define GPT_OVF_IT (1 << 1)
75
#define GPT_MAT_IT (1 << 0)
77
static inline void omap_gp_timer_intr(struct omap_gp_timer_s *timer, int it)
79
if (timer->it_ena & it) {
81
qemu_irq_raise(timer->irq);
84
/* Or are the status bits set even when masked?
85
* i.e. is masking applied before or after the status register? */
88
if (timer->wu_ena & it)
89
qemu_irq_pulse(timer->wkup);
92
static inline void omap_gp_timer_out(struct omap_gp_timer_s *timer, int level)
94
if (!timer->inout && timer->out_val != level) {
95
timer->out_val = level;
96
qemu_set_irq(timer->out, level);
100
static inline uint32_t omap_gp_timer_read(struct omap_gp_timer_s *timer)
104
if (timer->st && timer->rate) {
105
distance = qemu_get_clock_ns(vm_clock) - timer->time;
106
distance = muldiv64(distance, timer->rate, timer->ticks_per_sec);
108
if (distance >= 0xffffffff - timer->val)
111
return timer->val + distance;
116
static inline void omap_gp_timer_sync(struct omap_gp_timer_s *timer)
119
timer->val = omap_gp_timer_read(timer);
120
timer->time = qemu_get_clock_ns(vm_clock);
124
static inline void omap_gp_timer_update(struct omap_gp_timer_s *timer)
126
int64_t expires, matches;
128
if (timer->st && timer->rate) {
129
expires = muldiv64(0x100000000ll - timer->val,
130
timer->ticks_per_sec, timer->rate);
131
qemu_mod_timer(timer->timer, timer->time + expires);
133
if (timer->ce && timer->match_val >= timer->val) {
134
matches = muldiv64(timer->match_val - timer->val,
135
timer->ticks_per_sec, timer->rate);
136
qemu_mod_timer(timer->match, timer->time + matches);
138
qemu_del_timer(timer->match);
140
qemu_del_timer(timer->timer);
141
qemu_del_timer(timer->match);
142
omap_gp_timer_out(timer, timer->scpwm);
146
static inline void omap_gp_timer_trigger(struct omap_gp_timer_s *timer)
149
/* TODO in overflow-and-match mode if the first event to
150
* occur is the match, don't toggle. */
151
omap_gp_timer_out(timer, !timer->out_val);
153
/* TODO inverted pulse on timer->out_val == 1? */
154
qemu_irq_pulse(timer->out);
157
static void omap_gp_timer_tick(void *opaque)
159
struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
165
timer->val = timer->load_val;
166
timer->time = qemu_get_clock_ns(vm_clock);
169
if (timer->trigger == gpt_trigger_overflow ||
170
timer->trigger == gpt_trigger_both)
171
omap_gp_timer_trigger(timer);
173
omap_gp_timer_intr(timer, GPT_OVF_IT);
174
omap_gp_timer_update(timer);
177
static void omap_gp_timer_match(void *opaque)
179
struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
181
if (timer->trigger == gpt_trigger_both)
182
omap_gp_timer_trigger(timer);
184
omap_gp_timer_intr(timer, GPT_MAT_IT);
187
static void omap_gp_timer_input(void *opaque, int line, int on)
189
struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
192
switch (s->capture) {
194
case gpt_capture_none:
197
case gpt_capture_rising:
198
trigger = !s->in_val && on;
200
case gpt_capture_falling:
201
trigger = s->in_val && !on;
203
case gpt_capture_both:
204
trigger = (s->in_val == !on);
209
if (s->inout && trigger && s->capt_num < 2) {
210
s->capture_val[s->capt_num] = omap_gp_timer_read(s);
212
if (s->capt2 == s->capt_num ++)
213
omap_gp_timer_intr(s, GPT_TCAR_IT);
217
static void omap_gp_timer_clk_update(void *opaque, int line, int on)
219
struct omap_gp_timer_s *timer = (struct omap_gp_timer_s *) opaque;
221
omap_gp_timer_sync(timer);
222
timer->rate = on ? omap_clk_getrate(timer->clk) : 0;
223
omap_gp_timer_update(timer);
226
static void omap_gp_timer_clk_setup(struct omap_gp_timer_s *timer)
228
omap_clk_adduser(timer->clk,
229
qemu_allocate_irqs(omap_gp_timer_clk_update, timer, 1)[0]);
230
timer->rate = omap_clk_getrate(timer->clk);
233
void omap_gp_timer_reset(struct omap_gp_timer_s *s)
243
s->trigger = gpt_trigger_none;
244
s->capture = gpt_capture_none;
253
s->load_val = 0x00000000;
254
s->capture_val[0] = 0x00000000;
255
s->capture_val[1] = 0x00000000;
256
s->match_val = 0x00000000;
257
omap_gp_timer_update(s);
260
static uint32_t omap_gp_timer_readw(void *opaque, target_phys_addr_t addr)
262
struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
265
case 0x00: /* TIDR */
268
case 0x10: /* TIOCP_CFG */
271
case 0x14: /* TISTAT */
272
/* ??? When's this bit reset? */
273
return 1; /* RESETDONE */
275
case 0x18: /* TISR */
278
case 0x1c: /* TIER */
281
case 0x20: /* TWER */
284
case 0x24: /* TCLR */
285
return (s->inout << 14) |
297
case 0x28: /* TCRR */
298
return omap_gp_timer_read(s);
300
case 0x2c: /* TLDR */
303
case 0x30: /* TTGR */
306
case 0x34: /* TWPS */
307
return 0x00000000; /* No posted writes pending. */
309
case 0x38: /* TMAR */
312
case 0x3c: /* TCAR1 */
313
return s->capture_val[0];
315
case 0x40: /* TSICR */
316
return s->posted << 2;
318
case 0x44: /* TCAR2 */
319
return s->capture_val[1];
326
static uint32_t omap_gp_timer_readh(void *opaque, target_phys_addr_t addr)
328
struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
334
ret = omap_gp_timer_readw(opaque, addr);
335
s->readh = ret >> 16;
340
static CPUReadMemoryFunc * const omap_gp_timer_readfn[] = {
341
omap_badwidth_read32,
346
static void omap_gp_timer_write(void *opaque, target_phys_addr_t addr,
349
struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
352
case 0x00: /* TIDR */
353
case 0x14: /* TISTAT */
354
case 0x34: /* TWPS */
355
case 0x3c: /* TCAR1 */
356
case 0x44: /* TCAR2 */
360
case 0x10: /* TIOCP_CFG */
361
s->config = value & 0x33d;
362
if (((value >> 3) & 3) == 3) /* IDLEMODE */
363
fprintf(stderr, "%s: illegal IDLEMODE value in TIOCP_CFG\n",
365
if (value & 2) /* SOFTRESET */
366
omap_gp_timer_reset(s);
369
case 0x18: /* TISR */
370
if (value & GPT_TCAR_IT)
372
if (s->status && !(s->status &= ~value))
373
qemu_irq_lower(s->irq);
376
case 0x1c: /* TIER */
377
s->it_ena = value & 7;
380
case 0x20: /* TWER */
381
s->wu_ena = value & 7;
384
case 0x24: /* TCLR */
385
omap_gp_timer_sync(s);
386
s->inout = (value >> 14) & 1;
387
s->capt2 = (value >> 13) & 1;
388
s->pt = (value >> 12) & 1;
389
s->trigger = (value >> 10) & 3;
390
if (s->capture == gpt_capture_none &&
391
((value >> 8) & 3) != gpt_capture_none)
393
s->capture = (value >> 8) & 3;
394
s->scpwm = (value >> 7) & 1;
395
s->ce = (value >> 6) & 1;
396
s->pre = (value >> 5) & 1;
397
s->ptv = (value >> 2) & 7;
398
s->ar = (value >> 1) & 1;
399
s->st = (value >> 0) & 1;
400
if (s->inout && s->trigger != gpt_trigger_none)
401
fprintf(stderr, "%s: GP timer pin must be an output "
402
"for this trigger mode\n", __FUNCTION__);
403
if (!s->inout && s->capture != gpt_capture_none)
404
fprintf(stderr, "%s: GP timer pin must be an input "
405
"for this capture mode\n", __FUNCTION__);
406
if (s->trigger == gpt_trigger_none)
407
omap_gp_timer_out(s, s->scpwm);
408
/* TODO: make sure this doesn't overflow 32-bits */
409
s->ticks_per_sec = get_ticks_per_sec() << (s->pre ? s->ptv + 1 : 0);
410
omap_gp_timer_update(s);
413
case 0x28: /* TCRR */
414
s->time = qemu_get_clock_ns(vm_clock);
416
omap_gp_timer_update(s);
419
case 0x2c: /* TLDR */
423
case 0x30: /* TTGR */
424
s->time = qemu_get_clock_ns(vm_clock);
425
s->val = s->load_val;
426
omap_gp_timer_update(s);
429
case 0x38: /* TMAR */
430
omap_gp_timer_sync(s);
431
s->match_val = value;
432
omap_gp_timer_update(s);
435
case 0x40: /* TSICR */
436
s->posted = (value >> 2) & 1;
437
if (value & 2) /* How much exactly are we supposed to reset? */
438
omap_gp_timer_reset(s);
446
static void omap_gp_timer_writeh(void *opaque, target_phys_addr_t addr,
449
struct omap_gp_timer_s *s = (struct omap_gp_timer_s *) opaque;
452
return omap_gp_timer_write(opaque, addr, (value << 16) | s->writeh);
454
s->writeh = (uint16_t) value;
457
static CPUWriteMemoryFunc * const omap_gp_timer_writefn[] = {
458
omap_badwidth_write32,
459
omap_gp_timer_writeh,
463
struct omap_gp_timer_s *omap_gp_timer_init(struct omap_target_agent_s *ta,
464
qemu_irq irq, omap_clk fclk, omap_clk iclk)
467
struct omap_gp_timer_s *s = (struct omap_gp_timer_s *)
468
qemu_mallocz(sizeof(struct omap_gp_timer_s));
473
s->timer = qemu_new_timer_ns(vm_clock, omap_gp_timer_tick, s);
474
s->match = qemu_new_timer_ns(vm_clock, omap_gp_timer_match, s);
475
s->in = qemu_allocate_irqs(omap_gp_timer_input, s, 1)[0];
476
omap_gp_timer_reset(s);
477
omap_gp_timer_clk_setup(s);
479
iomemtype = l4_register_io_memory(omap_gp_timer_readfn,
480
omap_gp_timer_writefn, s);
481
omap_l4_attach(ta, 0, iomemtype);