summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-06-14 16:04:25 +0100
committerPeter Maydell <peter.maydell@linaro.org>2016-06-14 16:04:25 +0100
commit1be08a0946b1a189ac72822182c37367e8cd3d87 (patch)
tree2c41b2e3abf67957ea1b75e7d5330ab2b1dff4fe
parent7474f1be701f136b224af5e1abe55e97dc3f29a5 (diff)
parentfe8fcf3d642b4de1369841bf6acac13e0ec8770d (diff)
downloadfocaccia-qemu-1be08a0946b1a189ac72822182c37367e8cd3d87.tar.gz
focaccia-qemu-1be08a0946b1a189ac72822182c37367e8cd3d87.zip
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20160614-2' into staging
target-arm queue:
 * add PMU support for virt machine under KVM
 * fix reset and migration of TTBCR(S)
 * add virt-2.7 machine type
 * QOMify various ARM devices
 * implement xilinx DisplayPort device
 * don't permit ARMv8-only Neon insns to work on ARMv7

# gpg: Signature made Tue 14 Jun 2016 16:01:45 BST
# gpg:                using RSA key 0x3C2525ED14360CDE
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>"
# gpg:                 aka "Peter Maydell <pmaydell@gmail.com>"
# gpg:                 aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>"
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83  15CF 3C25 25ED 1436 0CDE

* remotes/pmaydell/tags/pull-target-arm-20160614-2: (30 commits)
  target-arm: Don't permit ARMv8-only Neon insns on ARMv7
  arm: xlnx-zynqmp: Add xlnx-dp and xlnx-dpdma
  introduce xlnx-dp
  introduce xlnx-dpdma
  hw/i2c-ddc.c: Implement DDC I2C slave
  introduce dpcd module
  introduce aux-bus
  i2c: Factor our send() and recv() common logic
  i2c: implement broadcast write
  i2cbus: remove unused dev field
  hw/sd: QOM'ify pl181.c
  hw/dma: QOM'ify pxa2xx_dma.c
  hw/misc: QOM'ify mst_fpga.c
  hw/misc: QOM'ify exynos4210_pmu.c
  hw/misc: QOM'ify arm_l2x0.c
  hw/gpio: QOM'ify zaurus.c
  hw/gpio: QOM'ify pl061.c
  hw/gpio: QOM'ify omap_gpio.c
  hw/i2c: QOM'ify versatile_i2c.c
  hw/i2c: QOM'ify omap_i2c.c
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--default-configs/aarch64-softmmu.mak3
-rw-r--r--hw/arm/virt-acpi-build.c4
-rw-r--r--hw/arm/virt.c99
-rw-r--r--hw/arm/xlnx-zynqmp.c32
-rw-r--r--hw/display/Makefile.objs2
-rw-r--r--hw/display/dpcd.c173
-rw-r--r--hw/display/xlnx_dp.c1336
-rw-r--r--hw/dma/Makefile.objs1
-rw-r--r--hw/dma/pxa2xx_dma.c38
-rw-r--r--hw/dma/xlnx_dpdma.c786
-rw-r--r--hw/gpio/omap_gpio.c61
-rw-r--r--hw/gpio/pl061.c24
-rw-r--r--hw/gpio/zaurus.c14
-rw-r--r--hw/i2c/Makefile.objs1
-rw-r--r--hw/i2c/bitbang_i2c.c14
-rw-r--r--hw/i2c/core.c161
-rw-r--r--hw/i2c/exynos4210_i2c.c13
-rw-r--r--hw/i2c/i2c-ddc.c308
-rw-r--r--hw/i2c/omap_i2c.c42
-rw-r--r--hw/i2c/versatile_i2c.c19
-rw-r--r--hw/misc/Makefile.objs1
-rw-r--r--hw/misc/arm_l2x0.c11
-rw-r--r--hw/misc/aux.c292
-rw-r--r--hw/misc/exynos4210_pmu.c11
-rw-r--r--hw/misc/mst_fpga.c13
-rw-r--r--hw/sd/pl181.c26
-rw-r--r--include/hw/arm/virt.h4
-rw-r--r--include/hw/arm/xlnx-zynqmp.h4
-rw-r--r--include/hw/display/dpcd.h105
-rw-r--r--include/hw/display/xlnx_dp.h109
-rw-r--r--include/hw/dma/xlnx_dpdma.h85
-rw-r--r--include/hw/i2c/i2c-ddc.h38
-rw-r--r--include/hw/i2c/i2c.h1
-rw-r--r--include/hw/misc/aux.h128
-rw-r--r--target-arm/cpu.h2
-rw-r--r--target-arm/helper.c5
-rw-r--r--target-arm/kvm32.c6
-rw-r--r--target-arm/kvm64.c46
-rw-r--r--target-arm/kvm_arm.h7
-rw-r--r--target-arm/translate.c28
40 files changed, 3830 insertions, 223 deletions
diff --git a/default-configs/aarch64-softmmu.mak b/default-configs/aarch64-softmmu.mak
index 96dd994b3c..24494832cf 100644
--- a/default-configs/aarch64-softmmu.mak
+++ b/default-configs/aarch64-softmmu.mak
@@ -3,4 +3,7 @@
 # We support all the 32 bit boards so need all their config
 include arm-softmmu.mak
 
+CONFIG_AUX=y
+CONFIG_DDC=y
+CONFIG_DPCD=y
 CONFIG_XLNX_ZYNQMP=y
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 735ab864a0..1fa0581e33 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -538,6 +538,10 @@ build_madt(GArray *table_data, BIOSLinker *linker, VirtGuestInfo *guest_info)
         gicc->arm_mpidr = armcpu->mp_affinity;
         gicc->uid = i;
         gicc->flags = cpu_to_le32(ACPI_GICC_ENABLED);
+
+        if (armcpu->has_pmu) {
+            gicc->performance_interrupt = cpu_to_le32(PPI(VIRTUAL_PMU_IRQ));
+        }
     }
 
     if (guest_info->gic_version == 3) {
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 73113cfc4d..c5c125e920 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -42,6 +42,7 @@
 #include "sysemu/sysemu.h"
 #include "sysemu/kvm.h"
 #include "hw/boards.h"
+#include "hw/compat.h"
 #include "hw/loader.h"
 #include "exec/address-spaces.h"
 #include "qemu/bitops.h"
@@ -98,6 +99,36 @@ typedef struct {
 #define VIRT_MACHINE_CLASS(klass) \
     OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE)
 
+
+#define DEFINE_VIRT_MACHINE_LATEST(major, minor, latest) \
+    static void virt_##major##_##minor##_class_init(ObjectClass *oc, \
+                                                    void *data) \
+    { \
+        MachineClass *mc = MACHINE_CLASS(oc); \
+        virt_machine_##major##_##minor##_options(mc); \
+        mc->desc = "QEMU " # major "." # minor " ARM Virtual Machine"; \
+        if (latest) { \
+            mc->alias = "virt"; \
+        } \
+    } \
+    static const TypeInfo machvirt_##major##_##minor##_info = { \
+        .name = MACHINE_TYPE_NAME("virt-" # major "." # minor), \
+        .parent = TYPE_VIRT_MACHINE, \
+        .instance_init = virt_##major##_##minor##_instance_init, \
+        .class_init = virt_##major##_##minor##_class_init, \
+    }; \
+    static void machvirt_machine_##major##_##minor##_init(void) \
+    { \
+        type_register_static(&machvirt_##major##_##minor##_info); \
+    } \
+    type_init(machvirt_machine_##major##_##minor##_init);
+
+#define DEFINE_VIRT_MACHINE_AS_LATEST(major, minor) \
+    DEFINE_VIRT_MACHINE_LATEST(major, minor, true)
+#define DEFINE_VIRT_MACHINE(major, minor) \
+    DEFINE_VIRT_MACHINE_LATEST(major, minor, false)
+
+
 /* RAM limit in GB. Since VIRT_MEM starts at the 1GB mark, this means
  * RAM can go up to the 256GB mark, leaving 256GB of the physical
  * address space unallocated and free for future use between 256G and 512G.
@@ -436,6 +467,37 @@ static void fdt_add_gic_node(VirtBoardInfo *vbi, int type)
     qemu_fdt_setprop_cell(vbi->fdt, "/intc", "phandle", vbi->gic_phandle);
 }
 
+static void fdt_add_pmu_nodes(const VirtBoardInfo *vbi, int gictype)
+{
+    CPUState *cpu;
+    ARMCPU *armcpu;
+    uint32_t irqflags = GIC_FDT_IRQ_FLAGS_LEVEL_HI;
+
+    CPU_FOREACH(cpu) {
+        armcpu = ARM_CPU(cpu);
+        if (!armcpu->has_pmu ||
+            !kvm_arm_pmu_create(cpu, PPI(VIRTUAL_PMU_IRQ))) {
+            return;
+        }
+    }
+
+    if (gictype == 2) {
+        irqflags = deposit32(irqflags, GIC_FDT_IRQ_PPI_CPU_START,
+                             GIC_FDT_IRQ_PPI_CPU_WIDTH,
+                             (1 << vbi->smp_cpus) - 1);
+    }
+
+    armcpu = ARM_CPU(qemu_get_cpu(0));
+    qemu_fdt_add_subnode(vbi->fdt, "/pmu");
+    if (arm_feature(&armcpu->env, ARM_FEATURE_V8)) {
+        const char compat[] = "arm,armv8-pmuv3";
+        qemu_fdt_setprop(vbi->fdt, "/pmu", "compatible",
+                         compat, sizeof(compat));
+        qemu_fdt_setprop_cells(vbi->fdt, "/pmu", "interrupts",
+                               GIC_FDT_IRQ_TYPE_PPI, VIRTUAL_PMU_IRQ, irqflags);
+    }
+}
+
 static void create_v2m(VirtBoardInfo *vbi, qemu_irq *pic)
 {
     int i;
@@ -1259,6 +1321,8 @@ static void machvirt_init(MachineState *machine)
 
     create_gic(vbi, pic, gic_version, vms->secure);
 
+    fdt_add_pmu_nodes(vbi, gic_version);
+
     create_uart(vbi, pic, VIRT_UART, sysmem, serial_hds[0]);
 
     if (vms->secure) {
@@ -1387,7 +1451,13 @@ static const TypeInfo virt_machine_info = {
     .class_init    = virt_machine_class_init,
 };
 
-static void virt_2_6_instance_init(Object *obj)
+static void machvirt_machine_init(void)
+{
+    type_register_static(&virt_machine_info);
+}
+type_init(machvirt_machine_init);
+
+static void virt_2_7_instance_init(Object *obj)
 {
     VirtMachineState *vms = VIRT_MACHINE(obj);
 
@@ -1420,25 +1490,22 @@ static void virt_2_6_instance_init(Object *obj)
                                     "Valid values are 2, 3 and host", NULL);
 }
 
-static void virt_2_6_class_init(ObjectClass *oc, void *data)
+static void virt_machine_2_7_options(MachineClass *mc)
 {
-    MachineClass *mc = MACHINE_CLASS(oc);
-
-    mc->desc = "QEMU 2.6 ARM Virtual Machine";
-    mc->alias = "virt";
 }
+DEFINE_VIRT_MACHINE_AS_LATEST(2, 7)
 
-static const TypeInfo machvirt_info = {
-    .name = MACHINE_TYPE_NAME("virt-2.6"),
-    .parent = TYPE_VIRT_MACHINE,
-    .instance_init = virt_2_6_instance_init,
-    .class_init = virt_2_6_class_init,
-};
+#define VIRT_COMPAT_2_6 \
+    HW_COMPAT_2_6
 
-static void machvirt_machine_init(void)
+static void virt_2_6_instance_init(Object *obj)
 {
-    type_register_static(&virt_machine_info);
-    type_register_static(&machvirt_info);
+    virt_2_7_instance_init(obj);
 }
 
-type_init(machvirt_machine_init);
+static void virt_machine_2_6_options(MachineClass *mc)
+{
+    virt_machine_2_7_options(mc);
+    SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_6);
+}
+DEFINE_VIRT_MACHINE(2, 6)
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 308d6770c0..23c7199867 100644
--- a/hw/arm/xlnx-zynqmp.c
+++ b/hw/arm/xlnx-zynqmp.c
@@ -38,6 +38,12 @@
 #define SATA_ADDR           0xFD0C0000
 #define SATA_NUM_PORTS      2
 
+#define DP_ADDR             0xfd4a0000
+#define DP_IRQ              113
+
+#define DPDMA_ADDR          0xfd4c0000
+#define DPDMA_IRQ           116
+
 static const uint64_t gem_addr[XLNX_ZYNQMP_NUM_GEMS] = {
     0xFF0B0000, 0xFF0C0000, 0xFF0D0000, 0xFF0E0000,
 };
@@ -165,6 +171,12 @@ static void xlnx_zynqmp_init(Object *obj)
                           TYPE_XILINX_SPIPS);
         qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
     }
+
+    object_initialize(&s->dp, sizeof(s->dp), TYPE_XLNX_DP);
+    qdev_set_parent_bus(DEVICE(&s->dp), sysbus_get_default());
+
+    object_initialize(&s->dpdma, sizeof(s->dpdma), TYPE_XLNX_DPDMA);
+    qdev_set_parent_bus(DEVICE(&s->dpdma), sysbus_get_default());
 }
 
 static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
@@ -388,8 +400,26 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
         object_property_add_alias(OBJECT(s), bus_name,
                                   OBJECT(&s->spi[i]), "spi0",
                                   &error_abort);
-	g_free(bus_name);
+        g_free(bus_name);
+    }
+
+    object_property_set_bool(OBJECT(&s->dp), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
+    }
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->dp), 0, DP_ADDR);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->dp), 0, gic_spi[DP_IRQ]);
+
+    object_property_set_bool(OBJECT(&s->dpdma), true, "realized", &err);
+    if (err) {
+        error_propagate(errp, err);
+        return;
     }
+    object_property_set_link(OBJECT(&s->dp), OBJECT(&s->dpdma), "dpdma",
+                             &error_abort);
+    sysbus_mmio_map(SYS_BUS_DEVICE(&s->dpdma), 0, DPDMA_ADDR);
+    sysbus_connect_irq(SYS_BUS_DEVICE(&s->dpdma), 0, gic_spi[DPDMA_IRQ]);
 }
 
 static Property xlnx_zynqmp_props[] = {
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index d99780eeb9..063889beaf 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -43,3 +43,5 @@ virtio-gpu.o-cflags := $(VIRGL_CFLAGS)
 virtio-gpu.o-libs += $(VIRGL_LIBS)
 virtio-gpu-3d.o-cflags := $(VIRGL_CFLAGS)
 virtio-gpu-3d.o-libs += $(VIRGL_LIBS)
+obj-$(CONFIG_DPCD) += dpcd.o
+obj-$(CONFIG_XLNX_ZYNQMP) += xlnx_dp.o
diff --git a/hw/display/dpcd.c b/hw/display/dpcd.c
new file mode 100644
index 0000000000..5a36855240
--- /dev/null
+++ b/hw/display/dpcd.c
@@ -0,0 +1,173 @@
+/*
+ * dpcd.c
+ *
+ *  Copyright (C) 2015 : GreenSocs Ltd
+ *      http://www.greensocs.com/ , email: info@greensocs.com
+ *
+ *  Developed by :
+ *  Frederic Konrad   <fred.konrad@greensocs.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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * This is a simple AUX slave which emulates a connected screen.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/misc/aux.h"
+#include "hw/display/dpcd.h"
+
+#ifndef DEBUG_DPCD
+#define DEBUG_DPCD 0
+#endif
+
+#define DPRINTF(fmt, ...) do {                                                 \
+    if (DEBUG_DPCD) {                                                          \
+        qemu_log("dpcd: " fmt, ## __VA_ARGS__);                                \
+    }                                                                          \
+} while (0);
+
+#define DPCD_READABLE_AREA                      0x600
+
+struct DPCDState {
+    /*< private >*/
+    AUXSlave parent_obj;
+
+    /*< public >*/
+    /*
+     * The DCPD is 0x7FFFF length but read as 0 after offset 0x5FF.
+     */
+    uint8_t dpcd_info[DPCD_READABLE_AREA];
+
+    MemoryRegion iomem;
+};
+
+static uint64_t dpcd_read(void *opaque, hwaddr offset, unsigned size)
+{
+    uint8_t ret;
+    DPCDState *e = DPCD(opaque);
+
+    if (offset < DPCD_READABLE_AREA) {
+        ret = e->dpcd_info[offset];
+    } else {
+        qemu_log_mask(LOG_GUEST_ERROR, "dpcd: Bad offset 0x%" HWADDR_PRIX "\n",
+                                       offset);
+        ret = 0;
+    }
+
+    DPRINTF("read 0x%" PRIX8 " @0x%" HWADDR_PRIX "\n", ret, offset);
+    return ret;
+}
+
+static void dpcd_write(void *opaque, hwaddr offset, uint64_t value,
+                       unsigned size)
+{
+    DPCDState *e = DPCD(opaque);
+
+    DPRINTF("write 0x%" PRIX8 " @0x%" HWADDR_PRIX "\n", (uint8_t)value, offset);
+
+    if (offset < DPCD_READABLE_AREA) {
+        e->dpcd_info[offset] = value;
+    } else {
+        qemu_log_mask(LOG_GUEST_ERROR, "dpcd: Bad offset 0x%" HWADDR_PRIX "\n",
+                                       offset);
+    }
+}
+
+static const MemoryRegionOps aux_ops = {
+    .read = dpcd_read,
+    .write = dpcd_write,
+    .valid = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+    .impl = {
+        .min_access_size = 1,
+        .max_access_size = 1,
+    },
+};
+
+static void dpcd_reset(DeviceState *dev)
+{
+    DPCDState *s = DPCD(dev);
+
+    memset(&(s->dpcd_info), 0, sizeof(s->dpcd_info));
+
+    s->dpcd_info[DPCD_REVISION] = DPCD_REV_1_0;
+    s->dpcd_info[DPCD_MAX_LINK_RATE] = DPCD_5_4GBPS;
+    s->dpcd_info[DPCD_MAX_LANE_COUNT] = DPCD_FOUR_LANES;
+    s->dpcd_info[DPCD_RECEIVE_PORT0_CAP_0] = DPCD_EDID_PRESENT;
+    /* buffer size */
+    s->dpcd_info[DPCD_RECEIVE_PORT0_CAP_1] = 0xFF;
+
+    s->dpcd_info[DPCD_LANE0_1_STATUS] = DPCD_LANE0_CR_DONE
+                                      | DPCD_LANE0_CHANNEL_EQ_DONE
+                                      | DPCD_LANE0_SYMBOL_LOCKED
+                                      | DPCD_LANE1_CR_DONE
+                                      | DPCD_LANE1_CHANNEL_EQ_DONE
+                                      | DPCD_LANE1_SYMBOL_LOCKED;
+    s->dpcd_info[DPCD_LANE2_3_STATUS] = DPCD_LANE2_CR_DONE
+                                      | DPCD_LANE2_CHANNEL_EQ_DONE
+                                      | DPCD_LANE2_SYMBOL_LOCKED
+                                      | DPCD_LANE3_CR_DONE
+                                      | DPCD_LANE3_CHANNEL_EQ_DONE
+                                      | DPCD_LANE3_SYMBOL_LOCKED;
+
+    s->dpcd_info[DPCD_LANE_ALIGN_STATUS_UPDATED] = DPCD_INTERLANE_ALIGN_DONE;
+    s->dpcd_info[DPCD_SINK_STATUS] = DPCD_RECEIVE_PORT_0_STATUS;
+}
+
+static void dpcd_init(Object *obj)
+{
+    DPCDState *s = DPCD(obj);
+
+    memory_region_init_io(&s->iomem, obj, &aux_ops, s, TYPE_DPCD, 0x7FFFF);
+    aux_init_mmio(AUX_SLAVE(obj), &s->iomem);
+}
+
+static const VMStateDescription vmstate_dpcd = {
+    .name = TYPE_DPCD,
+    .version_id = 0,
+    .minimum_version_id = 0,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT8_ARRAY_V(dpcd_info, DPCDState, DPCD_READABLE_AREA, 0),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void dpcd_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->reset = dpcd_reset;
+    dc->vmsd = &vmstate_dpcd;
+}
+
+static const TypeInfo dpcd_info = {
+    .name          = TYPE_DPCD,
+    .parent        = TYPE_AUX_SLAVE,
+    .instance_size = sizeof(DPCDState),
+    .class_init    = dpcd_class_init,
+    .instance_init = dpcd_init,
+};
+
+static void dpcd_register_types(void)
+{
+    type_register_static(&dpcd_info);
+}
+
+type_init(dpcd_register_types)
diff --git a/hw/display/xlnx_dp.c b/hw/display/xlnx_dp.c
new file mode 100644
index 0000000000..be53b756c3
--- /dev/null
+++ b/hw/display/xlnx_dp.c
@@ -0,0 +1,1336 @@
+/*
+ * xlnx_dp.c
+ *
+ *  Copyright (C) 2015 : GreenSocs Ltd
+ *      http://www.greensocs.com/ , email: info@greensocs.com
+ *
+ *  Developed by :
+ *  Frederic Konrad   <fred.konrad@greensocs.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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/display/xlnx_dp.h"
+
+#ifndef DEBUG_DP
+#define DEBUG_DP 0
+#endif
+
+#define DPRINTF(fmt, ...) do {                                                 \
+    if (DEBUG_DP) {                                                            \
+        qemu_log("xlnx_dp: " fmt , ## __VA_ARGS__);                            \
+    }                                                                          \
+} while (0);
+
+/*
+ * Register offset for DP.
+ */
+#define DP_LINK_BW_SET                      (0x0000 >> 2)
+#define DP_LANE_COUNT_SET                   (0x0004 >> 2)
+#define DP_ENHANCED_FRAME_EN                (0x0008 >> 2)
+#define DP_TRAINING_PATTERN_SET             (0x000C >> 2)
+#define DP_LINK_QUAL_PATTERN_SET            (0x0010 >> 2)
+#define DP_SCRAMBLING_DISABLE               (0x0014 >> 2)
+#define DP_DOWNSPREAD_CTRL                  (0x0018 >> 2)
+#define DP_SOFTWARE_RESET                   (0x001C >> 2)
+#define DP_TRANSMITTER_ENABLE               (0x0080 >> 2)
+#define DP_MAIN_STREAM_ENABLE               (0x0084 >> 2)
+#define DP_FORCE_SCRAMBLER_RESET            (0x00C0 >> 2)
+#define DP_VERSION_REGISTER                 (0x00F8 >> 2)
+#define DP_CORE_ID                          (0x00FC >> 2)
+
+#define DP_AUX_COMMAND_REGISTER             (0x0100 >> 2)
+#define AUX_ADDR_ONLY_MASK                  (0x1000)
+#define AUX_COMMAND_MASK                    (0x0F00)
+#define AUX_COMMAND_SHIFT                   (8)
+#define AUX_COMMAND_NBYTES                  (0x000F)
+
+#define DP_AUX_WRITE_FIFO                   (0x0104 >> 2)
+#define DP_AUX_ADDRESS                      (0x0108 >> 2)
+#define DP_AUX_CLOCK_DIVIDER                (0x010C >> 2)
+#define DP_TX_USER_FIFO_OVERFLOW            (0x0110 >> 2)
+#define DP_INTERRUPT_SIGNAL_STATE           (0x0130 >> 2)
+#define DP_AUX_REPLY_DATA                   (0x0134 >> 2)
+#define DP_AUX_REPLY_CODE                   (0x0138 >> 2)
+#define DP_AUX_REPLY_COUNT                  (0x013C >> 2)
+#define DP_REPLY_DATA_COUNT                 (0x0148 >> 2)
+#define DP_REPLY_STATUS                     (0x014C >> 2)
+#define DP_HPD_DURATION                     (0x0150 >> 2)
+#define DP_MAIN_STREAM_HTOTAL               (0x0180 >> 2)
+#define DP_MAIN_STREAM_VTOTAL               (0x0184 >> 2)
+#define DP_MAIN_STREAM_POLARITY             (0x0188 >> 2)
+#define DP_MAIN_STREAM_HSWIDTH              (0x018C >> 2)
+#define DP_MAIN_STREAM_VSWIDTH              (0x0190 >> 2)
+#define DP_MAIN_STREAM_HRES                 (0x0194 >> 2)
+#define DP_MAIN_STREAM_VRES                 (0x0198 >> 2)
+#define DP_MAIN_STREAM_HSTART               (0x019C >> 2)
+#define DP_MAIN_STREAM_VSTART               (0x01A0 >> 2)
+#define DP_MAIN_STREAM_MISC0                (0x01A4 >> 2)
+#define DP_MAIN_STREAM_MISC1                (0x01A8 >> 2)
+#define DP_MAIN_STREAM_M_VID                (0x01AC >> 2)
+#define DP_MSA_TRANSFER_UNIT_SIZE           (0x01B0 >> 2)
+#define DP_MAIN_STREAM_N_VID                (0x01B4 >> 2)
+#define DP_USER_DATA_COUNT_PER_LANE         (0x01BC >> 2)
+#define DP_MIN_BYTES_PER_TU                 (0x01C4 >> 2)
+#define DP_FRAC_BYTES_PER_TU                (0x01C8 >> 2)
+#define DP_INIT_WAIT                        (0x01CC >> 2)
+#define DP_PHY_RESET                        (0x0200 >> 2)
+#define DP_PHY_VOLTAGE_DIFF_LANE_0          (0x0220 >> 2)
+#define DP_PHY_VOLTAGE_DIFF_LANE_1          (0x0224 >> 2)
+#define DP_TRANSMIT_PRBS7                   (0x0230 >> 2)
+#define DP_PHY_CLOCK_SELECT                 (0x0234 >> 2)
+#define DP_TX_PHY_POWER_DOWN                (0x0238 >> 2)
+#define DP_PHY_PRECURSOR_LANE_0             (0x023C >> 2)
+#define DP_PHY_PRECURSOR_LANE_1             (0x0240 >> 2)
+#define DP_PHY_POSTCURSOR_LANE_0            (0x024C >> 2)
+#define DP_PHY_POSTCURSOR_LANE_1            (0x0250 >> 2)
+#define DP_PHY_STATUS                       (0x0280 >> 2)
+
+#define DP_TX_AUDIO_CONTROL                 (0x0300 >> 2)
+#define DP_TX_AUD_CTRL                      (1)
+
+#define DP_TX_AUDIO_CHANNELS                (0x0304 >> 2)
+#define DP_TX_AUDIO_INFO_DATA(n)            ((0x0308 + 4 * n) >> 2)
+#define DP_TX_M_AUD                         (0x0328 >> 2)
+#define DP_TX_N_AUD                         (0x032C >> 2)
+#define DP_TX_AUDIO_EXT_DATA(n)             ((0x0330 + 4 * n) >> 2)
+#define DP_INT_STATUS                       (0x03A0 >> 2)
+#define DP_INT_MASK                         (0x03A4 >> 2)
+#define DP_INT_EN                           (0x03A8 >> 2)
+#define DP_INT_DS                           (0x03AC >> 2)
+
+/*
+ * Registers offset for Audio Video Buffer configuration.
+ */
+#define V_BLEND_OFFSET                      (0xA000)
+#define V_BLEND_BG_CLR_0                    (0x0000 >> 2)
+#define V_BLEND_BG_CLR_1                    (0x0004 >> 2)
+#define V_BLEND_BG_CLR_2                    (0x0008 >> 2)
+#define V_BLEND_SET_GLOBAL_ALPHA_REG        (0x000C >> 2)
+#define V_BLEND_OUTPUT_VID_FORMAT           (0x0014 >> 2)
+#define V_BLEND_LAYER0_CONTROL              (0x0018 >> 2)
+#define V_BLEND_LAYER1_CONTROL              (0x001C >> 2)
+
+#define V_BLEND_RGB2YCBCR_COEFF(n)          ((0x0020 + 4 * n) >> 2)
+#define V_BLEND_IN1CSC_COEFF(n)             ((0x0044 + 4 * n) >> 2)
+
+#define V_BLEND_LUMA_IN1CSC_OFFSET          (0x0068 >> 2)
+#define V_BLEND_CR_IN1CSC_OFFSET            (0x006C >> 2)
+#define V_BLEND_CB_IN1CSC_OFFSET            (0x0070 >> 2)
+#define V_BLEND_LUMA_OUTCSC_OFFSET          (0x0074 >> 2)
+#define V_BLEND_CR_OUTCSC_OFFSET            (0x0078 >> 2)
+#define V_BLEND_CB_OUTCSC_OFFSET            (0x007C >> 2)
+
+#define V_BLEND_IN2CSC_COEFF(n)             ((0x0080 + 4 * n) >> 2)
+
+#define V_BLEND_LUMA_IN2CSC_OFFSET          (0x00A4 >> 2)
+#define V_BLEND_CR_IN2CSC_OFFSET            (0x00A8 >> 2)
+#define V_BLEND_CB_IN2CSC_OFFSET            (0x00AC >> 2)
+#define V_BLEND_CHROMA_KEY_ENABLE           (0x01D0 >> 2)
+#define V_BLEND_CHROMA_KEY_COMP1            (0x01D4 >> 2)
+#define V_BLEND_CHROMA_KEY_COMP2            (0x01D8 >> 2)
+#define V_BLEND_CHROMA_KEY_COMP3            (0x01DC >> 2)
+
+/*
+ * Registers offset for Audio Video Buffer configuration.
+ */
+#define AV_BUF_MANAGER_OFFSET               (0xB000)
+#define AV_BUF_FORMAT                       (0x0000 >> 2)
+#define AV_BUF_NON_LIVE_LATENCY             (0x0008 >> 2)
+#define AV_CHBUF0                           (0x0010 >> 2)
+#define AV_CHBUF1                           (0x0014 >> 2)
+#define AV_CHBUF2                           (0x0018 >> 2)
+#define AV_CHBUF3                           (0x001C >> 2)
+#define AV_CHBUF4                           (0x0020 >> 2)
+#define AV_CHBUF5                           (0x0024 >> 2)
+#define AV_BUF_STC_CONTROL                  (0x002C >> 2)
+#define AV_BUF_STC_INIT_VALUE0              (0x0030 >> 2)
+#define AV_BUF_STC_INIT_VALUE1              (0x0034 >> 2)
+#define AV_BUF_STC_ADJ                      (0x0038 >> 2)
+#define AV_BUF_STC_VIDEO_VSYNC_TS_REG0      (0x003C >> 2)
+#define AV_BUF_STC_VIDEO_VSYNC_TS_REG1      (0x0040 >> 2)
+#define AV_BUF_STC_EXT_VSYNC_TS_REG0        (0x0044 >> 2)
+#define AV_BUF_STC_EXT_VSYNC_TS_REG1        (0x0048 >> 2)
+#define AV_BUF_STC_CUSTOM_EVENT_TS_REG0     (0x004C >> 2)
+#define AV_BUF_STC_CUSTOM_EVENT_TS_REG1     (0x0050 >> 2)
+#define AV_BUF_STC_CUSTOM_EVENT2_TS_REG0    (0x0054 >> 2)
+#define AV_BUF_STC_CUSTOM_EVENT2_TS_REG1    (0x0058 >> 2)
+#define AV_BUF_STC_SNAPSHOT0                (0x0060 >> 2)
+#define AV_BUF_STC_SNAPSHOT1                (0x0064 >> 2)
+#define AV_BUF_OUTPUT_AUDIO_VIDEO_SELECT    (0x0070 >> 2)
+#define AV_BUF_HCOUNT_VCOUNT_INT0           (0x0074 >> 2)
+#define AV_BUF_HCOUNT_VCOUNT_INT1           (0x0078 >> 2)
+#define AV_BUF_DITHER_CONFIG                (0x007C >> 2)
+#define AV_BUF_DITHER_CONFIG_MAX            (0x008C >> 2)
+#define AV_BUF_DITHER_CONFIG_MIN            (0x0090 >> 2)
+#define AV_BUF_PATTERN_GEN_SELECT           (0x0100 >> 2)
+#define AV_BUF_AUD_VID_CLK_SOURCE           (0x0120 >> 2)
+#define AV_BUF_SRST_REG                     (0x0124 >> 2)
+#define AV_BUF_AUDIO_RDY_INTERVAL           (0x0128 >> 2)
+#define AV_BUF_AUDIO_CH_CONFIG              (0x012C >> 2)
+
+#define AV_BUF_GRAPHICS_COMP_SCALE_FACTOR(n)((0x0200 + 4 * n) >> 2)
+
+#define AV_BUF_VIDEO_COMP_SCALE_FACTOR(n)   ((0x020C + 4 * n) >> 2)
+
+#define AV_BUF_LIVE_VIDEO_COMP_SF(n)        ((0x0218 + 4 * n) >> 2)
+
+#define AV_BUF_LIVE_VID_CONFIG              (0x0224 >> 2)
+
+#define AV_BUF_LIVE_GFX_COMP_SF(n)          ((0x0228 + 4 * n) >> 2)
+
+#define AV_BUF_LIVE_GFX_CONFIG              (0x0234 >> 2)
+
+#define AUDIO_MIXER_REGISTER_OFFSET         (0xC000)
+#define AUDIO_MIXER_VOLUME_CONTROL          (0x0000 >> 2)
+#define AUDIO_MIXER_META_DATA               (0x0004 >> 2)
+#define AUD_CH_STATUS_REG(n)                ((0x0008 + 4 * n) >> 2)
+#define AUD_CH_A_DATA_REG(n)                ((0x0020 + 4 * n) >> 2)
+#define AUD_CH_B_DATA_REG(n)                ((0x0038 + 4 * n) >> 2)
+
+#define DP_AUDIO_DMA_CHANNEL(n)             (4 + n)
+#define DP_GRAPHIC_DMA_CHANNEL              (3)
+#define DP_VIDEO_DMA_CHANNEL                (0)
+
+enum DPGraphicFmt {
+    DP_GRAPHIC_RGBA8888 = 0 << 8,
+    DP_GRAPHIC_ABGR8888 = 1 << 8,
+    DP_GRAPHIC_RGB888 = 2 << 8,
+    DP_GRAPHIC_BGR888 = 3 << 8,
+    DP_GRAPHIC_RGBA5551 = 4 << 8,
+    DP_GRAPHIC_RGBA4444 = 5 << 8,
+    DP_GRAPHIC_RGB565 = 6 << 8,
+    DP_GRAPHIC_8BPP = 7 << 8,
+    DP_GRAPHIC_4BPP = 8 << 8,
+    DP_GRAPHIC_2BPP = 9 << 8,
+    DP_GRAPHIC_1BPP = 10 << 8,
+    DP_GRAPHIC_MASK = 0xF << 8
+};
+
+enum DPVideoFmt {
+    DP_NL_VID_CB_Y0_CR_Y1 = 0,
+    DP_NL_VID_CR_Y0_CB_Y1 = 1,
+    DP_NL_VID_Y0_CR_Y1_CB = 2,
+    DP_NL_VID_Y0_CB_Y1_CR = 3,
+    DP_NL_VID_YV16 = 4,
+    DP_NL_VID_YV24 = 5,
+    DP_NL_VID_YV16CL = 6,
+    DP_NL_VID_MONO = 7,
+    DP_NL_VID_YV16CL2 = 8,
+    DP_NL_VID_YUV444 = 9,
+    DP_NL_VID_RGB888 = 10,
+    DP_NL_VID_RGBA8880 = 11,
+    DP_NL_VID_RGB888_10BPC = 12,
+    DP_NL_VID_YUV444_10BPC = 13,
+    DP_NL_VID_YV16CL2_10BPC = 14,
+    DP_NL_VID_YV16CL_10BPC = 15,
+    DP_NL_VID_YV16_10BPC = 16,
+    DP_NL_VID_YV24_10BPC = 17,
+    DP_NL_VID_Y_ONLY_10BPC = 18,
+    DP_NL_VID_YV16_420 = 19,
+    DP_NL_VID_YV16CL_420 = 20,
+    DP_NL_VID_YV16CL2_420 = 21,
+    DP_NL_VID_YV16_420_10BPC = 22,
+    DP_NL_VID_YV16CL_420_10BPC = 23,
+    DP_NL_VID_YV16CL2_420_10BPC = 24,
+    DP_NL_VID_FMT_MASK = 0x1F
+};
+
+typedef enum DPGraphicFmt DPGraphicFmt;
+typedef enum DPVideoFmt DPVideoFmt;
+
+static const VMStateDescription vmstate_dp = {
+    .name = TYPE_XLNX_DP,
+    .version_id = 1,
+    .fields = (VMStateField[]){
+        VMSTATE_UINT32_ARRAY(core_registers, XlnxDPState,
+                             DP_CORE_REG_ARRAY_SIZE),
+        VMSTATE_UINT32_ARRAY(avbufm_registers, XlnxDPState,
+                             DP_AVBUF_REG_ARRAY_SIZE),
+        VMSTATE_UINT32_ARRAY(vblend_registers, XlnxDPState,
+                             DP_VBLEND_REG_ARRAY_SIZE),
+        VMSTATE_UINT32_ARRAY(audio_registers, XlnxDPState,
+                             DP_AUDIO_REG_ARRAY_SIZE),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void xlnx_dp_update_irq(XlnxDPState *s);
+
+static uint64_t xlnx_dp_audio_read(void *opaque, hwaddr offset, unsigned size)
+{
+    XlnxDPState *s = XLNX_DP(opaque);
+
+    offset = offset >> 2;
+    return s->audio_registers[offset];
+}
+
+static void xlnx_dp_audio_write(void *opaque, hwaddr offset, uint64_t value,
+                                unsigned size)
+{
+    XlnxDPState *s = XLNX_DP(opaque);
+
+    offset = offset >> 2;
+
+    switch (offset) {
+    case AUDIO_MIXER_META_DATA:
+        s->audio_registers[offset] = value & 0x00000001;
+        break;
+    default:
+        s->audio_registers[offset] = value;
+        break;
+    }
+}
+
+static const MemoryRegionOps audio_ops = {
+    .read = xlnx_dp_audio_read,
+    .write = xlnx_dp_audio_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+};
+
+static inline uint32_t xlnx_dp_audio_get_volume(XlnxDPState *s,
+                                                uint8_t channel)
+{
+    switch (channel) {
+    case 0:
+        return extract32(s->audio_registers[AUDIO_MIXER_VOLUME_CONTROL], 0, 16);
+    case 1:
+        return extract32(s->audio_registers[AUDIO_MIXER_VOLUME_CONTROL], 16,
+                                                                         16);
+    default:
+        return 0;
+    }
+}
+
+static inline void xlnx_dp_audio_activate(XlnxDPState *s)
+{
+    bool activated = ((s->core_registers[DP_TX_AUDIO_CONTROL]
+                   & DP_TX_AUD_CTRL) != 0);
+    AUD_set_active_out(s->amixer_output_stream, activated);
+    xlnx_dpdma_set_host_data_location(s->dpdma, DP_AUDIO_DMA_CHANNEL(0),
+                                      &s->audio_buffer_0);
+    xlnx_dpdma_set_host_data_location(s->dpdma, DP_AUDIO_DMA_CHANNEL(1),
+                                      &s->audio_buffer_1);
+}
+
+static inline void xlnx_dp_audio_mix_buffer(XlnxDPState *s)
+{
+    /*
+     * Audio packets are signed and have this shape:
+     * | 16 | 16 | 16 | 16 | 16 | 16 | 16 | 16 |
+     * | R3 | L3 | R2 | L2 | R1 | L1 | R0 | L0 |
+     *
+     * Output audio is 16bits saturated.
+     */
+    int i;
+
+    if ((s->audio_data_available[0]) && (xlnx_dp_audio_get_volume(s, 0))) {
+        for (i = 0; i < s->audio_data_available[0] / 2; i++) {
+            s->temp_buffer[i] = (int64_t)(s->audio_buffer_0[i])
+                              * xlnx_dp_audio_get_volume(s, 0) / 8192;
+        }
+        s->byte_left = s->audio_data_available[0];
+    } else {
+        memset(s->temp_buffer, 0, s->audio_data_available[1] / 2);
+    }
+
+    if ((s->audio_data_available[1]) && (xlnx_dp_audio_get_volume(s, 1))) {
+        if ((s->audio_data_available[0] == 0)
+        || (s->audio_data_available[1] == s->audio_data_available[0])) {
+            for (i = 0; i < s->audio_data_available[1] / 2; i++) {
+                s->temp_buffer[i] += (int64_t)(s->audio_buffer_1[i])
+                                   * xlnx_dp_audio_get_volume(s, 1) / 8192;
+            }
+            s->byte_left = s->audio_data_available[1];
+        }
+    }
+
+    for (i = 0; i < s->byte_left / 2; i++) {
+        s->out_buffer[i] = MAX(-32767, MIN(s->temp_buffer[i], 32767));
+    }
+
+    s->data_ptr = 0;
+}
+
+static void xlnx_dp_audio_callback(void *opaque, int avail)
+{
+    /*
+     * Get some data from the DPDMA and compute these datas.
+     * Then wait for QEMU's audio subsystem to call this callback.
+     */
+    XlnxDPState *s = XLNX_DP(opaque);
+    size_t written = 0;
+
+    /* If there are already some data don't get more data. */
+    if (s->byte_left == 0) {
+        s->audio_data_available[0] = xlnx_dpdma_start_operation(s->dpdma, 4,
+                                                                  true);
+        s->audio_data_available[1] = xlnx_dpdma_start_operation(s->dpdma, 5,
+                                                                  true);
+        xlnx_dp_audio_mix_buffer(s);
+    }
+
+    /* Send the buffer through the audio. */
+    if (s->byte_left <= MAX_QEMU_BUFFER_SIZE) {
+        if (s->byte_left != 0) {
+            written = AUD_write(s->amixer_output_stream,
+                                &s->out_buffer[s->data_ptr], s->byte_left);
+        } else {
+            /*
+             * There is nothing to play.. We don't have any data! Fill the
+             * buffer with zero's and send it.
+             */
+            written = 0;
+            memset(s->out_buffer, 0, 1024);
+            AUD_write(s->amixer_output_stream, s->out_buffer, 1024);
+        }
+    } else {
+        written = AUD_write(s->amixer_output_stream,
+                            &s->out_buffer[s->data_ptr], MAX_QEMU_BUFFER_SIZE);
+    }
+    s->byte_left -= written;
+    s->data_ptr += written;
+}
+
+/*
+ * AUX channel related function.
+ */
+static void xlnx_dp_aux_clear_rx_fifo(XlnxDPState *s)
+{
+    fifo8_reset(&s->rx_fifo);
+}
+
+static void xlnx_dp_aux_push_rx_fifo(XlnxDPState *s, uint8_t *buf, size_t len)
+{
+    DPRINTF("Push %u data in rx_fifo\n", (unsigned)len);
+    fifo8_push_all(&s->rx_fifo, buf, len);
+}
+
+static uint8_t xlnx_dp_aux_pop_rx_fifo(XlnxDPState *s)
+{
+    uint8_t ret;
+
+    if (fifo8_is_empty(&s->rx_fifo)) {
+        DPRINTF("rx_fifo underflow..\n");
+        abort();
+    }
+    ret = fifo8_pop(&s->rx_fifo);
+    DPRINTF("pop 0x%" PRIX8 " from rx_fifo.\n", ret);
+    return ret;
+}
+
+static void xlnx_dp_aux_clear_tx_fifo(XlnxDPState *s)
+{
+    fifo8_reset(&s->tx_fifo);
+}
+
+static void xlnx_dp_aux_push_tx_fifo(XlnxDPState *s, uint8_t val, size_t len)
+{
+    DPRINTF("Push %u data in tx_fifo\n", (unsigned)len);
+    fifo8_push_all(&s->tx_fifo, &val, len);
+}
+
+static uint8_t xlnx_dp_aux_pop_tx_fifo(XlnxDPState *s)
+{
+    uint8_t ret;
+
+    if (fifo8_is_empty(&s->tx_fifo)) {
+        DPRINTF("tx_fifo underflow..\n");
+        abort();
+    }
+    ret = fifo8_pop(&s->tx_fifo);
+    DPRINTF("pop 0x%2.2X from tx_fifo.\n", ret);
+    return ret;
+}
+
+static uint32_t xlnx_dp_aux_get_address(XlnxDPState *s)
+{
+    return s->core_registers[DP_AUX_ADDRESS];
+}
+
+/*
+ * Get command from the register.
+ */
+static void xlnx_dp_aux_set_command(XlnxDPState *s, uint32_t value)
+{
+    bool address_only = (value & AUX_ADDR_ONLY_MASK) != 0;
+    AUXCommand cmd = (value & AUX_COMMAND_MASK) >> AUX_COMMAND_SHIFT;
+    uint8_t nbytes = (value & AUX_COMMAND_NBYTES) + 1;
+    uint8_t buf[16];
+    int i;
+
+    /*
+     * When an address_only command is executed nothing happen to the fifo, so
+     * just make nbytes = 0.
+     */
+    if (address_only) {
+        nbytes = 0;
+    }
+
+    switch (cmd) {
+    case READ_AUX:
+    case READ_I2C:
+    case READ_I2C_MOT:
+        s->core_registers[DP_AUX_REPLY_CODE] = aux_request(s->aux_bus, cmd,
+                                               xlnx_dp_aux_get_address(s),
+                                               nbytes, buf);
+        s->core_registers[DP_REPLY_DATA_COUNT] = nbytes;
+
+        if (s->core_registers[DP_AUX_REPLY_CODE] == AUX_I2C_ACK) {
+            xlnx_dp_aux_push_rx_fifo(s, buf, nbytes);
+        }
+        break;
+    case WRITE_AUX:
+    case WRITE_I2C:
+    case WRITE_I2C_MOT:
+        for (i = 0; i < nbytes; i++) {
+            buf[i] = xlnx_dp_aux_pop_tx_fifo(s);
+        }
+        s->core_registers[DP_AUX_REPLY_CODE] = aux_request(s->aux_bus, cmd,
+                                               xlnx_dp_aux_get_address(s),
+                                               nbytes, buf);
+        xlnx_dp_aux_clear_tx_fifo(s);
+        break;
+    case WRITE_I2C_STATUS:
+        qemu_log_mask(LOG_UNIMP, "xlnx_dp: Write i2c status not implemented\n");
+        break;
+    default:
+        abort();
+    }
+
+    s->core_registers[DP_INTERRUPT_SIGNAL_STATE] |= 0x04;
+}
+
+static void xlnx_dp_set_dpdma(Object *obj, const char *name, Object *val,
+                              Error **errp)
+{
+    XlnxDPState *s = XLNX_DP(obj);
+    if (s->console) {
+        DisplaySurface *surface = qemu_console_surface(s->console);
+        XlnxDPDMAState *dma = XLNX_DPDMA(val);
+        xlnx_dpdma_set_host_data_location(dma, DP_GRAPHIC_DMA_CHANNEL,
+                                          surface_data(surface));
+    }
+}
+
+static inline uint8_t xlnx_dp_global_alpha_value(XlnxDPState *s)
+{
+    return (s->vblend_registers[V_BLEND_SET_GLOBAL_ALPHA_REG] & 0x1FE) >> 1;
+}
+
+static inline bool xlnx_dp_global_alpha_enabled(XlnxDPState *s)
+{
+    /*
+     * If the alpha is totally opaque (255) we consider the alpha is disabled to
+     * reduce CPU consumption.
+     */
+    return ((xlnx_dp_global_alpha_value(s) != 0xFF) &&
+           ((s->vblend_registers[V_BLEND_SET_GLOBAL_ALPHA_REG] & 0x01) != 0));
+}
+
+static void xlnx_dp_recreate_surface(XlnxDPState *s)
+{
+    /*
+     * Two possibilities, if blending is enabled the console displays
+     * bout_plane, if not g_plane is displayed.
+     */
+    uint16_t width = s->core_registers[DP_MAIN_STREAM_HRES];
+    uint16_t height = s->core_registers[DP_MAIN_STREAM_VRES];
+    DisplaySurface *current_console_surface = qemu_console_surface(s->console);
+
+    if ((width != 0) && (height != 0)) {
+        /*
+         * As dpy_gfx_replace_surface calls qemu_free_displaysurface on the
+         * surface we need to be carefull and don't free the surface associated
+         * to the console or double free will happen.
+         */
+        if (s->bout_plane.surface != current_console_surface) {
+            qemu_free_displaysurface(s->bout_plane.surface);
+        }
+        if (s->v_plane.surface != current_console_surface) {
+            qemu_free_displaysurface(s->v_plane.surface);
+        }
+        if (s->g_plane.surface != current_console_surface) {
+            qemu_free_displaysurface(s->g_plane.surface);
+        }
+
+        s->g_plane.surface
+                = qemu_create_displaysurface_from(width, height,
+                                                  s->g_plane.format, 0, NULL);
+        s->v_plane.surface
+                = qemu_create_displaysurface_from(width, height,
+                                                  s->v_plane.format, 0, NULL);
+        if (xlnx_dp_global_alpha_enabled(s)) {
+            s->bout_plane.surface =
+                            qemu_create_displaysurface_from(width,
+                                                            height,
+                                                            s->g_plane.format,
+                                                            0, NULL);
+            dpy_gfx_replace_surface(s->console, s->bout_plane.surface);
+        } else {
+            s->bout_plane.surface = NULL;
+            dpy_gfx_replace_surface(s->console, s->g_plane.surface);
+        }
+
+        xlnx_dpdma_set_host_data_location(s->dpdma, DP_GRAPHIC_DMA_CHANNEL,
+                                            surface_data(s->g_plane.surface));
+        xlnx_dpdma_set_host_data_location(s->dpdma, DP_VIDEO_DMA_CHANNEL,
+                                            surface_data(s->v_plane.surface));
+    }
+}
+
+/*
+ * Change the graphic format of the surface.
+ */
+static void xlnx_dp_change_graphic_fmt(XlnxDPState *s)
+{
+    switch (s->avbufm_registers[AV_BUF_FORMAT] & DP_GRAPHIC_MASK) {
+    case DP_GRAPHIC_RGBA8888:
+        s->g_plane.format = PIXMAN_r8g8b8a8;
+        break;
+    case DP_GRAPHIC_ABGR8888:
+        s->g_plane.format = PIXMAN_a8b8g8r8;
+        break;
+    case DP_GRAPHIC_RGB565:
+        s->g_plane.format = PIXMAN_r5g6b5;
+        break;
+    case DP_GRAPHIC_RGB888:
+        s->g_plane.format = PIXMAN_r8g8b8;
+        break;
+    case DP_GRAPHIC_BGR888:
+        s->g_plane.format = PIXMAN_b8g8r8;
+        break;
+    default:
+        DPRINTF("error: unsupported graphic format %u.\n",
+                s->avbufm_registers[AV_BUF_FORMAT] & DP_GRAPHIC_MASK);
+        abort();
+    }
+
+    switch (s->avbufm_registers[AV_BUF_FORMAT] & DP_NL_VID_FMT_MASK) {
+    case 0:
+        s->v_plane.format = PIXMAN_x8b8g8r8;
+        break;
+    case DP_NL_VID_RGBA8880:
+        s->v_plane.format = PIXMAN_x8b8g8r8;
+        break;
+    default:
+        DPRINTF("error: unsupported video format %u.\n",
+                s->avbufm_registers[AV_BUF_FORMAT] & DP_NL_VID_FMT_MASK);
+        abort();
+    }
+
+    xlnx_dp_recreate_surface(s);
+}
+
+static void xlnx_dp_update_irq(XlnxDPState *s)
+{
+    uint32_t flags;
+
+    flags = s->core_registers[DP_INT_STATUS] & ~s->core_registers[DP_INT_MASK];
+    DPRINTF("update IRQ value = %" PRIx32 "\n", flags);
+    qemu_set_irq(s->irq, flags != 0);
+}
+
+static uint64_t xlnx_dp_read(void *opaque, hwaddr offset, unsigned size)
+{
+    XlnxDPState *s = XLNX_DP(opaque);
+    uint64_t ret = 0;
+
+    offset = offset >> 2;
+
+    switch (offset) {
+    case DP_TX_USER_FIFO_OVERFLOW:
+        /* This register is cleared after a read */
+        ret = s->core_registers[DP_TX_USER_FIFO_OVERFLOW];
+        s->core_registers[DP_TX_USER_FIFO_OVERFLOW] = 0;
+        break;
+    case DP_AUX_REPLY_DATA:
+        ret = xlnx_dp_aux_pop_rx_fifo(s);
+        break;
+    case DP_INTERRUPT_SIGNAL_STATE:
+        /*
+         * XXX: Not sure it is the right thing to do actually.
+         * The register is not written by the device driver so it's stuck
+         * to 0x04.
+         */
+        ret = s->core_registers[DP_INTERRUPT_SIGNAL_STATE];
+        s->core_registers[DP_INTERRUPT_SIGNAL_STATE] &= ~0x04;
+        break;
+    case DP_AUX_WRITE_FIFO:
+    case DP_TX_AUDIO_INFO_DATA(0):
+    case DP_TX_AUDIO_INFO_DATA(1):
+    case DP_TX_AUDIO_INFO_DATA(2):
+    case DP_TX_AUDIO_INFO_DATA(3):
+    case DP_TX_AUDIO_INFO_DATA(4):
+    case DP_TX_AUDIO_INFO_DATA(5):
+    case DP_TX_AUDIO_INFO_DATA(6):
+    case DP_TX_AUDIO_INFO_DATA(7):
+    case DP_TX_AUDIO_EXT_DATA(0):
+    case DP_TX_AUDIO_EXT_DATA(1):
+    case DP_TX_AUDIO_EXT_DATA(2):
+    case DP_TX_AUDIO_EXT_DATA(3):
+    case DP_TX_AUDIO_EXT_DATA(4):
+    case DP_TX_AUDIO_EXT_DATA(5):
+    case DP_TX_AUDIO_EXT_DATA(6):
+    case DP_TX_AUDIO_EXT_DATA(7):
+    case DP_TX_AUDIO_EXT_DATA(8):
+        /* write only registers */
+        ret = 0;
+        break;
+    default:
+        assert(offset <= (0x3AC >> 2));
+        ret = s->core_registers[offset];
+        break;
+    }
+
+    DPRINTF("core read @%" PRIx64 " = 0x%8.8" PRIX64 "\n", offset << 2, ret);
+    return ret;
+}
+
+static void xlnx_dp_write(void *opaque, hwaddr offset, uint64_t value,
+                          unsigned size)
+{
+    XlnxDPState *s = XLNX_DP(opaque);
+
+    DPRINTF("core write @%" PRIx64 " = 0x%8.8" PRIX64 "\n", offset, value);
+
+    offset = offset >> 2;
+
+    switch (offset) {
+    /*
+     * Only special write case are handled.
+     */
+    case DP_LINK_BW_SET:
+        s->core_registers[offset] = value & 0x000000FF;
+        break;
+    case DP_LANE_COUNT_SET:
+    case DP_MAIN_STREAM_MISC0:
+        s->core_registers[offset] = value & 0x0000000F;
+        break;
+    case DP_TRAINING_PATTERN_SET:
+    case DP_LINK_QUAL_PATTERN_SET:
+    case DP_MAIN_STREAM_POLARITY:
+    case DP_PHY_VOLTAGE_DIFF_LANE_0:
+    case DP_PHY_VOLTAGE_DIFF_LANE_1:
+        s->core_registers[offset] = value & 0x00000003;
+        break;
+    case DP_ENHANCED_FRAME_EN:
+    case DP_SCRAMBLING_DISABLE:
+    case DP_DOWNSPREAD_CTRL:
+    case DP_MAIN_STREAM_ENABLE:
+    case DP_TRANSMIT_PRBS7:
+        s->core_registers[offset] = value & 0x00000001;
+        break;
+    case DP_PHY_CLOCK_SELECT:
+        s->core_registers[offset] = value & 0x00000007;
+        break;
+    case DP_SOFTWARE_RESET:
+        /*
+         * No need to update this bit as it's read '0'.
+         */
+        /*
+         * TODO: reset IP.
+         */
+        break;
+    case DP_TRANSMITTER_ENABLE:
+        s->core_registers[offset] = value & 0x01;
+        break;
+    case DP_FORCE_SCRAMBLER_RESET:
+        /*
+         * No need to update this bit as it's read '0'.
+         */
+        /*
+         * TODO: force a scrambler reset??
+         */
+        break;
+    case DP_AUX_COMMAND_REGISTER:
+        s->core_registers[offset] = value & 0x00001F0F;
+        xlnx_dp_aux_set_command(s, s->core_registers[offset]);
+        break;
+    case DP_MAIN_STREAM_HTOTAL:
+    case DP_MAIN_STREAM_VTOTAL:
+    case DP_MAIN_STREAM_HSTART:
+    case DP_MAIN_STREAM_VSTART:
+        s->core_registers[offset] = value & 0x0000FFFF;
+        break;
+    case DP_MAIN_STREAM_HRES:
+    case DP_MAIN_STREAM_VRES:
+        s->core_registers[offset] = value & 0x0000FFFF;
+        xlnx_dp_recreate_surface(s);
+        break;
+    case DP_MAIN_STREAM_HSWIDTH:
+    case DP_MAIN_STREAM_VSWIDTH:
+        s->core_registers[offset] = value & 0x00007FFF;
+        break;
+    case DP_MAIN_STREAM_MISC1:
+        s->core_registers[offset] = value & 0x00000086;
+        break;
+    case DP_MAIN_STREAM_M_VID:
+    case DP_MAIN_STREAM_N_VID:
+        s->core_registers[offset] = value & 0x00FFFFFF;
+        break;
+    case DP_MSA_TRANSFER_UNIT_SIZE:
+    case DP_MIN_BYTES_PER_TU:
+    case DP_INIT_WAIT:
+        s->core_registers[offset] = value & 0x00000007;
+        break;
+    case DP_USER_DATA_COUNT_PER_LANE:
+        s->core_registers[offset] = value & 0x0003FFFF;
+        break;
+    case DP_FRAC_BYTES_PER_TU:
+        s->core_registers[offset] = value & 0x000003FF;
+        break;
+    case DP_PHY_RESET:
+        s->core_registers[offset] = value & 0x00010003;
+        /*
+         * TODO: Reset something?
+         */
+        break;
+    case DP_TX_PHY_POWER_DOWN:
+        s->core_registers[offset] = value & 0x0000000F;
+        /*
+         * TODO: Power down things?
+         */
+        break;
+    case DP_AUX_WRITE_FIFO:
+        xlnx_dp_aux_push_tx_fifo(s, value, 1);
+        break;
+    case DP_AUX_CLOCK_DIVIDER:
+        break;
+    case DP_AUX_REPLY_COUNT:
+        /*
+         * Writing to this register clear the counter.
+         */
+        s->core_registers[offset] = 0x00000000;
+        break;
+    case DP_AUX_ADDRESS:
+        s->core_registers[offset] = value & 0x000FFFFF;
+        break;
+    case DP_VERSION_REGISTER:
+    case DP_CORE_ID:
+    case DP_TX_USER_FIFO_OVERFLOW:
+    case DP_AUX_REPLY_DATA:
+    case DP_AUX_REPLY_CODE:
+    case DP_REPLY_DATA_COUNT:
+    case DP_REPLY_STATUS:
+    case DP_HPD_DURATION:
+        /*
+         * Write to read only location..
+         */
+        break;
+    case DP_TX_AUDIO_CONTROL:
+        s->core_registers[offset] = value & 0x00000001;
+        xlnx_dp_audio_activate(s);
+        break;
+    case DP_TX_AUDIO_CHANNELS:
+        s->core_registers[offset] = value & 0x00000007;
+        xlnx_dp_audio_activate(s);
+        break;
+    case DP_INT_STATUS:
+        s->core_registers[DP_INT_STATUS] &= ~value;
+        xlnx_dp_update_irq(s);
+        break;
+    case DP_INT_EN:
+        s->core_registers[DP_INT_MASK] &= ~value;
+        xlnx_dp_update_irq(s);
+        break;
+    case DP_INT_DS:
+        s->core_registers[DP_INT_MASK] |= ~value;
+        xlnx_dp_update_irq(s);
+        break;
+    default:
+        assert(offset <= (0x504C >> 2));
+        s->core_registers[offset] = value;
+        break;
+    }
+}
+
+static const MemoryRegionOps dp_ops = {
+    .read = xlnx_dp_read,
+    .write = xlnx_dp_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+/*
+ * This is to handle Read/Write to the Video Blender.
+ */
+static void xlnx_dp_vblend_write(void *opaque, hwaddr offset,
+                                 uint64_t value, unsigned size)
+{
+    XlnxDPState *s = XLNX_DP(opaque);
+    bool alpha_was_enabled;
+
+    DPRINTF("vblend: write @0x%" HWADDR_PRIX " = 0x%" PRIX32 "\n", offset,
+                                                               (uint32_t)value);
+    offset = offset >> 2;
+
+    switch (offset) {
+    case V_BLEND_BG_CLR_0:
+    case V_BLEND_BG_CLR_1:
+    case V_BLEND_BG_CLR_2:
+        s->vblend_registers[offset] = value & 0x00000FFF;
+        break;
+    case V_BLEND_SET_GLOBAL_ALPHA_REG:
+        /*
+         * A write to this register can enable or disable blending. Thus we need
+         * to recreate the surfaces.
+         */
+        alpha_was_enabled = xlnx_dp_global_alpha_enabled(s);
+        s->vblend_registers[offset] = value & 0x000001FF;
+        if (xlnx_dp_global_alpha_enabled(s) != alpha_was_enabled) {
+            xlnx_dp_recreate_surface(s);
+        }
+        break;
+    case V_BLEND_OUTPUT_VID_FORMAT:
+        s->vblend_registers[offset] = value & 0x00000017;
+        break;
+    case V_BLEND_LAYER0_CONTROL:
+    case V_BLEND_LAYER1_CONTROL:
+        s->vblend_registers[offset] = value & 0x00000103;
+        break;
+    case V_BLEND_RGB2YCBCR_COEFF(0):
+    case V_BLEND_RGB2YCBCR_COEFF(1):
+    case V_BLEND_RGB2YCBCR_COEFF(2):
+    case V_BLEND_RGB2YCBCR_COEFF(3):
+    case V_BLEND_RGB2YCBCR_COEFF(4):
+    case V_BLEND_RGB2YCBCR_COEFF(5):
+    case V_BLEND_RGB2YCBCR_COEFF(6):
+    case V_BLEND_RGB2YCBCR_COEFF(7):
+    case V_BLEND_RGB2YCBCR_COEFF(8):
+    case V_BLEND_IN1CSC_COEFF(0):
+    case V_BLEND_IN1CSC_COEFF(1):
+    case V_BLEND_IN1CSC_COEFF(2):
+    case V_BLEND_IN1CSC_COEFF(3):
+    case V_BLEND_IN1CSC_COEFF(4):
+    case V_BLEND_IN1CSC_COEFF(5):
+    case V_BLEND_IN1CSC_COEFF(6):
+    case V_BLEND_IN1CSC_COEFF(7):
+    case V_BLEND_IN1CSC_COEFF(8):
+    case V_BLEND_IN2CSC_COEFF(0):
+    case V_BLEND_IN2CSC_COEFF(1):
+    case V_BLEND_IN2CSC_COEFF(2):
+    case V_BLEND_IN2CSC_COEFF(3):
+    case V_BLEND_IN2CSC_COEFF(4):
+    case V_BLEND_IN2CSC_COEFF(5):
+    case V_BLEND_IN2CSC_COEFF(6):
+    case V_BLEND_IN2CSC_COEFF(7):
+    case V_BLEND_IN2CSC_COEFF(8):
+        s->vblend_registers[offset] = value & 0x0000FFFF;
+        break;
+    case V_BLEND_LUMA_IN1CSC_OFFSET:
+    case V_BLEND_CR_IN1CSC_OFFSET:
+    case V_BLEND_CB_IN1CSC_OFFSET:
+    case V_BLEND_LUMA_IN2CSC_OFFSET:
+    case V_BLEND_CR_IN2CSC_OFFSET:
+    case V_BLEND_CB_IN2CSC_OFFSET:
+    case V_BLEND_LUMA_OUTCSC_OFFSET:
+    case V_BLEND_CR_OUTCSC_OFFSET:
+    case V_BLEND_CB_OUTCSC_OFFSET:
+        s->vblend_registers[offset] = value & 0x3FFF7FFF;
+        break;
+    case V_BLEND_CHROMA_KEY_ENABLE:
+        s->vblend_registers[offset] = value & 0x00000003;
+        break;
+    case V_BLEND_CHROMA_KEY_COMP1:
+    case V_BLEND_CHROMA_KEY_COMP2:
+    case V_BLEND_CHROMA_KEY_COMP3:
+        s->vblend_registers[offset] = value & 0x0FFF0FFF;
+        break;
+    default:
+        s->vblend_registers[offset] = value;
+        break;
+    }
+}
+
+static uint64_t xlnx_dp_vblend_read(void *opaque, hwaddr offset,
+                                    unsigned size)
+{
+    XlnxDPState *s = XLNX_DP(opaque);
+
+    DPRINTF("vblend: read @0x%" HWADDR_PRIX " = 0x%" PRIX32 "\n", offset,
+            s->vblend_registers[offset >> 2]);
+    return s->vblend_registers[offset >> 2];
+}
+
+static const MemoryRegionOps vblend_ops = {
+    .read = xlnx_dp_vblend_read,
+    .write = xlnx_dp_vblend_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+/*
+ * This is to handle Read/Write to the Audio Video buffer manager.
+ */
+static void xlnx_dp_avbufm_write(void *opaque, hwaddr offset, uint64_t value,
+                                 unsigned size)
+{
+    XlnxDPState *s = XLNX_DP(opaque);
+
+    DPRINTF("avbufm: write @0x%" HWADDR_PRIX " = 0x%" PRIX32 "\n", offset,
+                                                               (uint32_t)value);
+    offset = offset >> 2;
+
+    switch (offset) {
+    case AV_BUF_FORMAT:
+        s->avbufm_registers[offset] = value & 0x00000FFF;
+        xlnx_dp_change_graphic_fmt(s);
+        break;
+    case AV_CHBUF0:
+    case AV_CHBUF1:
+    case AV_CHBUF2:
+    case AV_CHBUF3:
+    case AV_CHBUF4:
+    case AV_CHBUF5:
+        s->avbufm_registers[offset] = value & 0x0000007F;
+        break;
+    case AV_BUF_OUTPUT_AUDIO_VIDEO_SELECT:
+        s->avbufm_registers[offset] = value & 0x0000007F;
+        break;
+    case AV_BUF_DITHER_CONFIG:
+        s->avbufm_registers[offset] = value & 0x000007FF;
+        break;
+    case AV_BUF_DITHER_CONFIG_MAX:
+    case AV_BUF_DITHER_CONFIG_MIN:
+        s->avbufm_registers[offset] = value & 0x00000FFF;
+        break;
+    case AV_BUF_PATTERN_GEN_SELECT:
+        s->avbufm_registers[offset] = value & 0xFFFFFF03;
+        break;
+    case AV_BUF_AUD_VID_CLK_SOURCE:
+        s->avbufm_registers[offset] = value & 0x00000007;
+        break;
+    case AV_BUF_SRST_REG:
+        s->avbufm_registers[offset] = value & 0x00000002;
+        break;
+    case AV_BUF_AUDIO_CH_CONFIG:
+        s->avbufm_registers[offset] = value & 0x00000003;
+        break;
+    case AV_BUF_GRAPHICS_COMP_SCALE_FACTOR(0):
+    case AV_BUF_GRAPHICS_COMP_SCALE_FACTOR(1):
+    case AV_BUF_GRAPHICS_COMP_SCALE_FACTOR(2):
+    case AV_BUF_VIDEO_COMP_SCALE_FACTOR(0):
+    case AV_BUF_VIDEO_COMP_SCALE_FACTOR(1):
+    case AV_BUF_VIDEO_COMP_SCALE_FACTOR(2):
+        s->avbufm_registers[offset] = value & 0x0000FFFF;
+        break;
+    case AV_BUF_LIVE_VIDEO_COMP_SF(0):
+    case AV_BUF_LIVE_VIDEO_COMP_SF(1):
+    case AV_BUF_LIVE_VIDEO_COMP_SF(2):
+    case AV_BUF_LIVE_VID_CONFIG:
+    case AV_BUF_LIVE_GFX_COMP_SF(0):
+    case AV_BUF_LIVE_GFX_COMP_SF(1):
+    case AV_BUF_LIVE_GFX_COMP_SF(2):
+    case AV_BUF_LIVE_GFX_CONFIG:
+    case AV_BUF_NON_LIVE_LATENCY:
+    case AV_BUF_STC_CONTROL:
+    case AV_BUF_STC_INIT_VALUE0:
+    case AV_BUF_STC_INIT_VALUE1:
+    case AV_BUF_STC_ADJ:
+    case AV_BUF_STC_VIDEO_VSYNC_TS_REG0:
+    case AV_BUF_STC_VIDEO_VSYNC_TS_REG1:
+    case AV_BUF_STC_EXT_VSYNC_TS_REG0:
+    case AV_BUF_STC_EXT_VSYNC_TS_REG1:
+    case AV_BUF_STC_CUSTOM_EVENT_TS_REG0:
+    case AV_BUF_STC_CUSTOM_EVENT_TS_REG1:
+    case AV_BUF_STC_CUSTOM_EVENT2_TS_REG0:
+    case AV_BUF_STC_CUSTOM_EVENT2_TS_REG1:
+    case AV_BUF_STC_SNAPSHOT0:
+    case AV_BUF_STC_SNAPSHOT1:
+    case AV_BUF_HCOUNT_VCOUNT_INT0:
+    case AV_BUF_HCOUNT_VCOUNT_INT1:
+        qemu_log_mask(LOG_UNIMP, "avbufm: unimplmented");
+        break;
+    default:
+        s->avbufm_registers[offset] = value;
+        break;
+    }
+}
+
+static uint64_t xlnx_dp_avbufm_read(void *opaque, hwaddr offset,
+                                    unsigned size)
+{
+    XlnxDPState *s = XLNX_DP(opaque);
+
+    offset = offset >> 2;
+    return s->avbufm_registers[offset];
+}
+
+static const MemoryRegionOps avbufm_ops = {
+    .read = xlnx_dp_avbufm_read,
+    .write = xlnx_dp_avbufm_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+/*
+ * This is a global alpha blending using pixman.
+ * Both graphic and video planes are multiplied with the global alpha
+ * coefficient and added.
+ */
+static inline void xlnx_dp_blend_surface(XlnxDPState *s)
+{
+    pixman_fixed_t alpha1[] = { pixman_double_to_fixed(1),
+                                pixman_double_to_fixed(1),
+                                pixman_double_to_fixed(1.0) };
+    pixman_fixed_t alpha2[] = { pixman_double_to_fixed(1),
+                                pixman_double_to_fixed(1),
+                                pixman_double_to_fixed(1.0) };
+
+    if ((surface_width(s->g_plane.surface)
+         != surface_width(s->v_plane.surface)) ||
+        (surface_height(s->g_plane.surface)
+         != surface_height(s->v_plane.surface))) {
+        return;
+    }
+
+    alpha1[2] = pixman_double_to_fixed((double)(xlnx_dp_global_alpha_value(s))
+                                       / 256.0);
+    alpha2[2] = pixman_double_to_fixed((255.0
+                                    - (double)xlnx_dp_global_alpha_value(s))
+                                       / 256.0);
+
+    pixman_image_set_filter(s->g_plane.surface->image,
+                            PIXMAN_FILTER_CONVOLUTION, alpha1, 3);
+    pixman_image_composite(PIXMAN_OP_SRC, s->g_plane.surface->image, 0,
+                           s->bout_plane.surface->image, 0, 0, 0, 0, 0, 0,
+                           surface_width(s->g_plane.surface),
+                           surface_height(s->g_plane.surface));
+    pixman_image_set_filter(s->v_plane.surface->image,
+                            PIXMAN_FILTER_CONVOLUTION, alpha2, 3);
+    pixman_image_composite(PIXMAN_OP_ADD, s->v_plane.surface->image, 0,
+                           s->bout_plane.surface->image, 0, 0, 0, 0, 0, 0,
+                           surface_width(s->g_plane.surface),
+                           surface_height(s->g_plane.surface));
+}
+
+static void xlnx_dp_update_display(void *opaque)
+{
+    XlnxDPState *s = XLNX_DP(opaque);
+
+    if ((s->core_registers[DP_TRANSMITTER_ENABLE] & 0x01) == 0) {
+        return;
+    }
+
+    s->core_registers[DP_INT_STATUS] |= (1 << 13);
+    xlnx_dp_update_irq(s);
+
+    xlnx_dpdma_trigger_vsync_irq(s->dpdma);
+
+    /*
+     * Trigger the DMA channel.
+     */
+    if (!xlnx_dpdma_start_operation(s->dpdma, 3, false)) {
+        /*
+         * An error occured don't do anything with the data..
+         * Trigger an underflow interrupt.
+         */
+        s->core_registers[DP_INT_STATUS] |= (1 << 21);
+        xlnx_dp_update_irq(s);
+        return;
+    }
+
+    if (xlnx_dp_global_alpha_enabled(s)) {
+        if (!xlnx_dpdma_start_operation(s->dpdma, 0, false)) {
+            s->core_registers[DP_INT_STATUS] |= (1 << 21);
+            xlnx_dp_update_irq(s);
+            return;
+        }
+        xlnx_dp_blend_surface(s);
+    }
+
+    /*
+     * XXX: We might want to update only what changed.
+     */
+    dpy_gfx_update(s->console, 0, 0, surface_width(s->g_plane.surface),
+                                     surface_height(s->g_plane.surface));
+}
+
+static const GraphicHwOps xlnx_dp_gfx_ops = {
+    .gfx_update  = xlnx_dp_update_display,
+};
+
+static void xlnx_dp_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    XlnxDPState *s = XLNX_DP(obj);
+
+    memory_region_init(&s->container, obj, TYPE_XLNX_DP, 0xC050);
+
+    memory_region_init_io(&s->core_iomem, obj, &dp_ops, s, TYPE_XLNX_DP
+                          ".core", 0x3AF);
+    memory_region_add_subregion(&s->container, 0x0000, &s->core_iomem);
+
+    memory_region_init_io(&s->vblend_iomem, obj, &vblend_ops, s, TYPE_XLNX_DP
+                          ".v_blend", 0x1DF);
+    memory_region_add_subregion(&s->container, 0xA000, &s->vblend_iomem);
+
+    memory_region_init_io(&s->avbufm_iomem, obj, &avbufm_ops, s, TYPE_XLNX_DP
+                          ".av_buffer_manager", 0x238);
+    memory_region_add_subregion(&s->container, 0xB000, &s->avbufm_iomem);
+
+    memory_region_init_io(&s->audio_iomem, obj, &audio_ops, s, TYPE_XLNX_DP
+                          ".audio", sizeof(s->audio_registers));
+    memory_region_add_subregion(&s->container, 0xC000, &s->audio_iomem);
+
+    sysbus_init_mmio(sbd, &s->container);
+    sysbus_init_irq(sbd, &s->irq);
+
+    object_property_add_link(obj, "dpdma", TYPE_XLNX_DPDMA,
+                             (Object **) &s->dpdma,
+                             xlnx_dp_set_dpdma,
+                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
+                             &error_abort);
+
+    /*
+     * Initialize AUX Bus.
+     */
+    s->aux_bus = aux_init_bus(DEVICE(obj), "aux");
+
+    /*
+     * Initialize DPCD and EDID..
+     */
+    s->dpcd = DPCD(aux_create_slave(s->aux_bus, "dpcd", 0x00000));
+    s->edid = I2CDDC(qdev_create(BUS(aux_get_i2c_bus(s->aux_bus)), "i2c-ddc"));
+    i2c_set_slave_address(I2C_SLAVE(s->edid), 0x50);
+
+    fifo8_create(&s->rx_fifo, 16);
+    fifo8_create(&s->tx_fifo, 16);
+}
+
+static void xlnx_dp_realize(DeviceState *dev, Error **errp)
+{
+    XlnxDPState *s = XLNX_DP(dev);
+    DisplaySurface *surface;
+    struct audsettings as;
+
+    s->console = graphic_console_init(dev, 0, &xlnx_dp_gfx_ops, s);
+    surface = qemu_console_surface(s->console);
+    xlnx_dpdma_set_host_data_location(s->dpdma, DP_GRAPHIC_DMA_CHANNEL,
+                                      surface_data(surface));
+
+    as.freq = 44100;
+    as.nchannels = 2;
+    as.fmt = AUD_FMT_S16;
+    as.endianness = 0;
+
+    AUD_register_card("xlnx_dp.audio", &s->aud_card);
+
+    s->amixer_output_stream = AUD_open_out(&s->aud_card,
+                                           s->amixer_output_stream,
+                                           "xlnx_dp.audio.out",
+                                           s,
+                                           xlnx_dp_audio_callback,
+                                           &as);
+    AUD_set_volume_out(s->amixer_output_stream, 0, 255, 255);
+    xlnx_dp_audio_activate(s);
+}
+
+static void xlnx_dp_reset(DeviceState *dev)
+{
+    XlnxDPState *s = XLNX_DP(dev);
+
+    memset(s->core_registers, 0, sizeof(s->core_registers));
+    s->core_registers[DP_VERSION_REGISTER] = 0x04010000;
+    s->core_registers[DP_CORE_ID] = 0x01020000;
+    s->core_registers[DP_REPLY_STATUS] = 0x00000010;
+    s->core_registers[DP_MSA_TRANSFER_UNIT_SIZE] = 0x00000040;
+    s->core_registers[DP_INIT_WAIT] = 0x00000020;
+    s->core_registers[DP_PHY_RESET] = 0x00010003;
+    s->core_registers[DP_INT_MASK] = 0xFFFFF03F;
+    s->core_registers[DP_PHY_STATUS] = 0x00000043;
+    s->core_registers[DP_INTERRUPT_SIGNAL_STATE] = 0x00000001;
+
+    s->vblend_registers[V_BLEND_RGB2YCBCR_COEFF(0)] = 0x00001000;
+    s->vblend_registers[V_BLEND_RGB2YCBCR_COEFF(4)] = 0x00001000;
+    s->vblend_registers[V_BLEND_RGB2YCBCR_COEFF(8)] = 0x00001000;
+    s->vblend_registers[V_BLEND_IN1CSC_COEFF(0)] = 0x00001000;
+    s->vblend_registers[V_BLEND_IN1CSC_COEFF(4)] = 0x00001000;
+    s->vblend_registers[V_BLEND_IN1CSC_COEFF(8)] = 0x00001000;
+    s->vblend_registers[V_BLEND_IN2CSC_COEFF(0)] = 0x00001000;
+    s->vblend_registers[V_BLEND_IN2CSC_COEFF(4)] = 0x00001000;
+    s->vblend_registers[V_BLEND_IN2CSC_COEFF(8)] = 0x00001000;
+
+    s->avbufm_registers[AV_BUF_NON_LIVE_LATENCY] = 0x00000180;
+    s->avbufm_registers[AV_BUF_OUTPUT_AUDIO_VIDEO_SELECT] = 0x00000008;
+    s->avbufm_registers[AV_BUF_DITHER_CONFIG_MAX] = 0x00000FFF;
+    s->avbufm_registers[AV_BUF_GRAPHICS_COMP_SCALE_FACTOR(0)] = 0x00010101;
+    s->avbufm_registers[AV_BUF_GRAPHICS_COMP_SCALE_FACTOR(1)] = 0x00010101;
+    s->avbufm_registers[AV_BUF_GRAPHICS_COMP_SCALE_FACTOR(2)] = 0x00010101;
+    s->avbufm_registers[AV_BUF_VIDEO_COMP_SCALE_FACTOR(0)] = 0x00010101;
+    s->avbufm_registers[AV_BUF_VIDEO_COMP_SCALE_FACTOR(1)] = 0x00010101;
+    s->avbufm_registers[AV_BUF_VIDEO_COMP_SCALE_FACTOR(2)] = 0x00010101;
+    s->avbufm_registers[AV_BUF_LIVE_VIDEO_COMP_SF(0)] = 0x00010101;
+    s->avbufm_registers[AV_BUF_LIVE_VIDEO_COMP_SF(1)] = 0x00010101;
+    s->avbufm_registers[AV_BUF_LIVE_VIDEO_COMP_SF(2)] = 0x00010101;
+    s->avbufm_registers[AV_BUF_LIVE_GFX_COMP_SF(0)] = 0x00010101;
+    s->avbufm_registers[AV_BUF_LIVE_GFX_COMP_SF(1)] = 0x00010101;
+    s->avbufm_registers[AV_BUF_LIVE_GFX_COMP_SF(2)] = 0x00010101;
+
+    memset(s->audio_registers, 0, sizeof(s->audio_registers));
+    s->byte_left = 0;
+
+    xlnx_dp_aux_clear_rx_fifo(s);
+    xlnx_dp_change_graphic_fmt(s);
+    xlnx_dp_update_irq(s);
+}
+
+static void xlnx_dp_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->realize = xlnx_dp_realize;
+    dc->vmsd = &vmstate_dp;
+    dc->reset = xlnx_dp_reset;
+}
+
+static const TypeInfo xlnx_dp_info = {
+    .name          = TYPE_XLNX_DP,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(XlnxDPState),
+    .instance_init = xlnx_dp_init,
+    .class_init    = xlnx_dp_class_init,
+};
+
+static void xlnx_dp_register_types(void)
+{
+    type_register_static(&xlnx_dp_info);
+}
+
+type_init(xlnx_dp_register_types)
diff --git a/hw/dma/Makefile.objs b/hw/dma/Makefile.objs
index a1abbcf746..8b0823e593 100644
--- a/hw/dma/Makefile.objs
+++ b/hw/dma/Makefile.objs
@@ -8,6 +8,7 @@ common-obj-$(CONFIG_XILINX_AXI) += xilinx_axidma.o
 common-obj-$(CONFIG_ETRAXFS) += etraxfs_dma.o
 common-obj-$(CONFIG_STP2000) += sparc32_dma.o
 common-obj-$(CONFIG_SUN4M) += sun4m_iommu.o
+obj-$(CONFIG_XLNX_ZYNQMP) += xlnx_dpdma.o
 
 obj-$(CONFIG_OMAP) += omap_dma.o soc_dma.o
 obj-$(CONFIG_PXA2XX) += pxa2xx_dma.o
diff --git a/hw/dma/pxa2xx_dma.c b/hw/dma/pxa2xx_dma.c
index 2306abc35b..634a4328f0 100644
--- a/hw/dma/pxa2xx_dma.c
+++ b/hw/dma/pxa2xx_dma.c
@@ -12,6 +12,7 @@
 #include "hw/hw.h"
 #include "hw/arm/pxa.h"
 #include "hw/sysbus.h"
+#include "qapi/error.h"
 
 #define PXA255_DMA_NUM_CHANNELS 16
 #define PXA27X_DMA_NUM_CHANNELS 32
@@ -450,31 +451,36 @@ static void pxa2xx_dma_request(void *opaque, int req_num, int on)
     }
 }
 
-static int pxa2xx_dma_init(SysBusDevice *sbd)
+static void pxa2xx_dma_init(Object *obj)
+{
+    DeviceState *dev = DEVICE(obj);
+    PXA2xxDMAState *s = PXA2XX_DMA(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+    memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
+
+    qdev_init_gpio_in(dev, pxa2xx_dma_request, PXA2XX_DMA_NUM_REQUESTS);
+
+    memory_region_init_io(&s->iomem, obj, &pxa2xx_dma_ops, s,
+                          "pxa2xx.dma", 0x00010000);
+    sysbus_init_mmio(sbd, &s->iomem);
+    sysbus_init_irq(sbd, &s->irq);
+}
+
+static void pxa2xx_dma_realize(DeviceState *dev, Error **errp)
 {
-    DeviceState *dev = DEVICE(sbd);
     PXA2xxDMAState *s = PXA2XX_DMA(dev);
     int i;
 
     if (s->channels <= 0) {
-        return -1;
+        error_setg(errp, "channels value invalid");
+        return;
     }
 
     s->chan = g_new0(PXA2xxDMAChannel, s->channels);
 
     for (i = 0; i < s->channels; i ++)
         s->chan[i].state = DCSR_STOPINTR;
-
-    memset(s->req, 0, sizeof(uint8_t) * PXA2XX_DMA_NUM_REQUESTS);
-
-    qdev_init_gpio_in(dev, pxa2xx_dma_request, PXA2XX_DMA_NUM_REQUESTS);
-
-    memory_region_init_io(&s->iomem, OBJECT(s), &pxa2xx_dma_ops, s,
-                          "pxa2xx.dma", 0x00010000);
-    sysbus_init_mmio(sbd, &s->iomem);
-    sysbus_init_irq(sbd, &s->irq);
-
-    return 0;
 }
 
 DeviceState *pxa27x_dma_init(hwaddr base, qemu_irq irq)
@@ -553,18 +559,18 @@ static Property pxa2xx_dma_properties[] = {
 static void pxa2xx_dma_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = pxa2xx_dma_init;
     dc->desc = "PXA2xx DMA controller";
     dc->vmsd = &vmstate_pxa2xx_dma;
     dc->props = pxa2xx_dma_properties;
+    dc->realize = pxa2xx_dma_realize;
 }
 
 static const TypeInfo pxa2xx_dma_info = {
     .name          = TYPE_PXA2XX_DMA,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(PXA2xxDMAState),
+    .instance_init = pxa2xx_dma_init,
     .class_init    = pxa2xx_dma_class_init,
 };
 
diff --git a/hw/dma/xlnx_dpdma.c b/hw/dma/xlnx_dpdma.c
new file mode 100644
index 0000000000..8ceb21ddb3
--- /dev/null
+++ b/hw/dma/xlnx_dpdma.c
@@ -0,0 +1,786 @@
+/*
+ * xlnx_dpdma.c
+ *
+ *  Copyright (C) 2015 : GreenSocs Ltd
+ *      http://www.greensocs.com/ , email: info@greensocs.com
+ *
+ *  Developed by :
+ *  Frederic Konrad   <fred.konrad@greensocs.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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/dma/xlnx_dpdma.h"
+
+#ifndef DEBUG_DPDMA
+#define DEBUG_DPDMA 0
+#endif
+
+#define DPRINTF(fmt, ...) do {                                                 \
+    if (DEBUG_DPDMA) {                                                         \
+        qemu_log("xlnx_dpdma: " fmt , ## __VA_ARGS__);                         \
+    }                                                                          \
+} while (0);
+
+/*
+ * Registers offset for DPDMA.
+ */
+#define DPDMA_ERR_CTRL                        (0x0000)
+#define DPDMA_ISR                             (0x0004 >> 2)
+#define DPDMA_IMR                             (0x0008 >> 2)
+#define DPDMA_IEN                             (0x000C >> 2)
+#define DPDMA_IDS                             (0x0010 >> 2)
+#define DPDMA_EISR                            (0x0014 >> 2)
+#define DPDMA_EIMR                            (0x0018 >> 2)
+#define DPDMA_EIEN                            (0x001C >> 2)
+#define DPDMA_EIDS                            (0x0020 >> 2)
+#define DPDMA_CNTL                            (0x0100 >> 2)
+
+#define DPDMA_GBL                             (0x0104 >> 2)
+#define DPDMA_GBL_TRG_CH(n)                   (1 << n)
+#define DPDMA_GBL_RTRG_CH(n)                  (1 << 6 << n)
+
+#define DPDMA_ALC0_CNTL                       (0x0108 >> 2)
+#define DPDMA_ALC0_STATUS                     (0x010C >> 2)
+#define DPDMA_ALC0_MAX                        (0x0110 >> 2)
+#define DPDMA_ALC0_MIN                        (0x0114 >> 2)
+#define DPDMA_ALC0_ACC                        (0x0118 >> 2)
+#define DPDMA_ALC0_ACC_TRAN                   (0x011C >> 2)
+#define DPDMA_ALC1_CNTL                       (0x0120 >> 2)
+#define DPDMA_ALC1_STATUS                     (0x0124 >> 2)
+#define DPDMA_ALC1_MAX                        (0x0128 >> 2)
+#define DPDMA_ALC1_MIN                        (0x012C >> 2)
+#define DPDMA_ALC1_ACC                        (0x0130 >> 2)
+#define DPDMA_ALC1_ACC_TRAN                   (0x0134 >> 2)
+
+#define DPDMA_DSCR_STRT_ADDRE_CH(n)           ((0x0200 + n * 0x100) >> 2)
+#define DPDMA_DSCR_STRT_ADDR_CH(n)            ((0x0204 + n * 0x100) >> 2)
+#define DPDMA_DSCR_NEXT_ADDRE_CH(n)           ((0x0208 + n * 0x100) >> 2)
+#define DPDMA_DSCR_NEXT_ADDR_CH(n)            ((0x020C + n * 0x100) >> 2)
+#define DPDMA_PYLD_CUR_ADDRE_CH(n)            ((0x0210 + n * 0x100) >> 2)
+#define DPDMA_PYLD_CUR_ADDR_CH(n)             ((0x0214 + n * 0x100) >> 2)
+
+#define DPDMA_CNTL_CH(n)                      ((0x0218 + n * 0x100) >> 2)
+#define DPDMA_CNTL_CH_EN                      (1)
+#define DPDMA_CNTL_CH_PAUSED                  (1 << 1)
+
+#define DPDMA_STATUS_CH(n)                    ((0x021C + n * 0x100) >> 2)
+#define DPDMA_STATUS_BURST_TYPE               (1 << 4)
+#define DPDMA_STATUS_MODE                     (1 << 5)
+#define DPDMA_STATUS_EN_CRC                   (1 << 6)
+#define DPDMA_STATUS_LAST_DSCR                (1 << 7)
+#define DPDMA_STATUS_LDSCR_FRAME              (1 << 8)
+#define DPDMA_STATUS_IGNR_DONE                (1 << 9)
+#define DPDMA_STATUS_DSCR_DONE                (1 << 10)
+#define DPDMA_STATUS_EN_DSCR_UP               (1 << 11)
+#define DPDMA_STATUS_EN_DSCR_INTR             (1 << 12)
+#define DPDMA_STATUS_PREAMBLE_OFF             (13)
+
+#define DPDMA_VDO_CH(n)                       ((0x0220 + n * 0x100) >> 2)
+#define DPDMA_PYLD_SZ_CH(n)                   ((0x0224 + n * 0x100) >> 2)
+#define DPDMA_DSCR_ID_CH(n)                   ((0x0228 + n * 0x100) >> 2)
+
+/*
+ * Descriptor control field.
+ */
+#define CONTROL_PREAMBLE_VALUE                0xA5
+
+#define DSCR_CTRL_PREAMBLE                    0xFF
+#define DSCR_CTRL_EN_DSCR_DONE_INTR           (1 << 8)
+#define DSCR_CTRL_EN_DSCR_UPDATE              (1 << 9)
+#define DSCR_CTRL_IGNORE_DONE                 (1 << 10)
+#define DSCR_CTRL_AXI_BURST_TYPE              (1 << 11)
+#define DSCR_CTRL_AXCACHE                     (0x0F << 12)
+#define DSCR_CTRL_AXPROT                      (0x2 << 16)
+#define DSCR_CTRL_DESCRIPTOR_MODE             (1 << 18)
+#define DSCR_CTRL_LAST_DESCRIPTOR             (1 << 19)
+#define DSCR_CTRL_ENABLE_CRC                  (1 << 20)
+#define DSCR_CTRL_LAST_DESCRIPTOR_OF_FRAME    (1 << 21)
+
+/*
+ * Descriptor timestamp field.
+ */
+#define STATUS_DONE                           (1 << 31)
+
+#define DPDMA_FRAG_MAX_SZ                     (4096)
+
+enum DPDMABurstType {
+    DPDMA_INCR = 0,
+    DPDMA_FIXED = 1
+};
+
+enum DPDMAMode {
+    DPDMA_CONTIGOUS = 0,
+    DPDMA_FRAGMENTED = 1
+};
+
+struct DPDMADescriptor {
+    uint32_t control;
+    uint32_t descriptor_id;
+    /* transfer size in byte. */
+    uint32_t xfer_size;
+    uint32_t line_size_stride;
+    uint32_t timestamp_lsb;
+    uint32_t timestamp_msb;
+    /* contains extension for both descriptor and source. */
+    uint32_t address_extension;
+    uint32_t next_descriptor;
+    uint32_t source_address;
+    uint32_t address_extension_23;
+    uint32_t address_extension_45;
+    uint32_t source_address2;
+    uint32_t source_address3;
+    uint32_t source_address4;
+    uint32_t source_address5;
+    uint32_t crc;
+};
+
+typedef enum DPDMABurstType DPDMABurstType;
+typedef enum DPDMAMode DPDMAMode;
+typedef struct DPDMADescriptor DPDMADescriptor;
+
+static bool xlnx_dpdma_desc_is_last(DPDMADescriptor *desc)
+{
+    return ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR) != 0);
+}
+
+static bool xlnx_dpdma_desc_is_last_of_frame(DPDMADescriptor *desc)
+{
+    return ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR_OF_FRAME) != 0);
+}
+
+static uint64_t xlnx_dpdma_desc_get_source_address(DPDMADescriptor *desc,
+                                                     uint8_t frag)
+{
+    uint64_t addr = 0;
+    assert(frag < 5);
+
+    switch (frag) {
+    case 0:
+        addr = desc->source_address
+            + (extract32(desc->address_extension, 16, 12) << 20);
+        break;
+    case 1:
+        addr = desc->source_address2
+            + (extract32(desc->address_extension_23, 0, 12) << 8);
+        break;
+    case 2:
+        addr = desc->source_address3
+            + (extract32(desc->address_extension_23, 16, 12) << 20);
+        break;
+    case 3:
+        addr = desc->source_address4
+            + (extract32(desc->address_extension_45, 0, 12) << 8);
+        break;
+    case 4:
+        addr = desc->source_address5
+            + (extract32(desc->address_extension_45, 16, 12) << 20);
+        break;
+    default:
+        addr = 0;
+        break;
+    }
+
+    return addr;
+}
+
+static uint32_t xlnx_dpdma_desc_get_transfer_size(DPDMADescriptor *desc)
+{
+    return desc->xfer_size;
+}
+
+static uint32_t xlnx_dpdma_desc_get_line_size(DPDMADescriptor *desc)
+{
+    return extract32(desc->line_size_stride, 0, 18);
+}
+
+static uint32_t xlnx_dpdma_desc_get_line_stride(DPDMADescriptor *desc)
+{
+    return extract32(desc->line_size_stride, 18, 14) * 16;
+}
+
+static inline bool xlnx_dpdma_desc_crc_enabled(DPDMADescriptor *desc)
+{
+    return (desc->control & DSCR_CTRL_ENABLE_CRC) != 0;
+}
+
+static inline bool xlnx_dpdma_desc_check_crc(DPDMADescriptor *desc)
+{
+    uint32_t *p = (uint32_t *)desc;
+    uint32_t crc = 0;
+    uint8_t i;
+
+    /*
+     * CRC is calculated on the whole descriptor except the last 32bits word
+     * using 32bits addition.
+     */
+    for (i = 0; i < 15; i++) {
+        crc += p[i];
+    }
+
+    return crc == desc->crc;
+}
+
+static inline bool xlnx_dpdma_desc_completion_interrupt(DPDMADescriptor *desc)
+{
+    return (desc->control & DSCR_CTRL_EN_DSCR_DONE_INTR) != 0;
+}
+
+static inline bool xlnx_dpdma_desc_is_valid(DPDMADescriptor *desc)
+{
+    return (desc->control & DSCR_CTRL_PREAMBLE) == CONTROL_PREAMBLE_VALUE;
+}
+
+static inline bool xlnx_dpdma_desc_is_contiguous(DPDMADescriptor *desc)
+{
+    return (desc->control & DSCR_CTRL_DESCRIPTOR_MODE) == 0;
+}
+
+static inline bool xlnx_dpdma_desc_update_enabled(DPDMADescriptor *desc)
+{
+    return (desc->control & DSCR_CTRL_EN_DSCR_UPDATE) != 0;
+}
+
+static inline void xlnx_dpdma_desc_set_done(DPDMADescriptor *desc)
+{
+    desc->timestamp_msb |= STATUS_DONE;
+}
+
+static inline bool xlnx_dpdma_desc_is_already_done(DPDMADescriptor *desc)
+{
+    return (desc->timestamp_msb & STATUS_DONE) != 0;
+}
+
+static inline bool xlnx_dpdma_desc_ignore_done_bit(DPDMADescriptor *desc)
+{
+    return (desc->control & DSCR_CTRL_IGNORE_DONE) != 0;
+}
+
+static const VMStateDescription vmstate_xlnx_dpdma = {
+    .name = TYPE_XLNX_DPDMA,
+    .version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(registers, XlnxDPDMAState,
+                             XLNX_DPDMA_REG_ARRAY_SIZE),
+        VMSTATE_BOOL_ARRAY(operation_finished, XlnxDPDMAState, 6),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void xlnx_dpdma_update_irq(XlnxDPDMAState *s)
+{
+    bool flags;
+
+    flags = ((s->registers[DPDMA_ISR] & (~s->registers[DPDMA_IMR]))
+          || (s->registers[DPDMA_EISR] & (~s->registers[DPDMA_EIMR])));
+    qemu_set_irq(s->irq, flags);
+}
+
+static uint64_t xlnx_dpdma_descriptor_start_address(XlnxDPDMAState *s,
+                                                      uint8_t channel)
+{
+    return (s->registers[DPDMA_DSCR_STRT_ADDRE_CH(channel)] << 16)
+          + s->registers[DPDMA_DSCR_STRT_ADDR_CH(channel)];
+}
+
+static uint64_t xlnx_dpdma_descriptor_next_address(XlnxDPDMAState *s,
+                                                     uint8_t channel)
+{
+    return ((uint64_t)s->registers[DPDMA_DSCR_NEXT_ADDRE_CH(channel)] << 32)
+           + s->registers[DPDMA_DSCR_NEXT_ADDR_CH(channel)];
+}
+
+static bool xlnx_dpdma_is_channel_enabled(XlnxDPDMAState *s,
+                                            uint8_t channel)
+{
+    return (s->registers[DPDMA_CNTL_CH(channel)] & DPDMA_CNTL_CH_EN) != 0;
+}
+
+static bool xlnx_dpdma_is_channel_paused(XlnxDPDMAState *s,
+                                           uint8_t channel)
+{
+    return (s->registers[DPDMA_CNTL_CH(channel)] & DPDMA_CNTL_CH_PAUSED) != 0;
+}
+
+static inline bool xlnx_dpdma_is_channel_retriggered(XlnxDPDMAState *s,
+                                                       uint8_t channel)
+{
+    /* Clear the retriggered bit after reading it. */
+    bool channel_is_retriggered = s->registers[DPDMA_GBL]
+                                & DPDMA_GBL_RTRG_CH(channel);
+    s->registers[DPDMA_GBL] &= ~DPDMA_GBL_RTRG_CH(channel);
+    return channel_is_retriggered;
+}
+
+static inline bool xlnx_dpdma_is_channel_triggered(XlnxDPDMAState *s,
+                                                     uint8_t channel)
+{
+    return s->registers[DPDMA_GBL] & DPDMA_GBL_TRG_CH(channel);
+}
+
+static void xlnx_dpdma_update_desc_info(XlnxDPDMAState *s, uint8_t channel,
+                                          DPDMADescriptor *desc)
+{
+    s->registers[DPDMA_DSCR_NEXT_ADDRE_CH(channel)] =
+                                extract32(desc->address_extension, 0, 16);
+    s->registers[DPDMA_DSCR_NEXT_ADDR_CH(channel)] = desc->next_descriptor;
+    s->registers[DPDMA_PYLD_CUR_ADDRE_CH(channel)] =
+                                extract32(desc->address_extension, 16, 16);
+    s->registers[DPDMA_PYLD_CUR_ADDR_CH(channel)] = desc->source_address;
+    s->registers[DPDMA_VDO_CH(channel)] =
+                                extract32(desc->line_size_stride, 18, 14)
+                                + (extract32(desc->line_size_stride, 0, 18)
+                                  << 14);
+    s->registers[DPDMA_PYLD_SZ_CH(channel)] = desc->xfer_size;
+    s->registers[DPDMA_DSCR_ID_CH(channel)] = desc->descriptor_id;
+
+    /* Compute the status register with the descriptor information. */
+    s->registers[DPDMA_STATUS_CH(channel)] =
+                                extract32(desc->control, 0, 8) << 13;
+    if ((desc->control & DSCR_CTRL_EN_DSCR_DONE_INTR) != 0) {
+        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_EN_DSCR_INTR;
+    }
+    if ((desc->control & DSCR_CTRL_EN_DSCR_UPDATE) != 0) {
+        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_EN_DSCR_UP;
+    }
+    if ((desc->timestamp_msb & STATUS_DONE) != 0) {
+        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_DSCR_DONE;
+    }
+    if ((desc->control & DSCR_CTRL_IGNORE_DONE) != 0) {
+        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_IGNR_DONE;
+    }
+    if ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR_OF_FRAME) != 0) {
+        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_LDSCR_FRAME;
+    }
+    if ((desc->control & DSCR_CTRL_LAST_DESCRIPTOR) != 0) {
+        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_LAST_DSCR;
+    }
+    if ((desc->control & DSCR_CTRL_ENABLE_CRC) != 0) {
+        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_EN_CRC;
+    }
+    if ((desc->control & DSCR_CTRL_DESCRIPTOR_MODE) != 0) {
+        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_MODE;
+    }
+    if ((desc->control & DSCR_CTRL_AXI_BURST_TYPE) != 0) {
+        s->registers[DPDMA_STATUS_CH(channel)] |= DPDMA_STATUS_BURST_TYPE;
+    }
+}
+
+static void xlnx_dpdma_dump_descriptor(DPDMADescriptor *desc)
+{
+    if (DEBUG_DPDMA) {
+        qemu_log("DUMP DESCRIPTOR:\n");
+        qemu_hexdump((char *)desc, stdout, "", sizeof(DPDMADescriptor));
+    }
+}
+
+static uint64_t xlnx_dpdma_read(void *opaque, hwaddr offset,
+                                unsigned size)
+{
+    XlnxDPDMAState *s = XLNX_DPDMA(opaque);
+
+    DPRINTF("read @%" HWADDR_PRIx "\n", offset);
+    offset = offset >> 2;
+
+    switch (offset) {
+    /*
+     * Trying to read a write only register.
+     */
+    case DPDMA_GBL:
+        return 0;
+    default:
+        assert(offset <= (0xFFC >> 2));
+        return s->registers[offset];
+    }
+    return 0;
+}
+
+static void xlnx_dpdma_write(void *opaque, hwaddr offset,
+                               uint64_t value, unsigned size)
+{
+    XlnxDPDMAState *s = XLNX_DPDMA(opaque);
+
+    DPRINTF("write @%" HWADDR_PRIx " = %" PRIx64 "\n", offset, value);
+    offset = offset >> 2;
+
+    switch (offset) {
+    case DPDMA_ISR:
+        s->registers[DPDMA_ISR] &= ~value;
+        xlnx_dpdma_update_irq(s);
+        break;
+    case DPDMA_IEN:
+        s->registers[DPDMA_IMR] &= ~value;
+        break;
+    case DPDMA_IDS:
+        s->registers[DPDMA_IMR] |= value;
+        break;
+    case DPDMA_EISR:
+        s->registers[DPDMA_EISR] &= ~value;
+        xlnx_dpdma_update_irq(s);
+        break;
+    case DPDMA_EIEN:
+        s->registers[DPDMA_EIMR] &= ~value;
+        break;
+    case DPDMA_EIDS:
+        s->registers[DPDMA_EIMR] |= value;
+        break;
+    case DPDMA_IMR:
+    case DPDMA_EIMR:
+    case DPDMA_DSCR_NEXT_ADDRE_CH(0):
+    case DPDMA_DSCR_NEXT_ADDRE_CH(1):
+    case DPDMA_DSCR_NEXT_ADDRE_CH(2):
+    case DPDMA_DSCR_NEXT_ADDRE_CH(3):
+    case DPDMA_DSCR_NEXT_ADDRE_CH(4):
+    case DPDMA_DSCR_NEXT_ADDRE_CH(5):
+    case DPDMA_DSCR_NEXT_ADDR_CH(0):
+    case DPDMA_DSCR_NEXT_ADDR_CH(1):
+    case DPDMA_DSCR_NEXT_ADDR_CH(2):
+    case DPDMA_DSCR_NEXT_ADDR_CH(3):
+    case DPDMA_DSCR_NEXT_ADDR_CH(4):
+    case DPDMA_DSCR_NEXT_ADDR_CH(5):
+    case DPDMA_PYLD_CUR_ADDRE_CH(0):
+    case DPDMA_PYLD_CUR_ADDRE_CH(1):
+    case DPDMA_PYLD_CUR_ADDRE_CH(2):
+    case DPDMA_PYLD_CUR_ADDRE_CH(3):
+    case DPDMA_PYLD_CUR_ADDRE_CH(4):
+    case DPDMA_PYLD_CUR_ADDRE_CH(5):
+    case DPDMA_PYLD_CUR_ADDR_CH(0):
+    case DPDMA_PYLD_CUR_ADDR_CH(1):
+    case DPDMA_PYLD_CUR_ADDR_CH(2):
+    case DPDMA_PYLD_CUR_ADDR_CH(3):
+    case DPDMA_PYLD_CUR_ADDR_CH(4):
+    case DPDMA_PYLD_CUR_ADDR_CH(5):
+    case DPDMA_STATUS_CH(0):
+    case DPDMA_STATUS_CH(1):
+    case DPDMA_STATUS_CH(2):
+    case DPDMA_STATUS_CH(3):
+    case DPDMA_STATUS_CH(4):
+    case DPDMA_STATUS_CH(5):
+    case DPDMA_VDO_CH(0):
+    case DPDMA_VDO_CH(1):
+    case DPDMA_VDO_CH(2):
+    case DPDMA_VDO_CH(3):
+    case DPDMA_VDO_CH(4):
+    case DPDMA_VDO_CH(5):
+    case DPDMA_PYLD_SZ_CH(0):
+    case DPDMA_PYLD_SZ_CH(1):
+    case DPDMA_PYLD_SZ_CH(2):
+    case DPDMA_PYLD_SZ_CH(3):
+    case DPDMA_PYLD_SZ_CH(4):
+    case DPDMA_PYLD_SZ_CH(5):
+    case DPDMA_DSCR_ID_CH(0):
+    case DPDMA_DSCR_ID_CH(1):
+    case DPDMA_DSCR_ID_CH(2):
+    case DPDMA_DSCR_ID_CH(3):
+    case DPDMA_DSCR_ID_CH(4):
+    case DPDMA_DSCR_ID_CH(5):
+        /*
+         * Trying to write to a read only register..
+         */
+        break;
+    case DPDMA_GBL:
+        /*
+         * This is a write only register so it's read as zero in the read
+         * callback.
+         * We store the value anyway so we can know if the channel is
+         * enabled.
+         */
+        s->registers[offset] |= value & 0x00000FFF;
+        break;
+    case DPDMA_DSCR_STRT_ADDRE_CH(0):
+    case DPDMA_DSCR_STRT_ADDRE_CH(1):
+    case DPDMA_DSCR_STRT_ADDRE_CH(2):
+    case DPDMA_DSCR_STRT_ADDRE_CH(3):
+    case DPDMA_DSCR_STRT_ADDRE_CH(4):
+    case DPDMA_DSCR_STRT_ADDRE_CH(5):
+        value &= 0x0000FFFF;
+        s->registers[offset] = value;
+        break;
+    case DPDMA_CNTL_CH(0):
+        s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(0);
+        value &= 0x3FFFFFFF;
+        s->registers[offset] = value;
+        break;
+    case DPDMA_CNTL_CH(1):
+        s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(1);
+        value &= 0x3FFFFFFF;
+        s->registers[offset] = value;
+        break;
+    case DPDMA_CNTL_CH(2):
+        s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(2);
+        value &= 0x3FFFFFFF;
+        s->registers[offset] = value;
+        break;
+    case DPDMA_CNTL_CH(3):
+        s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(3);
+        value &= 0x3FFFFFFF;
+        s->registers[offset] = value;
+        break;
+    case DPDMA_CNTL_CH(4):
+        s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(4);
+        value &= 0x3FFFFFFF;
+        s->registers[offset] = value;
+        break;
+    case DPDMA_CNTL_CH(5):
+        s->registers[DPDMA_GBL] &= ~DPDMA_GBL_TRG_CH(5);
+        value &= 0x3FFFFFFF;
+        s->registers[offset] = value;
+        break;
+    default:
+        assert(offset <= (0xFFC >> 2));
+        s->registers[offset] = value;
+        break;
+    }
+}
+
+static const MemoryRegionOps dma_ops = {
+    .read = xlnx_dpdma_read,
+    .write = xlnx_dpdma_write,
+    .endianness = DEVICE_NATIVE_ENDIAN,
+    .valid = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+    .impl = {
+        .min_access_size = 4,
+        .max_access_size = 4,
+    },
+};
+
+static void xlnx_dpdma_init(Object *obj)
+{
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+    XlnxDPDMAState *s = XLNX_DPDMA(obj);
+
+    memory_region_init_io(&s->iomem, obj, &dma_ops, s,
+                          TYPE_XLNX_DPDMA, 0x1000);
+    sysbus_init_mmio(sbd, &s->iomem);
+    sysbus_init_irq(sbd, &s->irq);
+}
+
+static void xlnx_dpdma_reset(DeviceState *dev)
+{
+    XlnxDPDMAState *s = XLNX_DPDMA(dev);
+    size_t i;
+
+    memset(s->registers, 0, sizeof(s->registers));
+    s->registers[DPDMA_IMR] =  0x07FFFFFF;
+    s->registers[DPDMA_EIMR] = 0xFFFFFFFF;
+    s->registers[DPDMA_ALC0_MIN] = 0x0000FFFF;
+    s->registers[DPDMA_ALC1_MIN] = 0x0000FFFF;
+
+    for (i = 0; i < 6; i++) {
+        s->data[i] = NULL;
+        s->operation_finished[i] = true;
+    }
+}
+
+static void xlnx_dpdma_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+
+    dc->vmsd = &vmstate_xlnx_dpdma;
+    dc->reset = xlnx_dpdma_reset;
+}
+
+static const TypeInfo xlnx_dpdma_info = {
+    .name          = TYPE_XLNX_DPDMA,
+    .parent        = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(XlnxDPDMAState),
+    .instance_init = xlnx_dpdma_init,
+    .class_init    = xlnx_dpdma_class_init,
+};
+
+static void xlnx_dpdma_register_types(void)
+{
+    type_register_static(&xlnx_dpdma_info);
+}
+
+size_t xlnx_dpdma_start_operation(XlnxDPDMAState *s, uint8_t channel,
+                                    bool one_desc)
+{
+    uint64_t desc_addr;
+    uint64_t source_addr[6];
+    DPDMADescriptor desc;
+    bool done = false;
+    size_t ptr = 0;
+
+    assert(channel <= 5);
+
+    DPRINTF("start dpdma channel 0x%" PRIX8 "\n", channel);
+
+    if (!xlnx_dpdma_is_channel_triggered(s, channel)) {
+        DPRINTF("Channel isn't triggered..\n");
+        return 0;
+    }
+
+    if (!xlnx_dpdma_is_channel_enabled(s, channel)) {
+        DPRINTF("Channel isn't enabled..\n");
+        return 0;
+    }
+
+    if (xlnx_dpdma_is_channel_paused(s, channel)) {
+        DPRINTF("Channel is paused..\n");
+        return 0;
+    }
+
+    do {
+        if ((s->operation_finished[channel])
+          || xlnx_dpdma_is_channel_retriggered(s, channel)) {
+            desc_addr = xlnx_dpdma_descriptor_start_address(s, channel);
+            s->operation_finished[channel] = false;
+        } else {
+            desc_addr = xlnx_dpdma_descriptor_next_address(s, channel);
+        }
+
+        if (dma_memory_read(&address_space_memory, desc_addr, &desc,
+                            sizeof(DPDMADescriptor))) {
+            s->registers[DPDMA_EISR] |= ((1 << 1) << channel);
+            xlnx_dpdma_update_irq(s);
+            s->operation_finished[channel] = true;
+            DPRINTF("Can't get the descriptor.\n");
+            break;
+        }
+
+        xlnx_dpdma_update_desc_info(s, channel, &desc);
+
+#ifdef DEBUG_DPDMA
+        xlnx_dpdma_dump_descriptor(&desc);
+#endif
+
+        DPRINTF("location of the descriptor: %" PRIx64 "\n", desc_addr);
+        if (!xlnx_dpdma_desc_is_valid(&desc)) {
+            s->registers[DPDMA_EISR] |= ((1 << 7) << channel);
+            xlnx_dpdma_update_irq(s);
+            s->operation_finished[channel] = true;
+            DPRINTF("Invalid descriptor..\n");
+            break;
+        }
+
+        if (xlnx_dpdma_desc_crc_enabled(&desc)
+            && !xlnx_dpdma_desc_check_crc(&desc)) {
+            s->registers[DPDMA_EISR] |= ((1 << 13) << channel);
+            xlnx_dpdma_update_irq(s);
+            s->operation_finished[channel] = true;
+            DPRINTF("Bad CRC for descriptor..\n");
+            break;
+        }
+
+        if (xlnx_dpdma_desc_is_already_done(&desc)
+            && !xlnx_dpdma_desc_ignore_done_bit(&desc)) {
+            /* We are trying to process an already processed descriptor. */
+            s->registers[DPDMA_EISR] |= ((1 << 25) << channel);
+            xlnx_dpdma_update_irq(s);
+            s->operation_finished[channel] = true;
+            DPRINTF("Already processed descriptor..\n");
+            break;
+        }
+
+        done = xlnx_dpdma_desc_is_last(&desc)
+             || xlnx_dpdma_desc_is_last_of_frame(&desc);
+
+        s->operation_finished[channel] = done;
+        if (s->data[channel]) {
+            int64_t transfer_len = xlnx_dpdma_desc_get_transfer_size(&desc);
+            uint32_t line_size = xlnx_dpdma_desc_get_line_size(&desc);
+            uint32_t line_stride = xlnx_dpdma_desc_get_line_stride(&desc);
+            if (xlnx_dpdma_desc_is_contiguous(&desc)) {
+                source_addr[0] = xlnx_dpdma_desc_get_source_address(&desc, 0);
+                while (transfer_len != 0) {
+                    if (dma_memory_read(&address_space_memory,
+                                        source_addr[0],
+                                        &s->data[channel][ptr],
+                                        line_size)) {
+                        s->registers[DPDMA_ISR] |= ((1 << 12) << channel);
+                        xlnx_dpdma_update_irq(s);
+                        DPRINTF("Can't get data.\n");
+                        break;
+                    }
+                    ptr += line_size;
+                    transfer_len -= line_size;
+                    source_addr[0] += line_stride;
+                }
+            } else {
+                DPRINTF("Source address:\n");
+                int frag;
+                for (frag = 0; frag < 5; frag++) {
+                    source_addr[frag] =
+                          xlnx_dpdma_desc_get_source_address(&desc, frag);
+                    DPRINTF("Fragment %u: %" PRIx64 "\n", frag + 1,
+                            source_addr[frag]);
+                }
+
+                frag = 0;
+                while ((transfer_len < 0) && (frag < 5)) {
+                    size_t fragment_len = DPDMA_FRAG_MAX_SZ
+                                    - (source_addr[frag] % DPDMA_FRAG_MAX_SZ);
+
+                    if (dma_memory_read(&address_space_memory,
+                                        source_addr[frag],
+                                        &(s->data[channel][ptr]),
+                                        fragment_len)) {
+                        s->registers[DPDMA_ISR] |= ((1 << 12) << channel);
+                        xlnx_dpdma_update_irq(s);
+                        DPRINTF("Can't get data.\n");
+                        break;
+                    }
+                    ptr += fragment_len;
+                    transfer_len -= fragment_len;
+                    frag += 1;
+                }
+            }
+        }
+
+        if (xlnx_dpdma_desc_update_enabled(&desc)) {
+            /* The descriptor need to be updated when it's completed. */
+            DPRINTF("update the descriptor with the done flag set.\n");
+            xlnx_dpdma_desc_set_done(&desc);
+            dma_memory_write(&address_space_memory, desc_addr, &desc,
+                             sizeof(DPDMADescriptor));
+        }
+
+        if (xlnx_dpdma_desc_completion_interrupt(&desc)) {
+            DPRINTF("completion interrupt enabled!\n");
+            s->registers[DPDMA_ISR] |= (1 << channel);
+            xlnx_dpdma_update_irq(s);
+        }
+
+    } while (!done && !one_desc);
+
+    return ptr;
+}
+
+void xlnx_dpdma_set_host_data_location(XlnxDPDMAState *s, uint8_t channel,
+                                         void *p)
+{
+    if (!s) {
+        qemu_log_mask(LOG_UNIMP, "DPDMA client not attached to valid DPDMA"
+                      " instance\n");
+        return;
+    }
+
+    assert(channel <= 5);
+    s->data[channel] = p;
+}
+
+void xlnx_dpdma_trigger_vsync_irq(XlnxDPDMAState *s)
+{
+    s->registers[DPDMA_ISR] |= (1 << 27);
+    xlnx_dpdma_update_irq(s);
+}
+
+type_init(xlnx_dpdma_register_types)
diff --git a/hw/gpio/omap_gpio.c b/hw/gpio/omap_gpio.c
index 9b1b004fc2..dabef4a119 100644
--- a/hw/gpio/omap_gpio.c
+++ b/hw/gpio/omap_gpio.c
@@ -23,6 +23,7 @@
 #include "hw/arm/omap.h"
 #include "hw/sysbus.h"
 #include "qemu/error-report.h"
+#include "qapi/error.h"
 
 struct omap_gpio_s {
     qemu_irq irq;
@@ -678,48 +679,46 @@ static const MemoryRegionOps omap2_gpif_top_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static int omap_gpio_init(SysBusDevice *sbd)
+static void omap_gpio_init(Object *obj)
 {
-    DeviceState *dev = DEVICE(sbd);
-    struct omap_gpif_s *s = OMAP1_GPIO(dev);
+    DeviceState *dev = DEVICE(obj);
+    struct omap_gpif_s *s = OMAP1_GPIO(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 
-    if (!s->clk) {
-        error_report("omap-gpio: clk not connected");
-        return -1;
-    }
     qdev_init_gpio_in(dev, omap_gpio_set, 16);
     qdev_init_gpio_out(dev, s->omap1.handler, 16);
     sysbus_init_irq(sbd, &s->omap1.irq);
-    memory_region_init_io(&s->iomem, OBJECT(s), &omap_gpio_ops, &s->omap1,
+    memory_region_init_io(&s->iomem, obj, &omap_gpio_ops, &s->omap1,
                           "omap.gpio", 0x1000);
     sysbus_init_mmio(sbd, &s->iomem);
-    return 0;
 }
 
-static int omap2_gpio_init(SysBusDevice *sbd)
+static void omap_gpio_realize(DeviceState *dev, Error **errp)
+{
+    struct omap_gpif_s *s = OMAP1_GPIO(dev);
+
+    if (!s->clk) {
+        error_setg(errp, "omap-gpio: clk not connected");
+    }
+}
+
+static void omap2_gpio_realize(DeviceState *dev, Error **errp)
 {
-    DeviceState *dev = DEVICE(sbd);
     struct omap2_gpif_s *s = OMAP2_GPIO(dev);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
     int i;
 
     if (!s->iclk) {
-        error_report("omap2-gpio: iclk not connected");
-        return -1;
+        error_setg(errp, "omap2-gpio: iclk not connected");
+        return;
     }
 
     s->modulecount = s->mpu_model < omap2430 ? 4
-                   : s->mpu_model < omap3430 ? 5
-                   : 6;
-
-    for (i = 0; i < s->modulecount; i++) {
-        if (!s->fclk[i]) {
-            error_report("omap2-gpio: fclk%d not connected", i);
-            return -1;
-        }
-    }
+        : s->mpu_model < omap3430 ? 5
+        : 6;
 
     if (s->mpu_model < omap3430) {
-        memory_region_init_io(&s->iomem, OBJECT(s), &omap2_gpif_top_ops, s,
+        memory_region_init_io(&s->iomem, OBJECT(dev), &omap2_gpif_top_ops, s,
                               "omap2.gpio", 0x1000);
         sysbus_init_mmio(sbd, &s->iomem);
     }
@@ -732,17 +731,20 @@ static int omap2_gpio_init(SysBusDevice *sbd)
     for (i = 0; i < s->modulecount; i++) {
         struct omap2_gpio_s *m = &s->modules[i];
 
+        if (!s->fclk[i]) {
+            error_setg(errp, "omap2-gpio: fclk%d not connected", i);
+            return;
+        }
+
         m->revision = (s->mpu_model < omap3430) ? 0x18 : 0x25;
         m->handler = &s->handler[i * 32];
         sysbus_init_irq(sbd, &m->irq[0]); /* mpu irq */
         sysbus_init_irq(sbd, &m->irq[1]); /* dsp irq */
         sysbus_init_irq(sbd, &m->wkup);
-        memory_region_init_io(&m->iomem, OBJECT(s), &omap2_gpio_module_ops, m,
+        memory_region_init_io(&m->iomem, OBJECT(dev), &omap2_gpio_module_ops, m,
                               "omap.gpio-module", 0x1000);
         sysbus_init_mmio(sbd, &m->iomem);
     }
-
-    return 0;
 }
 
 /* Using qdev pointer properties for the clocks is not ideal.
@@ -766,9 +768,8 @@ static Property omap_gpio_properties[] = {
 static void omap_gpio_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = omap_gpio_init;
+    dc->realize = omap_gpio_realize;
     dc->reset = omap_gpif_reset;
     dc->props = omap_gpio_properties;
     /* Reason: pointer property "clk" */
@@ -779,6 +780,7 @@ static const TypeInfo omap_gpio_info = {
     .name          = TYPE_OMAP1_GPIO,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(struct omap_gpif_s),
+    .instance_init = omap_gpio_init,
     .class_init    = omap_gpio_class_init,
 };
 
@@ -797,9 +799,8 @@ static Property omap2_gpio_properties[] = {
 static void omap2_gpio_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = omap2_gpio_init;
+    dc->realize = omap2_gpio_realize;
     dc->reset = omap2_gpif_reset;
     dc->props = omap2_gpio_properties;
     /* Reason: pointer properties "iclk", "fclk0", ..., "fclk5" */
diff --git a/hw/gpio/pl061.c b/hw/gpio/pl061.c
index 44faeb23b7..4ae2aa1566 100644
--- a/hw/gpio/pl061.c
+++ b/hw/gpio/pl061.c
@@ -341,20 +341,6 @@ static const MemoryRegionOps pl061_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static int pl061_initfn(SysBusDevice *sbd)
-{
-    DeviceState *dev = DEVICE(sbd);
-    PL061State *s = PL061(dev);
-
-    memory_region_init_io(&s->iomem, OBJECT(s), &pl061_ops, s, "pl061", 0x1000);
-    sysbus_init_mmio(sbd, &s->iomem);
-    sysbus_init_irq(sbd, &s->irq);
-    qdev_init_gpio_in(dev, pl061_set_irq, 8);
-    qdev_init_gpio_out(dev, s->out, 8);
-
-    return 0;
-}
-
 static void pl061_luminary_init(Object *obj)
 {
     PL061State *s = PL061(obj);
@@ -366,17 +352,23 @@ static void pl061_luminary_init(Object *obj)
 static void pl061_init(Object *obj)
 {
     PL061State *s = PL061(obj);
+    DeviceState *dev = DEVICE(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 
     s->id = pl061_id;
     s->rsvd_start = 0x424;
+
+    memory_region_init_io(&s->iomem, obj, &pl061_ops, s, "pl061", 0x1000);
+    sysbus_init_mmio(sbd, &s->iomem);
+    sysbus_init_irq(sbd, &s->irq);
+    qdev_init_gpio_in(dev, pl061_set_irq, 8);
+    qdev_init_gpio_out(dev, s->out, 8);
 }
 
 static void pl061_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = pl061_initfn;
     dc->vmsd = &vmstate_pl061;
     dc->reset = &pl061_reset;
 }
diff --git a/hw/gpio/zaurus.c b/hw/gpio/zaurus.c
index 555da281c6..15865e1081 100644
--- a/hw/gpio/zaurus.c
+++ b/hw/gpio/zaurus.c
@@ -167,19 +167,18 @@ static void scoop_gpio_set(void *opaque, int line, int level)
         s->gpio_level &= ~(1 << line);
 }
 
-static int scoop_init(SysBusDevice *sbd)
+static void scoop_init(Object *obj)
 {
-    DeviceState *dev = DEVICE(sbd);
-    ScoopInfo *s = SCOOP(dev);
+    DeviceState *dev = DEVICE(obj);
+    ScoopInfo *s = SCOOP(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 
     s->status = 0x02;
     qdev_init_gpio_out(dev, s->handler, 16);
     qdev_init_gpio_in(dev, scoop_gpio_set, 16);
-    memory_region_init_io(&s->iomem, OBJECT(s), &scoop_ops, s, "scoop", 0x1000);
+    memory_region_init_io(&s->iomem, obj, &scoop_ops, s, "scoop", 0x1000);
 
     sysbus_init_mmio(sbd, &s->iomem);
-
-    return 0;
 }
 
 static int scoop_post_load(void *opaque, int version_id)
@@ -239,9 +238,7 @@ static const VMStateDescription vmstate_scoop_regs = {
 static void scoop_sysbus_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = scoop_init;
     dc->desc = "Scoop2 Sharp custom ASIC";
     dc->vmsd = &vmstate_scoop_regs;
 }
@@ -250,6 +247,7 @@ static const TypeInfo scoop_sysbus_info = {
     .name          = TYPE_SCOOP,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(ScoopInfo),
+    .instance_init = scoop_init,
     .class_init    = scoop_sysbus_class_init,
 };
 
diff --git a/hw/i2c/Makefile.objs b/hw/i2c/Makefile.objs
index 1fd54edf4c..a081b8ef2c 100644
--- a/hw/i2c/Makefile.objs
+++ b/hw/i2c/Makefile.objs
@@ -1,4 +1,5 @@
 common-obj-y += core.o smbus.o smbus_eeprom.o
+common-obj-$(CONFIG_DDC) += i2c-ddc.o
 common-obj-$(CONFIG_VERSATILE_I2C) += versatile_i2c.o
 common-obj-$(CONFIG_ACPI_X86) += smbus_ich9.o
 common-obj-$(CONFIG_APM) += pm_smbus.o
diff --git a/hw/i2c/bitbang_i2c.c b/hw/i2c/bitbang_i2c.c
index 6ed2060203..d3a29891f8 100644
--- a/hw/i2c/bitbang_i2c.c
+++ b/hw/i2c/bitbang_i2c.c
@@ -210,13 +210,14 @@ static void bitbang_i2c_gpio_set(void *opaque, int irq, int level)
     }
 }
 
-static int gpio_i2c_init(SysBusDevice *sbd)
+static void gpio_i2c_init(Object *obj)
 {
-    DeviceState *dev = DEVICE(sbd);
-    GPIOI2CState *s = GPIO_I2C(dev);
+    DeviceState *dev = DEVICE(obj);
+    GPIOI2CState *s = GPIO_I2C(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
     I2CBus *bus;
 
-    memory_region_init(&s->dummy_iomem, OBJECT(s), "gpio_i2c", 0);
+    memory_region_init(&s->dummy_iomem, obj, "gpio_i2c", 0);
     sysbus_init_mmio(sbd, &s->dummy_iomem);
 
     bus = i2c_init_bus(dev, "i2c");
@@ -224,16 +225,12 @@ static int gpio_i2c_init(SysBusDevice *sbd)
 
     qdev_init_gpio_in(dev, bitbang_i2c_gpio_set, 2);
     qdev_init_gpio_out(dev, &s->out, 1);
-
-    return 0;
 }
 
 static void gpio_i2c_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = gpio_i2c_init;
     set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
     dc->desc = "Virtual GPIO to I2C bridge";
 }
@@ -242,6 +239,7 @@ static const TypeInfo gpio_i2c_info = {
     .name          = TYPE_GPIO_I2C,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(GPIOI2CState),
+    .instance_init = gpio_i2c_init,
     .class_init    = gpio_i2c_class_init,
 };
 
diff --git a/hw/i2c/core.c b/hw/i2c/core.c
index ba22104af8..abb3efb1db 100644
--- a/hw/i2c/core.c
+++ b/hw/i2c/core.c
@@ -10,12 +10,19 @@
 #include "qemu/osdep.h"
 #include "hw/i2c/i2c.h"
 
+typedef struct I2CNode I2CNode;
+
+struct I2CNode {
+    I2CSlave *elt;
+    QLIST_ENTRY(I2CNode) next;
+};
+
 struct I2CBus
 {
     BusState qbus;
-    I2CSlave *current_dev;
-    I2CSlave *dev;
+    QLIST_HEAD(, I2CNode) current_devs;
     uint8_t saved_address;
+    bool broadcast;
 };
 
 static Property i2c_props[] = {
@@ -36,17 +43,12 @@ static void i2c_bus_pre_save(void *opaque)
 {
     I2CBus *bus = opaque;
 
-    bus->saved_address = bus->current_dev ? bus->current_dev->address : -1;
-}
-
-static int i2c_bus_post_load(void *opaque, int version_id)
-{
-    I2CBus *bus = opaque;
-
-    /* The bus is loaded before attached devices, so load and save the
-       current device id.  Devices will check themselves as loaded.  */
-    bus->current_dev = NULL;
-    return 0;
+    bus->saved_address = -1;
+    if (!QLIST_EMPTY(&bus->current_devs)) {
+        if (!bus->broadcast) {
+            bus->saved_address = QLIST_FIRST(&bus->current_devs)->elt->address;
+        }
+    }
 }
 
 static const VMStateDescription vmstate_i2c_bus = {
@@ -54,9 +56,9 @@ static const VMStateDescription vmstate_i2c_bus = {
     .version_id = 1,
     .minimum_version_id = 1,
     .pre_save = i2c_bus_pre_save,
-    .post_load = i2c_bus_post_load,
     .fields = (VMStateField[]) {
         VMSTATE_UINT8(saved_address, I2CBus),
+        VMSTATE_BOOL(broadcast, I2CBus),
         VMSTATE_END_OF_LIST()
     }
 };
@@ -67,6 +69,7 @@ I2CBus *i2c_init_bus(DeviceState *parent, const char *name)
     I2CBus *bus;
 
     bus = I2C_BUS(qbus_create(TYPE_I2C_BUS, parent, name));
+    QLIST_INIT(&bus->current_devs);
     vmstate_register(NULL, -1, &vmstate_i2c_bus, bus);
     return bus;
 }
@@ -79,7 +82,7 @@ void i2c_set_slave_address(I2CSlave *dev, uint8_t address)
 /* Return nonzero if bus is busy.  */
 int i2c_bus_busy(I2CBus *bus)
 {
-    return bus->current_dev != NULL;
+    return !QLIST_EMPTY(&bus->current_devs);
 }
 
 /* Returns non-zero if the address is not valid.  */
@@ -87,95 +90,127 @@ int i2c_bus_busy(I2CBus *bus)
 int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv)
 {
     BusChild *kid;
-    I2CSlave *slave = NULL;
     I2CSlaveClass *sc;
+    I2CNode *node;
+
+    if (address == 0x00) {
+        /*
+         * This is a broadcast, the current_devs will be all the devices of the
+         * bus.
+         */
+        bus->broadcast = true;
+    }
 
     QTAILQ_FOREACH(kid, &bus->qbus.children, sibling) {
         DeviceState *qdev = kid->child;
         I2CSlave *candidate = I2C_SLAVE(qdev);
-        if (candidate->address == address) {
-            slave = candidate;
-            break;
+        if ((candidate->address == address) || (bus->broadcast)) {
+            node = g_malloc(sizeof(struct I2CNode));
+            node->elt = candidate;
+            QLIST_INSERT_HEAD(&bus->current_devs, node, next);
+            if (!bus->broadcast) {
+                break;
+            }
         }
     }
 
-    if (!slave) {
+    if (QLIST_EMPTY(&bus->current_devs)) {
         return 1;
     }
 
-    sc = I2C_SLAVE_GET_CLASS(slave);
-    /* If the bus is already busy, assume this is a repeated
-       start condition.  */
-    bus->current_dev = slave;
-    if (sc->event) {
-        sc->event(slave, recv ? I2C_START_RECV : I2C_START_SEND);
+    QLIST_FOREACH(node, &bus->current_devs, next) {
+        sc = I2C_SLAVE_GET_CLASS(node->elt);
+        /* If the bus is already busy, assume this is a repeated
+           start condition.  */
+        if (sc->event) {
+            sc->event(node->elt, recv ? I2C_START_RECV : I2C_START_SEND);
+        }
     }
     return 0;
 }
 
 void i2c_end_transfer(I2CBus *bus)
 {
-    I2CSlave *dev = bus->current_dev;
     I2CSlaveClass *sc;
+    I2CNode *node, *next;
 
-    if (!dev) {
+    if (QLIST_EMPTY(&bus->current_devs)) {
         return;
     }
 
-    sc = I2C_SLAVE_GET_CLASS(dev);
-    if (sc->event) {
-        sc->event(dev, I2C_FINISH);
+    QLIST_FOREACH_SAFE(node, &bus->current_devs, next, next) {
+        sc = I2C_SLAVE_GET_CLASS(node->elt);
+        if (sc->event) {
+            sc->event(node->elt, I2C_FINISH);
+        }
+        QLIST_REMOVE(node, next);
+        g_free(node);
     }
-
-    bus->current_dev = NULL;
+    bus->broadcast = false;
 }
 
-int i2c_send(I2CBus *bus, uint8_t data)
+int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send)
 {
-    I2CSlave *dev = bus->current_dev;
     I2CSlaveClass *sc;
+    I2CNode *node;
+    int ret = 0;
+
+    if (send) {
+        QLIST_FOREACH(node, &bus->current_devs, next) {
+            sc = I2C_SLAVE_GET_CLASS(node->elt);
+            if (sc->send) {
+                ret = ret || sc->send(node->elt, *data);
+            } else {
+                ret = -1;
+            }
+        }
+        return ret ? -1 : 0;
+    } else {
+        if ((QLIST_EMPTY(&bus->current_devs)) || (bus->broadcast)) {
+            return -1;
+        }
 
-    if (!dev) {
+        sc = I2C_SLAVE_GET_CLASS(QLIST_FIRST(&bus->current_devs)->elt);
+        if (sc->recv) {
+            ret = sc->recv(QLIST_FIRST(&bus->current_devs)->elt);
+            if (ret < 0) {
+                return ret;
+            } else {
+                *data = ret;
+                return 0;
+            }
+        }
         return -1;
     }
+}
 
-    sc = I2C_SLAVE_GET_CLASS(dev);
-    if (sc->send) {
-        return sc->send(dev, data);
-    }
-
-    return -1;
+int i2c_send(I2CBus *bus, uint8_t data)
+{
+    return i2c_send_recv(bus, &data, true);
 }
 
 int i2c_recv(I2CBus *bus)
 {
-    I2CSlave *dev = bus->current_dev;
-    I2CSlaveClass *sc;
-
-    if (!dev) {
-        return -1;
-    }
+    uint8_t data;
+    int ret = i2c_send_recv(bus, &data, false);
 
-    sc = I2C_SLAVE_GET_CLASS(dev);
-    if (sc->recv) {
-        return sc->recv(dev);
-    }
-
-    return -1;
+    return ret < 0 ? ret : data;
 }
 
 void i2c_nack(I2CBus *bus)
 {
-    I2CSlave *dev = bus->current_dev;
     I2CSlaveClass *sc;
+    I2CNode *node;
 
-    if (!dev) {
+    if (QLIST_EMPTY(&bus->current_devs)) {
         return;
     }
 
-    sc = I2C_SLAVE_GET_CLASS(dev);
-    if (sc->event) {
-        sc->event(dev, I2C_NACK);
+    QLIST_FOREACH(node, &bus->current_devs, next) {
+        sc = I2C_SLAVE_GET_CLASS(node->elt);
+        if (sc->event) {
+            sc->event(node->elt, I2C_NACK);
+        }
     }
 }
 
@@ -183,9 +218,13 @@ static int i2c_slave_post_load(void *opaque, int version_id)
 {
     I2CSlave *dev = opaque;
     I2CBus *bus;
+    I2CNode *node;
+
     bus = I2C_BUS(qdev_get_parent_bus(DEVICE(dev)));
-    if (bus->saved_address == dev->address) {
-        bus->current_dev = dev;
+    if ((bus->saved_address == dev->address) || (bus->broadcast)) {
+        node = g_malloc(sizeof(struct I2CNode));
+        node->elt = dev;
+        QLIST_INSERT_HEAD(&bus->current_devs, node, next);
     }
     return 0;
 }
diff --git a/hw/i2c/exynos4210_i2c.c b/hw/i2c/exynos4210_i2c.c
index 8c2a2c1632..c96fa7d7be 100644
--- a/hw/i2c/exynos4210_i2c.c
+++ b/hw/i2c/exynos4210_i2c.c
@@ -299,33 +299,32 @@ static void exynos4210_i2c_reset(DeviceState *d)
     s->scl_free = true;
 }
 
-static int exynos4210_i2c_realize(SysBusDevice *sbd)
+static void exynos4210_i2c_init(Object *obj)
 {
-    DeviceState *dev = DEVICE(sbd);
-    Exynos4210I2CState *s = EXYNOS4_I2C(dev);
+    DeviceState *dev = DEVICE(obj);
+    Exynos4210I2CState *s = EXYNOS4_I2C(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 
-    memory_region_init_io(&s->iomem, OBJECT(s), &exynos4210_i2c_ops, s,
+    memory_region_init_io(&s->iomem, obj, &exynos4210_i2c_ops, s,
                           TYPE_EXYNOS4_I2C, EXYNOS4_I2C_MEM_SIZE);
     sysbus_init_mmio(sbd, &s->iomem);
     sysbus_init_irq(sbd, &s->irq);
     s->bus = i2c_init_bus(dev, "i2c");
-    return 0;
 }
 
 static void exynos4210_i2c_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass);
 
     dc->vmsd = &exynos4210_i2c_vmstate;
     dc->reset = exynos4210_i2c_reset;
-    sbdc->init = exynos4210_i2c_realize;
 }
 
 static const TypeInfo exynos4210_i2c_type_info = {
     .name = TYPE_EXYNOS4_I2C,
     .parent = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(Exynos4210I2CState),
+    .instance_init = exynos4210_i2c_init,
     .class_init = exynos4210_i2c_class_init,
 };
 
diff --git a/hw/i2c/i2c-ddc.c b/hw/i2c/i2c-ddc.c
new file mode 100644
index 0000000000..1227212934
--- /dev/null
+++ b/hw/i2c/i2c-ddc.c
@@ -0,0 +1,308 @@
+/* A simple I2C slave for returning monitor EDID data via DDC.
+ *
+ * Copyright (c) 2011 Linaro Limited
+ * Written by Peter Maydell
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/i2c/i2c.h"
+#include "hw/i2c/i2c-ddc.h"
+
+#ifndef DEBUG_I2CDDC
+#define DEBUG_I2CDDC 0
+#endif
+
+#define DPRINTF(fmt, ...) do {                                                 \
+    if (DEBUG_I2CDDC) {                                                        \
+        qemu_log("i2c-ddc: " fmt , ## __VA_ARGS__);                            \
+    }                                                                          \
+} while (0);
+
+/* Structure defining a monitor's characteristics in a
+ * readable format: this should be passed to build_edid_blob()
+ * to convert it into the 128 byte binary EDID blob.
+ * Not all bits of the EDID are customisable here.
+ */
+struct EDIDData {
+    char manuf_id[3]; /* three upper case letters */
+    uint16_t product_id;
+    uint32_t serial_no;
+    uint8_t manuf_week;
+    int manuf_year;
+    uint8_t h_cm;
+    uint8_t v_cm;
+    uint8_t gamma;
+    char monitor_name[14];
+    char serial_no_string[14];
+    /* Range limits */
+    uint8_t vmin; /* Hz */
+    uint8_t vmax; /* Hz */
+    uint8_t hmin; /* kHz */
+    uint8_t hmax; /* kHz */
+    uint8_t pixclock; /* MHz / 10 */
+    uint8_t timing_data[18];
+};
+
+typedef struct EDIDData EDIDData;
+
+/* EDID data for a simple LCD monitor */
+static const EDIDData lcd_edid = {
+    /* The manuf_id ought really to be an assigned EISA ID */
+    .manuf_id = "QMU",
+    .product_id = 0,
+    .serial_no = 1,
+    .manuf_week = 1,
+    .manuf_year = 2011,
+    .h_cm = 40,
+    .v_cm = 30,
+    .gamma = 0x78,
+    .monitor_name = "QEMU monitor",
+    .serial_no_string = "1",
+    .vmin = 40,
+    .vmax = 120,
+    .hmin = 30,
+    .hmax = 100,
+    .pixclock = 18,
+    .timing_data = {
+        /* Borrowed from a 21" LCD */
+        0x48, 0x3f, 0x40, 0x30, 0x62, 0xb0, 0x32, 0x40, 0x40,
+        0xc0, 0x13, 0x00, 0x98, 0x32, 0x11, 0x00, 0x00, 0x1e
+    }
+};
+
+static uint8_t manuf_char_to_int(char c)
+{
+    return (c - 'A') & 0x1f;
+}
+
+static void write_ascii_descriptor_block(uint8_t *descblob, uint8_t blocktype,
+                                         const char *string)
+{
+    /* Write an EDID Descriptor Block of the "ascii string" type */
+    int i;
+    descblob[0] = descblob[1] = descblob[2] = descblob[4] = 0;
+    descblob[3] = blocktype;
+    /* The rest is 13 bytes of ASCII; if less then the rest must
+     * be filled with newline then spaces
+     */
+    for (i = 5; i < 19; i++) {
+        descblob[i] = string[i - 5];
+        if (!descblob[i]) {
+            break;
+        }
+    }
+    if (i < 19) {
+        descblob[i++] = '\n';
+    }
+    for ( ; i < 19; i++) {
+        descblob[i] = ' ';
+    }
+}
+
+static void write_range_limits_descriptor(const EDIDData *edid,
+                                          uint8_t *descblob)
+{
+    int i;
+    descblob[0] = descblob[1] = descblob[2] = descblob[4] = 0;
+    descblob[3] = 0xfd;
+    descblob[5] = edid->vmin;
+    descblob[6] = edid->vmax;
+    descblob[7] = edid->hmin;
+    descblob[8] = edid->hmax;
+    descblob[9] = edid->pixclock;
+    descblob[10] = 0;
+    descblob[11] = 0xa;
+    for (i = 12; i < 19; i++) {
+        descblob[i] = 0x20;
+    }
+}
+
+static void build_edid_blob(const EDIDData *edid, uint8_t *blob)
+{
+    /* Write an EDID 1.3 format blob (128 bytes) based
+     * on the EDIDData structure.
+     */
+    int i;
+    uint8_t cksum;
+
+    /* 00-07 : header */
+    blob[0] = blob[7] = 0;
+    for (i = 1 ; i < 7; i++) {
+        blob[i] = 0xff;
+    }
+    /* 08-09 : manufacturer ID */
+    blob[8] = (manuf_char_to_int(edid->manuf_id[0]) << 2)
+        | (manuf_char_to_int(edid->manuf_id[1]) >> 3);
+    blob[9] = (manuf_char_to_int(edid->manuf_id[1]) << 5)
+        | manuf_char_to_int(edid->manuf_id[2]);
+    /* 10-11 : product ID code */
+    blob[10] = edid->product_id;
+    blob[11] = edid->product_id >> 8;
+    blob[12] = edid->serial_no;
+    blob[13] = edid->serial_no >> 8;
+    blob[14] = edid->serial_no >> 16;
+    blob[15] = edid->serial_no >> 24;
+    /* 16 : week of manufacture */
+    blob[16] = edid->manuf_week;
+    /* 17 : year of manufacture - 1990 */
+    blob[17] = edid->manuf_year - 1990;
+    /* 18, 19 : EDID version and revision */
+    blob[18] = 1;
+    blob[19] = 3;
+    /* 20 - 24 : basic display parameters */
+    /* We are always a digital display */
+    blob[20] = 0x80;
+    /* 21, 22 : max h/v size in cm */
+    blob[21] = edid->h_cm;
+    blob[22] = edid->v_cm;
+    /* 23 : gamma (divide by 100 then add 1 for actual value) */
+    blob[23] = edid->gamma;
+    /* 24 feature support: no power management, RGB, preferred timing mode,
+     * standard colour space
+     */
+    blob[24] = 0x0e;
+    /* 25 - 34 : chromaticity coordinates. These are the
+     * standard sRGB chromaticity values
+     */
+    blob[25] = 0xee;
+    blob[26] = 0x91;
+    blob[27] = 0xa3;
+    blob[28] = 0x54;
+    blob[29] = 0x4c;
+    blob[30] = 0x99;
+    blob[31] = 0x26;
+    blob[32] = 0x0f;
+    blob[33] = 0x50;
+    blob[34] = 0x54;
+    /* 35, 36 : Established timings: claim to support everything */
+    blob[35] = blob[36] = 0xff;
+    /* 37 : manufacturer's reserved timing: none */
+    blob[37] = 0;
+    /* 38 - 53 : standard timing identification
+     * don't claim anything beyond what the 'established timings'
+     * already provide. Unused slots must be (0x1, 0x1)
+     */
+    for (i = 38; i < 54; i++) {
+        blob[i] = 0x1;
+    }
+    /* 54 - 71 : descriptor block 1 : must be preferred timing data */
+    memcpy(blob + 54, edid->timing_data, 18);
+    /* 72 - 89, 90 - 107, 108 - 125 : descriptor block 2, 3, 4
+     * Order not important, but we must have a monitor name and a
+     * range limits descriptor.
+     */
+    write_range_limits_descriptor(edid, blob + 72);
+    write_ascii_descriptor_block(blob + 90, 0xfc, edid->monitor_name);
+    write_ascii_descriptor_block(blob + 108, 0xff, edid->serial_no_string);
+
+    /* 126 : extension flag */
+    blob[126] = 0;
+
+    cksum = 0;
+    for (i = 0; i < 127; i++) {
+        cksum += blob[i];
+    }
+    /* 127 : checksum */
+    blob[127] = -cksum;
+    if (DEBUG_I2CDDC) {
+        qemu_hexdump((char *)blob, stdout, "", 128);
+    }
+}
+
+static void i2c_ddc_reset(DeviceState *ds)
+{
+    I2CDDCState *s = I2CDDC(ds);
+
+    s->firstbyte = false;
+    s->reg = 0;
+}
+
+static void i2c_ddc_event(I2CSlave *i2c, enum i2c_event event)
+{
+    I2CDDCState *s = I2CDDC(i2c);
+
+    if (event == I2C_START_SEND) {
+        s->firstbyte = true;
+    }
+}
+
+static int i2c_ddc_rx(I2CSlave *i2c)
+{
+    I2CDDCState *s = I2CDDC(i2c);
+
+    int value;
+    value = s->edid_blob[s->reg];
+    s->reg++;
+    return value;
+}
+
+static int i2c_ddc_tx(I2CSlave *i2c, uint8_t data)
+{
+    I2CDDCState *s = I2CDDC(i2c);
+    if (s->firstbyte) {
+        s->reg = data;
+        s->firstbyte = false;
+        DPRINTF("[EDID] Written new pointer: %u\n", data);
+        return 1;
+    }
+
+    /* Ignore all writes */
+    s->reg++;
+    return 1;
+}
+
+static void i2c_ddc_init(Object *obj)
+{
+    I2CDDCState *s = I2CDDC(obj);
+    build_edid_blob(&lcd_edid, s->edid_blob);
+}
+
+static const VMStateDescription vmstate_i2c_ddc = {
+    .name = TYPE_I2CDDC,
+    .version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_BOOL(firstbyte, I2CDDCState),
+        VMSTATE_UINT8(reg, I2CDDCState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static void i2c_ddc_class_init(ObjectClass *oc, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(oc);
+    I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc);
+
+    dc->reset = i2c_ddc_reset;
+    dc->vmsd = &vmstate_i2c_ddc;
+    isc->event = i2c_ddc_event;
+    isc->recv = i2c_ddc_rx;
+    isc->send = i2c_ddc_tx;
+}
+
+static TypeInfo i2c_ddc_info = {
+    .name = TYPE_I2CDDC,
+    .parent = TYPE_I2C_SLAVE,
+    .instance_size = sizeof(I2CDDCState),
+    .instance_init = i2c_ddc_init,
+    .class_init = i2c_ddc_class_init
+};
+
+static void ddc_register_devices(void)
+{
+    type_register_static(&i2c_ddc_info);
+}
+
+type_init(ddc_register_devices);
diff --git a/hw/i2c/omap_i2c.c b/hw/i2c/omap_i2c.c
index 67fbbff8e0..f7c92ea00c 100644
--- a/hw/i2c/omap_i2c.c
+++ b/hw/i2c/omap_i2c.c
@@ -22,6 +22,7 @@
 #include "hw/arm/omap.h"
 #include "hw/sysbus.h"
 #include "qemu/error-report.h"
+#include "qapi/error.h"
 
 #define TYPE_OMAP_I2C "omap_i2c"
 #define OMAP_I2C(obj) OBJECT_CHECK(OMAPI2CState, (obj), TYPE_OMAP_I2C)
@@ -445,29 +446,35 @@ static const MemoryRegionOps omap_i2c_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static int omap_i2c_init(SysBusDevice *sbd)
+static void omap_i2c_init(Object *obj)
+{
+    DeviceState *dev = DEVICE(obj);
+    OMAPI2CState *s = OMAP_I2C(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
+
+    sysbus_init_irq(sbd, &s->irq);
+    sysbus_init_irq(sbd, &s->drq[0]);
+    sysbus_init_irq(sbd, &s->drq[1]);
+    sysbus_init_mmio(sbd, &s->iomem);
+    s->bus = i2c_init_bus(dev, NULL);
+}
+
+static void omap_i2c_realize(DeviceState *dev, Error **errp)
 {
-    DeviceState *dev = DEVICE(sbd);
     OMAPI2CState *s = OMAP_I2C(dev);
 
+    memory_region_init_io(&s->iomem, OBJECT(dev), &omap_i2c_ops, s, "omap.i2c",
+                          (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000);
+
     if (!s->fclk) {
-        error_report("omap_i2c: fclk not connected");
-        return -1;
+        error_setg(errp, "omap_i2c: fclk not connected");
+        return;
     }
     if (s->revision >= OMAP2_INTR_REV && !s->iclk) {
         /* Note that OMAP1 doesn't have a separate interface clock */
-        error_report("omap_i2c: iclk not connected");
-        return -1;
+        error_setg(errp, "omap_i2c: iclk not connected");
+        return;
     }
-
-    sysbus_init_irq(sbd, &s->irq);
-    sysbus_init_irq(sbd, &s->drq[0]);
-    sysbus_init_irq(sbd, &s->drq[1]);
-    memory_region_init_io(&s->iomem, OBJECT(s), &omap_i2c_ops, s, "omap.i2c",
-                          (s->revision < OMAP2_INTR_REV) ? 0x800 : 0x1000);
-    sysbus_init_mmio(sbd, &s->iomem);
-    s->bus = i2c_init_bus(dev, NULL);
-    return 0;
 }
 
 static Property omap_i2c_properties[] = {
@@ -480,18 +487,19 @@ static Property omap_i2c_properties[] = {
 static void omap_i2c_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-    k->init = omap_i2c_init;
+
     dc->props = omap_i2c_properties;
     dc->reset = omap_i2c_reset;
     /* Reason: pointer properties "iclk", "fclk" */
     dc->cannot_instantiate_with_device_add_yet = true;
+    dc->realize = omap_i2c_realize;
 }
 
 static const TypeInfo omap_i2c_info = {
     .name = TYPE_OMAP_I2C,
     .parent = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(OMAPI2CState),
+    .instance_init = omap_i2c_init,
     .class_init = omap_i2c_class_init,
 };
 
diff --git a/hw/i2c/versatile_i2c.c b/hw/i2c/versatile_i2c.c
index 0bce52416e..da9f298ee5 100644
--- a/hw/i2c/versatile_i2c.c
+++ b/hw/i2c/versatile_i2c.c
@@ -79,32 +79,25 @@ static const MemoryRegionOps versatile_i2c_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
 };
 
-static int versatile_i2c_init(SysBusDevice *sbd)
+static void versatile_i2c_init(Object *obj)
 {
-    DeviceState *dev = DEVICE(sbd);
-    VersatileI2CState *s = VERSATILE_I2C(dev);
+    DeviceState *dev = DEVICE(obj);
+    VersatileI2CState *s = VERSATILE_I2C(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
     I2CBus *bus;
 
     bus = i2c_init_bus(dev, "i2c");
     s->bitbang = bitbang_i2c_init(bus);
-    memory_region_init_io(&s->iomem, OBJECT(s), &versatile_i2c_ops, s,
+    memory_region_init_io(&s->iomem, obj, &versatile_i2c_ops, s,
                           "versatile_i2c", 0x1000);
     sysbus_init_mmio(sbd, &s->iomem);
-    return 0;
-}
-
-static void versatile_i2c_class_init(ObjectClass *klass, void *data)
-{
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
-    k->init = versatile_i2c_init;
 }
 
 static const TypeInfo versatile_i2c_info = {
     .name          = TYPE_VERSATILE_I2C,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(VersatileI2CState),
-    .class_init    = versatile_i2c_class_init,
+    .instance_init = versatile_i2c_init,
 };
 
 static void versatile_i2c_register_types(void)
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index bc0dd2cc75..ffb49c11ac 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -51,3 +51,4 @@ obj-$(CONFIG_MIPS_ITU) += mips_itu.o
 obj-$(CONFIG_PVPANIC) += pvpanic.o
 obj-$(CONFIG_EDU) += edu.o
 obj-$(CONFIG_HYPERV_TESTDEV) += hyperv_testdev.o
+obj-$(CONFIG_AUX) += aux.o
diff --git a/hw/misc/arm_l2x0.c b/hw/misc/arm_l2x0.c
index 4442227877..66a0787c47 100644
--- a/hw/misc/arm_l2x0.c
+++ b/hw/misc/arm_l2x0.c
@@ -159,14 +159,14 @@ static const MemoryRegionOps l2x0_mem_ops = {
     .endianness = DEVICE_NATIVE_ENDIAN,
  };
 
-static int l2x0_priv_init(SysBusDevice *dev)
+static void l2x0_priv_init(Object *obj)
 {
-    L2x0State *s = ARM_L2X0(dev);
+    L2x0State *s = ARM_L2X0(obj);
+    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 
-    memory_region_init_io(&s->iomem, OBJECT(dev), &l2x0_mem_ops, s,
+    memory_region_init_io(&s->iomem, obj, &l2x0_mem_ops, s,
                           "l2x0_cc", 0x1000);
     sysbus_init_mmio(dev, &s->iomem);
-    return 0;
 }
 
 static Property l2x0_properties[] = {
@@ -176,10 +176,8 @@ static Property l2x0_properties[] = {
 
 static void l2x0_class_init(ObjectClass *klass, void *data)
 {
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
     DeviceClass *dc = DEVICE_CLASS(klass);
 
-    k->init = l2x0_priv_init;
     dc->vmsd = &vmstate_l2x0;
     dc->props = l2x0_properties;
     dc->reset = l2x0_priv_reset;
@@ -189,6 +187,7 @@ static const TypeInfo l2x0_info = {
     .name = TYPE_ARM_L2X0,
     .parent = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(L2x0State),
+    .instance_init = l2x0_priv_init,
     .class_init = l2x0_class_init,
 };
 
diff --git a/hw/misc/aux.c b/hw/misc/aux.c
new file mode 100644
index 0000000000..25d7712398
--- /dev/null
+++ b/hw/misc/aux.c
@@ -0,0 +1,292 @@
+/*
+ * aux.c
+ *
+ *  Copyright 2015 : GreenSocs Ltd
+ *      http://www.greensocs.com/ , email: info@greensocs.com
+ *
+ *  Developed by :
+ *  Frederic Konrad   <fred.konrad@greensocs.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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*
+ * This is an implementation of the AUX bus for VESA Display Port v1.1a.
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/log.h"
+#include "hw/misc/aux.h"
+#include "hw/i2c/i2c.h"
+#include "monitor/monitor.h"
+
+#ifndef DEBUG_AUX
+#define DEBUG_AUX 0
+#endif
+
+#define DPRINTF(fmt, ...) do {                                                 \
+    if (DEBUG_AUX) {                                                           \
+        qemu_log("aux: " fmt , ## __VA_ARGS__);                                \
+    }                                                                          \
+} while (0);
+
+#define TYPE_AUXTOI2C "aux-to-i2c-bridge"
+#define AUXTOI2C(obj) OBJECT_CHECK(AUXTOI2CState, (obj), TYPE_AUXTOI2C)
+
+static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent);
+static inline I2CBus *aux_bridge_get_i2c_bus(AUXTOI2CState *bridge);
+
+/* aux-bus implementation (internal not public) */
+static void aux_bus_class_init(ObjectClass *klass, void *data)
+{
+    BusClass *k = BUS_CLASS(klass);
+
+    /* AUXSlave has an MMIO so we need to change the way we print information
+     * in monitor.
+     */
+    k->print_dev = aux_slave_dev_print;
+}
+
+AUXBus *aux_init_bus(DeviceState *parent, const char *name)
+{
+    AUXBus *bus;
+
+    bus = AUX_BUS(qbus_create(TYPE_AUX_BUS, parent, name));
+    bus->bridge = AUXTOI2C(qdev_create(BUS(bus), TYPE_AUXTOI2C));
+
+    /* Memory related. */
+    bus->aux_io = g_malloc(sizeof(*bus->aux_io));
+    memory_region_init(bus->aux_io, OBJECT(bus), "aux-io", (1 << 20));
+    address_space_init(&bus->aux_addr_space, bus->aux_io, "aux-io");
+    return bus;
+}
+
+static void aux_bus_map_device(AUXBus *bus, AUXSlave *dev, hwaddr addr)
+{
+    memory_region_add_subregion(bus->aux_io, addr, dev->mmio);
+}
+
+static bool aux_bus_is_bridge(AUXBus *bus, DeviceState *dev)
+{
+    return (dev == DEVICE(bus->bridge));
+}
+
+I2CBus *aux_get_i2c_bus(AUXBus *bus)
+{
+    return aux_bridge_get_i2c_bus(bus->bridge);
+}
+
+AUXReply aux_request(AUXBus *bus, AUXCommand cmd, uint32_t address,
+                      uint8_t len, uint8_t *data)
+{
+    AUXReply ret = AUX_NACK;
+    I2CBus *i2c_bus = aux_get_i2c_bus(bus);
+    size_t i;
+    bool is_write = false;
+
+    DPRINTF("request at address 0x%" PRIX32 ", command %u, len %u\n", address,
+            cmd, len);
+
+    switch (cmd) {
+    /*
+     * Forward the request on the AUX bus..
+     */
+    case WRITE_AUX:
+    case READ_AUX:
+        is_write = cmd == READ_AUX ? false : true;
+        for (i = 0; i < len; i++) {
+            if (!address_space_rw(&bus->aux_addr_space, address++,
+                                  MEMTXATTRS_UNSPECIFIED, data++, 1,
+                                  is_write)) {
+                ret = AUX_I2C_ACK;
+            } else {
+                ret = AUX_NACK;
+                break;
+            }
+        }
+        break;
+    /*
+     * Classic I2C transactions..
+     */
+    case READ_I2C:
+    case WRITE_I2C:
+        is_write = cmd == READ_I2C ? false : true;
+        if (i2c_bus_busy(i2c_bus)) {
+            i2c_end_transfer(i2c_bus);
+        }
+
+        if (i2c_start_transfer(i2c_bus, address, is_write)) {
+            ret = AUX_I2C_NACK;
+            break;
+        }
+
+        ret = AUX_I2C_ACK;
+        while (len > 0) {
+            if (i2c_send_recv(i2c_bus, data++, is_write) < 0) {
+                ret = AUX_I2C_NACK;
+                break;
+            }
+            len--;
+        }
+        i2c_end_transfer(i2c_bus);
+        break;
+    /*
+     * I2C MOT transactions.
+     *
+     * Here we send a start when:
+     *  - We didn't start transaction yet.
+     *  - We had a READ and we do a WRITE.
+     *  - We changed the address.
+     */
+    case WRITE_I2C_MOT:
+    case READ_I2C_MOT:
+        is_write = cmd == READ_I2C_MOT ? false : true;
+        if (!i2c_bus_busy(i2c_bus)) {
+            /*
+             * No transactions started..
+             */
+            if (i2c_start_transfer(i2c_bus, address, is_write)) {
+                ret = AUX_I2C_NACK;
+                break;
+            }
+        } else if ((address != bus->last_i2c_address) ||
+                   (bus->last_transaction != cmd)) {
+            /*
+             * Transaction started but we need to restart..
+             */
+            i2c_end_transfer(i2c_bus);
+            if (i2c_start_transfer(i2c_bus, address, is_write)) {
+                ret = AUX_I2C_NACK;
+                break;
+            }
+        }
+
+        while (len > 0) {
+            if (i2c_send_recv(i2c_bus, data++, is_write) < 0) {
+                ret = AUX_I2C_NACK;
+                i2c_end_transfer(i2c_bus);
+                break;
+            }
+            len--;
+        }
+        bus->last_transaction = cmd;
+        bus->last_i2c_address = address;
+        ret = AUX_I2C_ACK;
+        break;
+    default:
+        DPRINTF("Not implemented!\n");
+        return AUX_NACK;
+    }
+
+    DPRINTF("reply: %u\n", ret);
+    return ret;
+}
+
+static const TypeInfo aux_bus_info = {
+    .name = TYPE_AUX_BUS,
+    .parent = TYPE_BUS,
+    .instance_size = sizeof(AUXBus),
+    .class_init = aux_bus_class_init
+};
+
+/* aux-i2c implementation (internal not public) */
+struct AUXTOI2CState {
+    /*< private >*/
+    DeviceState parent_obj;
+
+    /*< public >*/
+    I2CBus *i2c_bus;
+};
+
+static void aux_bridge_init(Object *obj)
+{
+    AUXTOI2CState *s = AUXTOI2C(obj);
+
+    s->i2c_bus = i2c_init_bus(DEVICE(obj), "aux-i2c");
+}
+
+static inline I2CBus *aux_bridge_get_i2c_bus(AUXTOI2CState *bridge)
+{
+    return bridge->i2c_bus;
+}
+
+static const TypeInfo aux_to_i2c_type_info = {
+    .name = TYPE_AUXTOI2C,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(AUXTOI2CState),
+    .instance_init = aux_bridge_init
+};
+
+/* aux-slave implementation */
+static void aux_slave_dev_print(Monitor *mon, DeviceState *dev, int indent)
+{
+    AUXBus *bus = AUX_BUS(qdev_get_parent_bus(dev));
+    AUXSlave *s;
+
+    /* Don't print anything if the device is I2C "bridge". */
+    if (aux_bus_is_bridge(bus, dev)) {
+        return;
+    }
+
+    s = AUX_SLAVE(dev);
+
+    monitor_printf(mon, "%*smemory " TARGET_FMT_plx "/" TARGET_FMT_plx "\n",
+                   indent, "",
+                   object_property_get_int(OBJECT(s->mmio), "addr", NULL),
+                   memory_region_size(s->mmio));
+}
+
+DeviceState *aux_create_slave(AUXBus *bus, const char *type, uint32_t addr)
+{
+    DeviceState *dev;
+
+    dev = DEVICE(object_new(type));
+    assert(dev);
+    qdev_set_parent_bus(dev, &bus->qbus);
+    qdev_init_nofail(dev);
+    aux_bus_map_device(AUX_BUS(qdev_get_parent_bus(dev)), AUX_SLAVE(dev), addr);
+    return dev;
+}
+
+void aux_init_mmio(AUXSlave *aux_slave, MemoryRegion *mmio)
+{
+    assert(!aux_slave->mmio);
+    aux_slave->mmio = mmio;
+}
+
+static void aux_slave_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *k = DEVICE_CLASS(klass);
+
+    set_bit(DEVICE_CATEGORY_MISC, k->categories);
+    k->bus_type = TYPE_AUX_BUS;
+}
+
+static const TypeInfo aux_slave_type_info = {
+    .name = TYPE_AUX_SLAVE,
+    .parent = TYPE_DEVICE,
+    .instance_size = sizeof(AUXSlave),
+    .abstract = true,
+    .class_init = aux_slave_class_init,
+};
+
+static void aux_register_types(void)
+{
+    type_register_static(&aux_bus_info);
+    type_register_static(&aux_slave_type_info);
+    type_register_static(&aux_to_i2c_type_info);
+}
+
+type_init(aux_register_types)
diff --git a/hw/misc/exynos4210_pmu.c b/hw/misc/exynos4210_pmu.c
index 889abadfe9..e30dbc7d3d 100644
--- a/hw/misc/exynos4210_pmu.c
+++ b/hw/misc/exynos4210_pmu.c
@@ -457,15 +457,15 @@ static void exynos4210_pmu_reset(DeviceState *dev)
     }
 }
 
-static int exynos4210_pmu_init(SysBusDevice *dev)
+static void exynos4210_pmu_init(Object *obj)
 {
-    Exynos4210PmuState *s = EXYNOS4210_PMU(dev);
+    Exynos4210PmuState *s = EXYNOS4210_PMU(obj);
+    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
 
     /* memory mapping */
-    memory_region_init_io(&s->iomem, OBJECT(dev), &exynos4210_pmu_ops, s,
+    memory_region_init_io(&s->iomem, obj, &exynos4210_pmu_ops, s,
                           "exynos4210.pmu", EXYNOS4210_PMU_REGS_MEM_SIZE);
     sysbus_init_mmio(dev, &s->iomem);
-    return 0;
 }
 
 static const VMStateDescription exynos4210_pmu_vmstate = {
@@ -481,9 +481,7 @@ static const VMStateDescription exynos4210_pmu_vmstate = {
 static void exynos4210_pmu_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = exynos4210_pmu_init;
     dc->reset = exynos4210_pmu_reset;
     dc->vmsd = &exynos4210_pmu_vmstate;
 }
@@ -492,6 +490,7 @@ static const TypeInfo exynos4210_pmu_info = {
     .name          = TYPE_EXYNOS4210_PMU,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(Exynos4210PmuState),
+    .instance_init = exynos4210_pmu_init,
     .class_init    = exynos4210_pmu_class_init,
 };
 
diff --git a/hw/misc/mst_fpga.c b/hw/misc/mst_fpga.c
index 48d7dfb2d7..a10f0496fe 100644
--- a/hw/misc/mst_fpga.c
+++ b/hw/misc/mst_fpga.c
@@ -200,10 +200,11 @@ static int mst_fpga_post_load(void *opaque, int version_id)
 	return 0;
 }
 
-static int mst_fpga_init(SysBusDevice *sbd)
+static void mst_fpga_init(Object *obj)
 {
-    DeviceState *dev = DEVICE(sbd);
-    mst_irq_state *s = MAINSTONE_FPGA(dev);
+    DeviceState *dev = DEVICE(obj);
+    mst_irq_state *s = MAINSTONE_FPGA(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 
     s->pcmcia0 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
     s->pcmcia1 = MST_PCMCIAx_READY | MST_PCMCIAx_nCD;
@@ -213,10 +214,9 @@ static int mst_fpga_init(SysBusDevice *sbd)
     /* alloc the external 16 irqs */
     qdev_init_gpio_in(dev, mst_fpga_set_irq, MST_NUM_IRQS);
 
-    memory_region_init_io(&s->iomem, OBJECT(s), &mst_fpga_ops, s,
+    memory_region_init_io(&s->iomem, obj, &mst_fpga_ops, s,
                           "fpga", 0x00100000);
     sysbus_init_mmio(sbd, &s->iomem);
-    return 0;
 }
 
 static VMStateDescription vmstate_mst_fpga_regs = {
@@ -245,9 +245,7 @@ static VMStateDescription vmstate_mst_fpga_regs = {
 static void mst_fpga_class_init(ObjectClass *klass, void *data)
 {
     DeviceClass *dc = DEVICE_CLASS(klass);
-    SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
 
-    k->init = mst_fpga_init;
     dc->desc = "Mainstone II FPGA";
     dc->vmsd = &vmstate_mst_fpga_regs;
 }
@@ -256,6 +254,7 @@ static const TypeInfo mst_fpga_info = {
     .name          = TYPE_MAINSTONE_FPGA,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(mst_irq_state),
+    .instance_init = mst_fpga_init,
     .class_init    = mst_fpga_class_init,
 };
 
diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c
index eb783c6b51..82c63a4fb5 100644
--- a/hw/sd/pl181.c
+++ b/hw/sd/pl181.c
@@ -13,6 +13,7 @@
 #include "hw/sysbus.h"
 #include "hw/sd/sd.h"
 #include "qemu/log.h"
+#include "qapi/error.h"
 
 //#define DEBUG_PL181 1
 
@@ -481,43 +482,48 @@ static void pl181_reset(DeviceState *d)
     sd_set_cb(s->card, s->cardstatus[0], s->cardstatus[1]);
 }
 
-static int pl181_init(SysBusDevice *sbd)
+static void pl181_init(Object *obj)
 {
-    DeviceState *dev = DEVICE(sbd);
-    PL181State *s = PL181(dev);
-    DriveInfo *dinfo;
+    DeviceState *dev = DEVICE(obj);
+    PL181State *s = PL181(obj);
+    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 
-    memory_region_init_io(&s->iomem, OBJECT(s), &pl181_ops, s, "pl181", 0x1000);
+    memory_region_init_io(&s->iomem, obj, &pl181_ops, s, "pl181", 0x1000);
     sysbus_init_mmio(sbd, &s->iomem);
     sysbus_init_irq(sbd, &s->irq[0]);
     sysbus_init_irq(sbd, &s->irq[1]);
     qdev_init_gpio_out(dev, s->cardstatus, 2);
+}
+
+static void pl181_realize(DeviceState *dev, Error **errp)
+{
+    PL181State *s = PL181(dev);
+    DriveInfo *dinfo;
+
     /* FIXME use a qdev drive property instead of drive_get_next() */
     dinfo = drive_get_next(IF_SD);
     s->card = sd_init(dinfo ? blk_by_legacy_dinfo(dinfo) : NULL, false);
     if (s->card == NULL) {
-        return -1;
+        error_setg(errp, "sd_init failed");
     }
-
-    return 0;
 }
 
 static void pl181_class_init(ObjectClass *klass, void *data)
 {
-    SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass);
     DeviceClass *k = DEVICE_CLASS(klass);
 
-    sdc->init = pl181_init;
     k->vmsd = &vmstate_pl181;
     k->reset = pl181_reset;
     /* Reason: init() method uses drive_get_next() */
     k->cannot_instantiate_with_device_add_yet = true;
+    k->realize = pl181_realize;
 }
 
 static const TypeInfo pl181_info = {
     .name          = TYPE_PL181,
     .parent        = TYPE_SYS_BUS_DEVICE,
     .instance_size = sizeof(PL181State),
+    .instance_init = pl181_init,
     .class_init    = pl181_class_init,
 };
 
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 82703d2ecd..9650193253 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -41,6 +41,10 @@
 #define ARCH_TIMER_NS_EL1_IRQ 14
 #define ARCH_TIMER_NS_EL2_IRQ 10
 
+#define VIRTUAL_PMU_IRQ 7
+
+#define PPI(irq) ((irq) + 16)
+
 enum {
     VIRT_FLASH,
     VIRT_MEM,
diff --git a/include/hw/arm/xlnx-zynqmp.h b/include/hw/arm/xlnx-zynqmp.h
index 68f6eb0c4d..c2931bf39c 100644
--- a/include/hw/arm/xlnx-zynqmp.h
+++ b/include/hw/arm/xlnx-zynqmp.h
@@ -26,6 +26,8 @@
 #include "hw/ide/ahci.h"
 #include "hw/sd/sdhci.h"
 #include "hw/ssi/xilinx_spips.h"
+#include "hw/dma/xlnx_dpdma.h"
+#include "hw/display/xlnx_dp.h"
 
 #define TYPE_XLNX_ZYNQMP "xlnx,zynqmp"
 #define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \
@@ -81,6 +83,8 @@ typedef struct XlnxZynqMPState {
     SysbusAHCIState sata;
     SDHCIState sdhci[XLNX_ZYNQMP_NUM_SDHCI];
     XilinxSPIPS spi[XLNX_ZYNQMP_NUM_SPIS];
+    XlnxDPState dp;
+    XlnxDPDMAState dpdma;
 
     char *boot_cpu;
     ARMCPU *boot_cpu_ptr;
diff --git a/include/hw/display/dpcd.h b/include/hw/display/dpcd.h
new file mode 100644
index 0000000000..274dc2e42d
--- /dev/null
+++ b/include/hw/display/dpcd.h
@@ -0,0 +1,105 @@
+/*
+ * dpcd.h
+ *
+ *  Copyright (C)2015 : GreenSocs Ltd
+ *      http://www.greensocs.com/ , email: info@greensocs.com
+ *
+ *  Developed by :
+ *  Frederic Konrad   <fred.konrad@greensocs.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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef DPCD_H
+#define DPCD_H
+
+typedef struct DPCDState DPCDState;
+
+#define TYPE_DPCD "dpcd"
+#define DPCD(obj) OBJECT_CHECK(DPCDState, (obj), TYPE_DPCD)
+
+/* DCPD Revision. */
+#define DPCD_REVISION                           0x00
+#define DPCD_REV_1_0                            0x10
+#define DPCD_REV_1_1                            0x11
+
+/* DCPD Max Link Rate. */
+#define DPCD_MAX_LINK_RATE                      0x01
+#define DPCD_1_62GBPS                           0x06
+#define DPCD_2_7GBPS                            0x0A
+#define DPCD_5_4GBPS                            0x14
+
+#define DPCD_MAX_LANE_COUNT                     0x02
+#define DPCD_ONE_LANE                           0x01
+#define DPCD_TWO_LANES                          0x02
+#define DPCD_FOUR_LANES                         0x04
+
+/* DCPD Max down spread. */
+#define DPCD_UP_TO_0_5                          0x01
+#define DPCD_NO_AUX_HANDSHAKE_LINK_TRAINING     0x40
+
+/* DCPD Downstream port type. */
+#define DPCD_DISPLAY_PORT                       0x00
+#define DPCD_ANALOG                             0x02
+#define DPCD_DVI_HDMI                           0x04
+#define DPCD_OTHER                              0x06
+
+/* DPCD Format conversion. */
+#define DPCD_FORMAT_CONVERSION                  0x08
+
+/* Main link channel coding. */
+#define DPCD_ANSI_8B_10B                        0x01
+
+/* Down stream port count. */
+#define DPCD_OUI_SUPPORTED                      0x80
+
+/* Receiver port capability. */
+#define DPCD_RECEIVE_PORT0_CAP_0                0x08
+#define DPCD_RECEIVE_PORT0_CAP_1                0x09
+#define DPCD_EDID_PRESENT                       0x02
+#define DPCD_ASSOCIATED_TO_PRECEDING_PORT       0x04
+
+/* Down stream port capability. */
+#define DPCD_CAP_DISPLAY_PORT                   0x000
+#define DPCD_CAP_ANALOG_VGA                     0x001
+#define DPCD_CAP_DVI                            0x002
+#define DPCD_CAP_HDMI                           0x003
+#define DPCD_CAP_OTHER                          0x100
+
+#define DPCD_LANE0_1_STATUS                     0x202
+#define DPCD_LANE0_CR_DONE                      (1 << 0)
+#define DPCD_LANE0_CHANNEL_EQ_DONE              (1 << 1)
+#define DPCD_LANE0_SYMBOL_LOCKED                (1 << 2)
+#define DPCD_LANE1_CR_DONE                      (1 << 4)
+#define DPCD_LANE1_CHANNEL_EQ_DONE              (1 << 5)
+#define DPCD_LANE1_SYMBOL_LOCKED                (1 << 6)
+
+#define DPCD_LANE2_3_STATUS                     0x203
+#define DPCD_LANE2_CR_DONE                      (1 << 0)
+#define DPCD_LANE2_CHANNEL_EQ_DONE              (1 << 1)
+#define DPCD_LANE2_SYMBOL_LOCKED                (1 << 2)
+#define DPCD_LANE3_CR_DONE                      (1 << 4)
+#define DPCD_LANE3_CHANNEL_EQ_DONE              (1 << 5)
+#define DPCD_LANE3_SYMBOL_LOCKED                (1 << 6)
+
+#define DPCD_LANE_ALIGN_STATUS_UPDATED          0x204
+#define DPCD_INTERLANE_ALIGN_DONE               0x01
+#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED     0x40
+#define DPCD_LINK_STATUS_UPDATED                0x80
+
+#define DPCD_SINK_STATUS                        0x205
+#define DPCD_RECEIVE_PORT_0_STATUS              0x01
+
+#endif /* !DPCD_H */
diff --git a/include/hw/display/xlnx_dp.h b/include/hw/display/xlnx_dp.h
new file mode 100644
index 0000000000..d3a03f118c
--- /dev/null
+++ b/include/hw/display/xlnx_dp.h
@@ -0,0 +1,109 @@
+/*
+ * xlnx_dp.h
+ *
+ *  Copyright (C) 2015 : GreenSocs Ltd
+ *      http://www.greensocs.com/ , email: info@greensocs.com
+ *
+ *  Developed by :
+ *  Frederic Konrad   <fred.konrad@greensocs.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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "hw/sysbus.h"
+#include "ui/console.h"
+#include "hw/misc/aux.h"
+#include "hw/i2c/i2c.h"
+#include "hw/display/dpcd.h"
+#include "hw/i2c/i2c-ddc.h"
+#include "qemu/fifo8.h"
+#include "hw/dma/xlnx_dpdma.h"
+#include "audio/audio.h"
+
+#ifndef XLNX_DP_H
+#define XLNX_DP_H
+
+#define AUD_CHBUF_MAX_DEPTH                 32768
+#define MAX_QEMU_BUFFER_SIZE                4096
+
+#define DP_CORE_REG_ARRAY_SIZE              (0x3AF >> 2)
+#define DP_AVBUF_REG_ARRAY_SIZE             (0x238 >> 2)
+#define DP_VBLEND_REG_ARRAY_SIZE            (0x1DF >> 2)
+#define DP_AUDIO_REG_ARRAY_SIZE             (0x50 >> 2)
+
+struct PixmanPlane {
+    pixman_format_code_t format;
+    DisplaySurface *surface;
+};
+
+typedef struct XlnxDPState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /* < public >*/
+    MemoryRegion container;
+
+    uint32_t core_registers[DP_CORE_REG_ARRAY_SIZE];
+    MemoryRegion core_iomem;
+
+    uint32_t avbufm_registers[DP_AVBUF_REG_ARRAY_SIZE];
+    MemoryRegion avbufm_iomem;
+
+    uint32_t vblend_registers[DP_VBLEND_REG_ARRAY_SIZE];
+    MemoryRegion vblend_iomem;
+
+    uint32_t audio_registers[DP_AUDIO_REG_ARRAY_SIZE];
+    MemoryRegion audio_iomem;
+
+    QemuConsole *console;
+
+    /*
+     * This is the planes used to display in console. When the blending is
+     * enabled bout_plane is displayed in console else it's g_plane.
+     */
+    struct PixmanPlane g_plane;
+    struct PixmanPlane v_plane;
+    struct PixmanPlane bout_plane;
+
+    QEMUSoundCard aud_card;
+    SWVoiceOut *amixer_output_stream;
+    int16_t audio_buffer_0[AUD_CHBUF_MAX_DEPTH];
+    int16_t audio_buffer_1[AUD_CHBUF_MAX_DEPTH];
+    size_t audio_data_available[2];
+    int64_t temp_buffer[AUD_CHBUF_MAX_DEPTH];
+    int16_t out_buffer[AUD_CHBUF_MAX_DEPTH];
+    size_t byte_left; /* byte available in out_buffer. */
+    size_t data_ptr;  /* next byte to be sent to QEMU. */
+
+    /* Associated DPDMA controller. */
+    XlnxDPDMAState *dpdma;
+
+    qemu_irq irq;
+
+    AUXBus *aux_bus;
+    Fifo8 rx_fifo;
+    Fifo8 tx_fifo;
+
+    /*
+     * XXX: This should be in an other module.
+     */
+    DPCDState *dpcd;
+    I2CDDCState *edid;
+} XlnxDPState;
+
+#define TYPE_XLNX_DP "xlnx.v-dp"
+#define XLNX_DP(obj) OBJECT_CHECK(XlnxDPState, (obj), TYPE_XLNX_DP)
+
+#endif /* !XLNX_DP_H */
diff --git a/include/hw/dma/xlnx_dpdma.h b/include/hw/dma/xlnx_dpdma.h
new file mode 100644
index 0000000000..ae571a0b2f
--- /dev/null
+++ b/include/hw/dma/xlnx_dpdma.h
@@ -0,0 +1,85 @@
+/*
+ * xlnx_dpdma.h
+ *
+ *  Copyright (C) 2015 : GreenSocs Ltd
+ *      http://www.greensocs.com/ , email: info@greensocs.com
+ *
+ *  Developed by :
+ *  Frederic Konrad   <fred.konrad@greensocs.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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef XLNX_DPDMA_H
+#define XLNX_DPDMA_H
+
+#include "hw/sysbus.h"
+#include "ui/console.h"
+#include "sysemu/dma.h"
+
+#define XLNX_DPDMA_REG_ARRAY_SIZE (0x1000 >> 2)
+
+struct XlnxDPDMAState {
+    /*< private >*/
+    SysBusDevice parent_obj;
+    /*< public >*/
+    MemoryRegion iomem;
+    uint32_t registers[XLNX_DPDMA_REG_ARRAY_SIZE];
+    uint8_t *data[6];
+    bool operation_finished[6];
+    qemu_irq irq;
+};
+
+typedef struct XlnxDPDMAState XlnxDPDMAState;
+
+#define TYPE_XLNX_DPDMA "xlnx.dpdma"
+#define XLNX_DPDMA(obj) OBJECT_CHECK(XlnxDPDMAState, (obj), TYPE_XLNX_DPDMA)
+
+/*
+ * xlnx_dpdma_start_operation: Start the operation on the specified channel. The
+ *                             DPDMA gets the current descriptor and retrieves
+ *                             data to the buffer specified by
+ *                             dpdma_set_host_data_location().
+ *
+ * Returns The number of bytes transfered by the DPDMA or 0 if an error occured.
+ *
+ * @s The DPDMA state.
+ * @channel The channel to start.
+ */
+size_t xlnx_dpdma_start_operation(XlnxDPDMAState *s, uint8_t channel,
+                                  bool one_desc);
+
+/*
+ * xlnx_dpdma_set_host_data_location: Set the location in the host memory where
+ *                                    to store the data out from the dma
+ *                                    channel.
+ *
+ * @s The DPDMA state.
+ * @channel The channel associated to the pointer.
+ * @p The buffer where to store the data.
+ */
+/* XXX: add a maximum size arg and send an interrupt in case of overflow. */
+void xlnx_dpdma_set_host_data_location(XlnxDPDMAState *s, uint8_t channel,
+                                       void *p);
+
+/*
+ * xlnx_dpdma_trigger_vsync_irq: Trigger a VSYNC IRQ when the display is
+ *                               updated.
+ *
+ * @s The DPDMA state.
+ */
+void xlnx_dpdma_trigger_vsync_irq(XlnxDPDMAState *s);
+
+#endif /* !XLNX_DPDMA_H */
diff --git a/include/hw/i2c/i2c-ddc.h b/include/hw/i2c/i2c-ddc.h
new file mode 100644
index 0000000000..cb8e62d622
--- /dev/null
+++ b/include/hw/i2c/i2c-ddc.h
@@ -0,0 +1,38 @@
+/* A simple I2C slave for returning monitor EDID data via DDC.
+ *
+ * Copyright (c) 2011 Linaro Limited
+ * Written by Peter Maydell
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef I2C_DDC
+#define I2C_DDC
+
+/* A simple I2C slave which just returns the contents of its EDID blob. */
+
+struct I2CDDCState {
+    /*< private >*/
+    I2CSlave i2c;
+    /*< public >*/
+    bool firstbyte;
+    uint8_t reg;
+    uint8_t edid_blob[128];
+};
+
+typedef struct I2CDDCState I2CDDCState;
+
+#define TYPE_I2CDDC "i2c-ddc"
+#define I2CDDC(obj) OBJECT_CHECK(I2CDDCState, (obj), TYPE_I2CDDC)
+
+#endif /* !I2C_DDC */
diff --git a/include/hw/i2c/i2c.h b/include/hw/i2c/i2c.h
index 4986ebc73c..c4085aa366 100644
--- a/include/hw/i2c/i2c.h
+++ b/include/hw/i2c/i2c.h
@@ -56,6 +56,7 @@ int i2c_bus_busy(I2CBus *bus);
 int i2c_start_transfer(I2CBus *bus, uint8_t address, int recv);
 void i2c_end_transfer(I2CBus *bus);
 void i2c_nack(I2CBus *bus);
+int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send);
 int i2c_send(I2CBus *bus, uint8_t data);
 int i2c_recv(I2CBus *bus);
 
diff --git a/include/hw/misc/aux.h b/include/hw/misc/aux.h
new file mode 100644
index 0000000000..759c3bf20c
--- /dev/null
+++ b/include/hw/misc/aux.h
@@ -0,0 +1,128 @@
+/*
+ * aux.h
+ *
+ *  Copyright (C)2014 : GreenSocs Ltd
+ *      http://www.greensocs.com/ , email: info@greensocs.com
+ *
+ *  Developed by :
+ *  Frederic Konrad   <fred.konrad@greensocs.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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef QEMU_AUX_H
+#define QEMU_AUX_H
+
+#include "hw/qdev.h"
+
+typedef struct AUXBus AUXBus;
+typedef struct AUXSlave AUXSlave;
+typedef enum AUXCommand AUXCommand;
+typedef enum AUXReply AUXReply;
+typedef struct AUXTOI2CState AUXTOI2CState;
+
+enum AUXCommand {
+    WRITE_I2C = 0,
+    READ_I2C = 1,
+    WRITE_I2C_STATUS = 2,
+    WRITE_I2C_MOT = 4,
+    READ_I2C_MOT = 5,
+    WRITE_AUX = 8,
+    READ_AUX = 9
+};
+
+enum AUXReply {
+    AUX_I2C_ACK = 0,
+    AUX_NACK = 1,
+    AUX_DEFER = 2,
+    AUX_I2C_NACK = 4,
+    AUX_I2C_DEFER = 8
+};
+
+#define TYPE_AUX_BUS "aux-bus"
+#define AUX_BUS(obj) OBJECT_CHECK(AUXBus, (obj), TYPE_AUX_BUS)
+
+struct AUXBus {
+    /* < private > */
+    BusState qbus;
+
+    /* < public > */
+    AUXSlave *current_dev;
+    AUXSlave *dev;
+    uint32_t last_i2c_address;
+    AUXCommand last_transaction;
+
+    AUXTOI2CState *bridge;
+
+    MemoryRegion *aux_io;
+    AddressSpace aux_addr_space;
+};
+
+#define TYPE_AUX_SLAVE "aux-slave"
+#define AUX_SLAVE(obj) \
+     OBJECT_CHECK(AUXSlave, (obj), TYPE_AUX_SLAVE)
+
+struct AUXSlave {
+    /* < private > */
+    DeviceState parent_obj;
+
+    /* < public > */
+    MemoryRegion *mmio;
+};
+
+/**
+ * aux_init_bus: Initialize an AUX bus.
+ *
+ * Returns the new AUX bus created.
+ *
+ * @parent The device where this bus is located.
+ * @name The name of the bus.
+ */
+AUXBus *aux_init_bus(DeviceState *parent, const char *name);
+
+/*
+ * aux_request: Make a request on the bus.
+ *
+ * Returns the reply of the request.
+ *
+ * @bus Ths bus where the request happen.
+ * @cmd The command requested.
+ * @address The 20bits address of the slave.
+ * @len The length of the read or write.
+ * @data The data array which will be filled or read during transfer.
+ */
+AUXReply aux_request(AUXBus *bus, AUXCommand cmd, uint32_t address,
+                              uint8_t len, uint8_t *data);
+
+/*
+ * aux_get_i2c_bus: Get the i2c bus for I2C over AUX command.
+ *
+ * Returns the i2c bus associated to this AUX bus.
+ *
+ * @bus The AUX bus.
+ */
+I2CBus *aux_get_i2c_bus(AUXBus *bus);
+
+/*
+ * aux_init_mmio: Init an mmio for an AUX slave.
+ *
+ * @aux_slave The AUX slave.
+ * @mmio The mmio to be registered.
+ */
+void aux_init_mmio(AUXSlave *aux_slave, MemoryRegion *mmio);
+
+DeviceState *aux_create_slave(AUXBus *bus, const char *name, uint32_t addr);
+
+#endif /* !QEMU_AUX_H */
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 17d80510da..942aa36d9b 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -572,6 +572,8 @@ struct ARMCPU {
     bool powered_off;
     /* CPU has security extension */
     bool has_el3;
+    /* CPU has PMU (Performance Monitor Unit) */
+    bool has_pmu;
 
     /* CPU has memory protection unit */
     bool has_mpu;
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 862e7808a2..c9730d6678 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -3765,8 +3765,11 @@ static const ARMCPRegInfo el3_cp_reginfo[] = {
       .opc0 = 3, .opc1 = 6, .crn = 2, .crm = 0, .opc2 = 2,
       .access = PL3_RW,
       /* no .writefn needed as this can't cause an ASID change;
-       * no .raw_writefn or .resetfn needed as we never use mask/base_mask
+       * we must provide a .raw_writefn and .resetfn because we handle
+       * reset and migration for the AArch32 TTBCR(S), which might be
+       * using mask and base_mask.
        */
+      .resetfn = vmsa_ttbcr_reset, .raw_writefn = vmsa_ttbcr_raw_write,
       .fieldoffset = offsetof(CPUARMState, cp15.tcr_el[3]) },
     { .name = "ELR_EL3", .state = ARM_CP_STATE_AA64,
       .type = ARM_CP_ALIAS,
diff --git a/target-arm/kvm32.c b/target-arm/kvm32.c
index c03e3e526a..c35c676e14 100644
--- a/target-arm/kvm32.c
+++ b/target-arm/kvm32.c
@@ -522,3 +522,9 @@ bool kvm_arm_hw_debug_active(CPUState *cs)
 {
     return false;
 }
+
+int kvm_arm_pmu_create(CPUState *cs, int irq)
+{
+    qemu_log_mask(LOG_UNIMP, "%s: not implemented\n", __func__);
+    return 0;
+}
diff --git a/target-arm/kvm64.c b/target-arm/kvm64.c
index e2a34f67a4..2d6a310ebb 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -382,6 +382,47 @@ static CPUWatchpoint *find_hw_watchpoint(CPUState *cpu, target_ulong addr)
     return NULL;
 }
 
+static bool kvm_arm_pmu_support_ctrl(CPUState *cs, struct kvm_device_attr *attr)
+{
+    return kvm_vcpu_ioctl(cs, KVM_HAS_DEVICE_ATTR, attr) == 0;
+}
+
+int kvm_arm_pmu_create(CPUState *cs, int irq)
+{
+    int err;
+
+    struct kvm_device_attr attr = {
+        .group = KVM_ARM_VCPU_PMU_V3_CTRL,
+        .addr = (intptr_t)&irq,
+        .attr = KVM_ARM_VCPU_PMU_V3_IRQ,
+        .flags = 0,
+    };
+
+    if (!kvm_arm_pmu_support_ctrl(cs, &attr)) {
+        return 0;
+    }
+
+    err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, &attr);
+    if (err < 0) {
+        fprintf(stderr, "KVM_SET_DEVICE_ATTR failed: %s\n",
+                strerror(-err));
+        abort();
+    }
+
+    attr.group = KVM_ARM_VCPU_PMU_V3_CTRL;
+    attr.attr = KVM_ARM_VCPU_PMU_V3_INIT;
+    attr.addr = 0;
+    attr.flags = 0;
+
+    err = kvm_vcpu_ioctl(cs, KVM_SET_DEVICE_ATTR, &attr);
+    if (err < 0) {
+        fprintf(stderr, "KVM_SET_DEVICE_ATTR failed: %s\n",
+                strerror(-err));
+        abort();
+    }
+
+    return 1;
+}
 
 static inline void set_feature(uint64_t *features, int feature)
 {
@@ -461,6 +502,11 @@ int kvm_arch_init_vcpu(CPUState *cs)
     if (!arm_feature(&cpu->env, ARM_FEATURE_AARCH64)) {
         cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_EL1_32BIT;
     }
+    if (kvm_irqchip_in_kernel() &&
+        kvm_check_extension(cs->kvm_state, KVM_CAP_ARM_PMU_V3)) {
+        cpu->has_pmu = true;
+        cpu->kvm_init_features[0] |= 1 << KVM_ARM_VCPU_PMU_V3;
+    }
 
     /* Do KVM_ARM_VCPU_INIT ioctl */
     ret = kvm_arm_vcpu_init(cs);
diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h
index 345233c18b..a4193684a8 100644
--- a/target-arm/kvm_arm.h
+++ b/target-arm/kvm_arm.h
@@ -194,6 +194,8 @@ int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu);
 
 int kvm_arm_vgic_probe(void);
 
+int kvm_arm_pmu_create(CPUState *cs, int irq);
+
 #else
 
 static inline int kvm_arm_vgic_probe(void)
@@ -201,6 +203,11 @@ static inline int kvm_arm_vgic_probe(void)
     return 0;
 }
 
+static inline int kvm_arm_pmu_create(CPUState *cs, int irq)
+{
+    return 0;
+}
+
 #endif
 
 static inline const char *gic_class_name(void)
diff --git a/target-arm/translate.c b/target-arm/translate.c
index 6815bc1a79..3e7146769d 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -5311,6 +5311,30 @@ static int neon_2rm_is_float_op(int op)
             op >= NEON_2RM_VRECPE_F);
 }
 
+static bool neon_2rm_is_v8_op(int op)
+{
+    /* Return true if this neon 2reg-misc op is ARMv8 and up */
+    switch (op) {
+    case NEON_2RM_VRINTN:
+    case NEON_2RM_VRINTA:
+    case NEON_2RM_VRINTM:
+    case NEON_2RM_VRINTP:
+    case NEON_2RM_VRINTZ:
+    case NEON_2RM_VRINTX:
+    case NEON_2RM_VCVTAU:
+    case NEON_2RM_VCVTAS:
+    case NEON_2RM_VCVTNU:
+    case NEON_2RM_VCVTNS:
+    case NEON_2RM_VCVTPU:
+    case NEON_2RM_VCVTPS:
+    case NEON_2RM_VCVTMU:
+    case NEON_2RM_VCVTMS:
+        return true;
+    default:
+        return false;
+    }
+}
+
 /* Each entry in this array has bit n set if the insn allows
  * size value n (otherwise it will UNDEF). Since unallocated
  * op values will have no bits set they always UNDEF.
@@ -6798,6 +6822,10 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn)
                 if ((neon_2rm_sizes[op] & (1 << size)) == 0) {
                     return 1;
                 }
+                if (neon_2rm_is_v8_op(op) &&
+                    !arm_dc_feature(s, ARM_FEATURE_V8)) {
+                    return 1;
+                }
                 if ((op != NEON_2RM_VMOVN && op != NEON_2RM_VQMOVN) &&
                     q && ((rm | rd) & 1)) {
                     return 1;