
A known hardware issue of USB1 port where bit 1 (connect status change) of PORTSC register will be set after issuing Port Reset (like "usb reset" in u-boot command line). This will be treated as an error and stops later device enumeration.
Therefore we add a definition in header file and a callback function to clear that bit after Port Reset in order to proceed later device enumeration.
CONFIG_USB_EHCI_SUBMIT_ROOT_POST_CALLBACK
Signed-off-by: Jim Lin jilin@nvidia.com --- To reproduce this issue, you can modify board .dts file to set as the following to build u-boot binary. " usb0 = "/usb@c5000000"; usb1 = "/usb@c5008000"; " Install device on USB1 port (address at 0xc5000000). And run "usb reset" in u-boot console to enumerate device.
Changes in v2: - Change config name - Add a callback function at the end of ehci_submit_root() function
drivers/usb/host/ehci-hcd.c | 4 ++++ drivers/usb/host/ehci-tegra.c | 34 ++++++++++++++++++++++++++++++++++ drivers/usb/host/ehci.h | 4 ++++ include/configs/tegra2-common.h | 8 ++++++++ 4 files changed, 50 insertions(+), 0 deletions(-)
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 38d6ae0..0b6b656 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -792,7 +792,11 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
dev->act_len = len; dev->status = 0; +#ifdef CONFIG_USB_EHCI_SUBMIT_ROOT_POST_CALLBACK + return ehci_submit_root_post_callback(dev, pipe, buffer, length, req); +#else return 0; +#endif
unknown: debug("requesttype=%x, request=%x, value=%x, index=%x, length=%x\n", diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index a7e105b..3dd18d3 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -29,6 +29,40 @@ #include <asm/errno.h> #include <asm/arch/usb.h>
+#ifdef CONFIG_USB_EHCI_SUBMIT_ROOT_POST_CALLBACK +int +ehci_submit_root_post_callback(struct usb_device *dev, unsigned long pipe, + void *buffer, int length, struct devrequest *req) +{ + u16 typeReq; + uint32_t reg; + uint32_t *status_reg; + + status_reg = (uint32_t *)&hcor->or_portsc[ + le16_to_cpu(req->index) - 1]; + if (((u32) status_reg & 0xFFFFC000) != TEGRA_USB1_BASE) + return 0; + typeReq = req->request | req->requesttype << 8; + switch (typeReq) { + case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8): + switch (le16_to_cpu(req->value)) { + /* + * A known HW issue on USB1 port where bit 1 (Connect Status + * Change) of PORTSC register will be set after issuing Port + * Reset. Clear that bit for later device enumeration. + */ + case USB_PORT_FEAT_RESET: + reg = ehci_readl(status_reg); + reg &= ~EHCI_PS_CLEAR; + reg |= EHCI_PS_CSC; + ehci_writel(status_reg, reg); + break; + } + break; + } + return 0; +} +#endif
/* * Create the appropriate control structures to manage diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index cc00ce4..6c5d8f3 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -204,4 +204,8 @@ struct QH { int ehci_hcd_init(void); int ehci_hcd_stop(void);
+#ifdef CONFIG_USB_EHCI_SUBMIT_ROOT_POST_CALLBACK +int ehci_submit_root_post_callback(struct usb_device *dev, unsigned long pipe, + void *buffer, int length, struct devrequest *req); +#endif #endif /* USB_EHCI_H */ diff --git a/include/configs/tegra2-common.h b/include/configs/tegra2-common.h index 1931179..b4822d4 100644 --- a/include/configs/tegra2-common.h +++ b/include/configs/tegra2-common.h @@ -111,6 +111,14 @@ #define CONFIG_EHCI_IS_TDI #define CONFIG_EHCI_DCACHE
+/* + * A known HW issue on USB1 port where bit 1 (Connect Status Change) of PORTSC + * register will be set after issuing Port Reset. + * This setting is to add a callback function to clear that bit for later + * device enumeration. + */ +#define CONFIG_USB_EHCI_SUBMIT_ROOT_POST_CALLBACK + /* Total I2C ports on Tegra2 */ #define TEGRA_I2C_NUM_CONTROLLERS 4