Statistics
| Branch: | Revision:

root / hw / arm_timer.c @ a88790a1

History | View | Annotate | Download (9.2 kB)

1 5fafdf24 ths
/*
2 cdbdb648 pbrook
 * ARM PrimeCell Timer modules.
3 cdbdb648 pbrook
 *
4 cdbdb648 pbrook
 * Copyright (c) 2005-2006 CodeSourcery.
5 cdbdb648 pbrook
 * Written by Paul Brook
6 cdbdb648 pbrook
 *
7 cdbdb648 pbrook
 * This code is licenced under the GPL.
8 cdbdb648 pbrook
 */
9 cdbdb648 pbrook
10 6a824ec3 Paul Brook
#include "sysbus.h"
11 87ecb68b pbrook
#include "qemu-timer.h"
12 cdbdb648 pbrook
13 cdbdb648 pbrook
/* Common timer implementation.  */
14 cdbdb648 pbrook
15 cdbdb648 pbrook
#define TIMER_CTRL_ONESHOT      (1 << 0)
16 cdbdb648 pbrook
#define TIMER_CTRL_32BIT        (1 << 1)
17 cdbdb648 pbrook
#define TIMER_CTRL_DIV1         (0 << 2)
18 cdbdb648 pbrook
#define TIMER_CTRL_DIV16        (1 << 2)
19 cdbdb648 pbrook
#define TIMER_CTRL_DIV256       (2 << 2)
20 cdbdb648 pbrook
#define TIMER_CTRL_IE           (1 << 5)
21 cdbdb648 pbrook
#define TIMER_CTRL_PERIODIC     (1 << 6)
22 cdbdb648 pbrook
#define TIMER_CTRL_ENABLE       (1 << 7)
23 cdbdb648 pbrook
24 cdbdb648 pbrook
typedef struct {
25 423f0742 pbrook
    ptimer_state *timer;
26 cdbdb648 pbrook
    uint32_t control;
27 cdbdb648 pbrook
    uint32_t limit;
28 cdbdb648 pbrook
    int freq;
29 cdbdb648 pbrook
    int int_level;
30 d537cf6c pbrook
    qemu_irq irq;
31 cdbdb648 pbrook
} arm_timer_state;
32 cdbdb648 pbrook
33 cdbdb648 pbrook
/* Check all active timers, and schedule the next timer interrupt.  */
34 cdbdb648 pbrook
35 423f0742 pbrook
static void arm_timer_update(arm_timer_state *s)
36 cdbdb648 pbrook
{
37 cdbdb648 pbrook
    /* Update interrupts.  */
38 cdbdb648 pbrook
    if (s->int_level && (s->control & TIMER_CTRL_IE)) {
39 d537cf6c pbrook
        qemu_irq_raise(s->irq);
40 cdbdb648 pbrook
    } else {
41 d537cf6c pbrook
        qemu_irq_lower(s->irq);
42 cdbdb648 pbrook
    }
43 cdbdb648 pbrook
}
44 cdbdb648 pbrook
45 c227f099 Anthony Liguori
static uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset)
46 cdbdb648 pbrook
{
47 cdbdb648 pbrook
    arm_timer_state *s = (arm_timer_state *)opaque;
48 cdbdb648 pbrook
49 cdbdb648 pbrook
    switch (offset >> 2) {
50 cdbdb648 pbrook
    case 0: /* TimerLoad */
51 cdbdb648 pbrook
    case 6: /* TimerBGLoad */
52 cdbdb648 pbrook
        return s->limit;
53 cdbdb648 pbrook
    case 1: /* TimerValue */
54 423f0742 pbrook
        return ptimer_get_count(s->timer);
55 cdbdb648 pbrook
    case 2: /* TimerControl */
56 cdbdb648 pbrook
        return s->control;
57 cdbdb648 pbrook
    case 4: /* TimerRIS */
58 cdbdb648 pbrook
        return s->int_level;
59 cdbdb648 pbrook
    case 5: /* TimerMIS */
60 cdbdb648 pbrook
        if ((s->control & TIMER_CTRL_IE) == 0)
61 cdbdb648 pbrook
            return 0;
62 cdbdb648 pbrook
        return s->int_level;
63 cdbdb648 pbrook
    default:
64 2ac71179 Paul Brook
        hw_error("arm_timer_read: Bad offset %x\n", (int)offset);
65 cdbdb648 pbrook
        return 0;
66 cdbdb648 pbrook
    }
67 cdbdb648 pbrook
}
68 cdbdb648 pbrook
69 423f0742 pbrook
/* Reset the timer limit after settings have changed.  */
70 423f0742 pbrook
static void arm_timer_recalibrate(arm_timer_state *s, int reload)
71 423f0742 pbrook
{
72 423f0742 pbrook
    uint32_t limit;
73 423f0742 pbrook
74 a9cf98d9 Rabin Vincent
    if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
75 423f0742 pbrook
        /* Free running.  */
76 423f0742 pbrook
        if (s->control & TIMER_CTRL_32BIT)
77 423f0742 pbrook
            limit = 0xffffffff;
78 423f0742 pbrook
        else
79 423f0742 pbrook
            limit = 0xffff;
80 423f0742 pbrook
    } else {
81 423f0742 pbrook
          /* Periodic.  */
82 423f0742 pbrook
          limit = s->limit;
83 423f0742 pbrook
    }
84 423f0742 pbrook
    ptimer_set_limit(s->timer, limit, reload);
85 423f0742 pbrook
}
86 423f0742 pbrook
87 c227f099 Anthony Liguori
static void arm_timer_write(void *opaque, target_phys_addr_t offset,
88 cdbdb648 pbrook
                            uint32_t value)
89 cdbdb648 pbrook
{
90 cdbdb648 pbrook
    arm_timer_state *s = (arm_timer_state *)opaque;
91 423f0742 pbrook
    int freq;
92 cdbdb648 pbrook
93 cdbdb648 pbrook
    switch (offset >> 2) {
94 cdbdb648 pbrook
    case 0: /* TimerLoad */
95 cdbdb648 pbrook
        s->limit = value;
96 423f0742 pbrook
        arm_timer_recalibrate(s, 1);
97 cdbdb648 pbrook
        break;
98 cdbdb648 pbrook
    case 1: /* TimerValue */
99 cdbdb648 pbrook
        /* ??? Linux seems to want to write to this readonly register.
100 cdbdb648 pbrook
           Ignore it.  */
101 cdbdb648 pbrook
        break;
102 cdbdb648 pbrook
    case 2: /* TimerControl */
103 cdbdb648 pbrook
        if (s->control & TIMER_CTRL_ENABLE) {
104 cdbdb648 pbrook
            /* Pause the timer if it is running.  This may cause some
105 cdbdb648 pbrook
               inaccuracy dure to rounding, but avoids a whole lot of other
106 cdbdb648 pbrook
               messyness.  */
107 423f0742 pbrook
            ptimer_stop(s->timer);
108 cdbdb648 pbrook
        }
109 cdbdb648 pbrook
        s->control = value;
110 423f0742 pbrook
        freq = s->freq;
111 cdbdb648 pbrook
        /* ??? Need to recalculate expiry time after changing divisor.  */
112 cdbdb648 pbrook
        switch ((value >> 2) & 3) {
113 423f0742 pbrook
        case 1: freq >>= 4; break;
114 423f0742 pbrook
        case 2: freq >>= 8; break;
115 cdbdb648 pbrook
        }
116 d6759902 Rabin Vincent
        arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE);
117 423f0742 pbrook
        ptimer_set_freq(s->timer, freq);
118 cdbdb648 pbrook
        if (s->control & TIMER_CTRL_ENABLE) {
119 cdbdb648 pbrook
            /* Restart the timer if still enabled.  */
120 423f0742 pbrook
            ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
121 cdbdb648 pbrook
        }
122 cdbdb648 pbrook
        break;
123 cdbdb648 pbrook
    case 3: /* TimerIntClr */
124 cdbdb648 pbrook
        s->int_level = 0;
125 cdbdb648 pbrook
        break;
126 cdbdb648 pbrook
    case 6: /* TimerBGLoad */
127 cdbdb648 pbrook
        s->limit = value;
128 423f0742 pbrook
        arm_timer_recalibrate(s, 0);
129 cdbdb648 pbrook
        break;
130 cdbdb648 pbrook
    default:
131 2ac71179 Paul Brook
        hw_error("arm_timer_write: Bad offset %x\n", (int)offset);
132 cdbdb648 pbrook
    }
133 423f0742 pbrook
    arm_timer_update(s);
134 cdbdb648 pbrook
}
135 cdbdb648 pbrook
136 cdbdb648 pbrook
static void arm_timer_tick(void *opaque)
137 cdbdb648 pbrook
{
138 423f0742 pbrook
    arm_timer_state *s = (arm_timer_state *)opaque;
139 423f0742 pbrook
    s->int_level = 1;
140 423f0742 pbrook
    arm_timer_update(s);
141 cdbdb648 pbrook
}
142 cdbdb648 pbrook
143 23e39294 pbrook
static void arm_timer_save(QEMUFile *f, void *opaque)
144 23e39294 pbrook
{
145 23e39294 pbrook
    arm_timer_state *s = (arm_timer_state *)opaque;
146 23e39294 pbrook
    qemu_put_be32(f, s->control);
147 23e39294 pbrook
    qemu_put_be32(f, s->limit);
148 23e39294 pbrook
    qemu_put_be32(f, s->int_level);
149 23e39294 pbrook
    qemu_put_ptimer(f, s->timer);
150 23e39294 pbrook
}
151 23e39294 pbrook
152 23e39294 pbrook
static int arm_timer_load(QEMUFile *f, void *opaque, int version_id)
153 23e39294 pbrook
{
154 23e39294 pbrook
    arm_timer_state *s = (arm_timer_state *)opaque;
155 23e39294 pbrook
156 23e39294 pbrook
    if (version_id != 1)
157 23e39294 pbrook
        return -EINVAL;
158 23e39294 pbrook
159 23e39294 pbrook
    s->control = qemu_get_be32(f);
160 23e39294 pbrook
    s->limit = qemu_get_be32(f);
161 23e39294 pbrook
    s->int_level = qemu_get_be32(f);
162 23e39294 pbrook
    qemu_get_ptimer(f, s->timer);
163 23e39294 pbrook
    return 0;
164 23e39294 pbrook
}
165 23e39294 pbrook
166 6a824ec3 Paul Brook
static arm_timer_state *arm_timer_init(uint32_t freq)
167 cdbdb648 pbrook
{
168 cdbdb648 pbrook
    arm_timer_state *s;
169 423f0742 pbrook
    QEMUBH *bh;
170 cdbdb648 pbrook
171 cdbdb648 pbrook
    s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
172 423f0742 pbrook
    s->freq = freq;
173 cdbdb648 pbrook
    s->control = TIMER_CTRL_IE;
174 cdbdb648 pbrook
175 423f0742 pbrook
    bh = qemu_bh_new(arm_timer_tick, s);
176 423f0742 pbrook
    s->timer = ptimer_init(bh);
177 23e39294 pbrook
    register_savevm("arm_timer", -1, 1, arm_timer_save, arm_timer_load, s);
178 cdbdb648 pbrook
    return s;
179 cdbdb648 pbrook
}
180 cdbdb648 pbrook
181 cdbdb648 pbrook
/* ARM PrimeCell SP804 dual timer module.
182 cdbdb648 pbrook
   Docs for this device don't seem to be publicly available.  This
183 d85fb99b pbrook
   implementation is based on guesswork, the linux kernel sources and the
184 cdbdb648 pbrook
   Integrator/CP timer modules.  */
185 cdbdb648 pbrook
186 cdbdb648 pbrook
typedef struct {
187 6a824ec3 Paul Brook
    SysBusDevice busdev;
188 6a824ec3 Paul Brook
    arm_timer_state *timer[2];
189 cdbdb648 pbrook
    int level[2];
190 d537cf6c pbrook
    qemu_irq irq;
191 cdbdb648 pbrook
} sp804_state;
192 cdbdb648 pbrook
193 d537cf6c pbrook
/* Merge the IRQs from the two component devices.  */
194 cdbdb648 pbrook
static void sp804_set_irq(void *opaque, int irq, int level)
195 cdbdb648 pbrook
{
196 cdbdb648 pbrook
    sp804_state *s = (sp804_state *)opaque;
197 cdbdb648 pbrook
198 cdbdb648 pbrook
    s->level[irq] = level;
199 d537cf6c pbrook
    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
200 cdbdb648 pbrook
}
201 cdbdb648 pbrook
202 c227f099 Anthony Liguori
static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
203 cdbdb648 pbrook
{
204 cdbdb648 pbrook
    sp804_state *s = (sp804_state *)opaque;
205 cdbdb648 pbrook
206 cdbdb648 pbrook
    /* ??? Don't know the PrimeCell ID for this device.  */
207 cdbdb648 pbrook
    if (offset < 0x20) {
208 cdbdb648 pbrook
        return arm_timer_read(s->timer[0], offset);
209 cdbdb648 pbrook
    } else {
210 cdbdb648 pbrook
        return arm_timer_read(s->timer[1], offset - 0x20);
211 cdbdb648 pbrook
    }
212 cdbdb648 pbrook
}
213 cdbdb648 pbrook
214 c227f099 Anthony Liguori
static void sp804_write(void *opaque, target_phys_addr_t offset,
215 cdbdb648 pbrook
                        uint32_t value)
216 cdbdb648 pbrook
{
217 cdbdb648 pbrook
    sp804_state *s = (sp804_state *)opaque;
218 cdbdb648 pbrook
219 cdbdb648 pbrook
    if (offset < 0x20) {
220 cdbdb648 pbrook
        arm_timer_write(s->timer[0], offset, value);
221 cdbdb648 pbrook
    } else {
222 cdbdb648 pbrook
        arm_timer_write(s->timer[1], offset - 0x20, value);
223 cdbdb648 pbrook
    }
224 cdbdb648 pbrook
}
225 cdbdb648 pbrook
226 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const sp804_readfn[] = {
227 cdbdb648 pbrook
   sp804_read,
228 cdbdb648 pbrook
   sp804_read,
229 cdbdb648 pbrook
   sp804_read
230 cdbdb648 pbrook
};
231 cdbdb648 pbrook
232 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const sp804_writefn[] = {
233 cdbdb648 pbrook
   sp804_write,
234 cdbdb648 pbrook
   sp804_write,
235 cdbdb648 pbrook
   sp804_write
236 cdbdb648 pbrook
};
237 cdbdb648 pbrook
238 23e39294 pbrook
static void sp804_save(QEMUFile *f, void *opaque)
239 23e39294 pbrook
{
240 23e39294 pbrook
    sp804_state *s = (sp804_state *)opaque;
241 23e39294 pbrook
    qemu_put_be32(f, s->level[0]);
242 23e39294 pbrook
    qemu_put_be32(f, s->level[1]);
243 23e39294 pbrook
}
244 23e39294 pbrook
245 23e39294 pbrook
static int sp804_load(QEMUFile *f, void *opaque, int version_id)
246 23e39294 pbrook
{
247 23e39294 pbrook
    sp804_state *s = (sp804_state *)opaque;
248 23e39294 pbrook
249 23e39294 pbrook
    if (version_id != 1)
250 23e39294 pbrook
        return -EINVAL;
251 23e39294 pbrook
252 23e39294 pbrook
    s->level[0] = qemu_get_be32(f);
253 23e39294 pbrook
    s->level[1] = qemu_get_be32(f);
254 23e39294 pbrook
    return 0;
255 23e39294 pbrook
}
256 23e39294 pbrook
257 81a322d4 Gerd Hoffmann
static int sp804_init(SysBusDevice *dev)
258 cdbdb648 pbrook
{
259 cdbdb648 pbrook
    int iomemtype;
260 6a824ec3 Paul Brook
    sp804_state *s = FROM_SYSBUS(sp804_state, dev);
261 d537cf6c pbrook
    qemu_irq *qi;
262 cdbdb648 pbrook
263 d537cf6c pbrook
    qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
264 6a824ec3 Paul Brook
    sysbus_init_irq(dev, &s->irq);
265 cdbdb648 pbrook
    /* ??? The timers are actually configurable between 32kHz and 1MHz, but
266 cdbdb648 pbrook
       we don't implement that.  */
267 6a824ec3 Paul Brook
    s->timer[0] = arm_timer_init(1000000);
268 6a824ec3 Paul Brook
    s->timer[1] = arm_timer_init(1000000);
269 6a824ec3 Paul Brook
    s->timer[0]->irq = qi[0];
270 6a824ec3 Paul Brook
    s->timer[1]->irq = qi[1];
271 1eed09cb Avi Kivity
    iomemtype = cpu_register_io_memory(sp804_readfn,
272 cdbdb648 pbrook
                                       sp804_writefn, s);
273 6a824ec3 Paul Brook
    sysbus_init_mmio(dev, 0x1000, iomemtype);
274 23e39294 pbrook
    register_savevm("sp804", -1, 1, sp804_save, sp804_load, s);
275 81a322d4 Gerd Hoffmann
    return 0;
276 cdbdb648 pbrook
}
277 cdbdb648 pbrook
278 cdbdb648 pbrook
279 cdbdb648 pbrook
/* Integrator/CP timer module.  */
280 cdbdb648 pbrook
281 cdbdb648 pbrook
typedef struct {
282 6a824ec3 Paul Brook
    SysBusDevice busdev;
283 6a824ec3 Paul Brook
    arm_timer_state *timer[3];
284 cdbdb648 pbrook
} icp_pit_state;
285 cdbdb648 pbrook
286 c227f099 Anthony Liguori
static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
287 cdbdb648 pbrook
{
288 cdbdb648 pbrook
    icp_pit_state *s = (icp_pit_state *)opaque;
289 cdbdb648 pbrook
    int n;
290 cdbdb648 pbrook
291 cdbdb648 pbrook
    /* ??? Don't know the PrimeCell ID for this device.  */
292 cdbdb648 pbrook
    n = offset >> 8;
293 2ac71179 Paul Brook
    if (n > 3) {
294 2ac71179 Paul Brook
        hw_error("sp804_read: Bad timer %d\n", n);
295 2ac71179 Paul Brook
    }
296 cdbdb648 pbrook
297 cdbdb648 pbrook
    return arm_timer_read(s->timer[n], offset & 0xff);
298 cdbdb648 pbrook
}
299 cdbdb648 pbrook
300 c227f099 Anthony Liguori
static void icp_pit_write(void *opaque, target_phys_addr_t offset,
301 cdbdb648 pbrook
                          uint32_t value)
302 cdbdb648 pbrook
{
303 cdbdb648 pbrook
    icp_pit_state *s = (icp_pit_state *)opaque;
304 cdbdb648 pbrook
    int n;
305 cdbdb648 pbrook
306 cdbdb648 pbrook
    n = offset >> 8;
307 2ac71179 Paul Brook
    if (n > 3) {
308 2ac71179 Paul Brook
        hw_error("sp804_write: Bad timer %d\n", n);
309 2ac71179 Paul Brook
    }
310 cdbdb648 pbrook
311 cdbdb648 pbrook
    arm_timer_write(s->timer[n], offset & 0xff, value);
312 cdbdb648 pbrook
}
313 cdbdb648 pbrook
314 cdbdb648 pbrook
315 d60efc6b Blue Swirl
static CPUReadMemoryFunc * const icp_pit_readfn[] = {
316 cdbdb648 pbrook
   icp_pit_read,
317 cdbdb648 pbrook
   icp_pit_read,
318 cdbdb648 pbrook
   icp_pit_read
319 cdbdb648 pbrook
};
320 cdbdb648 pbrook
321 d60efc6b Blue Swirl
static CPUWriteMemoryFunc * const icp_pit_writefn[] = {
322 cdbdb648 pbrook
   icp_pit_write,
323 cdbdb648 pbrook
   icp_pit_write,
324 cdbdb648 pbrook
   icp_pit_write
325 cdbdb648 pbrook
};
326 cdbdb648 pbrook
327 81a322d4 Gerd Hoffmann
static int icp_pit_init(SysBusDevice *dev)
328 cdbdb648 pbrook
{
329 cdbdb648 pbrook
    int iomemtype;
330 6a824ec3 Paul Brook
    icp_pit_state *s = FROM_SYSBUS(icp_pit_state, dev);
331 cdbdb648 pbrook
332 cdbdb648 pbrook
    /* Timer 0 runs at the system clock speed (40MHz).  */
333 6a824ec3 Paul Brook
    s->timer[0] = arm_timer_init(40000000);
334 cdbdb648 pbrook
    /* The other two timers run at 1MHz.  */
335 6a824ec3 Paul Brook
    s->timer[1] = arm_timer_init(1000000);
336 6a824ec3 Paul Brook
    s->timer[2] = arm_timer_init(1000000);
337 6a824ec3 Paul Brook
338 6a824ec3 Paul Brook
    sysbus_init_irq(dev, &s->timer[0]->irq);
339 6a824ec3 Paul Brook
    sysbus_init_irq(dev, &s->timer[1]->irq);
340 6a824ec3 Paul Brook
    sysbus_init_irq(dev, &s->timer[2]->irq);
341 cdbdb648 pbrook
342 1eed09cb Avi Kivity
    iomemtype = cpu_register_io_memory(icp_pit_readfn,
343 cdbdb648 pbrook
                                       icp_pit_writefn, s);
344 6a824ec3 Paul Brook
    sysbus_init_mmio(dev, 0x1000, iomemtype);
345 23e39294 pbrook
    /* This device has no state to save/restore.  The component timers will
346 23e39294 pbrook
       save themselves.  */
347 81a322d4 Gerd Hoffmann
    return 0;
348 cdbdb648 pbrook
}
349 6a824ec3 Paul Brook
350 6a824ec3 Paul Brook
static void arm_timer_register_devices(void)
351 6a824ec3 Paul Brook
{
352 6a824ec3 Paul Brook
    sysbus_register_dev("integrator_pit", sizeof(icp_pit_state), icp_pit_init);
353 6a824ec3 Paul Brook
    sysbus_register_dev("sp804", sizeof(sp804_state), sp804_init);
354 6a824ec3 Paul Brook
}
355 6a824ec3 Paul Brook
356 6a824ec3 Paul Brook
device_init(arm_timer_register_devices)