@@ -39,6 +39,7 @@
#include "sysemu/kvm.h"
#include "hw/boards.h"
#include "hw/loader.h"
+#include "hw/usb/hcd-ehci.h"
#include "exec/address-spaces.h"
#include "qemu/bitops.h"
#include "qemu/error-report.h"
@@ -71,6 +72,7 @@ enum {
VIRT_RTC,
VIRT_FW_CFG,
VIRT_PCIE,
+ VIRT_USB,
};
typedef struct MemMapEntry {
@@ -129,6 +131,7 @@ static const MemMapEntry a15memmap[] = {
[VIRT_UART] = { 0x09000000, 0x00001000 },
[VIRT_RTC] = { 0x09010000, 0x00001000 },
[VIRT_FW_CFG] = { 0x09020000, 0x0000000a },
+ [VIRT_USB] = { 0x09030000, 0x00001000 },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
/*
@@ -146,6 +149,7 @@ static const int a15irqmap[] = {
[VIRT_UART] = 1,
[VIRT_RTC] = 2,
[VIRT_PCIE] = 3, /* ... to 6 */
+ [VIRT_USB] = 7,
[VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
};
@@ -448,6 +452,27 @@ static void create_rtc(const VirtBoardInfo *vbi, qemu_irq *pic)
g_free(nodename);
}
+static void create_usb(const VirtBoardInfo *vbi, qemu_irq *pic)
+{
+ char *nodename;
+ hwaddr base = vbi->memmap[VIRT_USB].base;
+ hwaddr size = vbi->memmap[VIRT_USB].size;
+ int irq = vbi->irqmap[VIRT_USB];
+ const char compat[] = "generic-ehci";
+
+ sysbus_create_simple(TYPE_GENERIC_EHCI, base, pic[irq]);
+
+ nodename = g_strdup_printf("/ehci@%" PRIx64, base);
+ qemu_fdt_add_subnode(vbi->fdt, nodename);
+ qemu_fdt_setprop(vbi->fdt, nodename, "compatible", compat, sizeof(compat));
+ qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
+ 2, base, 2, size);
+ qemu_fdt_setprop_cells(vbi->fdt, nodename, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, irq,
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+ g_free(nodename);
+}
+
static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic)
{
int i;
@@ -821,6 +846,10 @@ static void machvirt_init(MachineState *machine)
create_pcie(vbi, pic, gic_phandle);
+ if (usb_enabled()) {
+ create_usb(vbi, pic);
+ }
+
/* Create mmio transports, so the user can create virtio backends
* (which will be automatically plugged in to the transports). If
* no backend is created the transport will just sit harmlessly idle.
@@ -217,6 +217,21 @@ static const TypeInfo ehci_fusbh200_type_info = {
.class_init = fusbh200_ehci_class_init,
};
+static void generic_ehci_class_init(ObjectClass *oc, void *data)
+{
+ SysBusEHCIClass *sec = SYS_BUS_EHCI_CLASS(oc);
+ DeviceClass *dc = DEVICE_CLASS(oc);
+
+ sec->capsbase = 0x0;
+ sec->opregbase = 0x10;
+ set_bit(DEVICE_CATEGORY_USB, dc->categories);
+}
+
+static const TypeInfo ehci_generic_type_info = {
+ .name = TYPE_GENERIC_EHCI,
+ .parent = TYPE_SYS_BUS_EHCI,
+ .class_init = generic_ehci_class_init,
+};
static void ehci_sysbus_register_types(void)
{
type_register_static(&ehci_type_info);
@@ -224,6 +239,7 @@ static void ehci_sysbus_register_types(void)
type_register_static(&ehci_exynos4210_type_info);
type_register_static(&ehci_tegra2_type_info);
type_register_static(&ehci_fusbh200_type_info);
+ type_register_static(&ehci_generic_type_info);
}
type_init(ehci_sysbus_register_types)
@@ -343,6 +343,7 @@ typedef struct EHCIPCIState {
#define TYPE_EXYNOS4210_EHCI "exynos4210-ehci-usb"
#define TYPE_TEGRA2_EHCI "tegra2-ehci-usb"
#define TYPE_FUSBH200_EHCI "fusbh200-ehci-usb"
+#define TYPE_GENERIC_EHCI "generic-ehci-usb"
#define SYS_BUS_EHCI(obj) \
OBJECT_CHECK(EHCISysBusState, (obj), TYPE_SYS_BUS_EHCI)