Statistics
| Branch: | Revision:

root / hw / arm_timer.c @ 5fafdf24

History | View | Annotate | Download (7.9 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 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 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 cdbdb648 pbrook
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 423f0742 pbrook
        cpu_abort (cpu_single_env, "arm_timer_read: Bad offset %x\n",
65 423f0742 pbrook
                   (int)offset);
66 cdbdb648 pbrook
        return 0;
67 cdbdb648 pbrook
    }
68 cdbdb648 pbrook
}
69 cdbdb648 pbrook
70 423f0742 pbrook
/* Reset the timer limit after settings have changed.  */
71 423f0742 pbrook
static void arm_timer_recalibrate(arm_timer_state *s, int reload)
72 423f0742 pbrook
{
73 423f0742 pbrook
    uint32_t limit;
74 423f0742 pbrook
75 423f0742 pbrook
    if ((s->control & TIMER_CTRL_PERIODIC) == 0) {
76 423f0742 pbrook
        /* Free running.  */
77 423f0742 pbrook
        if (s->control & TIMER_CTRL_32BIT)
78 423f0742 pbrook
            limit = 0xffffffff;
79 423f0742 pbrook
        else
80 423f0742 pbrook
            limit = 0xffff;
81 423f0742 pbrook
    } else {
82 423f0742 pbrook
          /* Periodic.  */
83 423f0742 pbrook
          limit = s->limit;
84 423f0742 pbrook
    }
85 423f0742 pbrook
    ptimer_set_limit(s->timer, limit, reload);
86 423f0742 pbrook
}
87 423f0742 pbrook
88 cdbdb648 pbrook
static void arm_timer_write(void *opaque, target_phys_addr_t offset,
89 cdbdb648 pbrook
                            uint32_t value)
90 cdbdb648 pbrook
{
91 cdbdb648 pbrook
    arm_timer_state *s = (arm_timer_state *)opaque;
92 423f0742 pbrook
    int freq;
93 cdbdb648 pbrook
94 cdbdb648 pbrook
    switch (offset >> 2) {
95 cdbdb648 pbrook
    case 0: /* TimerLoad */
96 cdbdb648 pbrook
        s->limit = value;
97 423f0742 pbrook
        arm_timer_recalibrate(s, 1);
98 cdbdb648 pbrook
        break;
99 cdbdb648 pbrook
    case 1: /* TimerValue */
100 cdbdb648 pbrook
        /* ??? Linux seems to want to write to this readonly register.
101 cdbdb648 pbrook
           Ignore it.  */
102 cdbdb648 pbrook
        break;
103 cdbdb648 pbrook
    case 2: /* TimerControl */
104 cdbdb648 pbrook
        if (s->control & TIMER_CTRL_ENABLE) {
105 cdbdb648 pbrook
            /* Pause the timer if it is running.  This may cause some
106 cdbdb648 pbrook
               inaccuracy dure to rounding, but avoids a whole lot of other
107 cdbdb648 pbrook
               messyness.  */
108 423f0742 pbrook
            ptimer_stop(s->timer);
109 cdbdb648 pbrook
        }
110 cdbdb648 pbrook
        s->control = value;
111 423f0742 pbrook
        freq = s->freq;
112 cdbdb648 pbrook
        /* ??? Need to recalculate expiry time after changing divisor.  */
113 cdbdb648 pbrook
        switch ((value >> 2) & 3) {
114 423f0742 pbrook
        case 1: freq >>= 4; break;
115 423f0742 pbrook
        case 2: freq >>= 8; break;
116 cdbdb648 pbrook
        }
117 423f0742 pbrook
        arm_timer_recalibrate(s, 0);
118 423f0742 pbrook
        ptimer_set_freq(s->timer, freq);
119 cdbdb648 pbrook
        if (s->control & TIMER_CTRL_ENABLE) {
120 cdbdb648 pbrook
            /* Restart the timer if still enabled.  */
121 423f0742 pbrook
            ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
122 cdbdb648 pbrook
        }
123 cdbdb648 pbrook
        break;
124 cdbdb648 pbrook
    case 3: /* TimerIntClr */
125 cdbdb648 pbrook
        s->int_level = 0;
126 cdbdb648 pbrook
        break;
127 cdbdb648 pbrook
    case 6: /* TimerBGLoad */
128 cdbdb648 pbrook
        s->limit = value;
129 423f0742 pbrook
        arm_timer_recalibrate(s, 0);
130 cdbdb648 pbrook
        break;
131 cdbdb648 pbrook
    default:
132 423f0742 pbrook
        cpu_abort (cpu_single_env, "arm_timer_write: Bad offset %x\n",
133 423f0742 pbrook
                   (int)offset);
134 cdbdb648 pbrook
    }
135 423f0742 pbrook
    arm_timer_update(s);
136 cdbdb648 pbrook
}
137 cdbdb648 pbrook
138 cdbdb648 pbrook
static void arm_timer_tick(void *opaque)
139 cdbdb648 pbrook
{
140 423f0742 pbrook
    arm_timer_state *s = (arm_timer_state *)opaque;
141 423f0742 pbrook
    s->int_level = 1;
142 423f0742 pbrook
    arm_timer_update(s);
143 cdbdb648 pbrook
}
144 cdbdb648 pbrook
145 d537cf6c pbrook
static void *arm_timer_init(uint32_t freq, qemu_irq irq)
146 cdbdb648 pbrook
{
147 cdbdb648 pbrook
    arm_timer_state *s;
148 423f0742 pbrook
    QEMUBH *bh;
149 cdbdb648 pbrook
150 cdbdb648 pbrook
    s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
151 cdbdb648 pbrook
    s->irq = irq;
152 423f0742 pbrook
    s->freq = freq;
153 cdbdb648 pbrook
    s->control = TIMER_CTRL_IE;
154 cdbdb648 pbrook
155 423f0742 pbrook
    bh = qemu_bh_new(arm_timer_tick, s);
156 423f0742 pbrook
    s->timer = ptimer_init(bh);
157 cdbdb648 pbrook
    /* ??? Save/restore.  */
158 cdbdb648 pbrook
    return s;
159 cdbdb648 pbrook
}
160 cdbdb648 pbrook
161 cdbdb648 pbrook
/* ARM PrimeCell SP804 dual timer module.
162 cdbdb648 pbrook
   Docs for this device don't seem to be publicly available.  This
163 d85fb99b pbrook
   implementation is based on guesswork, the linux kernel sources and the
164 cdbdb648 pbrook
   Integrator/CP timer modules.  */
165 cdbdb648 pbrook
166 cdbdb648 pbrook
typedef struct {
167 cdbdb648 pbrook
    void *timer[2];
168 cdbdb648 pbrook
    int level[2];
169 cdbdb648 pbrook
    uint32_t base;
170 d537cf6c pbrook
    qemu_irq irq;
171 cdbdb648 pbrook
} sp804_state;
172 cdbdb648 pbrook
173 d537cf6c pbrook
/* Merge the IRQs from the two component devices.  */
174 cdbdb648 pbrook
static void sp804_set_irq(void *opaque, int irq, int level)
175 cdbdb648 pbrook
{
176 cdbdb648 pbrook
    sp804_state *s = (sp804_state *)opaque;
177 cdbdb648 pbrook
178 cdbdb648 pbrook
    s->level[irq] = level;
179 d537cf6c pbrook
    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
180 cdbdb648 pbrook
}
181 cdbdb648 pbrook
182 cdbdb648 pbrook
static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
183 cdbdb648 pbrook
{
184 cdbdb648 pbrook
    sp804_state *s = (sp804_state *)opaque;
185 cdbdb648 pbrook
186 cdbdb648 pbrook
    /* ??? Don't know the PrimeCell ID for this device.  */
187 cdbdb648 pbrook
    offset -= s->base;
188 cdbdb648 pbrook
    if (offset < 0x20) {
189 cdbdb648 pbrook
        return arm_timer_read(s->timer[0], offset);
190 cdbdb648 pbrook
    } else {
191 cdbdb648 pbrook
        return arm_timer_read(s->timer[1], offset - 0x20);
192 cdbdb648 pbrook
    }
193 cdbdb648 pbrook
}
194 cdbdb648 pbrook
195 cdbdb648 pbrook
static void sp804_write(void *opaque, target_phys_addr_t offset,
196 cdbdb648 pbrook
                        uint32_t value)
197 cdbdb648 pbrook
{
198 cdbdb648 pbrook
    sp804_state *s = (sp804_state *)opaque;
199 cdbdb648 pbrook
200 cdbdb648 pbrook
    offset -= s->base;
201 cdbdb648 pbrook
    if (offset < 0x20) {
202 cdbdb648 pbrook
        arm_timer_write(s->timer[0], offset, value);
203 cdbdb648 pbrook
    } else {
204 cdbdb648 pbrook
        arm_timer_write(s->timer[1], offset - 0x20, value);
205 cdbdb648 pbrook
    }
206 cdbdb648 pbrook
}
207 cdbdb648 pbrook
208 cdbdb648 pbrook
static CPUReadMemoryFunc *sp804_readfn[] = {
209 cdbdb648 pbrook
   sp804_read,
210 cdbdb648 pbrook
   sp804_read,
211 cdbdb648 pbrook
   sp804_read
212 cdbdb648 pbrook
};
213 cdbdb648 pbrook
214 cdbdb648 pbrook
static CPUWriteMemoryFunc *sp804_writefn[] = {
215 cdbdb648 pbrook
   sp804_write,
216 cdbdb648 pbrook
   sp804_write,
217 cdbdb648 pbrook
   sp804_write
218 cdbdb648 pbrook
};
219 cdbdb648 pbrook
220 d537cf6c pbrook
void sp804_init(uint32_t base, qemu_irq irq)
221 cdbdb648 pbrook
{
222 cdbdb648 pbrook
    int iomemtype;
223 cdbdb648 pbrook
    sp804_state *s;
224 d537cf6c pbrook
    qemu_irq *qi;
225 cdbdb648 pbrook
226 cdbdb648 pbrook
    s = (sp804_state *)qemu_mallocz(sizeof(sp804_state));
227 d537cf6c pbrook
    qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
228 cdbdb648 pbrook
    s->base = base;
229 cdbdb648 pbrook
    s->irq = irq;
230 cdbdb648 pbrook
    /* ??? The timers are actually configurable between 32kHz and 1MHz, but
231 cdbdb648 pbrook
       we don't implement that.  */
232 d537cf6c pbrook
    s->timer[0] = arm_timer_init(1000000, qi[0]);
233 d537cf6c pbrook
    s->timer[1] = arm_timer_init(1000000, qi[1]);
234 cdbdb648 pbrook
    iomemtype = cpu_register_io_memory(0, sp804_readfn,
235 cdbdb648 pbrook
                                       sp804_writefn, s);
236 187337f8 pbrook
    cpu_register_physical_memory(base, 0x00001000, iomemtype);
237 cdbdb648 pbrook
    /* ??? Save/restore.  */
238 cdbdb648 pbrook
}
239 cdbdb648 pbrook
240 cdbdb648 pbrook
241 cdbdb648 pbrook
/* Integrator/CP timer module.  */
242 cdbdb648 pbrook
243 cdbdb648 pbrook
typedef struct {
244 cdbdb648 pbrook
    void *timer[3];
245 cdbdb648 pbrook
    uint32_t base;
246 cdbdb648 pbrook
} icp_pit_state;
247 cdbdb648 pbrook
248 cdbdb648 pbrook
static uint32_t icp_pit_read(void *opaque, target_phys_addr_t offset)
249 cdbdb648 pbrook
{
250 cdbdb648 pbrook
    icp_pit_state *s = (icp_pit_state *)opaque;
251 cdbdb648 pbrook
    int n;
252 cdbdb648 pbrook
253 cdbdb648 pbrook
    /* ??? Don't know the PrimeCell ID for this device.  */
254 cdbdb648 pbrook
    offset -= s->base;
255 cdbdb648 pbrook
    n = offset >> 8;
256 cdbdb648 pbrook
    if (n > 3)
257 cdbdb648 pbrook
        cpu_abort(cpu_single_env, "sp804_read: Bad timer %d\n", n);
258 cdbdb648 pbrook
259 cdbdb648 pbrook
    return arm_timer_read(s->timer[n], offset & 0xff);
260 cdbdb648 pbrook
}
261 cdbdb648 pbrook
262 cdbdb648 pbrook
static void icp_pit_write(void *opaque, target_phys_addr_t offset,
263 cdbdb648 pbrook
                          uint32_t value)
264 cdbdb648 pbrook
{
265 cdbdb648 pbrook
    icp_pit_state *s = (icp_pit_state *)opaque;
266 cdbdb648 pbrook
    int n;
267 cdbdb648 pbrook
268 cdbdb648 pbrook
    offset -= s->base;
269 cdbdb648 pbrook
    n = offset >> 8;
270 cdbdb648 pbrook
    if (n > 3)
271 cdbdb648 pbrook
        cpu_abort(cpu_single_env, "sp804_write: Bad timer %d\n", n);
272 cdbdb648 pbrook
273 cdbdb648 pbrook
    arm_timer_write(s->timer[n], offset & 0xff, value);
274 cdbdb648 pbrook
}
275 cdbdb648 pbrook
276 cdbdb648 pbrook
277 cdbdb648 pbrook
static CPUReadMemoryFunc *icp_pit_readfn[] = {
278 cdbdb648 pbrook
   icp_pit_read,
279 cdbdb648 pbrook
   icp_pit_read,
280 cdbdb648 pbrook
   icp_pit_read
281 cdbdb648 pbrook
};
282 cdbdb648 pbrook
283 cdbdb648 pbrook
static CPUWriteMemoryFunc *icp_pit_writefn[] = {
284 cdbdb648 pbrook
   icp_pit_write,
285 cdbdb648 pbrook
   icp_pit_write,
286 cdbdb648 pbrook
   icp_pit_write
287 cdbdb648 pbrook
};
288 cdbdb648 pbrook
289 d537cf6c pbrook
void icp_pit_init(uint32_t base, qemu_irq *pic, int irq)
290 cdbdb648 pbrook
{
291 cdbdb648 pbrook
    int iomemtype;
292 cdbdb648 pbrook
    icp_pit_state *s;
293 cdbdb648 pbrook
294 cdbdb648 pbrook
    s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state));
295 cdbdb648 pbrook
    s->base = base;
296 cdbdb648 pbrook
    /* Timer 0 runs at the system clock speed (40MHz).  */
297 d537cf6c pbrook
    s->timer[0] = arm_timer_init(40000000, pic[irq]);
298 cdbdb648 pbrook
    /* The other two timers run at 1MHz.  */
299 d537cf6c pbrook
    s->timer[1] = arm_timer_init(1000000, pic[irq + 1]);
300 d537cf6c pbrook
    s->timer[2] = arm_timer_init(1000000, pic[irq + 2]);
301 cdbdb648 pbrook
302 cdbdb648 pbrook
    iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
303 cdbdb648 pbrook
                                       icp_pit_writefn, s);
304 187337f8 pbrook
    cpu_register_physical_memory(base, 0x00001000, iomemtype);
305 cdbdb648 pbrook
    /* ??? Save/restore.  */
306 cdbdb648 pbrook
}