According to the "Enhanced Host Controller Interface Specification for Universal Serial Bus" after a USB port reset the EHCI Driver checks the PortEnable bit in the PORTSC register. If set to a one, the connected device is a high-speed device [...]. At the time the EHCI Driver receives the port reset and enable request the LineStatus bits might indicate a low-speed device. Additionally, when the port reset process is complete, the PortEnable field may indicate that a full-speed device is attached. In either case the EHCI driver sets the PortOwner bit in the PORTSC register to a one to release port ownership to a companion host controller. Signed-off-by: Peter Mamonov <pmamonov@xxxxxxxxx> --- drivers/usb/host/ehci-hcd.c | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 79bf4fb9d..d0be2104d 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -477,6 +477,18 @@ static inline void ehci_powerup_fixup(struct ehci_priv *ehci) } #endif +static void pass_to_companion(struct ehci_priv *ehci, int port) +{ + uint32_t *status_reg = (uint32_t *)&ehci->hcor->or_portsc[port - 1]; + uint32_t reg = ehci_readl(status_reg); + + reg &= ~EHCI_PS_CLEAR; + dev_dbg(ehci->dev, "port %d --> companion\n", + port - 1); + reg |= EHCI_PS_PO; + ehci_writel(status_reg, reg); +} + static int ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, int length, struct devrequest *req) @@ -509,6 +521,10 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, return -1; } status_reg = (uint32_t *)&ehci->hcor->or_portsc[port - 1]; + if (ehci_readl(status_reg) & EHCI_PS_PO) { + dev_dbg(ehci->dev, "Port %d is owned by companion controller\n", port); + return -1; + } break; default: status_reg = NULL; @@ -655,11 +671,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, if ((reg & (EHCI_PS_PE | EHCI_PS_CS)) == EHCI_PS_CS && !ehci_is_TDI() && EHCI_PS_IS_LOWSPEED(reg)) { - /* Low speed device, give up ownership. */ - dev_dbg(ehci->dev, "port %d low speed --> companion\n", - port - 1); - reg |= EHCI_PS_PO; - ehci_writel(status_reg, reg); + pass_to_companion(ehci, port); break; } else { int ret; @@ -690,7 +702,10 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, else dev_err(ehci->dev, "port(%d) reset error\n", port - 1); - + mdelay(200); + reg = ehci_readl(status_reg); + if (!(reg & EHCI_PS_PE)) + pass_to_companion(ehci, port); } break; default: -- 2.11.0 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox