Merge remote-tracking branch 'remotes/sstabellini/tags/xen-20160614-tag' into staging
Xen 2016/06/14
# gpg: Signature made Tue 14 Jun 2016 16:01:52 BST
# gpg: using RSA key 0x894F8F4870E1AE90
# gpg: Good signature from "Stefano Stabellini <stefano.stabellini@eu.citrix.com>"
# Primary key fingerprint: D04E 33AB A51F 67BA 07D3 0AEA 894F 8F48 70E1 AE90
* remotes/sstabellini/tags/xen-20160614-tag:
xen: Clean up includes
xen/blkif: avoid double access to any shared ring request fields
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/default-configs/aarch64-softmmu.mak b/default-configs/aarch64-softmmu.mak
index 96dd994..2449483 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/nseries.c b/hw/arm/nseries.c
index d4eb141..fea911e 100644
--- a/hw/arm/nseries.c
+++ b/hw/arm/nseries.c
@@ -1351,7 +1351,7 @@
n8x0_dss_setup(s);
n8x0_cbus_setup(s);
n8x0_uart_setup(s);
- if (usb_enabled()) {
+ if (machine_usb(machine)) {
n8x0_usb_setup(s);
}
diff --git a/hw/arm/pxa2xx.c b/hw/arm/pxa2xx.c
index e41a7c9..cb55704 100644
--- a/hw/arm/pxa2xx.c
+++ b/hw/arm/pxa2xx.c
@@ -2165,10 +2165,8 @@
s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
}
- if (usb_enabled()) {
- sysbus_create_simple("sysbus-ohci", 0x4c000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
- }
+ sysbus_create_simple("sysbus-ohci", 0x4c000000,
+ qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
s->pcmcia[0] = pxa2xx_pcmcia_init(address_space, 0x20000000);
s->pcmcia[1] = pxa2xx_pcmcia_init(address_space, 0x30000000);
@@ -2298,10 +2296,8 @@
s->ssp[i] = (SSIBus *)qdev_get_child_bus(dev, "ssi");
}
- if (usb_enabled()) {
- sysbus_create_simple("sysbus-ohci", 0x4c000000,
- qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
- }
+ sysbus_create_simple("sysbus-ohci", 0x4c000000,
+ qdev_get_gpio_in(s->pic, PXA2XX_PIC_USBH1));
s->pcmcia[0] = pxa2xx_pcmcia_init(address_space, 0x20000000);
s->pcmcia[1] = pxa2xx_pcmcia_init(address_space, 0x30000000);
diff --git a/hw/arm/realview.c b/hw/arm/realview.c
index 7d0aa6f..8eafcca 100644
--- a/hw/arm/realview.c
+++ b/hw/arm/realview.c
@@ -254,7 +254,7 @@
sysbus_connect_irq(busdev, 2, pic[50]);
sysbus_connect_irq(busdev, 3, pic[51]);
pci_bus = (PCIBus *)qdev_get_child_bus(dev, "pci");
- if (usb_enabled()) {
+ if (machine_usb(machine)) {
pci_create_simple(pci_bus, -1, "pci-ohci");
}
n = drive_get_max_bus(IF_SCSI);
diff --git a/hw/arm/versatilepb.c b/hw/arm/versatilepb.c
index 20dd356..8ae5392 100644
--- a/hw/arm/versatilepb.c
+++ b/hw/arm/versatilepb.c
@@ -276,7 +276,7 @@
pci_nic_init_nofail(nd, pci_bus, "rtl8139", NULL);
}
}
- if (usb_enabled()) {
+ if (machine_usb(machine)) {
pci_create_simple(pci_bus, -1, "pci-ohci");
}
n = drive_get_max_bus(IF_SCSI);
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 735ab86..1fa0581 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -538,6 +538,10 @@
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 73113cf..c5c125e 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 @@
#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 @@
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 @@
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 @@
.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 @@
"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);
+}
+DEFINE_VIRT_MACHINE_AS_LATEST(2, 7)
- mc->desc = "QEMU 2.6 ARM Virtual Machine";
- mc->alias = "virt";
+#define VIRT_COMPAT_2_6 \
+ HW_COMPAT_2_6
+
+static void virt_2_6_instance_init(Object *obj)
+{
+ virt_2_7_instance_init(obj);
}
-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,
-};
-
-static void machvirt_machine_init(void)
+static void virt_machine_2_6_options(MachineClass *mc)
{
- type_register_static(&virt_machine_info);
- type_register_static(&machvirt_info);
+ virt_machine_2_7_options(mc);
+ SET_MACHINE_COMPAT(mc, VIRT_COMPAT_2_6);
}
-
-type_init(machvirt_machine_init);
+DEFINE_VIRT_MACHINE(2, 6)
diff --git a/hw/arm/xlnx-zynqmp.c b/hw/arm/xlnx-zynqmp.c
index 308d677..23c7199 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 @@
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 @@
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/core/qdev.c b/hw/core/qdev.c
index 0a05a52..dcc00f8 100644
--- a/hw/core/qdev.c
+++ b/hw/core/qdev.c
@@ -35,6 +35,7 @@
#include "qemu/error-report.h"
#include "hw/hotplug.h"
#include "hw/boards.h"
+#include "hw/sysbus.h"
#include "qapi-event.h"
int qdev_hotplug = 0;
@@ -140,6 +141,12 @@
}
if (!bus) {
+ /* Assert that the device really is a SysBusDevice before
+ * we put it onto the sysbus. Non-sysbus devices which aren't
+ * being put onto a bus should be created with object_new(TYPE_FOO),
+ * not qdev_create(NULL, TYPE_FOO).
+ */
+ g_assert(object_dynamic_cast(OBJECT(dev), TYPE_SYS_BUS_DEVICE));
bus = sysbus_get_default();
}
diff --git a/hw/display/Makefile.objs b/hw/display/Makefile.objs
index d99780e..063889b 100644
--- a/hw/display/Makefile.objs
+++ b/hw/display/Makefile.objs
@@ -43,3 +43,5 @@
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 0000000..5a36855
--- /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 0000000..be53b75
--- /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 a1abbcf..8b0823e 100644
--- a/hw/dma/Makefile.objs
+++ b/hw/dma/Makefile.objs
@@ -8,6 +8,7 @@
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 2306abc..634a432 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 int pxa2xx_dma_init(SysBusDevice *sbd)
+static void pxa2xx_dma_init(Object *obj)
{
- DeviceState *dev = DEVICE(sbd);
+ 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)
+{
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 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 0000000..8ceb21d
--- /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 9b1b004..dabef4a 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 @@
.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)
{
- DeviceState *dev = DEVICE(sbd);
+ 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)
+{
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 @@
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 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 @@
.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 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 44faeb2..4ae2aa1 100644
--- a/hw/gpio/pl061.c
+++ b/hw/gpio/pl061.c
@@ -341,20 +341,6 @@
.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_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 555da28..15865e1 100644
--- a/hw/gpio/zaurus.c
+++ b/hw/gpio/zaurus.c
@@ -167,19 +167,18 @@
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 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 @@
.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 1fd54ed..a081b8e 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 6ed2060..d3a2989 100644
--- a/hw/i2c/bitbang_i2c.c
+++ b/hw/i2c/bitbang_i2c.c
@@ -210,13 +210,14 @@
}
}
-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 @@
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 @@
.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 ba22104..abb3efb 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 @@
{
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 @@
.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 *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 @@
/* 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_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->broadcast = false;
+}
- bus->current_dev = NULL;
+int i2c_send_recv(I2CBus *bus, uint8_t *data, bool send)
+{
+ 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;
+ }
+
+ 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;
+ }
}
int i2c_send(I2CBus *bus, uint8_t data)
{
- I2CSlave *dev = bus->current_dev;
- I2CSlaveClass *sc;
-
- if (!dev) {
- return -1;
- }
-
- sc = I2C_SLAVE_GET_CLASS(dev);
- if (sc->send) {
- return sc->send(dev, data);
- }
-
- return -1;
+ return i2c_send_recv(bus, &data, true);
}
int i2c_recv(I2CBus *bus)
{
- I2CSlave *dev = bus->current_dev;
- I2CSlaveClass *sc;
+ uint8_t data;
+ int ret = i2c_send_recv(bus, &data, false);
- if (!dev) {
- return -1;
- }
-
- 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 @@
{
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 8c2a2c1..c96fa7d 100644
--- a/hw/i2c/exynos4210_i2c.c
+++ b/hw/i2c/exynos4210_i2c.c
@@ -299,33 +299,32 @@
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 0000000..1227212
--- /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 67fbbff..f7c92ea 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 @@
.endianness = DEVICE_NATIVE_ENDIAN,
};
-static int omap_i2c_init(SysBusDevice *sbd)
+static void omap_i2c_init(Object *obj)
{
- DeviceState *dev = DEVICE(sbd);
- OMAPI2CState *s = OMAP_I2C(dev);
-
- if (!s->fclk) {
- error_report("omap_i2c: fclk not connected");
- return -1;
- }
- 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;
- }
+ 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]);
- 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 void omap_i2c_realize(DeviceState *dev, Error **errp)
+{
+ 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_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_setg(errp, "omap_i2c: iclk not connected");
+ return;
+ }
}
static Property omap_i2c_properties[] = {
@@ -480,18 +487,19 @@
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 0bce524..da9f298 100644
--- a/hw/i2c/versatile_i2c.c
+++ b/hw/i2c/versatile_i2c.c
@@ -79,32 +79,25 @@
.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/i386/pc_piix.c b/hw/i386/pc_piix.c
index 14dd0cc..82c7c0a 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -262,7 +262,7 @@
pc_cmos_init(pcms, idebus[0], idebus[1], rtc_state);
- if (pcmc->pci_enabled && usb_enabled()) {
+ if (pcmc->pci_enabled && machine_usb(machine)) {
pci_create_simple(pci_bus, piix3_devfn + 2, "piix3-usb-uhci");
}
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 04aae89..31a6a59 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -234,7 +234,7 @@
ide_drive_get(hd, ICH_AHCI(ahci)->ahci.ports);
ahci_ide_create_devs(ahci, hd);
- if (usb_enabled()) {
+ if (machine_usb(machine)) {
/* Should we create 6 UHCI according to ich9 spec? */
ehci_create_ich9_with_companions(host_bus, 0x1d);
}
diff --git a/hw/ide/macio.c b/hw/ide/macio.c
index 78c10a0..fa57352 100644
--- a/hw/ide/macio.c
+++ b/hw/ide/macio.c
@@ -66,8 +66,7 @@
DBDMA_io *io = opaque;
MACIOIDEState *m = io->opaque;
IDEState *s = idebus_active_if(&m->bus);
- dma_addr_t dma_addr, dma_len;
- void *mem;
+ dma_addr_t dma_addr;
int64_t sector_num;
int nsector;
uint64_t align = BDRV_SECTOR_SIZE;
@@ -84,9 +83,10 @@
sector_num, nsector);
dma_addr = io->addr;
- dma_len = io->len;
- mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len,
- DMA_DIRECTION_FROM_DEVICE);
+ io->dir = DMA_DIRECTION_FROM_DEVICE;
+ io->dma_len = io->len;
+ io->dma_mem = dma_memory_map(&address_space_memory, dma_addr, &io->dma_len,
+ io->dir);
if (offset & (align - 1)) {
head_bytes = offset & (align - 1);
@@ -100,7 +100,7 @@
offset = offset & ~(align - 1);
}
- qemu_iovec_add(&io->iov, mem, io->len);
+ qemu_iovec_add(&io->iov, io->dma_mem, io->len);
if ((offset + bytes) & (align - 1)) {
tail_bytes = (offset + bytes) & (align - 1);
@@ -130,8 +130,7 @@
DBDMA_io *io = opaque;
MACIOIDEState *m = io->opaque;
IDEState *s = idebus_active_if(&m->bus);
- dma_addr_t dma_addr, dma_len;
- void *mem;
+ dma_addr_t dma_addr;
int64_t sector_num;
int nsector;
uint64_t align = BDRV_SECTOR_SIZE;
@@ -149,9 +148,10 @@
sector_num, nsector);
dma_addr = io->addr;
- dma_len = io->len;
- mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len,
- DMA_DIRECTION_TO_DEVICE);
+ io->dir = DMA_DIRECTION_TO_DEVICE;
+ io->dma_len = io->len;
+ io->dma_mem = dma_memory_map(&address_space_memory, dma_addr, &io->dma_len,
+ io->dir);
if (offset & (align - 1)) {
head_bytes = offset & (align - 1);
@@ -163,7 +163,7 @@
blk_pread(s->blk, (sector_num << 9), &io->head_remainder, align);
qemu_iovec_add(&io->iov, &io->head_remainder, head_bytes);
- qemu_iovec_add(&io->iov, mem, io->len);
+ qemu_iovec_add(&io->iov, io->dma_mem, io->len);
bytes += offset & (align - 1);
offset = offset & ~(align - 1);
@@ -181,7 +181,7 @@
blk_pread(s->blk, (sector_num << 9), &io->tail_remainder, align);
if (!unaligned_head) {
- qemu_iovec_add(&io->iov, mem, io->len);
+ qemu_iovec_add(&io->iov, io->dma_mem, io->len);
}
qemu_iovec_add(&io->iov, &io->tail_remainder + tail_bytes,
@@ -193,7 +193,7 @@
}
if (!unaligned_head && !unaligned_tail) {
- qemu_iovec_add(&io->iov, mem, io->len);
+ qemu_iovec_add(&io->iov, io->dma_mem, io->len);
}
s->io_buffer_size -= io->len;
@@ -214,18 +214,18 @@
DBDMA_io *io = opaque;
MACIOIDEState *m = io->opaque;
IDEState *s = idebus_active_if(&m->bus);
- dma_addr_t dma_addr, dma_len;
- void *mem;
+ dma_addr_t dma_addr;
qemu_iovec_destroy(&io->iov);
qemu_iovec_init(&io->iov, io->len / MACIO_PAGE_SIZE + 1);
dma_addr = io->addr;
- dma_len = io->len;
- mem = dma_memory_map(&address_space_memory, dma_addr, &dma_len,
- DMA_DIRECTION_TO_DEVICE);
+ io->dir = DMA_DIRECTION_TO_DEVICE;
+ io->dma_len = io->len;
+ io->dma_mem = dma_memory_map(&address_space_memory, dma_addr, &io->dma_len,
+ io->dir);
- qemu_iovec_add(&io->iov, mem, io->len);
+ qemu_iovec_add(&io->iov, io->dma_mem, io->len);
s->io_buffer_size -= io->len;
s->io_buffer_index += io->len;
io->len = 0;
@@ -285,6 +285,9 @@
return;
done:
+ dma_memory_unmap(&address_space_memory, io->dma_mem, io->dma_len,
+ io->dir, io->dma_len);
+
if (ret < 0) {
block_acct_failed(blk_get_stats(s->blk), &s->acct);
} else {
@@ -351,6 +354,9 @@
return;
done:
+ dma_memory_unmap(&address_space_memory, io->dma_mem, io->dma_len,
+ io->dir, io->dma_len);
+
if (s->dma_cmd == IDE_DMA_READ || s->dma_cmd == IDE_DMA_WRITE) {
if (ret < 0) {
block_acct_failed(blk_get_stats(s->blk), &s->acct);
diff --git a/hw/intc/s390_flic.c b/hw/intc/s390_flic.c
index bc75fa7..6ab29ef 100644
--- a/hw/intc/s390_flic.c
+++ b/hw/intc/s390_flic.c
@@ -67,6 +67,13 @@
{
}
+static int qemu_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
+ uint16_t subchannel_nr)
+{
+ /* Fixme TCG */
+ return -ENOSYS;
+}
+
static void qemu_s390_flic_class_init(ObjectClass *oc, void *data)
{
S390FLICStateClass *fsc = S390_FLIC_COMMON_CLASS(oc);
@@ -75,6 +82,7 @@
fsc->io_adapter_map = qemu_s390_io_adapter_map;
fsc->add_adapter_routes = qemu_s390_add_adapter_routes;
fsc->release_adapter_routes = qemu_s390_release_adapter_routes;
+ fsc->clear_io_irq = qemu_s390_clear_io_flic;
}
static const TypeInfo qemu_s390_flic_info = {
diff --git a/hw/intc/s390_flic_kvm.c b/hw/intc/s390_flic_kvm.c
index eed6325..680857f 100644
--- a/hw/intc/s390_flic_kvm.c
+++ b/hw/intc/s390_flic_kvm.c
@@ -30,6 +30,7 @@
S390FLICState parent_obj;
uint32_t fd;
+ bool clear_io_supported;
} KVMS390FLICState;
DeviceState *s390_flic_kvm_create(void)
@@ -130,6 +131,24 @@
return flic_enqueue_irqs(irq, sizeof(*irq), flic);
}
+static int kvm_s390_clear_io_flic(S390FLICState *fs, uint16_t subchannel_id,
+ uint16_t subchannel_nr)
+{
+ KVMS390FLICState *flic = KVM_S390_FLIC(fs);
+ int rc;
+ uint32_t sid = subchannel_id << 16 | subchannel_nr;
+ struct kvm_device_attr attr = {
+ .group = KVM_DEV_FLIC_CLEAR_IO_IRQ,
+ .addr = (uint64_t) &sid,
+ .attr = sizeof(sid),
+ };
+ if (unlikely(!flic->clear_io_supported)) {
+ return -ENOSYS;
+ }
+ rc = ioctl(flic->fd, KVM_SET_DEVICE_ATTR, &attr);
+ return rc ? -errno : 0;
+}
+
/**
* __get_all_irqs - store all pending irqs in buffer
* @flic: pointer to flic device state
@@ -358,6 +377,7 @@
{
KVMS390FLICState *flic_state = KVM_S390_FLIC(dev);
struct kvm_create_device cd = {0};
+ struct kvm_device_attr test_attr = {0};
int ret;
flic_state->fd = -1;
@@ -374,6 +394,11 @@
}
flic_state->fd = cd.fd;
+ /* Check clear_io_irq support */
+ test_attr.group = KVM_DEV_FLIC_CLEAR_IO_IRQ;
+ flic_state->clear_io_supported = !ioctl(flic_state->fd,
+ KVM_HAS_DEVICE_ATTR, test_attr);
+
/* Register savevm handler for floating interrupts */
register_savevm(NULL, "s390-flic", 0, 1, kvm_flic_save,
kvm_flic_load, (void *) flic_state);
@@ -420,6 +445,7 @@
fsc->io_adapter_map = kvm_s390_io_adapter_map;
fsc->add_adapter_routes = kvm_s390_add_adapter_routes;
fsc->release_adapter_routes = kvm_s390_release_adapter_routes;
+ fsc->clear_io_irq = kvm_s390_clear_io_flic;
}
static const TypeInfo kvm_s390_flic_info = {
diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
index bc0dd2c..ffb49c1 100644
--- a/hw/misc/Makefile.objs
+++ b/hw/misc/Makefile.objs
@@ -51,3 +51,4 @@
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 4442227..66a0787 100644
--- a/hw/misc/arm_l2x0.c
+++ b/hw/misc/arm_l2x0.c
@@ -159,14 +159,14 @@
.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 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 @@
.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 0000000..25d7712
--- /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 889abad..e30dbc7 100644
--- a/hw/misc/exynos4210_pmu.c
+++ b/hw/misc/exynos4210_pmu.c
@@ -457,15 +457,15 @@
}
}
-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 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 @@
.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 48d7dfb..a10f049 100644
--- a/hw/misc/mst_fpga.c
+++ b/hw/misc/mst_fpga.c
@@ -200,10 +200,11 @@
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 @@
/* 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 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 @@
.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/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c
index a9bb1c2..4479487 100644
--- a/hw/ppc/mac_oldworld.c
+++ b/hw/ppc/mac_oldworld.c
@@ -309,7 +309,7 @@
dev = qdev_create(adb_bus, TYPE_ADB_MOUSE);
qdev_init_nofail(dev);
- if (usb_enabled()) {
+ if (machine_usb(machine)) {
pci_create_simple(pci_bus, -1, "pci-ohci");
}
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 07ffe72..054af1e 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -649,7 +649,7 @@
memory_region_add_subregion(sysmem, 0xFEFF0000, xcsr);
#endif
- if (usb_enabled()) {
+ if (machine_usb(machine)) {
pci_create_simple(pci_bus, -1, "pci-ohci");
}
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
index 0636642..9a4a803 100644
--- a/hw/ppc/spapr.c
+++ b/hw/ppc/spapr.c
@@ -762,14 +762,17 @@
int ret, i, offset;
uint64_t lmb_size = SPAPR_MEMORY_BLOCK_SIZE;
uint32_t prop_lmb_size[] = {0, cpu_to_be32(lmb_size)};
- uint32_t nr_lmbs = (machine->maxram_size - machine->ram_size)/lmb_size;
+ uint32_t hotplug_lmb_start = spapr->hotplug_memory.base / lmb_size;
+ uint32_t nr_lmbs = (spapr->hotplug_memory.base +
+ memory_region_size(&spapr->hotplug_memory.mr)) /
+ lmb_size;
uint32_t *int_buf, *cur_index, buf_len;
int nr_nodes = nb_numa_nodes ? nb_numa_nodes : 1;
/*
- * Don't create the node if there are no DR LMBs.
+ * Don't create the node if there is no hotpluggable memory
*/
- if (!nr_lmbs) {
+ if (machine->ram_size == machine->maxram_size) {
return 0;
}
@@ -803,26 +806,40 @@
int_buf[0] = cpu_to_be32(nr_lmbs);
cur_index++;
for (i = 0; i < nr_lmbs; i++) {
- sPAPRDRConnector *drc;
- sPAPRDRConnectorClass *drck;
- uint64_t addr = i * lmb_size + spapr->hotplug_memory.base;;
+ uint64_t addr = i * lmb_size;
uint32_t *dynamic_memory = cur_index;
- drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB,
- addr/lmb_size);
- g_assert(drc);
- drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+ if (i >= hotplug_lmb_start) {
+ sPAPRDRConnector *drc;
+ sPAPRDRConnectorClass *drck;
- dynamic_memory[0] = cpu_to_be32(addr >> 32);
- dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
- dynamic_memory[2] = cpu_to_be32(drck->get_index(drc));
- dynamic_memory[3] = cpu_to_be32(0); /* reserved */
- dynamic_memory[4] = cpu_to_be32(numa_get_node(addr, NULL));
- if (addr < machine->ram_size ||
- memory_region_present(get_system_memory(), addr)) {
- dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
+ drc = spapr_dr_connector_by_id(SPAPR_DR_CONNECTOR_TYPE_LMB, i);
+ g_assert(drc);
+ drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
+
+ dynamic_memory[0] = cpu_to_be32(addr >> 32);
+ dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
+ dynamic_memory[2] = cpu_to_be32(drck->get_index(drc));
+ dynamic_memory[3] = cpu_to_be32(0); /* reserved */
+ dynamic_memory[4] = cpu_to_be32(numa_get_node(addr, NULL));
+ if (memory_region_present(get_system_memory(), addr)) {
+ dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_ASSIGNED);
+ } else {
+ dynamic_memory[5] = cpu_to_be32(0);
+ }
} else {
- dynamic_memory[5] = cpu_to_be32(0);
+ /*
+ * LMB information for RMA, boot time RAM and gap b/n RAM and
+ * hotplug memory region -- all these are marked as reserved
+ * and as having no valid DRC.
+ */
+ dynamic_memory[0] = cpu_to_be32(addr >> 32);
+ dynamic_memory[1] = cpu_to_be32(addr & 0xffffffff);
+ dynamic_memory[2] = cpu_to_be32(0);
+ dynamic_memory[3] = cpu_to_be32(0); /* reserved */
+ dynamic_memory[4] = cpu_to_be32(-1);
+ dynamic_memory[5] = cpu_to_be32(SPAPR_LMB_FLAGS_RESERVED |
+ SPAPR_LMB_FLAGS_DRC_INVALID);
}
cur_index += SPAPR_DR_LMB_LIST_ENTRY_SIZE;
diff --git a/hw/ppc/spapr_hcall.c b/hw/ppc/spapr_hcall.c
index 9a3f4ec..2ba5cbd 100644
--- a/hw/ppc/spapr_hcall.c
+++ b/hw/ppc/spapr_hcall.c
@@ -922,6 +922,41 @@
((cpuver) == CPU_POWERPC_LOGICAL_2_06_PLUS) ? 2061 : \
((cpuver) == CPU_POWERPC_LOGICAL_2_07) ? 2070 : 0)
+static void cas_handle_compat_cpu(PowerPCCPUClass *pcc, uint32_t pvr,
+ unsigned max_lvl, unsigned *compat_lvl,
+ unsigned *cpu_version)
+{
+ unsigned lvl = get_compat_level(pvr);
+ bool is205, is206, is207;
+
+ if (!lvl) {
+ return;
+ }
+
+ /* If it is a logical PVR, try to determine the highest level */
+ is205 = (pcc->pcr_supported & PCR_COMPAT_2_05) &&
+ (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_05));
+ is206 = (pcc->pcr_supported & PCR_COMPAT_2_06) &&
+ ((lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06)) ||
+ (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06_PLUS)));
+ is207 = (pcc->pcr_supported & PCR_COMPAT_2_07) &&
+ (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_07));
+
+ if (is205 || is206 || is207) {
+ if (!max_lvl) {
+ /* User did not set the level, choose the highest */
+ if (*compat_lvl <= lvl) {
+ *compat_lvl = lvl;
+ *cpu_version = pvr;
+ }
+ } else if (max_lvl >= lvl) {
+ /* User chose the level, don't set higher than this */
+ *compat_lvl = lvl;
+ *cpu_version = pvr;
+ }
+ }
+}
+
#define OV5_DRCONF_MEMORY 0x20
static target_ulong h_client_architecture_support(PowerPCCPU *cpu_,
@@ -931,7 +966,7 @@
{
target_ulong list = ppc64_phys_to_real(args[0]);
target_ulong ov_table, ov5;
- PowerPCCPUClass *pcc_ = POWERPC_CPU_GET_CLASS(cpu_);
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu_);
CPUState *cs;
bool cpu_match = false, cpu_update = true, memory_update = false;
unsigned old_cpu_version = cpu_->cpu_version;
@@ -958,29 +993,7 @@
cpu_match = true;
cpu_version = cpu_->cpu_version;
} else if (!cpu_match) {
- /* If it is a logical PVR, try to determine the highest level */
- unsigned lvl = get_compat_level(pvr);
- if (lvl) {
- bool is205 = (pcc_->pcr_mask & PCR_COMPAT_2_05) &&
- (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_05));
- bool is206 = (pcc_->pcr_mask & PCR_COMPAT_2_06) &&
- ((lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06)) ||
- (lvl == get_compat_level(CPU_POWERPC_LOGICAL_2_06_PLUS)));
-
- if (is205 || is206) {
- if (!max_lvl) {
- /* User did not set the level, choose the highest */
- if (compat_lvl <= lvl) {
- compat_lvl = lvl;
- cpu_version = pvr;
- }
- } else if (max_lvl >= lvl) {
- /* User chose the level, don't set higher than this */
- compat_lvl = lvl;
- cpu_version = pvr;
- }
- }
- }
+ cas_handle_compat_cpu(pcc, pvr, max_lvl, &compat_lvl, &cpu_version);
}
/* Terminator record */
if (~pvr_mask & pvr) {
@@ -990,7 +1003,7 @@
/* Parsing finished */
trace_spapr_cas_pvr(cpu_->cpu_version, cpu_match,
- cpu_version, pcc_->pcr_mask);
+ cpu_version, pcc->pcr_mask);
/* Update CPUs */
if (old_cpu_version != cpu_version) {
diff --git a/hw/s390x/css.c b/hw/s390x/css.c
index 1675a19..7666881 100644
--- a/hw/s390x/css.c
+++ b/hw/s390x/css.c
@@ -10,6 +10,8 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qapi/visitor.h"
#include <hw/qdev.h>
#include "qemu/bitops.h"
#include "exec/address-spaces.h"
@@ -192,12 +194,46 @@
return ret;
}
-uint16_t css_build_subchannel_id(SubchDev *sch)
+static void css_clear_io_interrupt(uint16_t subchannel_id,
+ uint16_t subchannel_nr)
+{
+ Error *err = NULL;
+ static bool no_clear_irq;
+ S390FLICState *fs = s390_get_flic();
+ S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs);
+ int r;
+
+ if (unlikely(no_clear_irq)) {
+ return;
+ }
+ r = fsc->clear_io_irq(fs, subchannel_id, subchannel_nr);
+ switch (r) {
+ case 0:
+ break;
+ case -ENOSYS:
+ no_clear_irq = true;
+ /*
+ * Ignore unavailability, as the user can't do anything
+ * about it anyway.
+ */
+ break;
+ default:
+ error_setg_errno(&err, -r, "unexpected error condition");
+ error_propagate(&error_abort, err);
+ }
+}
+
+static inline uint16_t css_do_build_subchannel_id(uint8_t cssid, uint8_t ssid)
{
if (channel_subsys.max_cssid > 0) {
- return (sch->cssid << 8) | (1 << 3) | (sch->ssid << 1) | 1;
+ return (cssid << 8) | (1 << 3) | (ssid << 1) | 1;
}
- return (sch->ssid << 1) | 1;
+ return (ssid << 1) | 1;
+}
+
+uint16_t css_build_subchannel_id(SubchDev *sch)
+{
+ return css_do_build_subchannel_id(sch->cssid, sch->ssid);
}
static void css_inject_io_interrupt(SubchDev *sch)
@@ -1429,6 +1465,8 @@
css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, 0,
(guest_cssid << 8) | (ssid << 4));
}
+ /* RW_ERC_IPI --> clear pending interrupts */
+ css_clear_io_interrupt(css_do_build_subchannel_id(cssid, ssid), schid);
}
void css_generate_chp_crws(uint8_t cssid, uint8_t chpid)
@@ -1644,3 +1682,83 @@
channel_subsys.max_cssid = 0;
channel_subsys.max_ssid = 0;
}
+
+static void get_css_devid(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ CssDevId *dev_id = qdev_get_prop_ptr(dev, prop);
+ char buffer[] = "xx.x.xxxx";
+ char *p = buffer;
+ int r;
+
+ if (dev_id->valid) {
+
+ r = snprintf(buffer, sizeof(buffer), "%02x.%1x.%04x", dev_id->cssid,
+ dev_id->ssid, dev_id->devid);
+ assert(r == sizeof(buffer) - 1);
+
+ /* drop leading zero */
+ if (dev_id->cssid <= 0xf) {
+ p++;
+ }
+ } else {
+ snprintf(buffer, sizeof(buffer), "<unset>");
+ }
+
+ visit_type_str(v, name, &p, errp);
+}
+
+/*
+ * parse <cssid>.<ssid>.<devid> and assert valid range for cssid/ssid
+ */
+static void set_css_devid(Object *obj, Visitor *v, const char *name,
+ void *opaque, Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ Property *prop = opaque;
+ CssDevId *dev_id = qdev_get_prop_ptr(dev, prop);
+ Error *local_err = NULL;
+ char *str;
+ int num, n1, n2;
+ unsigned int cssid, ssid, devid;
+
+ if (dev->realized) {
+ qdev_prop_set_after_realize(dev, name, errp);
+ return;
+ }
+
+ visit_type_str(v, name, &str, &local_err);
+ if (local_err) {
+ error_propagate(errp, local_err);
+ return;
+ }
+
+ num = sscanf(str, "%2x.%1x%n.%4x%n", &cssid, &ssid, &n1, &devid, &n2);
+ if (num != 3 || (n2 - n1) != 5 || strlen(str) != n2) {
+ error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
+ goto out;
+ }
+ if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) {
+ error_setg(errp, "Invalid cssid or ssid: cssid %x, ssid %x",
+ cssid, ssid);
+ goto out;
+ }
+
+ dev_id->cssid = cssid;
+ dev_id->ssid = ssid;
+ dev_id->devid = devid;
+ dev_id->valid = true;
+
+out:
+ g_free(str);
+}
+
+PropertyInfo css_devid_propinfo = {
+ .name = "str",
+ .description = "Identifier of an I/O device in the channel "
+ "subsystem, example: fe.1.23ab",
+ .get = get_css_devid,
+ .set = set_css_devid,
+};
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index 95ff5e3..e257ca5 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -204,7 +204,7 @@
mc->no_parallel = 1;
mc->no_sdcard = 1;
mc->use_sclp = 1;
- mc->max_cpus = 255;
+ mc->max_cpus = 248;
mc->get_hotplug_handler = s390_get_hotplug_handler;
hc->plug = s390_machine_device_plug;
nc->nmi_monitor_handler = s390_nmi;
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c
index 2b68e5e..2192be8 100644
--- a/hw/s390x/virtio-ccw.c
+++ b/hw/s390x/virtio-ccw.c
@@ -737,14 +737,9 @@
static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
{
- unsigned int cssid = 0;
- unsigned int ssid = 0;
unsigned int schid;
- unsigned int devno;
- bool have_devno = false;
bool found = false;
SubchDev *sch;
- int num;
Error *err = NULL;
VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_GET_CLASS(dev);
@@ -763,54 +758,44 @@
* Use a device number if provided. Otherwise, fall back to subchannel
* number.
*/
- if (dev->bus_id) {
- num = sscanf(dev->bus_id, "%x.%x.%04x", &cssid, &ssid, &devno);
- if (num == 3) {
- if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) {
- error_setg(errp, "Invalid cssid or ssid: cssid %x, ssid %x",
- cssid, ssid);
- goto out_err;
- }
- /* Enforce use of virtual cssid. */
- if (cssid != VIRTUAL_CSSID) {
- error_setg(errp, "cssid %x not valid for virtio devices",
- cssid);
- goto out_err;
- }
- if (css_devno_used(cssid, ssid, devno)) {
- error_setg(errp, "Device %x.%x.%04x already exists",
- cssid, ssid, devno);
- goto out_err;
- }
- sch->cssid = cssid;
- sch->ssid = ssid;
- sch->devno = devno;
- have_devno = true;
- } else {
- error_setg(errp, "Malformed devno parameter '%s'", dev->bus_id);
+ if (dev->bus_id.valid) {
+ /* Enforce use of virtual cssid. */
+ if (dev->bus_id.cssid != VIRTUAL_CSSID) {
+ error_setg(errp, "cssid %x not valid for virtio devices",
+ dev->bus_id.cssid);
goto out_err;
}
- }
+ if (css_devno_used(dev->bus_id.cssid, dev->bus_id.ssid,
+ dev->bus_id.devid)) {
+ error_setg(errp, "Device %x.%x.%04x already exists",
+ dev->bus_id.cssid, dev->bus_id.ssid,
+ dev->bus_id.devid);
+ goto out_err;
+ }
+ sch->cssid = dev->bus_id.cssid;
+ sch->ssid = dev->bus_id.ssid;
+ sch->devno = dev->bus_id.devid;
- /* Find the next free id. */
- if (have_devno) {
+ /* Find the next free id. */
for (schid = 0; schid <= MAX_SCHID; schid++) {
- if (!css_find_subch(1, cssid, ssid, schid)) {
+ if (!css_find_subch(1, sch->cssid, sch->ssid, schid)) {
sch->schid = schid;
- css_subch_assign(cssid, ssid, schid, devno, sch);
+ css_subch_assign(sch->cssid, sch->ssid, sch->schid,
+ sch->devno, sch);
found = true;
break;
}
}
if (!found) {
error_setg(errp, "No free subchannel found for %x.%x.%04x",
- cssid, ssid, devno);
+ sch->cssid, sch->ssid, sch->devno);
goto out_err;
}
- trace_virtio_ccw_new_device(cssid, ssid, schid, devno,
- "user-configured");
+ trace_virtio_ccw_new_device(sch->cssid, sch->ssid, sch->schid,
+ sch->devno, "user-configured");
} else {
- cssid = VIRTUAL_CSSID;
+ unsigned int cssid = VIRTUAL_CSSID, ssid, devno;
+
for (ssid = 0; ssid <= MAX_SSID; ssid++) {
for (schid = 0; schid <= MAX_SCHID; schid++) {
if (!css_find_subch(1, cssid, ssid, schid)) {
@@ -868,7 +853,7 @@
}
if (err) {
error_propagate(errp, err);
- css_subch_assign(cssid, ssid, schid, devno, NULL);
+ css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
goto out_err;
}
@@ -1106,6 +1091,7 @@
ind_old = *ind_addr;
ind_new = ind_old | to_be_set;
} while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old);
+ trace_virtio_ccw_set_ind(ind_loc, ind_old, ind_new);
cpu_physical_memory_unmap(ind_addr, len, 1, len);
return ind_old;
@@ -1516,7 +1502,7 @@
/**************** Virtio-ccw Bus Device Descriptions *******************/
static Property virtio_ccw_net_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1545,7 +1531,7 @@
};
static Property virtio_ccw_blk_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1574,7 +1560,7 @@
};
static Property virtio_ccw_serial_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1603,7 +1589,7 @@
};
static Property virtio_ccw_balloon_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1632,7 +1618,7 @@
};
static Property virtio_ccw_scsi_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1662,7 +1648,7 @@
#ifdef CONFIG_VHOST_SCSI
static Property vhost_ccw_scsi_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
VIRTIO_CCW_MAX_REV),
DEFINE_PROP_END_OF_LIST(),
@@ -1700,7 +1686,7 @@
}
static Property virtio_ccw_rng_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
@@ -1856,7 +1842,7 @@
#ifdef CONFIG_VIRTFS
static Property virtio_ccw_9p_properties[] = {
- DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
+ DEFINE_PROP_CSS_DEV_ID("devno", VirtioCcwDevice, bus_id),
DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev,
diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h
index 86b9edb..0bfb5d9 100644
--- a/hw/s390x/virtio-ccw.h
+++ b/hw/s390x/virtio-ccw.h
@@ -80,7 +80,7 @@
struct VirtioCcwDevice {
DeviceState parent_obj;
SubchDev *sch;
- char *bus_id;
+ CssDevId bus_id;
int revision;
uint32_t max_rev;
VirtioBusState bus;
diff --git a/hw/sd/pl181.c b/hw/sd/pl181.c
index eb783c6..82c63a4 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 @@
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/hw/usb/dev-network.c b/hw/usb/dev-network.c
index 74306b5..5c18198 100644
--- a/hw/usb/dev-network.c
+++ b/hw/usb/dev-network.c
@@ -670,48 +670,49 @@
/* general oids (table 4-1) */
/* mandatory */
case OID_GEN_SUPPORTED_LIST:
- for (i = 0; i < ARRAY_SIZE(oid_supported_list); i++)
- ((le32 *) outbuf)[i] = cpu_to_le32(oid_supported_list[i]);
+ for (i = 0; i < ARRAY_SIZE(oid_supported_list); i++) {
+ stl_le_p(outbuf + (i * sizeof(le32)), oid_supported_list[i]);
+ }
return sizeof(oid_supported_list);
/* mandatory */
case OID_GEN_HARDWARE_STATUS:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* mandatory */
case OID_GEN_MEDIA_SUPPORTED:
- *((le32 *) outbuf) = cpu_to_le32(s->medium);
+ stl_le_p(outbuf, s->medium);
return sizeof(le32);
/* mandatory */
case OID_GEN_MEDIA_IN_USE:
- *((le32 *) outbuf) = cpu_to_le32(s->medium);
+ stl_le_p(outbuf, s->medium);
return sizeof(le32);
/* mandatory */
case OID_GEN_MAXIMUM_FRAME_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN);
+ stl_le_p(outbuf, ETH_FRAME_LEN);
return sizeof(le32);
/* mandatory */
case OID_GEN_LINK_SPEED:
- *((le32 *) outbuf) = cpu_to_le32(s->speed);
+ stl_le_p(outbuf, s->speed);
return sizeof(le32);
/* mandatory */
case OID_GEN_TRANSMIT_BLOCK_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN);
+ stl_le_p(outbuf, ETH_FRAME_LEN);
return sizeof(le32);
/* mandatory */
case OID_GEN_RECEIVE_BLOCK_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(ETH_FRAME_LEN);
+ stl_le_p(outbuf, ETH_FRAME_LEN);
return sizeof(le32);
/* mandatory */
case OID_GEN_VENDOR_ID:
- *((le32 *) outbuf) = cpu_to_le32(s->vendorid);
+ stl_le_p(outbuf, s->vendorid);
return sizeof(le32);
/* mandatory */
@@ -720,58 +721,57 @@
return strlen((char *)outbuf) + 1;
case OID_GEN_VENDOR_DRIVER_VERSION:
- *((le32 *) outbuf) = cpu_to_le32(1);
+ stl_le_p(outbuf, 1);
return sizeof(le32);
/* mandatory */
case OID_GEN_CURRENT_PACKET_FILTER:
- *((le32 *) outbuf) = cpu_to_le32(s->filter);
+ stl_le_p(outbuf, s->filter);
return sizeof(le32);
/* mandatory */
case OID_GEN_MAXIMUM_TOTAL_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
+ stl_le_p(outbuf, RNDIS_MAX_TOTAL_SIZE);
return sizeof(le32);
/* mandatory */
case OID_GEN_MEDIA_CONNECT_STATUS:
- *((le32 *) outbuf) = cpu_to_le32(s->media_state);
+ stl_le_p(outbuf, s->media_state);
return sizeof(le32);
case OID_GEN_PHYSICAL_MEDIUM:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
case OID_GEN_MAC_OPTIONS:
- *((le32 *) outbuf) = cpu_to_le32(
- NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
- NDIS_MAC_OPTION_FULL_DUPLEX);
+ stl_le_p(outbuf, NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
+ NDIS_MAC_OPTION_FULL_DUPLEX);
return sizeof(le32);
/* statistics OIDs (table 4-2) */
/* mandatory */
case OID_GEN_XMIT_OK:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* mandatory */
case OID_GEN_RCV_OK:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* mandatory */
case OID_GEN_XMIT_ERROR:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* mandatory */
case OID_GEN_RCV_ERROR:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* mandatory */
case OID_GEN_RCV_NO_BUFFER:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* ieee802.3 OIDs (table 4-3) */
@@ -787,12 +787,12 @@
/* mandatory */
case OID_802_3_MULTICAST_LIST:
- *((le32 *) outbuf) = cpu_to_le32(0xe0000000);
+ stl_le_p(outbuf, 0xe0000000);
return sizeof(le32);
/* mandatory */
case OID_802_3_MAXIMUM_LIST_SIZE:
- *((le32 *) outbuf) = cpu_to_le32(1);
+ stl_le_p(outbuf, 1);
return sizeof(le32);
case OID_802_3_MAC_OPTIONS:
@@ -801,17 +801,17 @@
/* ieee802.3 statistics OIDs (table 4-4) */
/* mandatory */
case OID_802_3_RCV_ERROR_ALIGNMENT:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* mandatory */
case OID_802_3_XMIT_ONE_COLLISION:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
/* mandatory */
case OID_802_3_XMIT_MORE_COLLISIONS:
- *((le32 *) outbuf) = cpu_to_le32(0);
+ stl_le_p(outbuf, 0);
return sizeof(le32);
default:
@@ -826,7 +826,7 @@
{
switch (oid) {
case OID_GEN_CURRENT_PACKET_FILTER:
- s->filter = le32_to_cpup((le32 *) inbuf);
+ s->filter = ldl_le_p(inbuf);
if (s->filter) {
s->rndis_state = RNDIS_DATA_INITIALIZED;
} else {
@@ -1026,10 +1026,7 @@
static int rndis_parse(USBNetState *s, uint8_t *data, int length)
{
- uint32_t msg_type;
- le32 *tmp = (le32 *) data;
-
- msg_type = le32_to_cpup(tmp);
+ uint32_t msg_type = ldl_le_p(data);
switch (msg_type) {
case RNDIS_INITIALIZE_MSG:
diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index 8b774f4..da59c29 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -81,6 +81,7 @@
uint32_t iso_urb_frames;
uint32_t options;
uint32_t loglevel;
+ bool needs_autoscan;
/* state */
QTAILQ_ENTRY(USBHostDevice) next;
@@ -974,9 +975,32 @@
}
}
+static libusb_device *usb_host_find_ref(int bus, int addr)
+{
+ libusb_device **devs = NULL;
+ libusb_device *ret = NULL;
+ int i, n;
+
+ if (usb_host_init() != 0) {
+ return NULL;
+ }
+ n = libusb_get_device_list(ctx, &devs);
+ for (i = 0; i < n; i++) {
+ if (libusb_get_bus_number(devs[i]) == bus &&
+ libusb_get_device_address(devs[i]) == addr) {
+ ret = libusb_ref_device(devs[i]);
+ break;
+ }
+ }
+ libusb_free_device_list(devs, 1);
+ return ret;
+}
+
static void usb_host_realize(USBDevice *udev, Error **errp)
{
USBHostDevice *s = USB_HOST_DEVICE(udev);
+ libusb_device *ldev;
+ int rc;
if (s->match.vendor_id > 0xffff) {
error_setg(errp, "vendorid out of range");
@@ -997,11 +1021,33 @@
QTAILQ_INIT(&s->requests);
QTAILQ_INIT(&s->isorings);
+ if (s->match.addr && s->match.bus_num &&
+ !s->match.vendor_id &&
+ !s->match.product_id &&
+ !s->match.port) {
+ s->needs_autoscan = false;
+ ldev = usb_host_find_ref(s->match.bus_num,
+ s->match.addr);
+ if (!ldev) {
+ error_setg(errp, "failed to find host usb device %d:%d",
+ s->match.bus_num, s->match.addr);
+ return;
+ }
+ rc = usb_host_open(s, ldev);
+ libusb_unref_device(ldev);
+ if (rc < 0) {
+ error_setg(errp, "failed to open host usb device %d:%d",
+ s->match.bus_num, s->match.addr);
+ return;
+ }
+ } else {
+ s->needs_autoscan = true;
+ QTAILQ_INSERT_TAIL(&hostdevs, s, next);
+ usb_host_auto_check(NULL);
+ }
+
s->exit.notify = usb_host_exit_notifier;
qemu_add_exit_notifier(&s->exit);
-
- QTAILQ_INSERT_TAIL(&hostdevs, s, next);
- usb_host_auto_check(NULL);
}
static void usb_host_instance_init(Object *obj)
@@ -1019,7 +1065,9 @@
USBHostDevice *s = USB_HOST_DEVICE(udev);
qemu_remove_exit_notifier(&s->exit);
- QTAILQ_REMOVE(&hostdevs, s, next);
+ if (s->needs_autoscan) {
+ QTAILQ_REMOVE(&hostdevs, s, next);
+ }
usb_host_close(s);
}
diff --git a/include/elf.h b/include/elf.h
index 28d448b..8533b2a 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -477,6 +477,19 @@
#define PPC_FEATURE_TRUE_LE 0x00000002
#define PPC_FEATURE_PPC_LE 0x00000001
+/* Bits present in AT_HWCAP2 for PowerPC. */
+
+#define PPC_FEATURE2_ARCH_2_07 0x80000000
+#define PPC_FEATURE2_HAS_HTM 0x40000000
+#define PPC_FEATURE2_HAS_DSCR 0x20000000
+#define PPC_FEATURE2_HAS_EBB 0x10000000
+#define PPC_FEATURE2_HAS_ISEL 0x08000000
+#define PPC_FEATURE2_HAS_TAR 0x04000000
+#define PPC_FEATURE2_HAS_VEC_CRYPTO 0x02000000
+#define PPC_FEATURE2_HTM_NOSC 0x01000000
+#define PPC_FEATURE2_ARCH_3_00 0x00800000
+#define PPC_FEATURE2_HAS_IEEE128 0x00400000
+
/* Bits present in AT_HWCAP for Sparc. */
#define HWCAP_SPARC_FLUSH 0x00000001
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 82703d2..9650193 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 68f6eb0..c2931bf 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 @@
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 0000000..274dc2e
--- /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 0000000..d3a03f1
--- /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 0000000..ae571a0
--- /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 0000000..cb8e62d
--- /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 4986ebc..c4085aa 100644
--- a/include/hw/i2c/i2c.h
+++ b/include/hw/i2c/i2c.h
@@ -56,6 +56,7 @@
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 0000000..759c3bf
--- /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/include/hw/ppc/mac_dbdma.h b/include/hw/ppc/mac_dbdma.h
index 0cce4e8..d15a6cc 100644
--- a/include/hw/ppc/mac_dbdma.h
+++ b/include/hw/ppc/mac_dbdma.h
@@ -24,6 +24,7 @@
#include "exec/memory.h"
#include "qemu/iov.h"
+#include "sysemu/dma.h"
typedef struct DBDMA_io DBDMA_io;
@@ -44,6 +45,10 @@
uint8_t head_remainder[0x200];
uint8_t tail_remainder[0x200];
QEMUIOVector iov;
+ /* DMA request */
+ void *dma_mem;
+ dma_addr_t dma_len;
+ DMADirection dir;
};
/*
diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h
index 971df3d..3ac85c0 100644
--- a/include/hw/ppc/spapr.h
+++ b/include/hw/ppc/spapr.h
@@ -620,9 +620,11 @@
#define SPAPR_DR_LMB_LIST_ENTRY_SIZE 6
/*
- * This flag value defines the LMB as assigned in ibm,dynamic-memory
- * property under ibm,dynamic-reconfiguration-memory node.
+ * Defines for flag value in ibm,dynamic-memory property under
+ * ibm,dynamic-reconfiguration-memory node.
*/
#define SPAPR_LMB_FLAGS_ASSIGNED 0x00000008
+#define SPAPR_LMB_FLAGS_DRC_INVALID 0x00000020
+#define SPAPR_LMB_FLAGS_RESERVED 0x00000080
#endif /* !defined (__HW_SPAPR_H__) */
diff --git a/include/hw/s390x/css.h b/include/hw/s390x/css.h
index 98b2e2c..38f4d77 100644
--- a/include/hw/s390x/css.h
+++ b/include/hw/s390x/css.h
@@ -151,5 +151,22 @@
int css_do_rchp(uint8_t cssid, uint8_t chpid);
bool css_present(uint8_t cssid);
#endif
+/*
+ * Identify a device within the channel subsystem.
+ * Note that this can be used to identify either the subchannel or
+ * the attached I/O device, as there's always one I/O device per
+ * subchannel.
+ */
+typedef struct CssDevId {
+ uint8_t cssid;
+ uint8_t ssid;
+ uint16_t devid;
+ bool valid;
+} CssDevId;
+
+extern PropertyInfo css_devid_propinfo;
+
+#define DEFINE_PROP_CSS_DEV_ID(_n, _s, _f) \
+ DEFINE_PROP(_n, _s, _f, css_devid_propinfo, CssDevId)
#endif
diff --git a/include/hw/s390x/s390_flic.h b/include/hw/s390x/s390_flic.h
index 200e7e9..1dac2ee 100644
--- a/include/hw/s390x/s390_flic.h
+++ b/include/hw/s390x/s390_flic.h
@@ -49,6 +49,8 @@
bool do_map);
int (*add_adapter_routes)(S390FLICState *fs, AdapterRoutes *routes);
void (*release_adapter_routes)(S390FLICState *fs, AdapterRoutes *routes);
+ int (*clear_io_irq)(S390FLICState *fs, uint16_t subchannel_id,
+ uint16_t subchannel_nr);
} S390FLICStateClass;
#define TYPE_KVM_S390_FLIC "s390-flic-kvm"
diff --git a/include/standard-headers/linux/pci_regs.h b/include/standard-headers/linux/pci_regs.h
index 1becea8..4040951 100644
--- a/include/standard-headers/linux/pci_regs.h
+++ b/include/standard-headers/linux/pci_regs.h
@@ -670,7 +670,8 @@
#define PCI_EXT_CAP_ID_SECPCI 0x19 /* Secondary PCIe Capability */
#define PCI_EXT_CAP_ID_PMUX 0x1A /* Protocol Multiplexing */
#define PCI_EXT_CAP_ID_PASID 0x1B /* Process Address Space ID */
-#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PASID
+#define PCI_EXT_CAP_ID_DPC 0x1D /* Downstream Port Containment */
+#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_DPC
#define PCI_EXT_CAP_DSN_SIZEOF 12
#define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40
@@ -946,4 +947,21 @@
#define PCI_TPH_CAP_ST_SHIFT 16 /* st table shift */
#define PCI_TPH_BASE_SIZEOF 12 /* size with no st table */
+/* Downstream Port Containment */
+#define PCI_EXP_DPC_CAP 4 /* DPC Capability */
+#define PCI_EXP_DPC_CAP_RP_EXT 0x20 /* Root Port Extensions for DPC */
+#define PCI_EXP_DPC_CAP_POISONED_TLP 0x40 /* Poisoned TLP Egress Blocking Supported */
+#define PCI_EXP_DPC_CAP_SW_TRIGGER 0x80 /* Software Triggering Supported */
+#define PCI_EXP_DPC_CAP_DL_ACTIVE 0x1000 /* ERR_COR signal on DL_Active supported */
+
+#define PCI_EXP_DPC_CTL 6 /* DPC control */
+#define PCI_EXP_DPC_CTL_EN_NONFATAL 0x02 /* Enable trigger on ERR_NONFATAL message */
+#define PCI_EXP_DPC_CTL_INT_EN 0x08 /* DPC Interrupt Enable */
+
+#define PCI_EXP_DPC_STATUS 8 /* DPC Status */
+#define PCI_EXP_DPC_STATUS_TRIGGER 0x01 /* Trigger Status */
+#define PCI_EXP_DPC_STATUS_INTERRUPT 0x08 /* Interrupt Status */
+
+#define PCI_EXP_DPC_SOURCE_ID 10 /* DPC Source Identifier */
+
#endif /* LINUX_PCI_REGS_H */
diff --git a/include/standard-headers/linux/virtio_config.h b/include/standard-headers/linux/virtio_config.h
index bcc445b..b30d0cb 100644
--- a/include/standard-headers/linux/virtio_config.h
+++ b/include/standard-headers/linux/virtio_config.h
@@ -40,6 +40,8 @@
#define VIRTIO_CONFIG_S_DRIVER_OK 4
/* Driver has finished configuring features */
#define VIRTIO_CONFIG_S_FEATURES_OK 8
+/* Device entered invalid state, driver must reset it */
+#define VIRTIO_CONFIG_S_NEEDS_RESET 0x40
/* We've given up on this device. */
#define VIRTIO_CONFIG_S_FAILED 0x80
diff --git a/include/sysemu/sysemu.h b/include/sysemu/sysemu.h
index 9428141..7313673 100644
--- a/include/sysemu/sysemu.h
+++ b/include/sysemu/sysemu.h
@@ -233,7 +233,6 @@
QemuOpts *qemu_get_machine_opts(void);
bool defaults_enabled(void);
-bool usb_enabled(void);
extern QemuOptsList qemu_legacy_drive_opts;
extern QemuOptsList qemu_common_drive_opts;
diff --git a/linux-headers/asm-arm/unistd.h b/linux-headers/asm-arm/unistd.h
index 3f6f727..ceb5450 100644
--- a/linux-headers/asm-arm/unistd.h
+++ b/linux-headers/asm-arm/unistd.h
@@ -418,6 +418,8 @@
#define __NR_membarrier (__NR_SYSCALL_BASE+389)
#define __NR_mlock2 (__NR_SYSCALL_BASE+390)
#define __NR_copy_file_range (__NR_SYSCALL_BASE+391)
+#define __NR_preadv2 (__NR_SYSCALL_BASE+392)
+#define __NR_pwritev2 (__NR_SYSCALL_BASE+393)
/*
* The following SWIs are ARM private.
diff --git a/linux-headers/asm-arm64/unistd.h b/linux-headers/asm-arm64/unistd.h
index 1caadc2..043d17a 100644
--- a/linux-headers/asm-arm64/unistd.h
+++ b/linux-headers/asm-arm64/unistd.h
@@ -13,4 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+
+#define __ARCH_WANT_RENAMEAT
+
#include <asm-generic/unistd.h>
diff --git a/linux-headers/asm-powerpc/unistd.h b/linux-headers/asm-powerpc/unistd.h
index cd92d98..1e66eba 100644
--- a/linux-headers/asm-powerpc/unistd.h
+++ b/linux-headers/asm-powerpc/unistd.h
@@ -390,5 +390,7 @@
#define __NR_membarrier 365
#define __NR_mlock2 378
#define __NR_copy_file_range 379
+#define __NR_preadv2 380
+#define __NR_pwritev2 381
#endif /* _ASM_POWERPC_UNISTD_H_ */
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index a59499b..09ae5dc 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -25,6 +25,7 @@
#define KVM_DEV_FLIC_APF_DISABLE_WAIT 5
#define KVM_DEV_FLIC_ADAPTER_REGISTER 6
#define KVM_DEV_FLIC_ADAPTER_MODIFY 7
+#define KVM_DEV_FLIC_CLEAR_IO_IRQ 8
/*
* We can have up to 4*64k pending subchannels + 8 adapter interrupts,
* as well as up to ASYNC_PF_PER_VCPU*KVM_MAX_VCPUS pfault done interrupts.
diff --git a/linux-headers/asm-s390/unistd.h b/linux-headers/asm-s390/unistd.h
index 885837e..8a404fd 100644
--- a/linux-headers/asm-s390/unistd.h
+++ b/linux-headers/asm-s390/unistd.h
@@ -311,7 +311,9 @@
#define __NR_shutdown 373
#define __NR_mlock2 374
#define __NR_copy_file_range 375
-#define NR_syscalls 376
+#define __NR_preadv2 376
+#define __NR_pwritev2 377
+#define NR_syscalls 378
/*
* There are some system calls that are not present on 64 bit, some
diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
index cd54147..739c0c5 100644
--- a/linux-headers/asm-x86/kvm.h
+++ b/linux-headers/asm-x86/kvm.h
@@ -216,9 +216,9 @@
__u32 padding[3];
};
-#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX BIT(0)
-#define KVM_CPUID_FLAG_STATEFUL_FUNC BIT(1)
-#define KVM_CPUID_FLAG_STATE_READ_NEXT BIT(2)
+#define KVM_CPUID_FLAG_SIGNIFCANT_INDEX (1 << 0)
+#define KVM_CPUID_FLAG_STATEFUL_FUNC (1 << 1)
+#define KVM_CPUID_FLAG_STATE_READ_NEXT (1 << 2)
/* for KVM_SET_CPUID2 */
struct kvm_cpuid2 {
diff --git a/linux-headers/asm-x86/unistd_x32.h b/linux-headers/asm-x86/unistd_x32.h
index 8f77ee8..0230779 100644
--- a/linux-headers/asm-x86/unistd_x32.h
+++ b/linux-headers/asm-x86/unistd_x32.h
@@ -306,7 +306,9 @@
#define __NR_vmsplice (__X32_SYSCALL_BIT + 532)
#define __NR_move_pages (__X32_SYSCALL_BIT + 533)
#define __NR_preadv (__X32_SYSCALL_BIT + 534)
+#define __NR_preadv2 (__X32_SYSCALL_BIT + 534)
#define __NR_pwritev (__X32_SYSCALL_BIT + 535)
+#define __NR_pwritev2 (__X32_SYSCALL_BIT + 535)
#define __NR_rt_tgsigqueueinfo (__X32_SYSCALL_BIT + 536)
#define __NR_recvmmsg (__X32_SYSCALL_BIT + 537)
#define __NR_sendmmsg (__X32_SYSCALL_BIT + 538)
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 3bae71a..e60e21b 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -865,6 +865,7 @@
#define KVM_CAP_SPAPR_TCE_64 125
#define KVM_CAP_ARM_PMU_V3 126
#define KVM_CAP_VCPU_ATTRIBUTES 127
+#define KVM_CAP_MAX_VCPU_ID 128
#ifdef KVM_CAP_IRQ_ROUTING
diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 17d8051..942aa36 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -572,6 +572,8 @@
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 862e780..c9730d6 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -3765,8 +3765,11 @@
.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 c03e3e5..c35c676 100644
--- a/target-arm/kvm32.c
+++ b/target-arm/kvm32.c
@@ -522,3 +522,9 @@
{
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 e2a34f6..2d6a310 100644
--- a/target-arm/kvm64.c
+++ b/target-arm/kvm64.c
@@ -382,6 +382,47 @@
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 @@
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 345233c..a419368 100644
--- a/target-arm/kvm_arm.h
+++ b/target-arm/kvm_arm.h
@@ -194,6 +194,8 @@
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 @@
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 6815bc1a..3e71467 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -5311,6 +5311,30 @@
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 @@
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;
diff --git a/target-ppc/cpu-qom.h b/target-ppc/cpu-qom.h
index 07358aa..969ecdf 100644
--- a/target-ppc/cpu-qom.h
+++ b/target-ppc/cpu-qom.h
@@ -165,7 +165,8 @@
uint32_t pvr;
bool (*pvr_match)(struct PowerPCCPUClass *pcc, uint32_t pvr);
- uint64_t pcr_mask;
+ uint64_t pcr_mask; /* Available bits in PCR register */
+ uint64_t pcr_supported; /* Bits for supported PowerISA versions */
uint32_t svr;
uint64_t insns_flags;
uint64_t insns_flags2;
diff --git a/target-ppc/cpu.h b/target-ppc/cpu.h
index cb8b912..93c2dd5 100644
--- a/target-ppc/cpu.h
+++ b/target-ppc/cpu.h
@@ -1187,7 +1187,9 @@
void ppc_cpu_list (FILE *f, fprintf_function cpu_fprintf);
int ppc_get_compat_smt_threads(PowerPCCPU *cpu);
+#if defined(TARGET_PPC64)
void ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version, Error **errp);
+#endif
/* Time-base and decrementer management */
#ifndef NO_CPU_IO_DEFS
@@ -2200,6 +2202,7 @@
enum {
PCR_COMPAT_2_05 = 1ull << (63-62),
PCR_COMPAT_2_06 = 1ull << (63-61),
+ PCR_COMPAT_2_07 = 1ull << (63-60),
PCR_VEC_DIS = 1ull << (63-0), /* Vec. disable (bit NA since POWER8) */
PCR_VSX_DIS = 1ull << (63-1), /* VSX disable (bit NA since POWER8) */
PCR_TM_DIS = 1ull << (63-2), /* Trans. memory disable (POWER8) */
diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c
index 24d6032..6c15361 100644
--- a/target-ppc/kvm.c
+++ b/target-ppc/kvm.c
@@ -2329,6 +2329,19 @@
return POWERPC_CPU_CLASS(oc);
}
+PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
+{
+ uint32_t host_pvr = mfpvr();
+ PowerPCCPUClass *pvr_pcc;
+
+ pvr_pcc = ppc_cpu_class_by_pvr(host_pvr);
+ if (pvr_pcc == NULL) {
+ pvr_pcc = ppc_cpu_class_by_pvr_mask(host_pvr);
+ }
+
+ return pvr_pcc;
+}
+
static int kvm_ppc_register_host_cpu_type(void)
{
TypeInfo type_info = {
@@ -2336,14 +2349,10 @@
.instance_init = kvmppc_host_cpu_initfn,
.class_init = kvmppc_host_cpu_class_init,
};
- uint32_t host_pvr = mfpvr();
PowerPCCPUClass *pvr_pcc;
DeviceClass *dc;
- pvr_pcc = ppc_cpu_class_by_pvr(host_pvr);
- if (pvr_pcc == NULL) {
- pvr_pcc = ppc_cpu_class_by_pvr_mask(host_pvr);
- }
+ pvr_pcc = kvm_ppc_get_host_cpu_class();
if (pvr_pcc == NULL) {
return -1;
}
diff --git a/target-ppc/kvm_ppc.h b/target-ppc/kvm_ppc.h
index 3b2090e..20bfb59 100644
--- a/target-ppc/kvm_ppc.h
+++ b/target-ppc/kvm_ppc.h
@@ -56,6 +56,7 @@
bool kvmppc_has_cap_fixup_hcalls(void);
int kvmppc_enable_hwrng(void);
int kvmppc_put_books_sregs(PowerPCCPU *cpu);
+PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void);
#else
@@ -252,6 +253,12 @@
{
abort();
}
+
+static inline PowerPCCPUClass *kvm_ppc_get_host_cpu_class(void)
+{
+ return NULL;
+}
+
#endif
#ifndef CONFIG_KVM
diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c
index a1db500..ca894ff 100644
--- a/target-ppc/translate_init.c
+++ b/target-ppc/translate_init.c
@@ -8365,7 +8365,8 @@
dc->desc = "POWER7";
dc->props = powerpc_servercpu_properties;
pcc->pvr_match = ppc_pvr_match_power7;
- pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06;
+ pcc->pcr_mask = PCR_VEC_DIS | PCR_VSX_DIS | PCR_COMPAT_2_05;
+ pcc->pcr_supported = PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
pcc->init_proc = init_proc_POWER7;
pcc->check_pow = check_pow_nocheck;
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
@@ -8445,7 +8446,8 @@
dc->desc = "POWER8";
dc->props = powerpc_servercpu_properties;
pcc->pvr_match = ppc_pvr_match_power8;
- pcc->pcr_mask = PCR_COMPAT_2_05 | PCR_COMPAT_2_06;
+ pcc->pcr_mask = PCR_TM_DIS | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
+ pcc->pcr_supported = PCR_COMPAT_2_07 | PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
pcc->init_proc = init_proc_POWER8;
pcc->check_pow = check_pow_nocheck;
pcc->insns_flags = PPC_INSNS_BASE | PPC_ISEL | PPC_STRING | PPC_MFTB |
@@ -9513,28 +9515,37 @@
return ret;
}
+#ifdef TARGET_PPC64
void ppc_set_compat(PowerPCCPU *cpu, uint32_t cpu_version, Error **errp)
{
int ret = 0;
CPUPPCState *env = &cpu->env;
+ PowerPCCPUClass *host_pcc;
cpu->cpu_version = cpu_version;
switch (cpu_version) {
case CPU_POWERPC_LOGICAL_2_05:
- env->spr[SPR_PCR] = PCR_COMPAT_2_05;
+ env->spr[SPR_PCR] = PCR_TM_DIS | PCR_VSX_DIS | PCR_COMPAT_2_07 |
+ PCR_COMPAT_2_06 | PCR_COMPAT_2_05;
break;
case CPU_POWERPC_LOGICAL_2_06:
- env->spr[SPR_PCR] = PCR_COMPAT_2_06;
- break;
case CPU_POWERPC_LOGICAL_2_06_PLUS:
- env->spr[SPR_PCR] = PCR_COMPAT_2_06;
+ env->spr[SPR_PCR] = PCR_TM_DIS | PCR_COMPAT_2_07 | PCR_COMPAT_2_06;
+ break;
+ case CPU_POWERPC_LOGICAL_2_07:
+ env->spr[SPR_PCR] = PCR_COMPAT_2_07;
break;
default:
env->spr[SPR_PCR] = 0;
break;
}
+ host_pcc = kvm_ppc_get_host_cpu_class();
+ if (host_pcc) {
+ env->spr[SPR_PCR] &= host_pcc->pcr_mask;
+ }
+
if (kvm_enabled()) {
ret = kvmppc_set_compat(cpu, cpu->cpu_version);
if (ret < 0) {
@@ -9543,6 +9554,7 @@
}
}
}
+#endif
static gint ppc_cpu_compare_class_pvr(gconstpointer a, gconstpointer b)
{
diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c
index 8f46fd0..f108cd3 100644
--- a/target-s390x/kvm.c
+++ b/target-s390x/kvm.c
@@ -2071,8 +2071,9 @@
if (io_int_word & IO_INT_WORD_AI) {
irq.type = KVM_S390_INT_IO(1, 0, 0, 0);
} else {
- irq.type = ((subchannel_id & 0xff00) << 24) |
- ((subchannel_id & 0x00060) << 22) | (subchannel_nr << 16);
+ irq.type = KVM_S390_INT_IO(0, (subchannel_id & 0xff00) >> 8,
+ (subchannel_id & 0x0006),
+ subchannel_nr);
}
kvm_s390_floating_interrupt(&irq);
}
diff --git a/trace-events b/trace-events
index 421d89f..2f14205 100644
--- a/trace-events
+++ b/trace-events
@@ -1475,6 +1475,7 @@
# hw/s390x/virtio-ccw.c
virtio_ccw_interpret_ccw(int cssid, int ssid, int schid, int cmd_code) "VIRTIO-CCW: %x.%x.%04x: interpret command %x"
virtio_ccw_new_device(int cssid, int ssid, int schid, int devno, const char *devno_mode) "VIRTIO-CCW: add subchannel %x.%x.%04x, devno %04x (%s)"
+virtio_ccw_set_ind(uint64_t ind_loc, uint8_t ind_old, uint8_t ind_new) "VIRTIO-CCW: indicator at %" PRIu64 ": %x->%x"
# hw/intc/s390_flic_kvm.c
flic_create_device(int err) "flic: create device failed %d"
diff --git a/vl.c b/vl.c
index b0bcc25..45eff56 100644
--- a/vl.c
+++ b/vl.c
@@ -1072,11 +1072,6 @@
return has_defaults;
}
-bool usb_enabled(void)
-{
- return machine_usb(current_machine);
-}
-
#ifndef _WIN32
static int parse_add_fd(void *opaque, QemuOpts *opts, Error **errp)
{
@@ -1393,7 +1388,7 @@
const char *p;
#endif
- if (!usb_enabled()) {
+ if (!machine_usb(current_machine)) {
return -1;
}
@@ -1425,7 +1420,7 @@
return -1;
}
- if (!usb_enabled()) {
+ if (!machine_usb(current_machine)) {
return -1;
}
@@ -4501,7 +4496,7 @@
}
/* init USB devices */
- if (usb_enabled()) {
+ if (machine_usb(current_machine)) {
if (foreach_device_config(DEV_USB, usb_parse) < 0)
exit(1);
}