]> git.proxmox.com Git - qemu.git/blobdiff - hw/pxa2xx_timer.c
Merge remote-tracking branch 'spice/spice.v39' into staging
[qemu.git] / hw / pxa2xx_timer.c
index 01cfc4fab999421d14c1c805e2f705c6ec02da00..f777a212262c8aaf699dc69689be04eb992f9c47 100644 (file)
@@ -11,6 +11,7 @@
 #include "qemu-timer.h"
 #include "sysemu.h"
 #include "pxa.h"
+#include "sysbus.h"
 
 #define OSMR0  0x00
 #define OSMR1  0x04
@@ -59,58 +60,70 @@ static int pxa2xx_timer4_freq[8] = {
     [5 ... 7] = 0,
 };
 
-struct pxa2xx_timer0_s {
+typedef struct PXA2xxTimerInfo PXA2xxTimerInfo;
+
+typedef struct {
     uint32_t value;
-    int level;
     qemu_irq irq;
     QEMUTimer *qtimer;
     int num;
-    void *info;
-};
+    PXA2xxTimerInfo *info;
+} PXA2xxTimer0;
 
-struct pxa2xx_timer4_s {
-    struct pxa2xx_timer0_s tm;
+typedef struct {
+    PXA2xxTimer0 tm;
     int32_t oldclock;
     int32_t clock;
     uint64_t lastload;
     uint32_t freq;
     uint32_t control;
-};
+} PXA2xxTimer4;
+
+struct PXA2xxTimerInfo {
+    SysBusDevice busdev;
+    uint32_t flags;
 
-typedef struct {
-    target_phys_addr_t base;
     int32_t clock;
     int32_t oldclock;
     uint64_t lastload;
     uint32_t freq;
-    struct pxa2xx_timer0_s timer[4];
-    struct pxa2xx_timer4_s *tm4;
+    PXA2xxTimer0 timer[4];
     uint32_t events;
     uint32_t irq_enabled;
     uint32_t reset3;
     uint32_t snapshot;
-} pxa2xx_timer_info;
+
+    qemu_irq irq4;
+    PXA2xxTimer4 tm4[8];
+};
+
+#define PXA2XX_TIMER_HAVE_TM4  0
+
+static inline int pxa2xx_timer_has_tm4(PXA2xxTimerInfo *s)
+{
+    return s->flags & (1 << PXA2XX_TIMER_HAVE_TM4);
+}
 
 static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
 {
-    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
     int i;
     uint32_t now_vm;
     uint64_t new_qemu;
 
     now_vm = s->clock +
-            muldiv64(now_qemu - s->lastload, s->freq, ticks_per_sec);
+            muldiv64(now_qemu - s->lastload, s->freq, get_ticks_per_sec());
 
     for (i = 0; i < 4; i ++) {
         new_qemu = now_qemu + muldiv64((uint32_t) (s->timer[i].value - now_vm),
-                        ticks_per_sec, s->freq);
+                        get_ticks_per_sec(), s->freq);
         qemu_mod_timer(s->timer[i].qtimer, new_qemu);
     }
 }
 
 static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
 {
-    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
     uint32_t now_vm;
     uint64_t new_qemu;
     static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
@@ -128,20 +141,18 @@ static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
 
     now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
                     s->tm4[counter].lastload,
-                    s->tm4[counter].freq, ticks_per_sec);
+                    s->tm4[counter].freq, get_ticks_per_sec());
 
     new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm),
-                    ticks_per_sec, s->tm4[counter].freq);
+                    get_ticks_per_sec(), s->tm4[counter].freq);
     qemu_mod_timer(s->tm4[n].tm.qtimer, new_qemu);
 }
 
 static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
 {
-    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
     int tm = 0;
 
-    offset -= s->base;
-
     switch (offset) {
     case OSMR3:  tm ++;
     case OSMR2:  tm ++;
@@ -156,12 +167,12 @@ static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
     case OSMR6:  tm ++;
     case OSMR5:  tm ++;
     case OSMR4:
-        if (!s->tm4)
+        if (!pxa2xx_timer_has_tm4(s))
             goto badreg;
         return s->tm4[tm].tm.value;
     case OSCR:
-        return s->clock + muldiv64(qemu_get_clock(vm_clock) -
-                        s->lastload, s->freq, ticks_per_sec);
+        return s->clock + muldiv64(qemu_get_clock_ns(vm_clock) -
+                        s->lastload, s->freq, get_ticks_per_sec());
     case OSCR11: tm ++;
     case OSCR10: tm ++;
     case OSCR9:  tm ++;
@@ -170,23 +181,23 @@ static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
     case OSCR6:  tm ++;
     case OSCR5:  tm ++;
     case OSCR4:
-        if (!s->tm4)
+        if (!pxa2xx_timer_has_tm4(s))
             goto badreg;
 
         if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
             if (s->tm4[tm - 1].freq)
                 s->snapshot = s->tm4[tm - 1].clock + muldiv64(
-                                qemu_get_clock(vm_clock) -
+                                qemu_get_clock_ns(vm_clock) -
                                 s->tm4[tm - 1].lastload,
-                                s->tm4[tm - 1].freq, ticks_per_sec);
+                                s->tm4[tm - 1].freq, get_ticks_per_sec());
             else
                 s->snapshot = s->tm4[tm - 1].clock;
         }
 
         if (!s->tm4[tm].freq)
             return s->tm4[tm].clock;
-        return s->tm4[tm].clock + muldiv64(qemu_get_clock(vm_clock) -
-                        s->tm4[tm].lastload, s->tm4[tm].freq, ticks_per_sec);
+        return s->tm4[tm].clock + muldiv64(qemu_get_clock_ns(vm_clock) -
+                        s->tm4[tm].lastload, s->tm4[tm].freq, get_ticks_per_sec());
     case OIER:
         return s->irq_enabled;
     case OSSR: /* Status register */
@@ -201,15 +212,14 @@ static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
     case OMCR6:  tm ++;
     case OMCR5:  tm ++;
     case OMCR4:
-        if (!s->tm4)
+        if (!pxa2xx_timer_has_tm4(s))
             goto badreg;
         return s->tm4[tm].control;
     case OSNR:
         return s->snapshot;
     default:
     badreg:
-        cpu_abort(cpu_single_env, "pxa2xx_timer_read: Bad offset "
-                        REG_FMT "\n", offset);
+        hw_error("pxa2xx_timer_read: Bad offset " REG_FMT "\n", offset);
     }
 
     return 0;
@@ -219,9 +229,7 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
                 uint32_t value)
 {
     int i, tm = 0;
-    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
-
-    offset -= s->base;
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
 
     switch (offset) {
     case OSMR3:  tm ++;
@@ -229,7 +237,7 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
     case OSMR1:  tm ++;
     case OSMR0:
         s->timer[tm].value = value;
-        pxa2xx_timer_update(s, qemu_get_clock(vm_clock));
+        pxa2xx_timer_update(s, qemu_get_clock_ns(vm_clock));
         break;
     case OSMR11: tm ++;
     case OSMR10: tm ++;
@@ -239,14 +247,14 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
     case OSMR6:  tm ++;
     case OSMR5:  tm ++;
     case OSMR4:
-        if (!s->tm4)
+        if (!pxa2xx_timer_has_tm4(s))
             goto badreg;
         s->tm4[tm].tm.value = value;
-        pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
+        pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
         break;
     case OSCR:
         s->oldclock = s->clock;
-        s->lastload = qemu_get_clock(vm_clock);
+        s->lastload = qemu_get_clock_ns(vm_clock);
         s->clock = value;
         pxa2xx_timer_update(s, s->lastload);
         break;
@@ -258,10 +266,10 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
     case OSCR6:  tm ++;
     case OSCR5:  tm ++;
     case OSCR4:
-        if (!s->tm4)
+        if (!pxa2xx_timer_has_tm4(s))
             goto badreg;
         s->tm4[tm].oldclock = s->tm4[tm].clock;
-        s->tm4[tm].lastload = qemu_get_clock(vm_clock);
+        s->tm4[tm].lastload = qemu_get_clock_ns(vm_clock);
         s->tm4[tm].clock = value;
         pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
         break;
@@ -269,20 +277,13 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
         s->irq_enabled = value & 0xfff;
         break;
     case OSSR: /* Status register */
+        value &= s->events;
         s->events &= ~value;
-        for (i = 0; i < 4; i ++, value >>= 1) {
-            if (s->timer[i].level && (value & 1)) {
-                s->timer[i].level = 0;
+        for (i = 0; i < 4; i ++, value >>= 1)
+            if (value & 1)
                 qemu_irq_lower(s->timer[i].irq);
-            }
-        }
-        if (s->tm4) {
-            for (i = 0; i < 8; i ++, value >>= 1)
-                if (s->tm4[i].tm.level && (value & 1))
-                    s->tm4[i].tm.level = 0;
-            if (!(s->events & 0xff0))
-                qemu_irq_lower(s->tm4->tm.irq);
-        }
+        if (pxa2xx_timer_has_tm4(s) && !(s->events & 0xff0) && value)
+            qemu_irq_lower(s->irq4);
         break;
     case OWER: /* XXX: Reset on OSMR3 match? */
         s->reset3 = value;
@@ -291,7 +292,7 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
     case OMCR6:  tm ++;
     case OMCR5:  tm ++;
     case OMCR4:
-        if (!s->tm4)
+        if (!pxa2xx_timer_has_tm4(s))
             goto badreg;
         s->tm4[tm].control = value & 0x0ff;
         /* XXX Stop if running (shouldn't happen) */
@@ -299,14 +300,14 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
             s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
         else {
             s->tm4[tm].freq = 0;
-            pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
+            pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
         }
         break;
     case OMCR11: tm ++;
     case OMCR10: tm ++;
     case OMCR9:  tm ++;
     case OMCR8:  tm += 4;
-        if (!s->tm4)
+        if (!pxa2xx_timer_has_tm4(s))
             goto badreg;
         s->tm4[tm].control = value & 0x3ff;
         /* XXX Stop if running (shouldn't happen) */
@@ -315,23 +316,22 @@ static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
                     pxa2xx_timer4_freq[(value & (1 << 8)) ?  0 : (value & 7)];
         else {
             s->tm4[tm].freq = 0;
-            pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
+            pxa2xx_timer_update4(s, qemu_get_clock_ns(vm_clock), tm);
         }
         break;
     default:
     badreg:
-        cpu_abort(cpu_single_env, "pxa2xx_timer_write: Bad offset "
-                        REG_FMT "\n", offset);
+        hw_error("pxa2xx_timer_write: Bad offset " REG_FMT "\n", offset);
     }
 }
 
-static CPUReadMemoryFunc *pxa2xx_timer_readfn[] = {
+static CPUReadMemoryFunc * const pxa2xx_timer_readfn[] = {
     pxa2xx_timer_read,
     pxa2xx_timer_read,
     pxa2xx_timer_read,
 };
 
-static CPUWriteMemoryFunc *pxa2xx_timer_writefn[] = {
+static CPUWriteMemoryFunc * const pxa2xx_timer_writefn[] = {
     pxa2xx_timer_write,
     pxa2xx_timer_write,
     pxa2xx_timer_write,
@@ -339,11 +339,10 @@ static CPUWriteMemoryFunc *pxa2xx_timer_writefn[] = {
 
 static void pxa2xx_timer_tick(void *opaque)
 {
-    struct pxa2xx_timer0_s *t = (struct pxa2xx_timer0_s *) opaque;
-    pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->info;
+    PXA2xxTimer0 *t = (PXA2xxTimer0 *) opaque;
+    PXA2xxTimerInfo *i = t->info;
 
     if (i->irq_enabled & (1 << t->num)) {
-        t->level = 1;
         i->events |= 1 << t->num;
         qemu_irq_raise(t->irq);
     }
@@ -357,142 +356,163 @@ static void pxa2xx_timer_tick(void *opaque)
 
 static void pxa2xx_timer_tick4(void *opaque)
 {
-    struct pxa2xx_timer4_s *t = (struct pxa2xx_timer4_s *) opaque;
-    pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->tm.info;
+    PXA2xxTimer4 *t = (PXA2xxTimer4 *) opaque;
+    PXA2xxTimerInfo *i = (PXA2xxTimerInfo *) t->tm.info;
 
     pxa2xx_timer_tick(&t->tm);
     if (t->control & (1 << 3))
         t->clock = 0;
     if (t->control & (1 << 6))
-        pxa2xx_timer_update4(i, qemu_get_clock(vm_clock), t->tm.num - 4);
-}
-
-static void pxa2xx_timer_save(QEMUFile *f, void *opaque)
-{
-    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
-    int i;
-
-    qemu_put_be32s(f, (uint32_t *) &s->clock);
-    qemu_put_be32s(f, (uint32_t *) &s->oldclock);
-    qemu_put_be64s(f, &s->lastload);
-
-    for (i = 0; i < 4; i ++) {
-        qemu_put_be32s(f, &s->timer[i].value);
-        qemu_put_be32(f, s->timer[i].level);
-    }
-    if (s->tm4)
-        for (i = 0; i < 8; i ++) {
-            qemu_put_be32s(f, &s->tm4[i].tm.value);
-            qemu_put_be32(f, s->tm4[i].tm.level);
-            qemu_put_sbe32s(f, &s->tm4[i].oldclock);
-            qemu_put_sbe32s(f, &s->tm4[i].clock);
-            qemu_put_be64s(f, &s->tm4[i].lastload);
-            qemu_put_be32s(f, &s->tm4[i].freq);
-            qemu_put_be32s(f, &s->tm4[i].control);
-        }
-
-    qemu_put_be32s(f, &s->events);
-    qemu_put_be32s(f, &s->irq_enabled);
-    qemu_put_be32s(f, &s->reset3);
-    qemu_put_be32s(f, &s->snapshot);
+        pxa2xx_timer_update4(i, qemu_get_clock_ns(vm_clock), t->tm.num - 4);
+    if (i->events & 0xff0)
+        qemu_irq_raise(i->irq4);
 }
 
-static int pxa2xx_timer_load(QEMUFile *f, void *opaque, int version_id)
+static int pxa25x_timer_post_load(void *opaque, int version_id)
 {
-    pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+    PXA2xxTimerInfo *s = (PXA2xxTimerInfo *) opaque;
     int64_t now;
     int i;
 
-    qemu_get_be32s(f, (uint32_t *) &s->clock);
-    qemu_get_be32s(f, (uint32_t *) &s->oldclock);
-    qemu_get_be64s(f, &s->lastload);
-
-    now = qemu_get_clock(vm_clock);
-    for (i = 0; i < 4; i ++) {
-        qemu_get_be32s(f, &s->timer[i].value);
-        s->timer[i].level = qemu_get_be32(f);
-    }
+    now = qemu_get_clock_ns(vm_clock);
     pxa2xx_timer_update(s, now);
 
-    if (s->tm4)
-        for (i = 0; i < 8; i ++) {
-            qemu_get_be32s(f, &s->tm4[i].tm.value);
-            s->tm4[i].tm.level = qemu_get_be32(f);
-            qemu_get_sbe32s(f, &s->tm4[i].oldclock);
-            qemu_get_sbe32s(f, &s->tm4[i].clock);
-            qemu_get_be64s(f, &s->tm4[i].lastload);
-            qemu_get_be32s(f, &s->tm4[i].freq);
-            qemu_get_be32s(f, &s->tm4[i].control);
+    if (pxa2xx_timer_has_tm4(s))
+        for (i = 0; i < 8; i ++)
             pxa2xx_timer_update4(s, now, i);
-        }
-
-    qemu_get_be32s(f, &s->events);
-    qemu_get_be32s(f, &s->irq_enabled);
-    qemu_get_be32s(f, &s->reset3);
-    qemu_get_be32s(f, &s->snapshot);
 
     return 0;
 }
 
-static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base,
-                qemu_irq *irqs)
+static int pxa2xx_timer_init(SysBusDevice *dev)
 {
     int i;
     int iomemtype;
-    pxa2xx_timer_info *s;
+    PXA2xxTimerInfo *s;
 
-    s = (pxa2xx_timer_info *) qemu_mallocz(sizeof(pxa2xx_timer_info));
-    s->base = base;
+    s = FROM_SYSBUS(PXA2xxTimerInfo, dev);
     s->irq_enabled = 0;
     s->oldclock = 0;
     s->clock = 0;
-    s->lastload = qemu_get_clock(vm_clock);
+    s->lastload = qemu_get_clock_ns(vm_clock);
     s->reset3 = 0;
 
     for (i = 0; i < 4; i ++) {
         s->timer[i].value = 0;
-        s->timer[i].irq = irqs[i];
+        sysbus_init_irq(dev, &s->timer[i].irq);
         s->timer[i].info = s;
         s->timer[i].num = i;
-        s->timer[i].level = 0;
-        s->timer[i].qtimer = qemu_new_timer(vm_clock,
+        s->timer[i].qtimer = qemu_new_timer_ns(vm_clock,
                         pxa2xx_timer_tick, &s->timer[i]);
     }
+    if (s->flags & (1 << PXA2XX_TIMER_HAVE_TM4)) {
+        sysbus_init_irq(dev, &s->irq4);
 
-    iomemtype = cpu_register_io_memory(0, pxa2xx_timer_readfn,
-                    pxa2xx_timer_writefn, s);
-    cpu_register_physical_memory(base, 0x00001000, iomemtype);
+        for (i = 0; i < 8; i ++) {
+            s->tm4[i].tm.value = 0;
+            s->tm4[i].tm.info = s;
+            s->tm4[i].tm.num = i + 4;
+            s->tm4[i].freq = 0;
+            s->tm4[i].control = 0x0;
+            s->tm4[i].tm.qtimer = qemu_new_timer_ns(vm_clock,
+                        pxa2xx_timer_tick4, &s->tm4[i]);
+        }
+    }
 
-    register_savevm("pxa2xx_timer", 0, 0,
-                    pxa2xx_timer_save, pxa2xx_timer_load, s);
+    iomemtype = cpu_register_io_memory(pxa2xx_timer_readfn,
+                    pxa2xx_timer_writefn, s, DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, 0x00001000, iomemtype);
 
-    return s;
+    return 0;
 }
 
-void pxa25x_timer_init(target_phys_addr_t base, qemu_irq *irqs)
+static const VMStateDescription vmstate_pxa2xx_timer0_regs = {
+    .name = "pxa2xx_timer0",
+    .version_id = 2,
+    .minimum_version_id = 2,
+    .minimum_version_id_old = 2,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(value, PXA2xxTimer0),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static const VMStateDescription vmstate_pxa2xx_timer4_regs = {
+    .name = "pxa2xx_timer4",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_STRUCT(tm, PXA2xxTimer4, 1,
+                        vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
+        VMSTATE_INT32(oldclock, PXA2xxTimer4),
+        VMSTATE_INT32(clock, PXA2xxTimer4),
+        VMSTATE_UINT64(lastload, PXA2xxTimer4),
+        VMSTATE_UINT32(freq, PXA2xxTimer4),
+        VMSTATE_UINT32(control, PXA2xxTimer4),
+        VMSTATE_END_OF_LIST(),
+    },
+};
+
+static bool pxa2xx_timer_has_tm4_test(void *opaque, int version_id)
 {
-    pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs);
-    s->freq = PXA25X_FREQ;
-    s->tm4 = 0;
+    return pxa2xx_timer_has_tm4(opaque);
 }
 
-void pxa27x_timer_init(target_phys_addr_t base,
-                qemu_irq *irqs, qemu_irq irq4)
-{
-    pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs);
-    int i;
-    s->freq = PXA27X_FREQ;
-    s->tm4 = (struct pxa2xx_timer4_s *) qemu_mallocz(8 *
-                    sizeof(struct pxa2xx_timer4_s));
-    for (i = 0; i < 8; i ++) {
-        s->tm4[i].tm.value = 0;
-        s->tm4[i].tm.irq = irq4;
-        s->tm4[i].tm.info = s;
-        s->tm4[i].tm.num = i + 4;
-        s->tm4[i].tm.level = 0;
-        s->tm4[i].freq = 0;
-        s->tm4[i].control = 0x0;
-        s->tm4[i].tm.qtimer = qemu_new_timer(vm_clock,
-                        pxa2xx_timer_tick4, &s->tm4[i]);
+static const VMStateDescription vmstate_pxa2xx_timer_regs = {
+    .name = "pxa2xx_timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .post_load = pxa25x_timer_post_load,
+    .fields = (VMStateField[]) {
+        VMSTATE_INT32(clock, PXA2xxTimerInfo),
+        VMSTATE_INT32(oldclock, PXA2xxTimerInfo),
+        VMSTATE_UINT64(lastload, PXA2xxTimerInfo),
+        VMSTATE_STRUCT_ARRAY(timer, PXA2xxTimerInfo, 4, 1,
+                        vmstate_pxa2xx_timer0_regs, PXA2xxTimer0),
+        VMSTATE_UINT32(events, PXA2xxTimerInfo),
+        VMSTATE_UINT32(irq_enabled, PXA2xxTimerInfo),
+        VMSTATE_UINT32(reset3, PXA2xxTimerInfo),
+        VMSTATE_UINT32(snapshot, PXA2xxTimerInfo),
+        VMSTATE_STRUCT_ARRAY_TEST(tm4, PXA2xxTimerInfo, 8,
+                        pxa2xx_timer_has_tm4_test, 0,
+                        vmstate_pxa2xx_timer4_regs, PXA2xxTimer4),
+        VMSTATE_END_OF_LIST(),
     }
-}
+};
+
+static SysBusDeviceInfo pxa25x_timer_dev_info = {
+    .init       = pxa2xx_timer_init,
+    .qdev.name  = "pxa25x-timer",
+    .qdev.desc  = "PXA25x timer",
+    .qdev.size  = sizeof(PXA2xxTimerInfo),
+    .qdev.vmsd  = &vmstate_pxa2xx_timer_regs,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA25X_FREQ),
+        DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
+                        PXA2XX_TIMER_HAVE_TM4, false),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static SysBusDeviceInfo pxa27x_timer_dev_info = {
+    .init       = pxa2xx_timer_init,
+    .qdev.name  = "pxa27x-timer",
+    .qdev.desc  = "PXA27x timer",
+    .qdev.size  = sizeof(PXA2xxTimerInfo),
+    .qdev.vmsd  = &vmstate_pxa2xx_timer_regs,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("freq", PXA2xxTimerInfo, freq, PXA27X_FREQ),
+        DEFINE_PROP_BIT("tm4", PXA2xxTimerInfo, flags,
+                        PXA2XX_TIMER_HAVE_TM4, true),
+        DEFINE_PROP_END_OF_LIST(),
+    },
+};
+
+static void pxa2xx_timer_register(void)
+{
+    sysbus_register_withprop(&pxa25x_timer_dev_info);
+    sysbus_register_withprop(&pxa27x_timer_dev_info);
+};
+device_init(pxa2xx_timer_register);