Hi Paul, On 3/29/20 1:17 AM, Paul Zimmerman wrote: > Add the dwc-hsotg (dwc2) USB host controller emulation code. > Based on hw/usb/hcd-ehci.c and hw/usb/hcd-ohci.c. > > Note that to use this with the dwc-otg driver in the Raspbian > kernel, you must pass the option "dwc_otg.fiq_fsm_enable=0" on > the kernel command line. > > Emulation of slave mode and of descriptor-DMA mode has not been > implemented yet. These modes are seldom used. > > I have used some on-line sources of information while developing > this emulation, including: > > http://www.capital-micro.com/PDF/CME-M7_Family_User_Guide_EN.pdf > has a pretty complete description of the controller starting on > page 370. > > https://sourceforge.net/p/wive-ng/wive-ng-mt/ci/master/tree/docs/DataSheets/RT3050_5x_V2.0_081408_0902.pdf > has a description of the controller registers starting on page > 130. > > Signed-off-by: Paul Zimmerman <pauld...@gmail.com> > --- > hw/usb/hcd-dwc2.c | 1301 +++++++++++++++++++++++++++++++++++++++++++ > hw/usb/trace-events | 47 ++ > 2 files changed, 1348 insertions(+) > create mode 100644 hw/usb/hcd-dwc2.c > > diff --git a/hw/usb/hcd-dwc2.c b/hw/usb/hcd-dwc2.c [...] > +static void dwc2_init(DWC2State *s, DeviceState *dev) > +{ > + s->usb_frame_time = NANOSECONDS_PER_SECOND / 1000; /* 1000000 */ > + if (NANOSECONDS_PER_SECOND >= USB_HZ_FS) { > + s->usb_bit_time = NANOSECONDS_PER_SECOND / USB_HZ_FS; /* 83.3 */ > + } else { > + s->usb_bit_time = 1; > + } > + > + s->fi = 11999;
What is this magic number? > + > + memory_region_init(&s->mem, OBJECT(dev), "dwc2", DWC2_MMIO_SIZE); > + memory_region_init_io(&s->mem_glbreg, OBJECT(dev), > &dwc2_mmio_glbreg_ops, s, > + "global", 0x70); > + memory_region_init_io(&s->mem_fszreg, OBJECT(dev), > &dwc2_mmio_fszreg_ops, s, > + "hptxfsiz", 0x4); > + memory_region_init_io(&s->mem_hreg0, OBJECT(dev), &dwc2_mmio_hreg0_ops, > s, > + "host", 0x44); > + memory_region_init_io(&s->mem_hreg1, OBJECT(dev), &dwc2_mmio_hreg1_ops, > s, > + "host channels", 0x20 * NB_CHAN); > + memory_region_init_io(&s->mem_pcgreg, OBJECT(dev), > &dwc2_mmio_pcgreg_ops, s, > + "power/clock", 0x8); > + memory_region_init_io(&s->mem_hreg2, OBJECT(dev), &dwc2_mmio_hreg2_ops, > s, > + "host fifos", NB_CHAN * 0x1000); > + > + memory_region_add_subregion(&s->mem, s->glbregbase, &s->mem_glbreg); > + memory_region_add_subregion(&s->mem, s->fszregbase, &s->mem_fszreg); > + memory_region_add_subregion(&s->mem, s->hreg0base, &s->mem_hreg0); > + memory_region_add_subregion(&s->mem, s->hreg1base, &s->mem_hreg1); > + memory_region_add_subregion(&s->mem, s->pcgregbase, &s->mem_pcgreg); > + memory_region_add_subregion(&s->mem, s->hreg2base, &s->mem_hreg2); > + > + s->eof_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, > + dwc2_frame_boundary, s); > +} > + > +static void dwc2_sysbus_reset(DeviceState *dev) > +{ > + SysBusDevice *d = SYS_BUS_DEVICE(dev); > + DWC2State *s = DWC2_USB(d); > + > + dwc2_reset(s); > +} > + > +static void dwc2_sysbus_realize(DeviceState *dev, Error **errp) > +{ > + SysBusDevice *d = SYS_BUS_DEVICE(dev); > + DWC2State *s = DWC2_USB(dev); > + > + s->glbregbase = 0; > + s->fszregbase = 0x0100; > + s->hreg0base = 0x0400; > + s->hreg1base = 0x0500; > + s->pcgregbase = 0x0e00; > + s->hreg2base = 0x1000; No need to use variable for the constant base addresses, use them directly in as argument to memory_region_add_subregion(). Since you don't reuse each block, and blocks cover very few registers, have you considered using a pair of MRs instead? One of 4KB and the other 64KB. hreg2 is the only one particularly different. > + s->portnr = NB_PORTS; > + s->as = &address_space_memory; > + > + dwc2_realize(s, dev, errp); > + dwc2_init(s, dev); > + sysbus_init_irq(d, &s->irq); > + sysbus_init_mmio(d, &s->mem); > +} [...]