Per DesignWare USB OTG databook, driver should retry up to 3 times when transaction error (hcint.xacterr) happen. But the 3 times doesn't count when the response is nack (hcint.nak) or frame overrun (hcint.frmoverun)
This patch solved the enumeration error as spotted at socfpga cyclone5_socdk when plugging in certain pendrive. Signed-off-by: Chin Liang See <cl...@altera.com> Cc: Marek Vasut <ma...@denx.de> Cc: Dinh Nguyen <dingu...@opensource.altera.com> Cc: Dinh Nguyen <dinh.li...@gmail.com> Cc: Pavel Machek <pa...@denx.de> Cc: Oleksandr Tymoshenko <go...@bluezbox.com> Cc: Stephen Warren <swar...@wwwdotorg.org> Cc: Alexander Stein <alexander...@web.de> Cc: Peter Griffin <peter.grif...@linaro.org> --- drivers/usb/host/dwc2.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/usb/host/dwc2.c b/drivers/usb/host/dwc2.c index 541c0f9..f00cd1b 100644 --- a/drivers/usb/host/dwc2.c +++ b/drivers/usb/host/dwc2.c @@ -786,15 +786,12 @@ int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev, uint32_t xfer_len; uint32_t num_packets; int stop_transfer = 0; + int error_retry_count = 0; debug("%s: msg: pipe %lx pid %d in %d len %d\n", __func__, pipe, *pid, in, len); do { - /* Initialize channel */ - dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, dev, devnum, ep, in, - eptype, max); - xfer_len = len - done; if (xfer_len > CONFIG_DWC2_MAX_TRANSFER_SIZE) xfer_len = CONFIG_DWC2_MAX_TRANSFER_SIZE - max + 1; @@ -818,6 +815,14 @@ int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev, debug("%s: chunk: pid %d xfer_len %u pkts %u\n", __func__, *pid, xfer_len, num_packets); + /* per DW spec, we can retry up to 3 times */ + error_retry_count = 3; + +error_retry: + /* Initialize channel */ + dwc_otg_hc_init(regs, DWC2_HC_CHANNEL, dev, devnum, ep, in, + eptype, max); + writel((xfer_len << DWC2_HCTSIZ_XFERSIZE_OFFSET) | (num_packets << DWC2_HCTSIZ_PKTCNT_OFFSET) | (*pid << DWC2_HCTSIZ_PID_OFFSET), @@ -841,8 +846,14 @@ int chunk_msg(struct dwc2_priv *priv, struct usb_device *dev, DWC2_HCCHAR_CHEN); ret = wait_for_chhltd(regs, &sub, pid, ignore_ack); - if (ret) - break; + if (ret) { + if (ret == -EINVAL) + error_retry_count--; + if (error_retry_count) + goto error_retry; + else + break; + } if (in) { xfer_len -= sub; -- 1.9.2.468.g3f0c02a _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot