Statistics
| Branch: | Revision:

root / hw / arm_timer.c @ 7ba1e619

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