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 */
> 

Reply via email to