Statistics
| Branch: | Revision:

root / hw / arm_timer.c @ d537cf6c

History | View | Annotate | Download (10 kB)

1
/* 
2
 * ARM PrimeCell Timer modules.
3
 *
4
 * Copyright (c) 2005-2006 CodeSourcery.
5
 * Written by Paul Brook
6
 *
7
 * This code is licenced under the GPL.
8
 */
9

    
10
#include "vl.h"
11
#include "arm_pic.h"
12

    
13
/* Common timer implementation.  */
14

    
15
#define TIMER_CTRL_ONESHOT      (1 << 0)
16
#define TIMER_CTRL_32BIT        (1 << 1)
17
#define TIMER_CTRL_DIV1         (0 << 2)
18
#define TIMER_CTRL_DIV16        (1 << 2)
19
#define TIMER_CTRL_DIV256       (2 << 2)
20
#define TIMER_CTRL_IE           (1 << 5)
21
#define TIMER_CTRL_PERIODIC     (1 << 6)
22
#define TIMER_CTRL_ENABLE       (1 << 7)
23

    
24
typedef struct {
25
    int64_t next_time;
26
    int64_t expires;
27
    int64_t loaded;
28
    QEMUTimer *timer;
29
    uint32_t control;
30
    uint32_t count;
31
    uint32_t limit;
32
    int raw_freq;
33
    int freq;
34
    int int_level;
35
    qemu_irq irq;
36
} arm_timer_state;
37

    
38
/* Calculate the new expiry time of the given timer.  */
39

    
40
static void arm_timer_reload(arm_timer_state *s)
41
{
42
    int64_t delay;
43

    
44
    s->loaded = s->expires;
45
    delay = muldiv64(s->count, ticks_per_sec, s->freq);
46
    if (delay == 0)
47
        delay = 1;
48
    s->expires += delay;
49
}
50

    
51
/* Check all active timers, and schedule the next timer interrupt.  */
52

    
53
static void arm_timer_update(arm_timer_state *s, int64_t now)
54
{
55
    int64_t next;
56

    
57
    /* Ignore disabled timers.  */
58
    if ((s->control & TIMER_CTRL_ENABLE) == 0)
59
        return;
60
    /* Ignore expired one-shot timers.  */
61
    if (s->count == 0 && (s->control & TIMER_CTRL_ONESHOT))
62
        return;
63
    if (s->expires - now <= 0) {
64
        /* Timer has expired.  */
65
        s->int_level = 1;
66
        if (s->control & TIMER_CTRL_ONESHOT) {
67
            /* One-shot.  */
68
            s->count = 0;
69
        } else {
70
            if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
71
                /* Free running.  */
72
                if (s->control & TIMER_CTRL_32BIT)
73
                    s->count = 0xffffffff;
74
                else
75
                    s->count = 0xffff;
76
            } else {
77
                  /* Periodic.  */
78
                  s->count = s->limit;
79
            }
80
        }
81
    }
82
    while (s->expires - now <= 0) {
83
        arm_timer_reload(s);
84
    }
85
    /* Update interrupts.  */
86
    if (s->int_level && (s->control & TIMER_CTRL_IE)) {
87
        qemu_irq_raise(s->irq);
88
    } else {
89
        qemu_irq_lower(s->irq);
90
    }
91

    
92
    next = now;
93
    if (next - s->expires < 0)
94
        next = s->expires;
95

    
96
    /* Schedule the next timer interrupt.  */
97
    if (next == now) {
98
        qemu_del_timer(s->timer);
99
        s->next_time = 0;
100
    } else if (next != s->next_time) {
101
        qemu_mod_timer(s->timer, next);
102
        s->next_time = next;
103
    }
104
}
105

    
106
/* Return the current value of the timer.  */
107
static uint32_t arm_timer_getcount(arm_timer_state *s, int64_t now)
108
{
109
    int64_t left;
110
    int64_t period;
111

    
112
    if (s->count == 0)
113
        return 0;
114
    if ((s->control & TIMER_CTRL_ENABLE) == 0)
115
        return s->count;
116
    left = s->expires - now;
117
    period = s->expires - s->loaded;
118
    /* If the timer should have expired then return 0.  This can happen
119
       when the host timer signal doesnt occur immediately.  It's better to
120
       have a timer appear to sit at zero for a while than have it wrap
121
       around before the guest interrupt is raised.  */
122
    /* ??? Could we trigger the interrupt here?  */
123
    if (left < 0)
124
        return 0;
125
    /* We need to calculate count * elapsed / period without overfowing.
126
       Scale both elapsed and period so they fit in a 32-bit int.  */
127
    while (period != (int32_t)period) {
128
        period >>= 1;
129
        left >>= 1;
130
    }
131
    return ((uint64_t)s->count * (uint64_t)(int32_t)left)
132
            / (int32_t)period;
133
}
134

    
135
uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset)
136
{
137
    arm_timer_state *s = (arm_timer_state *)opaque;
138

    
139
    switch (offset >> 2) {
140
    case 0: /* TimerLoad */
141
    case 6: /* TimerBGLoad */
142
        return s->limit;
143
    case 1: /* TimerValue */
144
        return arm_timer_getcount(s, qemu_get_clock(vm_clock));
145
    case 2: /* TimerControl */
146
        return s->control;
147
    case 4: /* TimerRIS */
148
        return s->int_level;
149
    case 5: /* TimerMIS */
150
        if ((s->control & TIMER_CTRL_IE) == 0)
151
            return 0;
152
        return s->int_level;
153
    default:
154
        cpu_abort (cpu_single_env, "arm_timer_read: Bad offset %x\n", offset);
155
        return 0;
156
    }
157
}
158

    
159
static void arm_timer_write(void *opaque, target_phys_addr_t offset,
160
                            uint32_t value)
161
{
162
    arm_timer_state *s = (arm_timer_state *)opaque;
163
    int64_t now;
164

    
165
    now = qemu_get_clock(vm_clock);
166
    switch (offset >> 2) {
167
    case 0: /* TimerLoad */
168
        s->limit = value;
169
        s->count = value;
170
        s->expires = now;
171
        arm_timer_reload(s);
172
        break;
173
    case 1: /* TimerValue */
174
        /* ??? Linux seems to want to write to this readonly register.
175
           Ignore it.  */
176
        break;
177
    case 2: /* TimerControl */
178
        if (s->control & TIMER_CTRL_ENABLE) {
179
            /* Pause the timer if it is running.  This may cause some
180
               inaccuracy dure to rounding, but avoids a whole lot of other
181
               messyness.  */
182
            s->count = arm_timer_getcount(s, now);
183
        }
184
        s->control = value;
185
        s->freq = s->raw_freq;
186
        /* ??? Need to recalculate expiry time after changing divisor.  */
187
        switch ((value >> 2) & 3) {
188
        case 1: s->freq >>= 4; break;
189
        case 2: s->freq >>= 8; break;
190
        }
191
        if (s->control & TIMER_CTRL_ENABLE) {
192
            /* Restart the timer if still enabled.  */
193
            s->expires = now;
194
            arm_timer_reload(s);
195
        }
196
        break;
197
    case 3: /* TimerIntClr */
198
        s->int_level = 0;
199
        break;
200
    case 6: /* TimerBGLoad */
201
        s->limit = value;
202
        break;
203
    default:
204
        cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n", offset);
205
    }
206
    arm_timer_update(s, now);
207
}
208

    
209
static void arm_timer_tick(void *opaque)
210
{
211
    int64_t now;
212

    
213
    now = qemu_get_clock(vm_clock);
214
    arm_timer_update((arm_timer_state *)opaque, now);
215
}
216

    
217
static void *arm_timer_init(uint32_t freq, qemu_irq irq)
218
{
219
    arm_timer_state *s;
220

    
221
    s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
222
    s->irq = irq;
223
    s->raw_freq = s->freq = 1000000;
224
    s->control = TIMER_CTRL_IE;
225
    s->count = 0xffffffff;
226

    
227
    s->timer = qemu_new_timer(vm_clock, arm_timer_tick, s);
228
    /* ??? Save/restore.  */
229
    return s;
230
}
231

    
232
/* ARM PrimeCell SP804 dual timer module.
233
   Docs for this device don't seem to be publicly available.  This
234
   implementation is based on guesswork, the linux kernel sources and the
235
   Integrator/CP timer modules.  */
236

    
237
typedef struct {
238
    void *timer[2];
239
    int level[2];
240
    uint32_t base;
241
    qemu_irq irq;
242
} sp804_state;
243

    
244
/* Merge the IRQs from the two component devices.  */
245
static void sp804_set_irq(void *opaque, int irq, int level)
246
{
247
    sp804_state *s = (sp804_state *)opaque;
248

    
249
    s->level[irq] = level;
250
    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
251
}
252

    
253
static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
254
{
255
    sp804_state *s = (sp804_state *)opaque;
256

    
257
    /* ??? Don't know the PrimeCell ID for this device.  */
258
    offset -= s->base;
259
    if (offset < 0x20) {
260
        return arm_timer_read(s->timer[0], offset);
261
    } else {
262
        return arm_timer_read(s->timer[1], offset - 0x20);
263
    }
264
}
265

    
266
static void sp804_write(void *opaque, target_phys_addr_t offset,
267
                        uint32_t value)
268
{
269
    sp804_state *s = (sp804_state *)opaque;
270

    
271
    offset -= s->base;
272
    if (offset < 0x20) {
273
        arm_timer_write(s->timer[0], offset, value);
274
    } else {
275
        arm_timer_write(s->timer[1], offset - 0x20, value);
276
    }
277
}
278

    
279
static CPUReadMemoryFunc *sp804_readfn[] = {
280
   sp804_read,
281
   sp804_read,
282
   sp804_read
283
};
284

    
285
static CPUWriteMemoryFunc *sp804_writefn[] = {
286
   sp804_write,
287
   sp804_write,
288
   sp804_write
289
};
290

    
291
void sp804_init(uint32_t base, qemu_irq irq)
292
{
293
    int iomemtype;
294
    sp804_state *s;
295
    qemu_irq *qi;
296

    
297
    s = (sp804_state *)qemu_mallocz(sizeof(sp804_state));
298
    qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
299
    s->base = base;
300
    s->irq = irq;
301
    /* ??? The timers are actually configurable between 32kHz and 1MHz, but
302
       we don't implement that.  */
303
    s->timer[0] = arm_timer_init(1000000, qi[0]);
304
    s->timer[1] = arm_timer_init(1000000, qi[1]);
305
    iomemtype = cpu_register_io_memory(0, sp804_readfn,
306
                                       sp804_writefn, s);
307
    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
308
    /* ??? Save/restore.  */
309
}
310

    
311

    
312
/* Integrator/CP timer module.  */
313

    
314
typedef struct {
315
    void *timer[3];
316
    uint32_t base;
317
} icp_pit_state;
318

    
319
static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
320
{
321
    icp_pit_state *s = (icp_pit_state *)opaque;
322
    int n;
323

    
324
    /* ??? Don't know the PrimeCell ID for this device.  */
325
    offset -= s->base;
326
    n = offset >> 8;
327
    if (n > 3)
328
        cpu_abort(cpu_single_env, "sp804_read: Bad timer %d\n", n);
329

    
330
    return arm_timer_read(s->timer[n], offset & 0xff);
331
}
332

    
333
static void icp_pit_write(void *opaque, target_phys_addr_t offset,
334
                          uint32_t value)
335
{
336
    icp_pit_state *s = (icp_pit_state *)opaque;
337
    int n;
338

    
339
    offset -= s->base;
340
    n = offset >> 8;
341
    if (n > 3)
342
        cpu_abort(cpu_single_env, "sp804_write: Bad timer %d\n", n);
343

    
344
    arm_timer_write(s->timer[n], offset & 0xff, value);
345
}
346

    
347

    
348
static CPUReadMemoryFunc *icp_pit_readfn[] = {
349
   icp_pit_read,
350
   icp_pit_read,
351
   icp_pit_read
352
};
353

    
354
static CPUWriteMemoryFunc *icp_pit_writefn[] = {
355
   icp_pit_write,
356
   icp_pit_write,
357
   icp_pit_write
358
};
359

    
360
void icp_pit_init(uint32_t base, qemu_irq *pic, int irq)
361
{
362
    int iomemtype;
363
    icp_pit_state *s;
364

    
365
    s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state));
366
    s->base = base;
367
    /* Timer 0 runs at the system clock speed (40MHz).  */
368
    s->timer[0] = arm_timer_init(40000000, pic[irq]);
369
    /* The other two timers run at 1MHz.  */
370
    s->timer[1] = arm_timer_init(1000000, pic[irq + 1]);
371
    s->timer[2] = arm_timer_init(1000000, pic[irq + 2]);
372

    
373
    iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
374
                                       icp_pit_writefn, s);
375
    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
376
    /* ??? Save/restore.  */
377
}
378