summary refs log tree commit diff stats
path: root/hw/timer
diff options
context:
space:
mode:
Diffstat (limited to 'hw/timer')
-rw-r--r--hw/timer/Makefile.objs3
-rw-r--r--hw/timer/allwinner-a10-pit.c254
-rw-r--r--hw/timer/arm_mptimer.c1
-rw-r--r--hw/timer/digic-timer.c163
-rw-r--r--hw/timer/hpet.c30
-rw-r--r--hw/timer/i8254_common.c7
-rw-r--r--hw/timer/m48t59.c3
-rw-r--r--hw/timer/mc146818rtc.c3
-rw-r--r--hw/timer/pl031.c1
9 files changed, 449 insertions, 16 deletions
diff --git a/hw/timer/Makefile.objs b/hw/timer/Makefile.objs
index 3ae091c95e..2c86c3d412 100644
--- a/hw/timer/Makefile.objs
+++ b/hw/timer/Makefile.objs
@@ -26,5 +26,8 @@ obj-$(CONFIG_OMAP) += omap_synctimer.o
 obj-$(CONFIG_PXA2XX) += pxa2xx_timer.o
 obj-$(CONFIG_SH4) += sh_timer.o
 obj-$(CONFIG_TUSB6010) += tusb6010.o
+obj-$(CONFIG_DIGIC) += digic-timer.o
 
 obj-$(CONFIG_MC146818RTC) += mc146818rtc.o
+
+obj-$(CONFIG_ALLWINNER_A10_PIT) += allwinner-a10-pit.o
diff --git a/hw/timer/allwinner-a10-pit.c b/hw/timer/allwinner-a10-pit.c
new file mode 100644
index 0000000000..b27fce8cd2
--- /dev/null
+++ b/hw/timer/allwinner-a10-pit.c
@@ -0,0 +1,254 @@
+/*
+ * Allwinner A10 timer device emulation
+ *
+ * Copyright (C) 2013 Li Guang
+ * Written by Li Guang <lig.fnst@cn.fujitsu.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "hw/sysbus.h"
+#include "sysemu/sysemu.h"
+#include "hw/timer/allwinner-a10-pit.h"
+
+static uint64_t a10_pit_read(void *opaque, hwaddr offset, unsigned size)
+{
+    AwA10PITState *s = AW_A10_PIT(opaque);
+    uint8_t index;
+
+    switch (offset) {
+    case AW_A10_PIT_TIMER_IRQ_EN:
+        return s->irq_enable;
+    case AW_A10_PIT_TIMER_IRQ_ST:
+        return s->irq_status;
+    case AW_A10_PIT_TIMER_BASE ... AW_A10_PIT_TIMER_BASE_END:
+        index = offset & 0xf0;
+        index >>= 4;
+        index -= 1;
+        switch (offset & 0x0f) {
+        case AW_A10_PIT_TIMER_CONTROL:
+            return s->control[index];
+        case AW_A10_PIT_TIMER_INTERVAL:
+            return s->interval[index];
+        case AW_A10_PIT_TIMER_COUNT:
+            s->count[index] = ptimer_get_count(s->timer[index]);
+            return s->count[index];
+        default:
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: Bad offset 0x%x\n",  __func__, (int)offset);
+            break;
+        }
+    case AW_A10_PIT_WDOG_CONTROL:
+        break;
+    case AW_A10_PIT_WDOG_MODE:
+        break;
+    case AW_A10_PIT_COUNT_LO:
+        return s->count_lo;
+    case AW_A10_PIT_COUNT_HI:
+        return s->count_hi;
+    case AW_A10_PIT_COUNT_CTL:
+        return s->count_ctl;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%x\n",  __func__, (int)offset);
+        break;
+    }
+
+    return 0;
+}
+
+static void a10_pit_write(void *opaque, hwaddr offset, uint64_t value,
+                            unsigned size)
+{
+     AwA10PITState *s = AW_A10_PIT(opaque);
+     uint8_t index;
+
+    switch (offset) {
+    case AW_A10_PIT_TIMER_IRQ_EN:
+        s->irq_enable = value;
+        break;
+    case AW_A10_PIT_TIMER_IRQ_ST:
+        s->irq_status &= ~value;
+        break;
+    case AW_A10_PIT_TIMER_BASE ... AW_A10_PIT_TIMER_BASE_END:
+        index = offset & 0xf0;
+        index >>= 4;
+        index -= 1;
+        switch (offset & 0x0f) {
+        case AW_A10_PIT_TIMER_CONTROL:
+            s->control[index] = value;
+            if (s->control[index] & AW_A10_PIT_TIMER_RELOAD) {
+                ptimer_set_count(s->timer[index], s->interval[index]);
+            }
+            if (s->control[index] & AW_A10_PIT_TIMER_EN) {
+                int oneshot = 0;
+                if (s->control[index] & AW_A10_PIT_TIMER_MODE) {
+                    oneshot = 1;
+                }
+                ptimer_run(s->timer[index], oneshot);
+            } else {
+                ptimer_stop(s->timer[index]);
+            }
+            break;
+        case AW_A10_PIT_TIMER_INTERVAL:
+            s->interval[index] = value;
+            ptimer_set_limit(s->timer[index], s->interval[index], 1);
+            break;
+        case AW_A10_PIT_TIMER_COUNT:
+            s->count[index] = value;
+            break;
+        default:
+            qemu_log_mask(LOG_GUEST_ERROR,
+                          "%s: Bad offset 0x%x\n",  __func__, (int)offset);
+        }
+        break;
+    case AW_A10_PIT_WDOG_CONTROL:
+        s->watch_dog_control = value;
+        break;
+    case AW_A10_PIT_WDOG_MODE:
+        s->watch_dog_mode = value;
+        break;
+    case AW_A10_PIT_COUNT_LO:
+        s->count_lo = value;
+        break;
+    case AW_A10_PIT_COUNT_HI:
+        s->count_hi = value;
+        break;
+    case AW_A10_PIT_COUNT_CTL:
+        s->count_ctl = value;
+        if (s->count_ctl & AW_A10_PIT_COUNT_RL_EN) {
+            uint64_t  tmp_count = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
+
+            s->count_lo = tmp_count;
+            s->count_hi = tmp_count >> 32;
+            s->count_ctl &= ~AW_A10_PIT_COUNT_RL_EN;
+        }
+        if (s->count_ctl & AW_A10_PIT_COUNT_CLR_EN) {
+            s->count_lo = 0;
+            s->count_hi = 0;
+            s->count_ctl &= ~AW_A10_PIT_COUNT_CLR_EN;
+        }
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: Bad offset 0x%x\n",  __func__, (int)offset);
+        break;
+    }
+}
+
+static const MemoryRegionOps a10_pit_ops = {
+    .read = a10_pit_read,
+    .write = a10_pit_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static const VMStateDescription vmstate_a10_pit = {
+    .name = "a10.pit",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32(irq_enable, AwA10PITState),
+        VMSTATE_UINT32(irq_status, AwA10PITState),
+        VMSTATE_UINT32_ARRAY(control, AwA10PITState, AW_A10_PIT_TIMER_NR),
+        VMSTATE_UINT32_ARRAY(interval, AwA10PITState, AW_A10_PIT_TIMER_NR),
+        VMSTATE_UINT32_ARRAY(count, AwA10PITState, AW_A10_PIT_TIMER_NR),
+        VMSTATE_UINT32(watch_dog_mode, AwA10PITState),
+        VMSTATE_UINT32(watch_dog_control, AwA10PITState),
+        VMSTATE_UINT32(count_lo, AwA10PITState),
+        VMSTATE_UINT32(count_hi, AwA10PITState),
+        VMSTATE_UINT32(count_ctl, AwA10PITState),
+        VMSTATE_PTIMER_ARRAY(timer, AwA10PITState, AW_A10_PIT_TIMER_NR),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void a10_pit_reset(DeviceState *dev)
+{
+    AwA10PITState *s = AW_A10_PIT(dev);
+    uint8_t i;
+
+    s->irq_enable = 0;
+    s->irq_status = 0;
+    for (i = 0; i < 6; i++) {
+        s->control[i] = AW_A10_PIT_DEFAULT_CLOCK;
+        s->interval[i] = 0;
+        s->count[i] = 0;
+        ptimer_stop(s->timer[i]);
+    }
+    s->watch_dog_mode = 0;
+    s->watch_dog_control = 0;
+    s->count_lo = 0;
+    s->count_hi = 0;
+    s->count_ctl = 0;
+}
+
+static void a10_pit_timer_cb(void *opaque)
+{
+    AwA10PITState *s = AW_A10_PIT(opaque);
+    uint8_t i;
+
+    for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
+        if (s->control[i] & AW_A10_PIT_TIMER_EN) {
+            s->irq_status |= 1 << i;
+            if (s->control[i] & AW_A10_PIT_TIMER_MODE) {
+                ptimer_stop(s->timer[i]);
+                s->control[i] &= ~AW_A10_PIT_TIMER_EN;
+            }
+            qemu_irq_pulse(s->irq[i]);
+        }
+    }
+}
+
+static void a10_pit_init(Object *obj)
+{
+    AwA10PITState *s = AW_A10_PIT(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    QEMUBH * bh[AW_A10_PIT_TIMER_NR];
+    uint8_t i;
+
+    for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
+        sysbus_init_irq(sbd, &s->irq[i]);
+    }
+    memory_region_init_io(&s->iomem, OBJECT(s), &a10_pit_ops, s,
+                          TYPE_AW_A10_PIT, 0x400);
+    sysbus_init_mmio(sbd, &s->iomem);
+
+    for (i = 0; i < AW_A10_PIT_TIMER_NR; i++) {
+        bh[i] = qemu_bh_new(a10_pit_timer_cb, s);
+        s->timer[i] = ptimer_init(bh[i]);
+        ptimer_set_freq(s->timer[i], 240000);
+    }
+}
+
+static void a10_pit_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = a10_pit_reset;
+    dc->desc = "allwinner a10 timer";
+    dc->vmsd = &vmstate_a10_pit;
+}
+
+static const TypeInfo a10_pit_info = {
+    .name = TYPE_AW_A10_PIT,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(AwA10PITState),
+    .instance_init = a10_pit_init,
+    .class_init = a10_pit_class_init,
+};
+
+static void a10_register_types(void)
+{
+    type_register_static(&a10_pit_info);
+}
+
+type_init(a10_register_types);
diff --git a/hw/timer/arm_mptimer.c b/hw/timer/arm_mptimer.c
index d9f9494f26..35a0a2356f 100644
--- a/hw/timer/arm_mptimer.c
+++ b/hw/timer/arm_mptimer.c
@@ -274,7 +274,6 @@ static void arm_mptimer_class_init(ObjectClass *klass, void *data)
     dc->realize = arm_mptimer_realize;
     dc->vmsd = &vmstate_arm_mptimer;
     dc->reset = arm_mptimer_reset;
-    dc->no_user = 1;
     dc->props = arm_mptimer_properties;
 }
 
diff --git a/hw/timer/digic-timer.c b/hw/timer/digic-timer.c
new file mode 100644
index 0000000000..1fde22c67f
--- /dev/null
+++ b/hw/timer/digic-timer.c
@@ -0,0 +1,163 @@
+/*
+ * QEMU model of the Canon DIGIC timer block.
+ *
+ * Copyright (C) 2013 Antony Pavlov <antonynpavlov@gmail.com>
+ *
+ * This model is based on reverse engineering efforts
+ * made by CHDK (http://chdk.wikia.com) and
+ * Magic Lantern (http://www.magiclantern.fm) projects
+ * contributors.
+ *
+ * See "Timer/Clock Module" docs here:
+ *   http://magiclantern.wikia.com/wiki/Register_Map
+ *
+ * The QEMU model of the OSTimer in PKUnity SoC by Guan Xuetao
+ * is used as a template.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "hw/sysbus.h"
+#include "hw/ptimer.h"
+#include "qemu/main-loop.h"
+
+#include "hw/timer/digic-timer.h"
+
+static const VMStateDescription vmstate_digic_timer = {
+    .name = "digic.timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_PTIMER(ptimer, DigicTimerState),
+        VMSTATE_UINT32(control, DigicTimerState),
+        VMSTATE_UINT32(relvalue, DigicTimerState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void digic_timer_reset(DeviceState *dev)
+{
+    DigicTimerState *s = DIGIC_TIMER(dev);
+
+    ptimer_stop(s->ptimer);
+    s->control = 0;
+    s->relvalue = 0;
+}
+
+static uint64_t digic_timer_read(void *opaque, hwaddr offset, unsigned size)
+{
+    DigicTimerState *s = opaque;
+    uint64_t ret = 0;
+
+    switch (offset) {
+    case DIGIC_TIMER_CONTROL:
+        ret = s->control;
+        break;
+    case DIGIC_TIMER_RELVALUE:
+        ret = s->relvalue;
+        break;
+    case DIGIC_TIMER_VALUE:
+        ret = ptimer_get_count(s->ptimer) & 0xffff;
+        break;
+    default:
+        qemu_log_mask(LOG_UNIMP,
+                      "digic-timer: read access to unknown register 0x"
+                      TARGET_FMT_plx, offset);
+    }
+
+    return ret;
+}
+
+static void digic_timer_write(void *opaque, hwaddr offset,
+                              uint64_t value, unsigned size)
+{
+    DigicTimerState *s = opaque;
+
+    switch (offset) {
+    case DIGIC_TIMER_CONTROL:
+        if (value & DIGIC_TIMER_CONTROL_RST) {
+            digic_timer_reset((DeviceState *)s);
+            break;
+        }
+
+        if (value & DIGIC_TIMER_CONTROL_EN) {
+            ptimer_run(s->ptimer, 0);
+        }
+
+        s->control = (uint32_t)value;
+        break;
+
+    case DIGIC_TIMER_RELVALUE:
+        s->relvalue = extract32(value, 0, 16);
+        ptimer_set_limit(s->ptimer, s->relvalue, 1);
+        break;
+
+    case DIGIC_TIMER_VALUE:
+        break;
+
+    default:
+        qemu_log_mask(LOG_UNIMP,
+                      "digic-timer: read access to unknown register 0x"
+                      TARGET_FMT_plx, offset);
+    }
+}
+
+static const MemoryRegionOps digic_timer_ops = {
+    .read = digic_timer_read,
+    .write = digic_timer_write,
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static void digic_timer_init(Object *obj)
+{
+    DigicTimerState *s = DIGIC_TIMER(obj);
+
+    s->ptimer = ptimer_init(NULL);
+
+    /*
+     * FIXME: there is no documentation on Digic timer
+     * frequency setup so let it always run at 1 MHz
+     */
+    ptimer_set_freq(s->ptimer, 1 * 1000 * 1000);
+
+    memory_region_init_io(&s->iomem, OBJECT(s), &digic_timer_ops, s,
+                          TYPE_DIGIC_TIMER, 0x100);
+    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
+}
+
+static void digic_timer_class_init(ObjectClass *klass, void *class_data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = digic_timer_reset;
+    dc->vmsd = &vmstate_digic_timer;
+}
+
+static const TypeInfo digic_timer_info = {
+    .name = TYPE_DIGIC_TIMER,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(DigicTimerState),
+    .instance_init = digic_timer_init,
+    .class_init = digic_timer_class_init,
+};
+
+static void digic_timer_register_type(void)
+{
+    type_register_static(&digic_timer_info);
+}
+
+type_init(digic_timer_register_type)
diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c
index 2eb75ea945..2fbbeb1735 100644
--- a/hw/timer/hpet.c
+++ b/hw/timer/hpet.c
@@ -42,7 +42,6 @@
 
 #define HPET_MSI_SUPPORT        0
 
-#define TYPE_HPET "hpet"
 #define HPET(obj) OBJECT_CHECK(HPETState, (obj), TYPE_HPET)
 
 struct HPETState;
@@ -73,6 +72,7 @@ typedef struct HPETState {
     uint8_t rtc_irq_level;
     qemu_irq pit_enabled;
     uint8_t num_timers;
+    uint32_t intcap;
     HPETTimer timer[HPET_MAX_TIMERS];
 
     /* Memory-mapped, software visible registers */
@@ -198,13 +198,23 @@ static void update_irq(struct HPETTimer *timer, int set)
     if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) {
         s->isr &= ~mask;
         if (!timer_fsb_route(timer)) {
-            qemu_irq_lower(s->irqs[route]);
+            /* fold the ICH PIRQ# pin's internal inversion logic into hpet */
+            if (route >= ISA_NUM_IRQS) {
+                qemu_irq_raise(s->irqs[route]);
+            } else {
+                qemu_irq_lower(s->irqs[route]);
+            }
         }
     } else if (timer_fsb_route(timer)) {
         stl_le_phys(timer->fsb >> 32, timer->fsb & 0xffffffff);
     } else if (timer->config & HPET_TN_TYPE_LEVEL) {
         s->isr |= mask;
-        qemu_irq_raise(s->irqs[route]);
+        /* fold the ICH PIRQ# pin's internal inversion logic into hpet */
+        if (route >= ISA_NUM_IRQS) {
+            qemu_irq_lower(s->irqs[route]);
+        } else {
+            qemu_irq_raise(s->irqs[route]);
+        }
     } else {
         s->isr &= ~mask;
         qemu_irq_pulse(s->irqs[route]);
@@ -653,8 +663,8 @@ static void hpet_reset(DeviceState *d)
         if (s->flags & (1 << HPET_MSI_SUPPORT)) {
             timer->config |= HPET_TN_FSB_CAP;
         }
-        /* advertise availability of ioapic inti2 */
-        timer->config |=  0x00000004ULL << 32;
+        /* advertise availability of ioapic int */
+        timer->config |=  (uint64_t)s->intcap << 32;
         timer->period = 0ULL;
         timer->wrap_flag = 0;
     }
@@ -703,6 +713,9 @@ static void hpet_realize(DeviceState *dev, Error **errp)
     int i;
     HPETTimer *timer;
 
+    if (!s->intcap) {
+        error_printf("Hpet's intcap not initialized.\n");
+    }
     if (hpet_cfg.count == UINT8_MAX) {
         /* first instance */
         hpet_cfg.count = 0;
@@ -743,6 +756,7 @@ static void hpet_realize(DeviceState *dev, Error **errp)
 static Property hpet_device_properties[] = {
     DEFINE_PROP_UINT8("timers", HPETState, num_timers, HPET_MIN_TIMERS),
     DEFINE_PROP_BIT("msi", HPETState, flags, HPET_MSI_SUPPORT, false),
+    DEFINE_PROP_UINT32(HPET_INTCAP, HPETState, intcap, 0),
     DEFINE_PROP_END_OF_LIST(),
 };
 
@@ -751,17 +765,11 @@ static void hpet_device_class_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     dc->realize = hpet_realize;
-    dc->no_user = 1;
     dc->reset = hpet_reset;
     dc->vmsd = &vmstate_hpet;
     dc->props = hpet_device_properties;
 }
 
-bool hpet_find(void)
-{
-    return object_resolve_path_type("", TYPE_HPET, NULL);
-}
-
 static const TypeInfo hpet_device_info = {
     .name          = TYPE_HPET,
     .parent        = TYPE_SYS_BUS_DEVICE,
diff --git a/hw/timer/i8254_common.c b/hw/timer/i8254_common.c
index e8fb971488..9db5c9d129 100644
--- a/hw/timer/i8254_common.c
+++ b/hw/timer/i8254_common.c
@@ -282,7 +282,12 @@ static void pit_common_class_init(ObjectClass *klass, void *data)
 
     dc->realize = pit_common_realize;
     dc->vmsd = &vmstate_pit_common;
-    dc->no_user = 1;
+    /*
+     * Reason: unlike ordinary ISA devices, the PIT may need to be
+     * wired to the HPET, and because of that, some wiring is always
+     * done by board code.
+     */
+    dc->cannot_instantiate_with_device_add_yet = true;
 }
 
 static const TypeInfo pit_common_type = {
diff --git a/hw/timer/m48t59.c b/hw/timer/m48t59.c
index be0592b53d..3cfb18a8b3 100644
--- a/hw/timer/m48t59.c
+++ b/hw/timer/m48t59.c
@@ -750,9 +750,10 @@ static void m48t59_isa_class_init(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     dc->realize = m48t59_isa_realize;
-    dc->no_user = 1;
     dc->reset = m48t59_reset_isa;
     dc->props = m48t59_isa_properties;
+    /* Reason: needs to be wired up by m48t59_init_isa() */
+    dc->cannot_instantiate_with_device_add_yet = true;
 }
 
 static const TypeInfo m48t59_isa_info = {
diff --git a/hw/timer/mc146818rtc.c b/hw/timer/mc146818rtc.c
index b0116381c0..6fb124fead 100644
--- a/hw/timer/mc146818rtc.c
+++ b/hw/timer/mc146818rtc.c
@@ -899,9 +899,10 @@ static void rtc_class_initfn(ObjectClass *klass, void *data)
     DeviceClass *dc = DEVICE_CLASS(klass);
 
     dc->realize = rtc_realizefn;
-    dc->no_user = 1;
     dc->vmsd = &vmstate_rtc;
     dc->props = mc146818rtc_properties;
+    /* Reason: needs to be wired up by rtc_init() */
+    dc->cannot_instantiate_with_device_add_yet = true;
 }
 
 static const TypeInfo mc146818rtc_info = {
diff --git a/hw/timer/pl031.c b/hw/timer/pl031.c
index 65928a4819..34d9b44e7e 100644
--- a/hw/timer/pl031.c
+++ b/hw/timer/pl031.c
@@ -251,7 +251,6 @@ static void pl031_class_init(ObjectClass *klass, void *data)
     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
     k->init = pl031_init;
-    dc->no_user = 1;
     dc->vmsd = &vmstate_pl031;
 }