Statistics
| Branch: | Revision:

root / hw / arm_timer.c @ 0986ac3b

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