Statistics
| Branch: | Revision:

root / hw / arm_timer.c @ f5654039

History | View | Annotate | Download (8.8 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 8e31bf38 Matthew Fernandez
 * This code is licensed 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 eecd33a5 Juan Quintela
static const VMStateDescription vmstate_arm_timer = {
144 eecd33a5 Juan Quintela
    .name = "arm_timer",
145 eecd33a5 Juan Quintela
    .version_id = 1,
146 eecd33a5 Juan Quintela
    .minimum_version_id = 1,
147 eecd33a5 Juan Quintela
    .minimum_version_id_old = 1,
148 eecd33a5 Juan Quintela
    .fields      = (VMStateField[]) {
149 eecd33a5 Juan Quintela
        VMSTATE_UINT32(control, arm_timer_state),
150 eecd33a5 Juan Quintela
        VMSTATE_UINT32(limit, arm_timer_state),
151 eecd33a5 Juan Quintela
        VMSTATE_INT32(int_level, arm_timer_state),
152 eecd33a5 Juan Quintela
        VMSTATE_PTIMER(timer, arm_timer_state),
153 eecd33a5 Juan Quintela
        VMSTATE_END_OF_LIST()
154 eecd33a5 Juan Quintela
    }
155 eecd33a5 Juan Quintela
};
156 23e39294 pbrook
157 6a824ec3 Paul Brook
static arm_timer_state *arm_timer_init(uint32_t freq)
158 cdbdb648 pbrook
{
159 cdbdb648 pbrook
    arm_timer_state *s;
160 423f0742 pbrook
    QEMUBH *bh;
161 cdbdb648 pbrook
162 7267c094 Anthony Liguori
    s = (arm_timer_state *)g_malloc0(sizeof(arm_timer_state));
163 423f0742 pbrook
    s->freq = freq;
164 cdbdb648 pbrook
    s->control = TIMER_CTRL_IE;
165 cdbdb648 pbrook
166 423f0742 pbrook
    bh = qemu_bh_new(arm_timer_tick, s);
167 423f0742 pbrook
    s->timer = ptimer_init(bh);
168 eecd33a5 Juan Quintela
    vmstate_register(NULL, -1, &vmstate_arm_timer, s);
169 cdbdb648 pbrook
    return s;
170 cdbdb648 pbrook
}
171 cdbdb648 pbrook
172 cdbdb648 pbrook
/* ARM PrimeCell SP804 dual timer module.
173 cdbdb648 pbrook
   Docs for this device don't seem to be publicly available.  This
174 d85fb99b pbrook
   implementation is based on guesswork, the linux kernel sources and the
175 cdbdb648 pbrook
   Integrator/CP timer modules.  */
176 cdbdb648 pbrook
177 cdbdb648 pbrook
typedef struct {
178 6a824ec3 Paul Brook
    SysBusDevice busdev;
179 e219dea2 Avi Kivity
    MemoryRegion iomem;
180 6a824ec3 Paul Brook
    arm_timer_state *timer[2];
181 cdbdb648 pbrook
    int level[2];
182 d537cf6c pbrook
    qemu_irq irq;
183 cdbdb648 pbrook
} sp804_state;
184 cdbdb648 pbrook
185 d537cf6c pbrook
/* Merge the IRQs from the two component devices.  */
186 cdbdb648 pbrook
static void sp804_set_irq(void *opaque, int irq, int level)
187 cdbdb648 pbrook
{
188 cdbdb648 pbrook
    sp804_state *s = (sp804_state *)opaque;
189 cdbdb648 pbrook
190 cdbdb648 pbrook
    s->level[irq] = level;
191 d537cf6c pbrook
    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
192 cdbdb648 pbrook
}
193 cdbdb648 pbrook
194 e219dea2 Avi Kivity
static uint64_t sp804_read(void *opaque, target_phys_addr_t offset,
195 e219dea2 Avi Kivity
                           unsigned size)
196 cdbdb648 pbrook
{
197 cdbdb648 pbrook
    sp804_state *s = (sp804_state *)opaque;
198 cdbdb648 pbrook
199 cdbdb648 pbrook
    /* ??? Don't know the PrimeCell ID for this device.  */
200 cdbdb648 pbrook
    if (offset < 0x20) {
201 cdbdb648 pbrook
        return arm_timer_read(s->timer[0], offset);
202 cdbdb648 pbrook
    } else {
203 cdbdb648 pbrook
        return arm_timer_read(s->timer[1], offset - 0x20);
204 cdbdb648 pbrook
    }
205 cdbdb648 pbrook
}
206 cdbdb648 pbrook
207 c227f099 Anthony Liguori
static void sp804_write(void *opaque, target_phys_addr_t offset,
208 e219dea2 Avi Kivity
                        uint64_t value, unsigned size)
209 cdbdb648 pbrook
{
210 cdbdb648 pbrook
    sp804_state *s = (sp804_state *)opaque;
211 cdbdb648 pbrook
212 cdbdb648 pbrook
    if (offset < 0x20) {
213 cdbdb648 pbrook
        arm_timer_write(s->timer[0], offset, value);
214 cdbdb648 pbrook
    } else {
215 cdbdb648 pbrook
        arm_timer_write(s->timer[1], offset - 0x20, value);
216 cdbdb648 pbrook
    }
217 cdbdb648 pbrook
}
218 cdbdb648 pbrook
219 e219dea2 Avi Kivity
static const MemoryRegionOps sp804_ops = {
220 e219dea2 Avi Kivity
    .read = sp804_read,
221 e219dea2 Avi Kivity
    .write = sp804_write,
222 e219dea2 Avi Kivity
    .endianness = DEVICE_NATIVE_ENDIAN,
223 cdbdb648 pbrook
};
224 cdbdb648 pbrook
225 81986ac4 Juan Quintela
static const VMStateDescription vmstate_sp804 = {
226 81986ac4 Juan Quintela
    .name = "sp804",
227 81986ac4 Juan Quintela
    .version_id = 1,
228 81986ac4 Juan Quintela
    .minimum_version_id = 1,
229 81986ac4 Juan Quintela
    .minimum_version_id_old = 1,
230 81986ac4 Juan Quintela
    .fields      = (VMStateField[]) {
231 81986ac4 Juan Quintela
        VMSTATE_INT32_ARRAY(level, sp804_state, 2),
232 81986ac4 Juan Quintela
        VMSTATE_END_OF_LIST()
233 81986ac4 Juan Quintela
    }
234 81986ac4 Juan Quintela
};
235 23e39294 pbrook
236 81a322d4 Gerd Hoffmann
static int sp804_init(SysBusDevice *dev)
237 cdbdb648 pbrook
{
238 6a824ec3 Paul Brook
    sp804_state *s = FROM_SYSBUS(sp804_state, dev);
239 d537cf6c pbrook
    qemu_irq *qi;
240 cdbdb648 pbrook
241 d537cf6c pbrook
    qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
242 6a824ec3 Paul Brook
    sysbus_init_irq(dev, &s->irq);
243 cdbdb648 pbrook
    /* ??? The timers are actually configurable between 32kHz and 1MHz, but
244 cdbdb648 pbrook
       we don't implement that.  */
245 6a824ec3 Paul Brook
    s->timer[0] = arm_timer_init(1000000);
246 6a824ec3 Paul Brook
    s->timer[1] = arm_timer_init(1000000);
247 6a824ec3 Paul Brook
    s->timer[0]->irq = qi[0];
248 6a824ec3 Paul Brook
    s->timer[1]->irq = qi[1];
249 e219dea2 Avi Kivity
    memory_region_init_io(&s->iomem, &sp804_ops, s, "sp804", 0x1000);
250 e219dea2 Avi Kivity
    sysbus_init_mmio_region(dev, &s->iomem);
251 81986ac4 Juan Quintela
    vmstate_register(&dev->qdev, -1, &vmstate_sp804, s);
252 81a322d4 Gerd Hoffmann
    return 0;
253 cdbdb648 pbrook
}
254 cdbdb648 pbrook
255 cdbdb648 pbrook
256 cdbdb648 pbrook
/* Integrator/CP timer module.  */
257 cdbdb648 pbrook
258 cdbdb648 pbrook
typedef struct {
259 6a824ec3 Paul Brook
    SysBusDevice busdev;
260 e219dea2 Avi Kivity
    MemoryRegion iomem;
261 6a824ec3 Paul Brook
    arm_timer_state *timer[3];
262 cdbdb648 pbrook
} icp_pit_state;
263 cdbdb648 pbrook
264 e219dea2 Avi Kivity
static uint64_t icp_pit_read(void *opaque, target_phys_addr_t offset,
265 e219dea2 Avi Kivity
                             unsigned size)
266 cdbdb648 pbrook
{
267 cdbdb648 pbrook
    icp_pit_state *s = (icp_pit_state *)opaque;
268 cdbdb648 pbrook
    int n;
269 cdbdb648 pbrook
270 cdbdb648 pbrook
    /* ??? Don't know the PrimeCell ID for this device.  */
271 cdbdb648 pbrook
    n = offset >> 8;
272 ee71c984 Peter Maydell
    if (n > 2) {
273 2ac71179 Paul Brook
        hw_error("sp804_read: Bad timer %d\n", n);
274 2ac71179 Paul Brook
    }
275 cdbdb648 pbrook
276 cdbdb648 pbrook
    return arm_timer_read(s->timer[n], offset & 0xff);
277 cdbdb648 pbrook
}
278 cdbdb648 pbrook
279 c227f099 Anthony Liguori
static void icp_pit_write(void *opaque, target_phys_addr_t offset,
280 e219dea2 Avi Kivity
                          uint64_t value, unsigned size)
281 cdbdb648 pbrook
{
282 cdbdb648 pbrook
    icp_pit_state *s = (icp_pit_state *)opaque;
283 cdbdb648 pbrook
    int n;
284 cdbdb648 pbrook
285 cdbdb648 pbrook
    n = offset >> 8;
286 ee71c984 Peter Maydell
    if (n > 2) {
287 2ac71179 Paul Brook
        hw_error("sp804_write: Bad timer %d\n", n);
288 2ac71179 Paul Brook
    }
289 cdbdb648 pbrook
290 cdbdb648 pbrook
    arm_timer_write(s->timer[n], offset & 0xff, value);
291 cdbdb648 pbrook
}
292 cdbdb648 pbrook
293 e219dea2 Avi Kivity
static const MemoryRegionOps icp_pit_ops = {
294 e219dea2 Avi Kivity
    .read = icp_pit_read,
295 e219dea2 Avi Kivity
    .write = icp_pit_write,
296 e219dea2 Avi Kivity
    .endianness = DEVICE_NATIVE_ENDIAN,
297 cdbdb648 pbrook
};
298 cdbdb648 pbrook
299 81a322d4 Gerd Hoffmann
static int icp_pit_init(SysBusDevice *dev)
300 cdbdb648 pbrook
{
301 6a824ec3 Paul Brook
    icp_pit_state *s = FROM_SYSBUS(icp_pit_state, dev);
302 cdbdb648 pbrook
303 cdbdb648 pbrook
    /* Timer 0 runs at the system clock speed (40MHz).  */
304 6a824ec3 Paul Brook
    s->timer[0] = arm_timer_init(40000000);
305 cdbdb648 pbrook
    /* The other two timers run at 1MHz.  */
306 6a824ec3 Paul Brook
    s->timer[1] = arm_timer_init(1000000);
307 6a824ec3 Paul Brook
    s->timer[2] = arm_timer_init(1000000);
308 6a824ec3 Paul Brook
309 6a824ec3 Paul Brook
    sysbus_init_irq(dev, &s->timer[0]->irq);
310 6a824ec3 Paul Brook
    sysbus_init_irq(dev, &s->timer[1]->irq);
311 6a824ec3 Paul Brook
    sysbus_init_irq(dev, &s->timer[2]->irq);
312 cdbdb648 pbrook
313 e219dea2 Avi Kivity
    memory_region_init_io(&s->iomem, &icp_pit_ops, s, "icp_pit", 0x1000);
314 e219dea2 Avi Kivity
    sysbus_init_mmio_region(dev, &s->iomem);
315 23e39294 pbrook
    /* This device has no state to save/restore.  The component timers will
316 23e39294 pbrook
       save themselves.  */
317 81a322d4 Gerd Hoffmann
    return 0;
318 cdbdb648 pbrook
}
319 6a824ec3 Paul Brook
320 6a824ec3 Paul Brook
static void arm_timer_register_devices(void)
321 6a824ec3 Paul Brook
{
322 6a824ec3 Paul Brook
    sysbus_register_dev("integrator_pit", sizeof(icp_pit_state), icp_pit_init);
323 6a824ec3 Paul Brook
    sysbus_register_dev("sp804", sizeof(sp804_state), sp804_init);
324 6a824ec3 Paul Brook
}
325 6a824ec3 Paul Brook
326 6a824ec3 Paul Brook
device_init(arm_timer_register_devices)