Statistics
| Branch: | Revision:

root / hw / arm_timer.c @ 2ac71179

History | View | Annotate | Download (8.8 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 "hw.h"
11
#include "qemu-timer.h"
12
#include "primecell.h"
13

    
14
/* Common timer implementation.  */
15

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

    
25
typedef struct {
26
    ptimer_state *timer;
27
    uint32_t control;
28
    uint32_t limit;
29
    int freq;
30
    int int_level;
31
    qemu_irq irq;
32
} arm_timer_state;
33

    
34
/* Check all active timers, and schedule the next timer interrupt.  */
35

    
36
static void arm_timer_update(arm_timer_state *s)
37
{
38
    /* Update interrupts.  */
39
    if (s->int_level && (s->control & TIMER_CTRL_IE)) {
40
        qemu_irq_raise(s->irq);
41
    } else {
42
        qemu_irq_lower(s->irq);
43
    }
44
}
45

    
46
static uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset)
47
{
48
    arm_timer_state *s = (arm_timer_state *)opaque;
49

    
50
    switch (offset >> 2) {
51
    case 0: /* TimerLoad */
52
    case 6: /* TimerBGLoad */
53
        return s->limit;
54
    case 1: /* TimerValue */
55
        return ptimer_get_count(s->timer);
56
    case 2: /* TimerControl */
57
        return s->control;
58
    case 4: /* TimerRIS */
59
        return s->int_level;
60
    case 5: /* TimerMIS */
61
        if ((s->control & TIMER_CTRL_IE) == 0)
62
            return 0;
63
        return s->int_level;
64
    default:
65
        hw_error("arm_timer_read: Bad offset %x\n", (int)offset);
66
        return 0;
67
    }
68
}
69

    
70
/* Reset the timer limit after settings have changed.  */
71
static void arm_timer_recalibrate(arm_timer_state *s, int reload)
72
{
73
    uint32_t limit;
74

    
75
    if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
76
        /* Free running.  */
77
        if (s->control & TIMER_CTRL_32BIT)
78
            limit = 0xffffffff;
79
        else
80
            limit = 0xffff;
81
    } else {
82
          /* Periodic.  */
83
          limit = s->limit;
84
    }
85
    ptimer_set_limit(s->timer, limit, reload);
86
}
87

    
88
static void arm_timer_write(void *opaque, target_phys_addr_t offset,
89
                            uint32_t value)
90
{
91
    arm_timer_state *s = (arm_timer_state *)opaque;
92
    int freq;
93

    
94
    switch (offset >> 2) {
95
    case 0: /* TimerLoad */
96
        s->limit = value;
97
        arm_timer_recalibrate(s, 1);
98
        break;
99
    case 1: /* TimerValue */
100
        /* ??? Linux seems to want to write to this readonly register.
101
           Ignore it.  */
102
        break;
103
    case 2: /* TimerControl */
104
        if (s->control & TIMER_CTRL_ENABLE) {
105
            /* Pause the timer if it is running.  This may cause some
106
               inaccuracy dure to rounding, but avoids a whole lot of other
107
               messyness.  */
108
            ptimer_stop(s->timer);
109
        }
110
        s->control = value;
111
        freq = s->freq;
112
        /* ??? Need to recalculate expiry time after changing divisor.  */
113
        switch ((value >> 2) & 3) {
114
        case 1: freq >>= 4; break;
115
        case 2: freq >>= 8; break;
116
        }
117
        arm_timer_recalibrate(s, 0);
118
        ptimer_set_freq(s->timer, freq);
119
        if (s->control & TIMER_CTRL_ENABLE) {
120
            /* Restart the timer if still enabled.  */
121
            ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
122
        }
123
        break;
124
    case 3: /* TimerIntClr */
125
        s->int_level = 0;
126
        break;
127
    case 6: /* TimerBGLoad */
128
        s->limit = value;
129
        arm_timer_recalibrate(s, 0);
130
        break;
131
    default:
132
        hw_error("arm_timer_write: Bad offset %x\n", (int)offset);
133
    }
134
    arm_timer_update(s);
135
}
136

    
137
static void arm_timer_tick(void *opaque)
138
{
139
    arm_timer_state *s = (arm_timer_state *)opaque;
140
    s->int_level = 1;
141
    arm_timer_update(s);
142
}
143

    
144
static void arm_timer_save(QEMUFile *f, void *opaque)
145
{
146
    arm_timer_state *s = (arm_timer_state *)opaque;
147
    qemu_put_be32(f, s->control);
148
    qemu_put_be32(f, s->limit);
149
    qemu_put_be32(f, s->int_level);
150
    qemu_put_ptimer(f, s->timer);
151
}
152

    
153
static int arm_timer_load(QEMUFile *f, void *opaque, int version_id)
154
{
155
    arm_timer_state *s = (arm_timer_state *)opaque;
156

    
157
    if (version_id != 1)
158
        return -EINVAL;
159

    
160
    s->control = qemu_get_be32(f);
161
    s->limit = qemu_get_be32(f);
162
    s->int_level = qemu_get_be32(f);
163
    qemu_get_ptimer(f, s->timer);
164
    return 0;
165
}
166

    
167
static void *arm_timer_init(uint32_t freq, qemu_irq irq)
168
{
169
    arm_timer_state *s;
170
    QEMUBH *bh;
171

    
172
    s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
173
    s->irq = irq;
174
    s->freq = freq;
175
    s->control = TIMER_CTRL_IE;
176

    
177
    bh = qemu_bh_new(arm_timer_tick, s);
178
    s->timer = ptimer_init(bh);
179
    register_savevm("arm_timer", -1, 1, arm_timer_save, arm_timer_load, s);
180
    return s;
181
}
182

    
183
/* ARM PrimeCell SP804 dual timer module.
184
   Docs for this device don't seem to be publicly available.  This
185
   implementation is based on guesswork, the linux kernel sources and the
186
   Integrator/CP timer modules.  */
187

    
188
typedef struct {
189
    void *timer[2];
190
    int level[2];
191
    qemu_irq irq;
192
} sp804_state;
193

    
194
/* Merge the IRQs from the two component devices.  */
195
static void sp804_set_irq(void *opaque, int irq, int level)
196
{
197
    sp804_state *s = (sp804_state *)opaque;
198

    
199
    s->level[irq] = level;
200
    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
201
}
202

    
203
static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
204
{
205
    sp804_state *s = (sp804_state *)opaque;
206

    
207
    /* ??? Don't know the PrimeCell ID for this device.  */
208
    if (offset < 0x20) {
209
        return arm_timer_read(s->timer[0], offset);
210
    } else {
211
        return arm_timer_read(s->timer[1], offset - 0x20);
212
    }
213
}
214

    
215
static void sp804_write(void *opaque, target_phys_addr_t offset,
216
                        uint32_t value)
217
{
218
    sp804_state *s = (sp804_state *)opaque;
219

    
220
    if (offset < 0x20) {
221
        arm_timer_write(s->timer[0], offset, value);
222
    } else {
223
        arm_timer_write(s->timer[1], offset - 0x20, value);
224
    }
225
}
226

    
227
static CPUReadMemoryFunc *sp804_readfn[] = {
228
   sp804_read,
229
   sp804_read,
230
   sp804_read
231
};
232

    
233
static CPUWriteMemoryFunc *sp804_writefn[] = {
234
   sp804_write,
235
   sp804_write,
236
   sp804_write
237
};
238

    
239
static void sp804_save(QEMUFile *f, void *opaque)
240
{
241
    sp804_state *s = (sp804_state *)opaque;
242
    qemu_put_be32(f, s->level[0]);
243
    qemu_put_be32(f, s->level[1]);
244
}
245

    
246
static int sp804_load(QEMUFile *f, void *opaque, int version_id)
247
{
248
    sp804_state *s = (sp804_state *)opaque;
249

    
250
    if (version_id != 1)
251
        return -EINVAL;
252

    
253
    s->level[0] = qemu_get_be32(f);
254
    s->level[1] = qemu_get_be32(f);
255
    return 0;
256
}
257

    
258
void sp804_init(uint32_t base, qemu_irq irq)
259
{
260
    int iomemtype;
261
    sp804_state *s;
262
    qemu_irq *qi;
263

    
264
    s = (sp804_state *)qemu_mallocz(sizeof(sp804_state));
265
    qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
266
    s->irq = irq;
267
    /* ??? The timers are actually configurable between 32kHz and 1MHz, but
268
       we don't implement that.  */
269
    s->timer[0] = arm_timer_init(1000000, qi[0]);
270
    s->timer[1] = arm_timer_init(1000000, qi[1]);
271
    iomemtype = cpu_register_io_memory(0, sp804_readfn,
272
                                       sp804_writefn, s);
273
    cpu_register_physical_memory(base, 0x00001000, iomemtype);
274
    register_savevm("sp804", -1, 1, sp804_save, sp804_load, s);
275
}
276

    
277

    
278
/* Integrator/CP timer module.  */
279

    
280
typedef struct {
281
    void *timer[3];
282
} icp_pit_state;
283

    
284
static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
285
{
286
    icp_pit_state *s = (icp_pit_state *)opaque;
287
    int n;
288

    
289
    /* ??? Don't know the PrimeCell ID for this device.  */
290
    n = offset >> 8;
291
    if (n > 3) {
292
        hw_error("sp804_read: Bad timer %d\n", n);
293
    }
294

    
295
    return arm_timer_read(s->timer[n], offset & 0xff);
296
}
297

    
298
static void icp_pit_write(void *opaque, target_phys_addr_t offset,
299
                          uint32_t value)
300
{
301
    icp_pit_state *s = (icp_pit_state *)opaque;
302
    int n;
303

    
304
    n = offset >> 8;
305
    if (n > 3) {
306
        hw_error("sp804_write: Bad timer %d\n", n);
307
    }
308

    
309
    arm_timer_write(s->timer[n], offset & 0xff, value);
310
}
311

    
312

    
313
static CPUReadMemoryFunc *icp_pit_readfn[] = {
314
   icp_pit_read,
315
   icp_pit_read,
316
   icp_pit_read
317
};
318

    
319
static CPUWriteMemoryFunc *icp_pit_writefn[] = {
320
   icp_pit_write,
321
   icp_pit_write,
322
   icp_pit_write
323
};
324

    
325
void icp_pit_init(uint32_t base, qemu_irq *pic, int irq)
326
{
327
    int iomemtype;
328
    icp_pit_state *s;
329

    
330
    s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state));
331
    /* Timer 0 runs at the system clock speed (40MHz).  */
332
    s->timer[0] = arm_timer_init(40000000, pic[irq]);
333
    /* The other two timers run at 1MHz.  */
334
    s->timer[1] = arm_timer_init(1000000, pic[irq + 1]);
335
    s->timer[2] = arm_timer_init(1000000, pic[irq + 2]);
336

    
337
    iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
338
                                       icp_pit_writefn, s);
339
    cpu_register_physical_memory(base, 0x00001000, iomemtype);
340
    /* This device has no state to save/restore.  The component timers will
341
       save themselves.  */
342
}