Statistics
| Branch: | Revision:

root / hw / arm_timer.c @ 57c83dac

History | View | Annotate | Download (10.3 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 104a26a2 Mark Langsdorf
#include "qemu-common.h"
13 104a26a2 Mark Langsdorf
#include "qdev.h"
14 49d4d9b6 Paolo Bonzini
#include "ptimer.h"
15 cdbdb648 pbrook
16 cdbdb648 pbrook
/* Common timer implementation.  */
17 cdbdb648 pbrook
18 cdbdb648 pbrook
#define TIMER_CTRL_ONESHOT      (1 << 0)
19 cdbdb648 pbrook
#define TIMER_CTRL_32BIT        (1 << 1)
20 cdbdb648 pbrook
#define TIMER_CTRL_DIV1         (0 << 2)
21 cdbdb648 pbrook
#define TIMER_CTRL_DIV16        (1 << 2)
22 cdbdb648 pbrook
#define TIMER_CTRL_DIV256       (2 << 2)
23 cdbdb648 pbrook
#define TIMER_CTRL_IE           (1 << 5)
24 cdbdb648 pbrook
#define TIMER_CTRL_PERIODIC     (1 << 6)
25 cdbdb648 pbrook
#define TIMER_CTRL_ENABLE       (1 << 7)
26 cdbdb648 pbrook
27 cdbdb648 pbrook
typedef struct {
28 423f0742 pbrook
    ptimer_state *timer;
29 cdbdb648 pbrook
    uint32_t control;
30 cdbdb648 pbrook
    uint32_t limit;
31 cdbdb648 pbrook
    int freq;
32 cdbdb648 pbrook
    int int_level;
33 d537cf6c pbrook
    qemu_irq irq;
34 cdbdb648 pbrook
} arm_timer_state;
35 cdbdb648 pbrook
36 cdbdb648 pbrook
/* Check all active timers, and schedule the next timer interrupt.  */
37 cdbdb648 pbrook
38 423f0742 pbrook
static void arm_timer_update(arm_timer_state *s)
39 cdbdb648 pbrook
{
40 cdbdb648 pbrook
    /* Update interrupts.  */
41 cdbdb648 pbrook
    if (s->int_level && (s->control & TIMER_CTRL_IE)) {
42 d537cf6c pbrook
        qemu_irq_raise(s->irq);
43 cdbdb648 pbrook
    } else {
44 d537cf6c pbrook
        qemu_irq_lower(s->irq);
45 cdbdb648 pbrook
    }
46 cdbdb648 pbrook
}
47 cdbdb648 pbrook
48 c227f099 Anthony Liguori
static uint32_t arm_timer_read(void *opaque, target_phys_addr_t offset)
49 cdbdb648 pbrook
{
50 cdbdb648 pbrook
    arm_timer_state *s = (arm_timer_state *)opaque;
51 cdbdb648 pbrook
52 cdbdb648 pbrook
    switch (offset >> 2) {
53 cdbdb648 pbrook
    case 0: /* TimerLoad */
54 cdbdb648 pbrook
    case 6: /* TimerBGLoad */
55 cdbdb648 pbrook
        return s->limit;
56 cdbdb648 pbrook
    case 1: /* TimerValue */
57 423f0742 pbrook
        return ptimer_get_count(s->timer);
58 cdbdb648 pbrook
    case 2: /* TimerControl */
59 cdbdb648 pbrook
        return s->control;
60 cdbdb648 pbrook
    case 4: /* TimerRIS */
61 cdbdb648 pbrook
        return s->int_level;
62 cdbdb648 pbrook
    case 5: /* TimerMIS */
63 cdbdb648 pbrook
        if ((s->control & TIMER_CTRL_IE) == 0)
64 cdbdb648 pbrook
            return 0;
65 cdbdb648 pbrook
        return s->int_level;
66 cdbdb648 pbrook
    default:
67 4abc7ebf Peter Chubb
        hw_error("%s: Bad offset %x\n", __func__, (int)offset);
68 cdbdb648 pbrook
        return 0;
69 cdbdb648 pbrook
    }
70 cdbdb648 pbrook
}
71 cdbdb648 pbrook
72 423f0742 pbrook
/* Reset the timer limit after settings have changed.  */
73 423f0742 pbrook
static void arm_timer_recalibrate(arm_timer_state *s, int reload)
74 423f0742 pbrook
{
75 423f0742 pbrook
    uint32_t limit;
76 423f0742 pbrook
77 a9cf98d9 Rabin Vincent
    if ((s->control & (TIMER_CTRL_PERIODIC | TIMER_CTRL_ONESHOT)) == 0) {
78 423f0742 pbrook
        /* Free running.  */
79 423f0742 pbrook
        if (s->control & TIMER_CTRL_32BIT)
80 423f0742 pbrook
            limit = 0xffffffff;
81 423f0742 pbrook
        else
82 423f0742 pbrook
            limit = 0xffff;
83 423f0742 pbrook
    } else {
84 423f0742 pbrook
          /* Periodic.  */
85 423f0742 pbrook
          limit = s->limit;
86 423f0742 pbrook
    }
87 423f0742 pbrook
    ptimer_set_limit(s->timer, limit, reload);
88 423f0742 pbrook
}
89 423f0742 pbrook
90 c227f099 Anthony Liguori
static void arm_timer_write(void *opaque, target_phys_addr_t offset,
91 cdbdb648 pbrook
                            uint32_t value)
92 cdbdb648 pbrook
{
93 cdbdb648 pbrook
    arm_timer_state *s = (arm_timer_state *)opaque;
94 423f0742 pbrook
    int freq;
95 cdbdb648 pbrook
96 cdbdb648 pbrook
    switch (offset >> 2) {
97 cdbdb648 pbrook
    case 0: /* TimerLoad */
98 cdbdb648 pbrook
        s->limit = value;
99 423f0742 pbrook
        arm_timer_recalibrate(s, 1);
100 cdbdb648 pbrook
        break;
101 cdbdb648 pbrook
    case 1: /* TimerValue */
102 cdbdb648 pbrook
        /* ??? Linux seems to want to write to this readonly register.
103 cdbdb648 pbrook
           Ignore it.  */
104 cdbdb648 pbrook
        break;
105 cdbdb648 pbrook
    case 2: /* TimerControl */
106 cdbdb648 pbrook
        if (s->control & TIMER_CTRL_ENABLE) {
107 cdbdb648 pbrook
            /* Pause the timer if it is running.  This may cause some
108 cdbdb648 pbrook
               inaccuracy dure to rounding, but avoids a whole lot of other
109 cdbdb648 pbrook
               messyness.  */
110 423f0742 pbrook
            ptimer_stop(s->timer);
111 cdbdb648 pbrook
        }
112 cdbdb648 pbrook
        s->control = value;
113 423f0742 pbrook
        freq = s->freq;
114 cdbdb648 pbrook
        /* ??? Need to recalculate expiry time after changing divisor.  */
115 cdbdb648 pbrook
        switch ((value >> 2) & 3) {
116 423f0742 pbrook
        case 1: freq >>= 4; break;
117 423f0742 pbrook
        case 2: freq >>= 8; break;
118 cdbdb648 pbrook
        }
119 d6759902 Rabin Vincent
        arm_timer_recalibrate(s, s->control & TIMER_CTRL_ENABLE);
120 423f0742 pbrook
        ptimer_set_freq(s->timer, freq);
121 cdbdb648 pbrook
        if (s->control & TIMER_CTRL_ENABLE) {
122 cdbdb648 pbrook
            /* Restart the timer if still enabled.  */
123 423f0742 pbrook
            ptimer_run(s->timer, (s->control & TIMER_CTRL_ONESHOT) != 0);
124 cdbdb648 pbrook
        }
125 cdbdb648 pbrook
        break;
126 cdbdb648 pbrook
    case 3: /* TimerIntClr */
127 cdbdb648 pbrook
        s->int_level = 0;
128 cdbdb648 pbrook
        break;
129 cdbdb648 pbrook
    case 6: /* TimerBGLoad */
130 cdbdb648 pbrook
        s->limit = value;
131 423f0742 pbrook
        arm_timer_recalibrate(s, 0);
132 cdbdb648 pbrook
        break;
133 cdbdb648 pbrook
    default:
134 4abc7ebf Peter Chubb
        hw_error("%s: Bad offset %x\n", __func__, (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 eecd33a5 Juan Quintela
static const VMStateDescription vmstate_arm_timer = {
147 eecd33a5 Juan Quintela
    .name = "arm_timer",
148 eecd33a5 Juan Quintela
    .version_id = 1,
149 eecd33a5 Juan Quintela
    .minimum_version_id = 1,
150 eecd33a5 Juan Quintela
    .minimum_version_id_old = 1,
151 eecd33a5 Juan Quintela
    .fields      = (VMStateField[]) {
152 eecd33a5 Juan Quintela
        VMSTATE_UINT32(control, arm_timer_state),
153 eecd33a5 Juan Quintela
        VMSTATE_UINT32(limit, arm_timer_state),
154 eecd33a5 Juan Quintela
        VMSTATE_INT32(int_level, arm_timer_state),
155 eecd33a5 Juan Quintela
        VMSTATE_PTIMER(timer, arm_timer_state),
156 eecd33a5 Juan Quintela
        VMSTATE_END_OF_LIST()
157 eecd33a5 Juan Quintela
    }
158 eecd33a5 Juan Quintela
};
159 23e39294 pbrook
160 6a824ec3 Paul Brook
static arm_timer_state *arm_timer_init(uint32_t freq)
161 cdbdb648 pbrook
{
162 cdbdb648 pbrook
    arm_timer_state *s;
163 423f0742 pbrook
    QEMUBH *bh;
164 cdbdb648 pbrook
165 7267c094 Anthony Liguori
    s = (arm_timer_state *)g_malloc0(sizeof(arm_timer_state));
166 423f0742 pbrook
    s->freq = freq;
167 cdbdb648 pbrook
    s->control = TIMER_CTRL_IE;
168 cdbdb648 pbrook
169 423f0742 pbrook
    bh = qemu_bh_new(arm_timer_tick, s);
170 423f0742 pbrook
    s->timer = ptimer_init(bh);
171 eecd33a5 Juan Quintela
    vmstate_register(NULL, -1, &vmstate_arm_timer, s);
172 cdbdb648 pbrook
    return s;
173 cdbdb648 pbrook
}
174 cdbdb648 pbrook
175 cdbdb648 pbrook
/* ARM PrimeCell SP804 dual timer module.
176 7b4252e8 Peter Chubb
 * Docs at
177 7b4252e8 Peter Chubb
 * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0271d/index.html
178 7b4252e8 Peter Chubb
*/
179 cdbdb648 pbrook
180 cdbdb648 pbrook
typedef struct {
181 6a824ec3 Paul Brook
    SysBusDevice busdev;
182 e219dea2 Avi Kivity
    MemoryRegion iomem;
183 6a824ec3 Paul Brook
    arm_timer_state *timer[2];
184 104a26a2 Mark Langsdorf
    uint32_t freq0, freq1;
185 cdbdb648 pbrook
    int level[2];
186 d537cf6c pbrook
    qemu_irq irq;
187 cdbdb648 pbrook
} sp804_state;
188 cdbdb648 pbrook
189 7b4252e8 Peter Chubb
static const uint8_t sp804_ids[] = {
190 7b4252e8 Peter Chubb
    /* Timer ID */
191 7b4252e8 Peter Chubb
    0x04, 0x18, 0x14, 0,
192 7b4252e8 Peter Chubb
    /* PrimeCell ID */
193 7b4252e8 Peter Chubb
    0xd, 0xf0, 0x05, 0xb1
194 7b4252e8 Peter Chubb
};
195 7b4252e8 Peter Chubb
196 d537cf6c pbrook
/* Merge the IRQs from the two component devices.  */
197 cdbdb648 pbrook
static void sp804_set_irq(void *opaque, int irq, int level)
198 cdbdb648 pbrook
{
199 cdbdb648 pbrook
    sp804_state *s = (sp804_state *)opaque;
200 cdbdb648 pbrook
201 cdbdb648 pbrook
    s->level[irq] = level;
202 d537cf6c pbrook
    qemu_set_irq(s->irq, s->level[0] || s->level[1]);
203 cdbdb648 pbrook
}
204 cdbdb648 pbrook
205 e219dea2 Avi Kivity
static uint64_t sp804_read(void *opaque, target_phys_addr_t offset,
206 e219dea2 Avi Kivity
                           unsigned size)
207 cdbdb648 pbrook
{
208 cdbdb648 pbrook
    sp804_state *s = (sp804_state *)opaque;
209 cdbdb648 pbrook
210 cdbdb648 pbrook
    if (offset < 0x20) {
211 cdbdb648 pbrook
        return arm_timer_read(s->timer[0], offset);
212 7b4252e8 Peter Chubb
    }
213 7b4252e8 Peter Chubb
    if (offset < 0x40) {
214 cdbdb648 pbrook
        return arm_timer_read(s->timer[1], offset - 0x20);
215 cdbdb648 pbrook
    }
216 7b4252e8 Peter Chubb
217 7b4252e8 Peter Chubb
    /* TimerPeriphID */
218 7b4252e8 Peter Chubb
    if (offset >= 0xfe0 && offset <= 0xffc) {
219 7b4252e8 Peter Chubb
        return sp804_ids[(offset - 0xfe0) >> 2];
220 7b4252e8 Peter Chubb
    }
221 7b4252e8 Peter Chubb
222 7b4252e8 Peter Chubb
    switch (offset) {
223 7b4252e8 Peter Chubb
    /* Integration Test control registers, which we won't support */
224 7b4252e8 Peter Chubb
    case 0xf00: /* TimerITCR */
225 7b4252e8 Peter Chubb
    case 0xf04: /* TimerITOP (strictly write only but..) */
226 7b4252e8 Peter Chubb
        return 0;
227 7b4252e8 Peter Chubb
    }
228 7b4252e8 Peter Chubb
229 7b4252e8 Peter Chubb
    hw_error("%s: Bad offset %x\n", __func__, (int)offset);
230 7b4252e8 Peter Chubb
    return 0;
231 cdbdb648 pbrook
}
232 cdbdb648 pbrook
233 c227f099 Anthony Liguori
static void sp804_write(void *opaque, target_phys_addr_t offset,
234 e219dea2 Avi Kivity
                        uint64_t value, unsigned size)
235 cdbdb648 pbrook
{
236 cdbdb648 pbrook
    sp804_state *s = (sp804_state *)opaque;
237 cdbdb648 pbrook
238 cdbdb648 pbrook
    if (offset < 0x20) {
239 cdbdb648 pbrook
        arm_timer_write(s->timer[0], offset, value);
240 7b4252e8 Peter Chubb
        return;
241 7b4252e8 Peter Chubb
    }
242 7b4252e8 Peter Chubb
243 7b4252e8 Peter Chubb
    if (offset < 0x40) {
244 cdbdb648 pbrook
        arm_timer_write(s->timer[1], offset - 0x20, value);
245 7b4252e8 Peter Chubb
        return;
246 cdbdb648 pbrook
    }
247 7b4252e8 Peter Chubb
248 7b4252e8 Peter Chubb
    /* Technically we could be writing to the Test Registers, but not likely */
249 7b4252e8 Peter Chubb
    hw_error("%s: Bad offset %x\n", __func__, (int)offset);
250 cdbdb648 pbrook
}
251 cdbdb648 pbrook
252 e219dea2 Avi Kivity
static const MemoryRegionOps sp804_ops = {
253 e219dea2 Avi Kivity
    .read = sp804_read,
254 e219dea2 Avi Kivity
    .write = sp804_write,
255 e219dea2 Avi Kivity
    .endianness = DEVICE_NATIVE_ENDIAN,
256 cdbdb648 pbrook
};
257 cdbdb648 pbrook
258 81986ac4 Juan Quintela
static const VMStateDescription vmstate_sp804 = {
259 81986ac4 Juan Quintela
    .name = "sp804",
260 81986ac4 Juan Quintela
    .version_id = 1,
261 81986ac4 Juan Quintela
    .minimum_version_id = 1,
262 81986ac4 Juan Quintela
    .minimum_version_id_old = 1,
263 81986ac4 Juan Quintela
    .fields      = (VMStateField[]) {
264 81986ac4 Juan Quintela
        VMSTATE_INT32_ARRAY(level, sp804_state, 2),
265 81986ac4 Juan Quintela
        VMSTATE_END_OF_LIST()
266 81986ac4 Juan Quintela
    }
267 81986ac4 Juan Quintela
};
268 23e39294 pbrook
269 81a322d4 Gerd Hoffmann
static int sp804_init(SysBusDevice *dev)
270 cdbdb648 pbrook
{
271 6a824ec3 Paul Brook
    sp804_state *s = FROM_SYSBUS(sp804_state, dev);
272 d537cf6c pbrook
    qemu_irq *qi;
273 cdbdb648 pbrook
274 d537cf6c pbrook
    qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
275 6a824ec3 Paul Brook
    sysbus_init_irq(dev, &s->irq);
276 104a26a2 Mark Langsdorf
    s->timer[0] = arm_timer_init(s->freq0);
277 104a26a2 Mark Langsdorf
    s->timer[1] = arm_timer_init(s->freq1);
278 6a824ec3 Paul Brook
    s->timer[0]->irq = qi[0];
279 6a824ec3 Paul Brook
    s->timer[1]->irq = qi[1];
280 e219dea2 Avi Kivity
    memory_region_init_io(&s->iomem, &sp804_ops, s, "sp804", 0x1000);
281 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->iomem);
282 81986ac4 Juan Quintela
    vmstate_register(&dev->qdev, -1, &vmstate_sp804, s);
283 81a322d4 Gerd Hoffmann
    return 0;
284 cdbdb648 pbrook
}
285 cdbdb648 pbrook
286 cdbdb648 pbrook
/* Integrator/CP timer module.  */
287 cdbdb648 pbrook
288 cdbdb648 pbrook
typedef struct {
289 6a824ec3 Paul Brook
    SysBusDevice busdev;
290 e219dea2 Avi Kivity
    MemoryRegion iomem;
291 6a824ec3 Paul Brook
    arm_timer_state *timer[3];
292 cdbdb648 pbrook
} icp_pit_state;
293 cdbdb648 pbrook
294 e219dea2 Avi Kivity
static uint64_t icp_pit_read(void *opaque, target_phys_addr_t offset,
295 e219dea2 Avi Kivity
                             unsigned size)
296 cdbdb648 pbrook
{
297 cdbdb648 pbrook
    icp_pit_state *s = (icp_pit_state *)opaque;
298 cdbdb648 pbrook
    int n;
299 cdbdb648 pbrook
300 cdbdb648 pbrook
    /* ??? Don't know the PrimeCell ID for this device.  */
301 cdbdb648 pbrook
    n = offset >> 8;
302 ee71c984 Peter Maydell
    if (n > 2) {
303 4abc7ebf Peter Chubb
        hw_error("%s: Bad timer %d\n", __func__, n);
304 2ac71179 Paul Brook
    }
305 cdbdb648 pbrook
306 cdbdb648 pbrook
    return arm_timer_read(s->timer[n], offset & 0xff);
307 cdbdb648 pbrook
}
308 cdbdb648 pbrook
309 c227f099 Anthony Liguori
static void icp_pit_write(void *opaque, target_phys_addr_t offset,
310 e219dea2 Avi Kivity
                          uint64_t value, unsigned size)
311 cdbdb648 pbrook
{
312 cdbdb648 pbrook
    icp_pit_state *s = (icp_pit_state *)opaque;
313 cdbdb648 pbrook
    int n;
314 cdbdb648 pbrook
315 cdbdb648 pbrook
    n = offset >> 8;
316 ee71c984 Peter Maydell
    if (n > 2) {
317 4abc7ebf Peter Chubb
        hw_error("%s: Bad timer %d\n", __func__, n);
318 2ac71179 Paul Brook
    }
319 cdbdb648 pbrook
320 cdbdb648 pbrook
    arm_timer_write(s->timer[n], offset & 0xff, value);
321 cdbdb648 pbrook
}
322 cdbdb648 pbrook
323 e219dea2 Avi Kivity
static const MemoryRegionOps icp_pit_ops = {
324 e219dea2 Avi Kivity
    .read = icp_pit_read,
325 e219dea2 Avi Kivity
    .write = icp_pit_write,
326 e219dea2 Avi Kivity
    .endianness = DEVICE_NATIVE_ENDIAN,
327 cdbdb648 pbrook
};
328 cdbdb648 pbrook
329 81a322d4 Gerd Hoffmann
static int icp_pit_init(SysBusDevice *dev)
330 cdbdb648 pbrook
{
331 6a824ec3 Paul Brook
    icp_pit_state *s = FROM_SYSBUS(icp_pit_state, dev);
332 cdbdb648 pbrook
333 cdbdb648 pbrook
    /* Timer 0 runs at the system clock speed (40MHz).  */
334 6a824ec3 Paul Brook
    s->timer[0] = arm_timer_init(40000000);
335 cdbdb648 pbrook
    /* The other two timers run at 1MHz.  */
336 6a824ec3 Paul Brook
    s->timer[1] = arm_timer_init(1000000);
337 6a824ec3 Paul Brook
    s->timer[2] = arm_timer_init(1000000);
338 6a824ec3 Paul Brook
339 6a824ec3 Paul Brook
    sysbus_init_irq(dev, &s->timer[0]->irq);
340 6a824ec3 Paul Brook
    sysbus_init_irq(dev, &s->timer[1]->irq);
341 6a824ec3 Paul Brook
    sysbus_init_irq(dev, &s->timer[2]->irq);
342 cdbdb648 pbrook
343 e219dea2 Avi Kivity
    memory_region_init_io(&s->iomem, &icp_pit_ops, s, "icp_pit", 0x1000);
344 750ecd44 Avi Kivity
    sysbus_init_mmio(dev, &s->iomem);
345 23e39294 pbrook
    /* This device has no state to save/restore.  The component timers will
346 23e39294 pbrook
       save themselves.  */
347 81a322d4 Gerd Hoffmann
    return 0;
348 cdbdb648 pbrook
}
349 6a824ec3 Paul Brook
350 999e12bb Anthony Liguori
static void icp_pit_class_init(ObjectClass *klass, void *data)
351 999e12bb Anthony Liguori
{
352 999e12bb Anthony Liguori
    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
353 999e12bb Anthony Liguori
354 999e12bb Anthony Liguori
    sdc->init = icp_pit_init;
355 999e12bb Anthony Liguori
}
356 999e12bb Anthony Liguori
357 39bffca2 Anthony Liguori
static TypeInfo icp_pit_info = {
358 39bffca2 Anthony Liguori
    .name          = "integrator_pit",
359 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
360 39bffca2 Anthony Liguori
    .instance_size = sizeof(icp_pit_state),
361 39bffca2 Anthony Liguori
    .class_init    = icp_pit_class_init,
362 39bffca2 Anthony Liguori
};
363 39bffca2 Anthony Liguori
364 39bffca2 Anthony Liguori
static Property sp804_properties[] = {
365 39bffca2 Anthony Liguori
    DEFINE_PROP_UINT32("freq0", sp804_state, freq0, 1000000),
366 39bffca2 Anthony Liguori
    DEFINE_PROP_UINT32("freq1", sp804_state, freq1, 1000000),
367 39bffca2 Anthony Liguori
    DEFINE_PROP_END_OF_LIST(),
368 999e12bb Anthony Liguori
};
369 999e12bb Anthony Liguori
370 999e12bb Anthony Liguori
static void sp804_class_init(ObjectClass *klass, void *data)
371 999e12bb Anthony Liguori
{
372 999e12bb Anthony Liguori
    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
373 39bffca2 Anthony Liguori
    DeviceClass *k = DEVICE_CLASS(klass);
374 999e12bb Anthony Liguori
375 999e12bb Anthony Liguori
    sdc->init = sp804_init;
376 39bffca2 Anthony Liguori
    k->props = sp804_properties;
377 999e12bb Anthony Liguori
}
378 999e12bb Anthony Liguori
379 39bffca2 Anthony Liguori
static TypeInfo sp804_info = {
380 39bffca2 Anthony Liguori
    .name          = "sp804",
381 39bffca2 Anthony Liguori
    .parent        = TYPE_SYS_BUS_DEVICE,
382 39bffca2 Anthony Liguori
    .instance_size = sizeof(sp804_state),
383 39bffca2 Anthony Liguori
    .class_init    = sp804_class_init,
384 999e12bb Anthony Liguori
};
385 999e12bb Anthony Liguori
386 6a824ec3 Paul Brook
static void arm_timer_register_devices(void)
387 6a824ec3 Paul Brook
{
388 39bffca2 Anthony Liguori
    type_register_static(&icp_pit_info);
389 39bffca2 Anthony Liguori
    type_register_static(&sp804_info);
390 6a824ec3 Paul Brook
}
391 6a824ec3 Paul Brook
392 6a824ec3 Paul Brook
device_init(arm_timer_register_devices)