On Sat, Oct 01, 2016 at 03:48:35PM +0200, Mark Kettenis wrote: > The USB controller on the Freescale i.MX application processors has a > dual role port that can act as device (OTG) or as host. Since we > don't have any device mode support in our kernel, we try to switch the > port into host mode. Unfortunately that never worked. Here's why: > > The USBMODE register that controls the mode, gets reset whenever we > reset the controller, i.e. when ehci_reset() gets called. Since > ehci_init() calls ehci_reset() we lose the host mode setting almost > immediately, and nothing works. > > The diff below adds code to save and restore the USBMODE register if > the EHCIF_USBMODE flag is set, and sets this flag in the imxehci(4) > driver. I also moved the defines for this register to ehcireg.h. > While this isn't a standard EHCI register, it seems that it is present > on many dual-role USB 2.0 controller. Allegedly it is part of a > design that ended up being licensed to many other companies. > > Note that the register offset changed from 0xa8 to 0x68. This is not > a bug. Imade the offset relative to the offset given by the > EHCI_CAPLENGTH register. It is now accessed using EOREAD4/EOWRITE4 > instead of EREAD4/EWRITE4. > > ok?
The top usb port on the cubox now works with this. ok jsg@ > > > Index: arch/armv7/imx/imxehci.c > =================================================================== > RCS file: /cvs/src/sys/arch/armv7/imx/imxehci.c,v > retrieving revision 1.17 > diff -u -p -r1.17 imxehci.c > --- arch/armv7/imx/imxehci.c 13 Aug 2016 11:08:58 -0000 1.17 > +++ arch/armv7/imx/imxehci.c 1 Oct 2016 13:26:02 -0000 > @@ -58,9 +58,6 @@ > /* ehci */ > #define USB_EHCI_OFFSET 0x100 > > -#define EHCI_USBMODE 0xa8 > - > -#define EHCI_USBMODE_HOST (3 << 0) > #define EHCI_PS_PTS_UTMI_MASK ((1 << 25) | (3 << 30)) > > /* usb non-core */ > @@ -144,6 +141,7 @@ imxehci_attach(struct device *parent, st > sc->sc.iot = faa->fa_iot; > sc->sc.sc_bus.dmatag = faa->fa_dmat; > sc->sc.sc_size = faa->fa_reg[0].size - USB_EHCI_OFFSET; > + sc->sc.sc_flags = EHCIF_USBMODE; > > /* Map I/O space */ > if (bus_space_map(sc->sc.iot, faa->fa_reg[0].addr, > @@ -247,8 +245,8 @@ imxehci_attach(struct device *parent, st > USBPHY_CTRL_ENUTMILEVEL2 | USBPHY_CTRL_ENUTMILEVEL3); > > /* set host mode */ > - EWRITE4(&sc->sc, EHCI_USBMODE, > - EREAD4(&sc->sc, EHCI_USBMODE) | EHCI_USBMODE_HOST); > + EOWRITE4(&sc->sc, EHCI_USBMODE, > + EOREAD4(&sc->sc, EHCI_USBMODE) | EHCI_USBMODE_CM_HOST); > > /* set to UTMI mode */ > EOWRITE4(&sc->sc, EHCI_PORTSC(1), > Index: dev/usb/ehci.c > =================================================================== > RCS file: /cvs/src/sys/dev/usb/ehci.c,v > retrieving revision 1.193 > diff -u -p -r1.193 ehci.c > --- dev/usb/ehci.c 15 Sep 2016 02:00:17 -0000 1.193 > +++ dev/usb/ehci.c 1 Oct 2016 13:26:02 -0000 > @@ -1114,7 +1114,7 @@ ehci_activate(struct device *self, int a > usbd_status > ehci_reset(struct ehci_softc *sc) > { > - u_int32_t hcr; > + u_int32_t hcr, usbmode; > int i; > > EOWRITE4(sc, EHCI_USBCMD, 0); /* Halt controller */ > @@ -1128,6 +1128,9 @@ ehci_reset(struct ehci_softc *sc) > if (!hcr) > printf("%s: halt timeout\n", sc->sc_bus.bdev.dv_xname); > > + if (sc->sc_flags & EHCIF_USBMODE) > + usbmode = EOREAD4(sc, EHCI_USBMODE); > + > EOWRITE4(sc, EHCI_USBCMD, EHCI_CMD_HCRESET); > for (i = 0; i < 100; i++) { > usb_delay_ms(&sc->sc_bus, 1); > @@ -1140,6 +1143,9 @@ ehci_reset(struct ehci_softc *sc) > printf("%s: reset timeout\n", sc->sc_bus.bdev.dv_xname); > return (USBD_IOERROR); > } > + > + if (sc->sc_flags & EHCIF_USBMODE) > + EOWRITE4(sc, EHCI_USBMODE, usbmode); > > return (USBD_NORMAL_COMPLETION); > } > Index: dev/usb/ehcireg.h > =================================================================== > RCS file: /cvs/src/sys/dev/usb/ehcireg.h,v > retrieving revision 1.20 > diff -u -p -r1.20 ehcireg.h > --- dev/usb/ehcireg.h 10 Apr 2015 13:56:42 -0000 1.20 > +++ dev/usb/ehcireg.h 1 Oct 2016 13:26:02 -0000 > @@ -162,6 +162,13 @@ > > #define EHCI_PORT_RESET_COMPLETE 2 /* ms */ > > +/* Nonstandard register to set controller mode. */ > +#define EHCI_USBMODE 0x68 > +#define EHCI_USBMODE_CM_M 0x00000003 > +#define EHCI_USBMODE_CM_IDLE 0x00000000 > +#define EHCI_USBMODE_CM_DEVICE 0x00000002 > +#define EHCI_USBMODE_CM_HOST 0x00000003 > + > #define EHCI_FLALIGN_ALIGN 0x1000 > > /* No data structure may cross a page boundary. */ > Index: dev/usb/ehcivar.h > =================================================================== > RCS file: /cvs/src/sys/dev/usb/ehcivar.h,v > retrieving revision 1.36 > diff -u -p -r1.36 ehcivar.h > --- dev/usb/ehcivar.h 2 Nov 2015 14:55:41 -0000 1.36 > +++ dev/usb/ehcivar.h 1 Oct 2016 13:26:02 -0000 > @@ -130,6 +130,7 @@ struct ehci_softc { > int sc_flags; /* misc flags */ > #define EHCIF_DROPPED_INTR_WORKAROUND 0x01 > #define EHCIF_PCB_INTR 0x02 > +#define EHCIF_USBMODE 0x04 > > char sc_vendor[16]; /* vendor string for root hub */ > int sc_id_vendor; /* vendor ID for root hub */ >