Statistics
| Branch: | Revision:

root / hw / arm_timer.c @ 9c02f1a2

History | View | Annotate | Download (10 kB)

1 cdbdb648 pbrook
/* 
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 cdbdb648 pbrook
#include "vl.h"
11 cdbdb648 pbrook
#include "arm_pic.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 cdbdb648 pbrook
    int64_t next_time;
26 cdbdb648 pbrook
    int64_t expires;
27 cdbdb648 pbrook
    int64_t loaded;
28 cdbdb648 pbrook
    QEMUTimer *timer;
29 cdbdb648 pbrook
    uint32_t control;
30 cdbdb648 pbrook
    uint32_t count;
31 cdbdb648 pbrook
    uint32_t limit;
32 cdbdb648 pbrook
    int raw_freq;
33 cdbdb648 pbrook
    int freq;
34 cdbdb648 pbrook
    int int_level;
35 d537cf6c pbrook
    qemu_irq irq;
36 cdbdb648 pbrook
} arm_timer_state;
37 cdbdb648 pbrook
38 cdbdb648 pbrook
/* Calculate the new expiry time of the given timer.  */
39 cdbdb648 pbrook
40 cdbdb648 pbrook
static void arm_timer_reload(arm_timer_state *s)
41 cdbdb648 pbrook
{
42 cdbdb648 pbrook
    int64_t delay;
43 cdbdb648 pbrook
44 cdbdb648 pbrook
    s->loaded = s->expires;
45 cdbdb648 pbrook
    delay = muldiv64(s->count, ticks_per_sec, s->freq);
46 cdbdb648 pbrook
    if (delay == 0)
47 cdbdb648 pbrook
        delay = 1;
48 cdbdb648 pbrook
    s->expires += delay;
49 cdbdb648 pbrook
}
50 cdbdb648 pbrook
51 cdbdb648 pbrook
/* Check all active timers, and schedule the next timer interrupt.  */
52 cdbdb648 pbrook
53 cdbdb648 pbrook
static void arm_timer_update(arm_timer_state *s, int64_t now)
54 cdbdb648 pbrook
{
55 cdbdb648 pbrook
    int64_t next;
56 cdbdb648 pbrook
57 cdbdb648 pbrook
    /* Ignore disabled timers.  */
58 cdbdb648 pbrook
    if ((s->control & TIMER_CTRL_ENABLE) == 0)
59 cdbdb648 pbrook
        return;
60 cdbdb648 pbrook
    /* Ignore expired one-shot timers.  */
61 cdbdb648 pbrook
    if (s->count == 0 && (s->control & TIMER_CTRL_ONESHOT))
62 cdbdb648 pbrook
        return;
63 cdbdb648 pbrook
    if (s->expires - now <= 0) {
64 cdbdb648 pbrook
        /* Timer has expired.  */
65 cdbdb648 pbrook
        s->int_level = 1;
66 cdbdb648 pbrook
        if (s->control & TIMER_CTRL_ONESHOT) {
67 cdbdb648 pbrook
            /* One-shot.  */
68 cdbdb648 pbrook
            s->count = 0;
69 cdbdb648 pbrook
        } else {
70 cdbdb648 pbrook
            if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
71 cdbdb648 pbrook
                /* Free running.  */
72 cdbdb648 pbrook
                if (s->control & TIMER_CTRL_32BIT)
73 cdbdb648 pbrook
                    s->count = 0xffffffff;
74 cdbdb648 pbrook
                else
75 cdbdb648 pbrook
                    s->count = 0xffff;
76 cdbdb648 pbrook
            } else {
77 cdbdb648 pbrook
                  /* Periodic.  */
78 cdbdb648 pbrook
                  s->count = s->limit;
79 cdbdb648 pbrook
            }
80 cdbdb648 pbrook
        }
81 cdbdb648 pbrook
    }
82 cdbdb648 pbrook
    while (s->expires - now <= 0) {
83 cdbdb648 pbrook
        arm_timer_reload(s);
84 cdbdb648 pbrook
    }
85 cdbdb648 pbrook
    /* Update interrupts.  */
86 cdbdb648 pbrook
    if (s->int_level && (s->control & TIMER_CTRL_IE)) {
87 d537cf6c pbrook
        qemu_irq_raise(s->irq);
88 cdbdb648 pbrook
    } else {
89 d537cf6c pbrook
        qemu_irq_lower(s->irq);
90 cdbdb648 pbrook
    }
91 cdbdb648 pbrook
92 cdbdb648 pbrook
    next = now;
93 cdbdb648 pbrook
    if (next - s->expires < 0)
94 cdbdb648 pbrook
        next = s->expires;
95 cdbdb648 pbrook
96 cdbdb648 pbrook
    /* Schedule the next timer interrupt.  */
97 cdbdb648 pbrook
    if (next == now) {
98 cdbdb648 pbrook
        qemu_del_timer(s->timer);
99 cdbdb648 pbrook
        s->next_time = 0;
100 cdbdb648 pbrook
    } else if (next != s->next_time) {
101 cdbdb648 pbrook
        qemu_mod_timer(s->timer, next);
102 cdbdb648 pbrook
        s->next_time = next;
103 cdbdb648 pbrook
    }
104 cdbdb648 pbrook
}
105 cdbdb648 pbrook
106 cdbdb648 pbrook
/* Return the current value of the timer.  */
107 cdbdb648 pbrook
static uint32_t arm_timer_getcount(arm_timer_state *s, int64_t now)
108 cdbdb648 pbrook
{
109 ec2db7de pbrook
    int64_t left;
110 cdbdb648 pbrook
    int64_t period;
111 cdbdb648 pbrook
112 cdbdb648 pbrook
    if (s->count == 0)
113 cdbdb648 pbrook
        return 0;
114 cdbdb648 pbrook
    if ((s->control & TIMER_CTRL_ENABLE) == 0)
115 cdbdb648 pbrook
        return s->count;
116 ec2db7de pbrook
    left = s->expires - now;
117 cdbdb648 pbrook
    period = s->expires - s->loaded;
118 cdbdb648 pbrook
    /* If the timer should have expired then return 0.  This can happen
119 cdbdb648 pbrook
       when the host timer signal doesnt occur immediately.  It's better to
120 cdbdb648 pbrook
       have a timer appear to sit at zero for a while than have it wrap
121 cdbdb648 pbrook
       around before the guest interrupt is raised.  */
122 cdbdb648 pbrook
    /* ??? Could we trigger the interrupt here?  */
123 ec2db7de pbrook
    if (left < 0)
124 cdbdb648 pbrook
        return 0;
125 cdbdb648 pbrook
    /* We need to calculate count * elapsed / period without overfowing.
126 cdbdb648 pbrook
       Scale both elapsed and period so they fit in a 32-bit int.  */
127 cdbdb648 pbrook
    while (period != (int32_t)period) {
128 cdbdb648 pbrook
        period >>= 1;
129 ec2db7de pbrook
        left >>= 1;
130 cdbdb648 pbrook
    }
131 ec2db7de pbrook
    return ((uint64_t)s->count * (uint64_t)(int32_t)left)
132 cdbdb648 pbrook
            / (int32_t)period;
133 cdbdb648 pbrook
}
134 cdbdb648 pbrook
135 cdbdb648 pbrook
uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset)
136 cdbdb648 pbrook
{
137 cdbdb648 pbrook
    arm_timer_state *s = (arm_timer_state *)opaque;
138 cdbdb648 pbrook
139 cdbdb648 pbrook
    switch (offset >> 2) {
140 cdbdb648 pbrook
    case 0: /* TimerLoad */
141 cdbdb648 pbrook
    case 6: /* TimerBGLoad */
142 cdbdb648 pbrook
        return s->limit;
143 cdbdb648 pbrook
    case 1: /* TimerValue */
144 cdbdb648 pbrook
        return arm_timer_getcount(s, qemu_get_clock(vm_clock));
145 cdbdb648 pbrook
    case 2: /* TimerControl */
146 cdbdb648 pbrook
        return s->control;
147 cdbdb648 pbrook
    case 4: /* TimerRIS */
148 cdbdb648 pbrook
        return s->int_level;
149 cdbdb648 pbrook
    case 5: /* TimerMIS */
150 cdbdb648 pbrook
        if ((s->control & TIMER_CTRL_IE) == 0)
151 cdbdb648 pbrook
            return 0;
152 cdbdb648 pbrook
        return s->int_level;
153 cdbdb648 pbrook
    default:
154 cdbdb648 pbrook
        cpu_abort (cpu_single_env, "arm_timer_read: Bad offset %x\n", offset);
155 cdbdb648 pbrook
        return 0;
156 cdbdb648 pbrook
    }
157 cdbdb648 pbrook
}
158 cdbdb648 pbrook
159 cdbdb648 pbrook
static void arm_timer_write(void *opaque, target_phys_addr_t offset,
160 cdbdb648 pbrook
                            uint32_t value)
161 cdbdb648 pbrook
{
162 cdbdb648 pbrook
    arm_timer_state *s = (arm_timer_state *)opaque;
163 cdbdb648 pbrook
    int64_t now;
164 cdbdb648 pbrook
165 cdbdb648 pbrook
    now = qemu_get_clock(vm_clock);
166 cdbdb648 pbrook
    switch (offset >> 2) {
167 cdbdb648 pbrook
    case 0: /* TimerLoad */
168 cdbdb648 pbrook
        s->limit = value;
169 cdbdb648 pbrook
        s->count = value;
170 cdbdb648 pbrook
        s->expires = now;
171 cdbdb648 pbrook
        arm_timer_reload(s);
172 cdbdb648 pbrook
        break;
173 cdbdb648 pbrook
    case 1: /* TimerValue */
174 cdbdb648 pbrook
        /* ??? Linux seems to want to write to this readonly register.
175 cdbdb648 pbrook
           Ignore it.  */
176 cdbdb648 pbrook
        break;
177 cdbdb648 pbrook
    case 2: /* TimerControl */
178 cdbdb648 pbrook
        if (s->control & TIMER_CTRL_ENABLE) {
179 cdbdb648 pbrook
            /* Pause the timer if it is running.  This may cause some
180 cdbdb648 pbrook
               inaccuracy dure to rounding, but avoids a whole lot of other
181 cdbdb648 pbrook
               messyness.  */
182 cdbdb648 pbrook
            s->count = arm_timer_getcount(s, now);
183 cdbdb648 pbrook
        }
184 cdbdb648 pbrook
        s->control = value;
185 cdbdb648 pbrook
        s->freq = s->raw_freq;
186 cdbdb648 pbrook
        /* ??? Need to recalculate expiry time after changing divisor.  */
187 cdbdb648 pbrook
        switch ((value >> 2) & 3) {
188 cdbdb648 pbrook
        case 1: s->freq >>= 4; break;
189 cdbdb648 pbrook
        case 2: s->freq >>= 8; break;
190 cdbdb648 pbrook
        }
191 cdbdb648 pbrook
        if (s->control & TIMER_CTRL_ENABLE) {
192 cdbdb648 pbrook
            /* Restart the timer if still enabled.  */
193 cdbdb648 pbrook
            s->expires = now;
194 cdbdb648 pbrook
            arm_timer_reload(s);
195 cdbdb648 pbrook
        }
196 cdbdb648 pbrook
        break;
197 cdbdb648 pbrook
    case 3: /* TimerIntClr */
198 cdbdb648 pbrook
        s->int_level = 0;
199 cdbdb648 pbrook
        break;
200 cdbdb648 pbrook
    case 6: /* TimerBGLoad */
201 cdbdb648 pbrook
        s->limit = value;
202 cdbdb648 pbrook
        break;
203 cdbdb648 pbrook
    default:
204 cdbdb648 pbrook
        cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n", offset);
205 cdbdb648 pbrook
    }
206 cdbdb648 pbrook
    arm_timer_update(s, now);
207 cdbdb648 pbrook
}
208 cdbdb648 pbrook
209 cdbdb648 pbrook
static void arm_timer_tick(void *opaque)
210 cdbdb648 pbrook
{
211 cdbdb648 pbrook
    int64_t now;
212 cdbdb648 pbrook
213 cdbdb648 pbrook
    now = qemu_get_clock(vm_clock);
214 cdbdb648 pbrook
    arm_timer_update((arm_timer_state *)opaque, now);
215 cdbdb648 pbrook
}
216 cdbdb648 pbrook
217 d537cf6c pbrook
static void *arm_timer_init(uint32_t freq, qemu_irq irq)
218 cdbdb648 pbrook
{
219 cdbdb648 pbrook
    arm_timer_state *s;
220 cdbdb648 pbrook
221 cdbdb648 pbrook
    s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
222 cdbdb648 pbrook
    s->irq = irq;
223 cdbdb648 pbrook
    s->raw_freq = s->freq = 1000000;
224 cdbdb648 pbrook
    s->control = TIMER_CTRL_IE;
225 cdbdb648 pbrook
    s->count = 0xffffffff;
226 cdbdb648 pbrook
227 cdbdb648 pbrook
    s->timer = qemu_new_timer(vm_clock, arm_timer_tick, s);
228 cdbdb648 pbrook
    /* ??? Save/restore.  */
229 cdbdb648 pbrook
    return s;
230 cdbdb648 pbrook
}
231 cdbdb648 pbrook
232 cdbdb648 pbrook
/* ARM PrimeCell SP804 dual timer module.
233 cdbdb648 pbrook
   Docs for this device don't seem to be publicly available.  This
234 d85fb99b pbrook
   implementation is based on guesswork, the linux kernel sources and the
235 cdbdb648 pbrook
   Integrator/CP timer modules.  */
236 cdbdb648 pbrook
237 cdbdb648 pbrook
typedef struct {
238 cdbdb648 pbrook
    void *timer[2];
239 cdbdb648 pbrook
    int level[2];
240 cdbdb648 pbrook
    uint32_t base;
241 d537cf6c pbrook
    qemu_irq irq;
242 cdbdb648 pbrook
} sp804_state;
243 cdbdb648 pbrook
244 d537cf6c pbrook
/* Merge the IRQs from the two component devices.  */
245 cdbdb648 pbrook
static void sp804_set_irq(void *opaque, int irq, int level)
246 cdbdb648 pbrook
{
247 cdbdb648 pbrook
    sp804_state *s = (sp804_state *)opaque;
248 cdbdb648 pbrook
249 cdbdb648 pbrook
    s->level[irq] = level;
250 d537cf6c pbrook
    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
251 cdbdb648 pbrook
}
252 cdbdb648 pbrook
253 cdbdb648 pbrook
static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
254 cdbdb648 pbrook
{
255 cdbdb648 pbrook
    sp804_state *s = (sp804_state *)opaque;
256 cdbdb648 pbrook
257 cdbdb648 pbrook
    /* ??? Don't know the PrimeCell ID for this device.  */
258 cdbdb648 pbrook
    offset -= s->base;
259 cdbdb648 pbrook
    if (offset < 0x20) {
260 cdbdb648 pbrook
        return arm_timer_read(s->timer[0], offset);
261 cdbdb648 pbrook
    } else {
262 cdbdb648 pbrook
        return arm_timer_read(s->timer[1], offset - 0x20);
263 cdbdb648 pbrook
    }
264 cdbdb648 pbrook
}
265 cdbdb648 pbrook
266 cdbdb648 pbrook
static void sp804_write(void *opaque, target_phys_addr_t offset,
267 cdbdb648 pbrook
                        uint32_t value)
268 cdbdb648 pbrook
{
269 cdbdb648 pbrook
    sp804_state *s = (sp804_state *)opaque;
270 cdbdb648 pbrook
271 cdbdb648 pbrook
    offset -= s->base;
272 cdbdb648 pbrook
    if (offset < 0x20) {
273 cdbdb648 pbrook
        arm_timer_write(s->timer[0], offset, value);
274 cdbdb648 pbrook
    } else {
275 cdbdb648 pbrook
        arm_timer_write(s->timer[1], offset - 0x20, value);
276 cdbdb648 pbrook
    }
277 cdbdb648 pbrook
}
278 cdbdb648 pbrook
279 cdbdb648 pbrook
static CPUReadMemoryFunc *sp804_readfn[] = {
280 cdbdb648 pbrook
   sp804_read,
281 cdbdb648 pbrook
   sp804_read,
282 cdbdb648 pbrook
   sp804_read
283 cdbdb648 pbrook
};
284 cdbdb648 pbrook
285 cdbdb648 pbrook
static CPUWriteMemoryFunc *sp804_writefn[] = {
286 cdbdb648 pbrook
   sp804_write,
287 cdbdb648 pbrook
   sp804_write,
288 cdbdb648 pbrook
   sp804_write
289 cdbdb648 pbrook
};
290 cdbdb648 pbrook
291 d537cf6c pbrook
void sp804_init(uint32_t base, qemu_irq irq)
292 cdbdb648 pbrook
{
293 cdbdb648 pbrook
    int iomemtype;
294 cdbdb648 pbrook
    sp804_state *s;
295 d537cf6c pbrook
    qemu_irq *qi;
296 cdbdb648 pbrook
297 cdbdb648 pbrook
    s = (sp804_state *)qemu_mallocz(sizeof(sp804_state));
298 d537cf6c pbrook
    qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
299 cdbdb648 pbrook
    s->base = base;
300 cdbdb648 pbrook
    s->irq = irq;
301 cdbdb648 pbrook
    /* ??? The timers are actually configurable between 32kHz and 1MHz, but
302 cdbdb648 pbrook
       we don't implement that.  */
303 d537cf6c pbrook
    s->timer[0] = arm_timer_init(1000000, qi[0]);
304 d537cf6c pbrook
    s->timer[1] = arm_timer_init(1000000, qi[1]);
305 cdbdb648 pbrook
    iomemtype = cpu_register_io_memory(0, sp804_readfn,
306 cdbdb648 pbrook
                                       sp804_writefn, s);
307 cdbdb648 pbrook
    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
308 cdbdb648 pbrook
    /* ??? Save/restore.  */
309 cdbdb648 pbrook
}
310 cdbdb648 pbrook
311 cdbdb648 pbrook
312 cdbdb648 pbrook
/* Integrator/CP timer module.  */
313 cdbdb648 pbrook
314 cdbdb648 pbrook
typedef struct {
315 cdbdb648 pbrook
    void *timer[3];
316 cdbdb648 pbrook
    uint32_t base;
317 cdbdb648 pbrook
} icp_pit_state;
318 cdbdb648 pbrook
319 cdbdb648 pbrook
static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
320 cdbdb648 pbrook
{
321 cdbdb648 pbrook
    icp_pit_state *s = (icp_pit_state *)opaque;
322 cdbdb648 pbrook
    int n;
323 cdbdb648 pbrook
324 cdbdb648 pbrook
    /* ??? Don't know the PrimeCell ID for this device.  */
325 cdbdb648 pbrook
    offset -= s->base;
326 cdbdb648 pbrook
    n = offset >> 8;
327 cdbdb648 pbrook
    if (n > 3)
328 cdbdb648 pbrook
        cpu_abort(cpu_single_env, "sp804_read: Bad timer %d\n", n);
329 cdbdb648 pbrook
330 cdbdb648 pbrook
    return arm_timer_read(s->timer[n], offset & 0xff);
331 cdbdb648 pbrook
}
332 cdbdb648 pbrook
333 cdbdb648 pbrook
static void icp_pit_write(void *opaque, target_phys_addr_t offset,
334 cdbdb648 pbrook
                          uint32_t value)
335 cdbdb648 pbrook
{
336 cdbdb648 pbrook
    icp_pit_state *s = (icp_pit_state *)opaque;
337 cdbdb648 pbrook
    int n;
338 cdbdb648 pbrook
339 cdbdb648 pbrook
    offset -= s->base;
340 cdbdb648 pbrook
    n = offset >> 8;
341 cdbdb648 pbrook
    if (n > 3)
342 cdbdb648 pbrook
        cpu_abort(cpu_single_env, "sp804_write: Bad timer %d\n", n);
343 cdbdb648 pbrook
344 cdbdb648 pbrook
    arm_timer_write(s->timer[n], offset & 0xff, value);
345 cdbdb648 pbrook
}
346 cdbdb648 pbrook
347 cdbdb648 pbrook
348 cdbdb648 pbrook
static CPUReadMemoryFunc *icp_pit_readfn[] = {
349 cdbdb648 pbrook
   icp_pit_read,
350 cdbdb648 pbrook
   icp_pit_read,
351 cdbdb648 pbrook
   icp_pit_read
352 cdbdb648 pbrook
};
353 cdbdb648 pbrook
354 cdbdb648 pbrook
static CPUWriteMemoryFunc *icp_pit_writefn[] = {
355 cdbdb648 pbrook
   icp_pit_write,
356 cdbdb648 pbrook
   icp_pit_write,
357 cdbdb648 pbrook
   icp_pit_write
358 cdbdb648 pbrook
};
359 cdbdb648 pbrook
360 d537cf6c pbrook
void icp_pit_init(uint32_t base, qemu_irq *pic, int irq)
361 cdbdb648 pbrook
{
362 cdbdb648 pbrook
    int iomemtype;
363 cdbdb648 pbrook
    icp_pit_state *s;
364 cdbdb648 pbrook
365 cdbdb648 pbrook
    s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state));
366 cdbdb648 pbrook
    s->base = base;
367 cdbdb648 pbrook
    /* Timer 0 runs at the system clock speed (40MHz).  */
368 d537cf6c pbrook
    s->timer[0] = arm_timer_init(40000000, pic[irq]);
369 cdbdb648 pbrook
    /* The other two timers run at 1MHz.  */
370 d537cf6c pbrook
    s->timer[1] = arm_timer_init(1000000, pic[irq + 1]);
371 d537cf6c pbrook
    s->timer[2] = arm_timer_init(1000000, pic[irq + 2]);
372 cdbdb648 pbrook
373 cdbdb648 pbrook
    iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
374 cdbdb648 pbrook
                                       icp_pit_writefn, s);
375 cdbdb648 pbrook
    cpu_register_physical_memory(base, 0x00000fff, iomemtype);
376 cdbdb648 pbrook
    /* ??? Save/restore.  */
377 cdbdb648 pbrook
}