From afb526ce8bb0a0cfc86ea2b30316c1d458837f8d Mon Sep 17 00:00:00 2001 From: Andrew Baumann Date: Wed, 25 Nov 2015 15:39:10 -0800 Subject: [PATCH] bcm2835_usb: add header file, convert to init/realize, fix dma bug I hadn't noticed that this was still using address_space_memory for DMA, so it was even more broken than usual. --- hw/arm/bcm2835_peripherals.c | 22 ++--- hw/usb/bcm2835_usb.c | 152 +++++++++++------------------------ include/hw/arm/bcm2835_peripherals.h | 4 +- include/hw/usb/bcm2835_usb.h | 77 ++++++++++++++++++ 4 files changed, 140 insertions(+), 115 deletions(-) create mode 100644 include/hw/usb/bcm2835_usb.h diff --git a/hw/arm/bcm2835_peripherals.c b/hw/arm/bcm2835_peripherals.c index d4c7c91f73..4690e55ce2 100644 --- a/hw/arm/bcm2835_peripherals.c +++ b/hw/arm/bcm2835_peripherals.c @@ -15,7 +15,6 @@ static void bcm2835_peripherals_init(Object *obj) { BCM2835PeripheralState *s = BCM2835_PERIPHERALS(obj); - SysBusDevice *dev; /* Memory region for peripheral devices, which we export to our parent */ memory_region_init_io(&s->peri_mr, OBJECT(s), NULL, s, @@ -38,9 +37,9 @@ static void bcm2835_peripherals_init(Object *obj) qdev_set_parent_bus(DEVICE(&s->ic), sysbus_get_default()); /* UART0 */ - s->uart0 = dev = SYS_BUS_DEVICE(object_new("pl011")); - object_property_add_child(obj, "uart0", OBJECT(dev), NULL); - qdev_set_parent_bus(DEVICE(dev), sysbus_get_default()); + s->uart0 = SYS_BUS_DEVICE(object_new("pl011")); + object_property_add_child(obj, "uart0", OBJECT(s->uart0), NULL); + qdev_set_parent_bus(DEVICE(s->uart0), sysbus_get_default()); /* AUX / UART1 */ object_initialize(&s->aux, sizeof(s->aux), TYPE_BCM2835_AUX); @@ -58,9 +57,12 @@ static void bcm2835_peripherals_init(Object *obj) qdev_set_parent_bus(DEVICE(&s->timer), sysbus_get_default()); /* USB controller */ - s->usb = dev = SYS_BUS_DEVICE(object_new("bcm2835_usb")); - object_property_add_child(obj, "usb", OBJECT(dev), NULL); - qdev_set_parent_bus(DEVICE(dev), sysbus_get_default()); + object_initialize(&s->usb, sizeof(s->usb), TYPE_BCM2835_USB); + object_property_add_child(obj, "usb", OBJECT(&s->usb), NULL); + qdev_set_parent_bus(DEVICE(&s->usb), sysbus_get_default()); + + object_property_add_const_link(OBJECT(&s->usb), "dma_mr", + OBJECT(&s->gpu_bus_mr), &error_abort); /* MPHI - Message-based Parallel Host Interface */ object_initialize(&s->mphi, sizeof(s->mphi), TYPE_BCM2835_MPHI); @@ -215,15 +217,15 @@ static void bcm2835_peripherals_realize(DeviceState *dev, Error **errp) qdev_get_gpio_in(DEVICE(&s->ic), INTERRUPT_ARM_TIMER)); /* USB controller */ - object_property_set_bool(OBJECT(s->usb), true, "realized", &err); + object_property_set_bool(OBJECT(&s->usb), true, "realized", &err); if (err) { error_propagate(errp, err); return; } memory_region_add_subregion(&s->peri_mr, USB_OFFSET, - sysbus_mmio_get_region(s->usb, 0)); - sysbus_connect_irq(s->usb, 0, + sysbus_mmio_get_region(SYS_BUS_DEVICE(&s->usb), 0)); + sysbus_connect_irq(SYS_BUS_DEVICE(&s->usb), 0, qdev_get_gpio_in(DEVICE(&s->ic), INTERRUPT_VC_USB)); /* MPHI - Message-based Parallel Host Interface */ diff --git a/hw/usb/bcm2835_usb.c b/hw/usb/bcm2835_usb.c index bf5b2158c6..270094e697 100644 --- a/hw/usb/bcm2835_usb.c +++ b/hw/usb/bcm2835_usb.c @@ -5,9 +5,7 @@ /* This is wrong at so many levels, but well, I'm releasing it anyway */ -#include "qemu/timer.h" -#include "hw/sysbus.h" -#include "hw/usb.h" +#include "hw/usb/bcm2835_usb.h" #include "sysemu/dma.h" #include "bcm2835_usb_regs.h" @@ -19,77 +17,12 @@ #define SOF_INCR 1 #define SOF_DELAY 5000 -#define NB_HCHANS 8 - - -#define TYPE_BCM2835_USB "bcm2835_usb" -#define BCM2835_USB(obj) \ - OBJECT_CHECK(Bcm2835UsbState, (obj), TYPE_BCM2835_USB) - -typedef struct Bcm2835UsbState Bcm2835UsbState; - -typedef struct { - Bcm2835UsbState *parent; - int index; - - uint32_t hcchar; - uint32_t hcsplt; - uint32_t hcint; - uint32_t hcintmsk; - uint32_t hctsiz; - uint32_t hcdma; - uint32_t reserved; - uint32_t hcdmab; - - USBPacket packet; - uint8_t buffer[8192]; -} Bcm2835UsbHcState; - -struct Bcm2835UsbState { - SysBusDevice busdev; - MemoryRegion iomem; - AddressSpace *dma; - - USBBus bus; - USBPort port; - int attached; - int reset_done; - QEMUTimer *sof_timer; - - - uint32_t gusbcfg; - uint32_t hptxfsiz; - uint32_t hcfg; - uint32_t dcfg; - uint32_t grxfsiz; - uint32_t gnptxfsiz; - uint32_t dtxfsiz[15]; - uint32_t gahbcfg; - uint32_t grstctl; - uint32_t gotgctl; - uint32_t gotgint; - uint32_t gintsts; - uint32_t gintmsk; - uint32_t gdfifocfg; - uint32_t hprt0; - uint32_t haint; - uint32_t haintmsk; - uint32_t gnptxsts; - uint32_t hfnum; - uint32_t hptxsts; - uint32_t guid; - - Bcm2835UsbHcState hchan[NB_HCHANS]; - - qemu_irq irq; -}; - -static void bcm2835_usb_update_irq(Bcm2835UsbState *s) +static void bcm2835_usb_update_irq(BCM2835UsbState *s) { int n; s->haint = 0; - for (n = 0; n < NB_HCHANS; n++) { + for (n = 0; n < BCM2835_USB_HCHANS; n++) { if (s->hchan[n].hcint & s->hchan[n].hcintmsk) { s->haint |= (1 << n); } @@ -100,8 +33,7 @@ static void bcm2835_usb_update_irq(Bcm2835UsbState *s) } if ((s->hprt0 & hprt0_prtconndet) - || (s->hprt0 & hprt0_prtenchng) - ) { + || (s->hprt0 & hprt0_prtenchng)) { s->gintsts |= gintsts_portintr; } else { s->gintsts &= ~gintsts_portintr; @@ -123,7 +55,7 @@ static void bcm2835_usb_update_irq(Bcm2835UsbState *s) static void bcm2835_usb_sof_tick(void *opaque) { - Bcm2835UsbState *s = (Bcm2835UsbState *)opaque; + BCM2835UsbState *s = (BCM2835UsbState *)opaque; int64_t now; uint32_t num = (s->hfnum & 0x3fff) + SOF_INCR; @@ -136,7 +68,7 @@ static void bcm2835_usb_sof_tick(void *opaque) timer_mod(s->sof_timer, now + SOF_DELAY); } -static void channel_enable(Bcm2835UsbHcState *c) +static void channel_enable(BCM2835UsbHcState *c) { USBEndpoint *ep; USBDevice *dev; @@ -174,7 +106,7 @@ static void channel_enable(Bcm2835UsbHcState *c) usb_packet_setup(&c->packet, qpid, ep, 0, devaddr, 0, 0); if (xfersize > 0) { - dma_memory_read(c->parent->dma, dma_addr, c->buffer, xfersize); + dma_memory_read(&c->parent->dma_as, dma_addr, c->buffer, xfersize); usb_packet_addbuf(&c->packet, c->buffer, xfersize); } @@ -188,8 +120,8 @@ static void channel_enable(Bcm2835UsbHcState *c) c->hctsiz &= ~(hctsiz_xfersize_mask << hctsiz_xfersize_shift); c->hctsiz |= xfersize << hctsiz_xfersize_shift; - dma_memory_write(c->parent->dma, dma_addr, c->buffer, - actual_length); + dma_memory_write(&c->parent->dma_as, dma_addr, c->buffer, + actual_length); } c->hcint |= hcint_xfercomp | hcint_chhltd; @@ -205,10 +137,10 @@ static void channel_enable(Bcm2835UsbHcState *c) } -static uint32_t bcm2835_usb_hchan_read(Bcm2835UsbState *s, int ch, +static uint32_t bcm2835_usb_hchan_read(BCM2835UsbState *s, int ch, int offset) { - Bcm2835UsbHcState *c = &s->hchan[ch]; + BCM2835UsbHcState *c = &s->hchan[ch]; uint32_t res; switch (offset) { @@ -239,10 +171,10 @@ static uint32_t bcm2835_usb_hchan_read(Bcm2835UsbState *s, int ch, } return res; } -static void bcm2835_usb_hchan_write(Bcm2835UsbState *s, int ch, +static void bcm2835_usb_hchan_write(BCM2835UsbState *s, int ch, int offset, uint32_t value, int *pset_irq) { - Bcm2835UsbHcState *c = &s->hchan[ch]; + BCM2835UsbHcState *c = &s->hchan[ch]; switch (offset) { case 0x0: @@ -283,7 +215,7 @@ static void bcm2835_usb_hchan_write(Bcm2835UsbState *s, int ch, static uint64_t bcm2835_usb_read(void *opaque, hwaddr offset, unsigned size) { - Bcm2835UsbState *s = (Bcm2835UsbState *)opaque; + BCM2835UsbState *s = (BCM2835UsbState *)opaque; uint32_t res = 0; int i; @@ -381,7 +313,7 @@ static uint64_t bcm2835_usb_read(void *opaque, hwaddr offset, default: if ((offset >= 0x104) && (offset < 0x104 + (15 << 2))) { res = s->dtxfsiz[(offset - 0x104) >> 2]; - } else if ((offset >= 0x500) && (offset < 0x500 + 0x20*NB_HCHANS)) { + } else if ((offset >= 0x500) && (offset < 0x500 + 0x20*BCM2835_USB_HCHANS)) { i = (offset - 0x500) >> 5; res = bcm2835_usb_hchan_read(s, i, offset & 0x1f); } else { @@ -397,7 +329,7 @@ static uint64_t bcm2835_usb_read(void *opaque, hwaddr offset, static void bcm2835_usb_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { - Bcm2835UsbState *s = (Bcm2835UsbState *)opaque; + BCM2835UsbState *s = (BCM2835UsbState *)opaque; int i; int set_irq = 0; @@ -460,7 +392,7 @@ static void bcm2835_usb_write(void *opaque, hwaddr offset, /* Probably RO */ break; case 0x418: - s->haintmsk = value & ((1 << NB_HCHANS) - 1); + s->haintmsk = value & ((1 << BCM2835_USB_HCHANS) - 1); set_irq = 1; break; case 0x440: @@ -509,7 +441,7 @@ static void bcm2835_usb_write(void *opaque, hwaddr offset, default: if ((offset >= 0x104) && (offset < 0x104 + (15 << 2))) { s->dtxfsiz[(offset - 0x104) >> 2] = value; - } else if ((offset >= 0x500) && (offset < 0x500 + 0x20*NB_HCHANS)) { + } else if ((offset >= 0x500) && (offset < 0x500 + 0x20*BCM2835_USB_HCHANS)) { i = (offset - 0x500) >> 5; bcm2835_usb_hchan_write(s, i, offset & 0x1f, value, &set_irq); } else { @@ -526,7 +458,7 @@ static void bcm2835_usb_write(void *opaque, hwaddr offset, static void bcm2835_usb_attach(USBPort *port1) { - Bcm2835UsbState *s = port1->opaque; + BCM2835UsbState *s = port1->opaque; s->attached = 1; } static void bcm2835_usb_detach(USBPort *port1) @@ -570,13 +502,31 @@ static USBPortOps bcm2835_usb_port_ops = { static USBBusOps bcm2835_usb_bus_ops = { }; -static int bcm2835_usb_init(SysBusDevice *sbd) +static void bcm2835_usb_init(Object *obj) +{ + BCM2835UsbState *s = BCM2835_USB(obj); + + memory_region_init_io(&s->iomem, obj, &bcm2835_usb_ops, s, + TYPE_BCM2835_USB, 0x20000); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); + sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq); +} + +static void bcm2835_usb_realize(DeviceState *dev, Error **errp) { int n; - DeviceState *dev = DEVICE(sbd); - Bcm2835UsbState *s = BCM2835_USB(dev); + BCM2835UsbState *s = BCM2835_USB(dev); + Error *err = NULL; + Object *obj; - s->dma = &address_space_memory; + obj = object_property_get_link(OBJECT(dev), "dma_mr", &err); + if (err || obj == NULL) { + error_setg(errp, "bcm2835_usb: required dma_mr property not found"); + return; + } + + s->dma_mr = MEMORY_REGION(obj); + address_space_init(&s->dma_as, s->dma_mr, NULL); s->gusbcfg = 0x20402700; s->hptxfsiz = 0x02002000; @@ -600,7 +550,7 @@ static int bcm2835_usb_init(SysBusDevice *sbd) s->hptxsts = 0x080200; s->guid = 0x2708A000; - for (n = 0; n < NB_HCHANS; n++) { + for (n = 0; n < BCM2835_USB_HCHANS; n++) { s->hchan[n].parent = s; s->hchan[n].index = n; @@ -615,36 +565,30 @@ static int bcm2835_usb_init(SysBusDevice *sbd) usb_packet_init(&s->hchan[n].packet); } - memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_usb_ops, s, - TYPE_BCM2835_USB, 0x20000); - sysbus_init_mmio(sbd, &s->iomem); - vmstate_register(dev, -1, &vmstate_bcm2835_usb, s); - - sysbus_init_irq(sbd, &s->irq); - s->attached = 0; s->reset_done = 0; s->sof_timer = timer_new_us(QEMU_CLOCK_VIRTUAL, bcm2835_usb_sof_tick, s); - usb_bus_new(&s->bus, sizeof(s->bus), &bcm2835_usb_bus_ops, dev); + usb_bus_new(&s->bus, sizeof(s->bus), &bcm2835_usb_bus_ops, DEVICE(s)); usb_register_port(&s->bus, &s->port, s, 0, &bcm2835_usb_port_ops, USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL); - return 0; } static void bcm2835_usb_class_init(ObjectClass *klass, void *data) { - SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); + DeviceClass *dc = DEVICE_CLASS(klass); - sdc->init = bcm2835_usb_init; + dc->realize = bcm2835_usb_realize; + dc->vmsd = &vmstate_bcm2835_usb; } static TypeInfo bcm2835_usb_info = { .name = TYPE_BCM2835_USB, .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(Bcm2835UsbState), + .instance_size = sizeof(BCM2835UsbState), .class_init = bcm2835_usb_class_init, + .instance_init = bcm2835_usb_init, }; static void bcm2835_usb_register_types(void) diff --git a/include/hw/arm/bcm2835_peripherals.h b/include/hw/arm/bcm2835_peripherals.h index 581aeefc27..f78f9e5481 100644 --- a/include/hw/arm/bcm2835_peripherals.h +++ b/include/hw/arm/bcm2835_peripherals.h @@ -26,6 +26,7 @@ #include "hw/sd/bcm2835_emmc.h" #include "hw/timer/bcm2835_st.h" #include "hw/timer/bcm2835_timer.h" +#include "hw/usb/bcm2835_usb.h" #define TYPE_BCM2835_PERIPHERALS "bcm2835_peripherals" #define BCM2835_PERIPHERALS(obj) \ @@ -40,6 +41,7 @@ typedef struct BCM2835PeripheralState { MemoryRegion ram_alias[4]; qemu_irq irq, fiq; + SysBusDevice *uart0; BCM2835AuxState aux; BCM2835FbState fb; BCM2835DmaState dma; @@ -52,7 +54,7 @@ typedef struct BCM2835PeripheralState { BCM2835EmmcState emmc; BCM2835StState st; BCM2835TimerState timer; - SysBusDevice *uart0, *usb; + BCM2835UsbState usb; } BCM2835PeripheralState; #endif /* BCM2835_PERIPHERALS_H */ diff --git a/include/hw/usb/bcm2835_usb.h b/include/hw/usb/bcm2835_usb.h new file mode 100644 index 0000000000..5fa648bbda --- /dev/null +++ b/include/hw/usb/bcm2835_usb.h @@ -0,0 +1,77 @@ +/* + * Raspberry Pi emulation (c) 2012 Gregory Estrade + * This code is licensed under the GNU GPLv2 and later. + */ + +#ifndef BCM2835_USB_H +#define BCM2835_USB_H + +#include "qemu/timer.h" +#include "hw/sysbus.h" +#include "hw/usb.h" + +#define BCM2835_USB_HCHANS 8 + +#define TYPE_BCM2835_USB "bcm2835_usb" +#define BCM2835_USB(obj) \ + OBJECT_CHECK(BCM2835UsbState, (obj), TYPE_BCM2835_USB) + +typedef struct BCM2835UsbState BCM2835UsbState; + +typedef struct { + BCM2835UsbState *parent; + int index; + + uint32_t hcchar; + uint32_t hcsplt; + uint32_t hcint; + uint32_t hcintmsk; + uint32_t hctsiz; + uint32_t hcdma; + uint32_t reserved; + uint32_t hcdmab; + + USBPacket packet; + uint8_t buffer[8192]; +} BCM2835UsbHcState; + +struct BCM2835UsbState { + SysBusDevice busdev; + MemoryRegion iomem; + MemoryRegion *dma_mr; + AddressSpace dma_as; + + USBBus bus; + USBPort port; + int attached; + int reset_done; + QEMUTimer *sof_timer; + + uint32_t gusbcfg; + uint32_t hptxfsiz; + uint32_t hcfg; + uint32_t dcfg; + uint32_t grxfsiz; + uint32_t gnptxfsiz; + uint32_t dtxfsiz[15]; + uint32_t gahbcfg; + uint32_t grstctl; + uint32_t gotgctl; + uint32_t gotgint; + uint32_t gintsts; + uint32_t gintmsk; + uint32_t gdfifocfg; + uint32_t hprt0; + uint32_t haint; + uint32_t haintmsk; + uint32_t gnptxsts; + uint32_t hfnum; + uint32_t hptxsts; + uint32_t guid; + + BCM2835UsbHcState hchan[BCM2835_USB_HCHANS]; + + qemu_irq irq; +}; + +#endif -- 2.11.4.GIT