Prerequisites (apart from proper config): 1. The HSUSBTLL clock has to be enabled along with the other HW_AUTO essentials, that is, cm_l3init_hsusbtll_clkctrl has to reside in the clk_modules_hw_auto_essential[] array and not in clk_modules_explicit_en_essential[]. Please see related patch to hw_data.c.
2. Other functional clocks have to be enabled prior to starting USB (and, possibly, disabled upon stopping). The proper place for this would be the board file, in the ehci_hcd_init() and ehci_hcd_stop() functions. Please see som5_evb.c as example. 3. If we have HSIC devices on some OMAP5 ports, they shall work only if the design employs reset capability via GPIO. This is performed by the ehci-hcd driver upon applying port power, and requires that we have defined CONFIG_OMAP_HSIC_PORTx_RESET_GPIO in the board config header as appropriate. Please see omap5_som5_evb.h as an example. Note that this additional reset is not needed for OMAP4 HSIC (tested on OMAP4460 and 4470). 4. Can somebody explain why arch/arm/include/asm/arch-omap5/ehci.h has disappeared? It is in fact needed for EHCI USB. Adding it. Signed-off-by: Lubomir Popov <lpo...@mm-sol.com> --- arch/arm/include/asm/arch-omap5/ehci.h | 44 +++++++++++++++++ drivers/usb/host/ehci-hcd.c | 6 +++ drivers/usb/host/ehci-omap.c | 83 +++++++++++++++++++++++++++++--- drivers/usb/host/ehci.h | 9 ++++ 4 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 arch/arm/include/asm/arch-omap5/ehci.h diff --git a/arch/arm/include/asm/arch-omap5/ehci.h b/arch/arm/include/asm/arch-omap5/ehci.h new file mode 100644 index 0000000..49197f2 --- /dev/null +++ b/arch/arm/include/asm/arch-omap5/ehci.h @@ -0,0 +1,44 @@ +/* + * OMAP EHCI port support + * Based on LINUX KERNEL + * drivers/usb/host/ehci-omap.c and drivers/mfd/omap-usb-host.c + * + * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com* + * Author: Govindraj R <govindraj.r...@ti.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _EHCI_H +#define _EHCI_H + +#define OMAP_EHCI_BASE (OMAP54XX_L4_CORE_BASE + 0x64C00) +#define OMAP_UHH_BASE (OMAP54XX_L4_CORE_BASE + 0x64000) +#define OMAP_USBTLL_BASE (OMAP54XX_L4_CORE_BASE + 0x62000) + +/* TLL Register Set */ +#define OMAP_USBTLL_SYSCONFIG_SIDLEMODE (1 << 3) +#define OMAP_USBTLL_SYSCONFIG_ENAWAKEUP (1 << 2) +#define OMAP_USBTLL_SYSCONFIG_SOFTRESET (1 << 1) +#define OMAP_USBTLL_SYSCONFIG_CACTIVITY (1 << 8) +#define OMAP_USBTLL_SYSSTATUS_RESETDONE 1 + +#define OMAP_UHH_SYSCONFIG_SOFTRESET 1 +#define OMAP_UHH_SYSSTATUS_EHCI_RESETDONE (1 << 2) +#define OMAP_UHH_SYSCONFIG_NOIDLE (1 << 2) +#define OMAP_UHH_SYSCONFIG_NOSTDBY (1 << 4) + +#define OMAP_UHH_SYSCONFIG_VAL (OMAP_UHH_SYSCONFIG_NOIDLE | \ + OMAP_UHH_SYSCONFIG_NOSTDBY) + +#endif /* _EHCI_H */ diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index c816878..33d954d 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -750,6 +750,12 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, if (HCS_PPC(ehci_readl(&ctrl->hccr->cr_hcsparams))) { reg |= EHCI_PS_PP; ehci_writel(status_reg, reg); + /* + * OMAP5: Reset device for 'fail to connect' + * workaround. Compiled only for OMAP5, and + * only if we have ports in HSIC mode. + */ + omap5_ehci_hsic_reset_device(le16_to_cpu(req->index)); } break; case USB_PORT_FEAT_RESET: diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c index 086c697..07f3774 100644 --- a/drivers/usb/host/ehci-omap.c +++ b/drivers/usb/host/ehci-omap.c @@ -92,12 +92,15 @@ static void omap_usbhs_hsic_init(int port) static void omap_ehci_soft_phy_reset(int port) { + /* This requires proper configs: */ +#if defined(CONFIG_USB_ULPI) && defined(CONFIG_USB_ULPI_VIEWPORT_OMAP) struct ulpi_viewport ulpi_vp; ulpi_vp.viewport_addr = (u32)&ehci->insreg05_utmi_ulpi; ulpi_vp.port_num = port; ulpi_reset(&ulpi_vp); +#endif } inline int __board_usb_init(void) @@ -107,7 +110,7 @@ inline int __board_usb_init(void) int board_usb_init(void) __attribute__((weak, alias("__board_usb_init"))); #if defined(CONFIG_OMAP_EHCI_PHY1_RESET_GPIO) || \ - defined(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO) + defined(CONFIG_OMAP_EHCI_PHY2_RESET_GPIO) /* controls PHY(s) reset signal(s) */ static inline void omap_ehci_phy_reset(int on, int delay) { @@ -136,10 +139,71 @@ static inline void omap_ehci_phy_reset(int on, int delay) #define omap_ehci_phy_reset(on, delay) do {} while (0) #endif +/* Separate HSIC USB devices reset to fix fail to connect on OMAP5. + * Patch needed in ehci-hcd. See driver code. + */ +#if defined(CONFIG_OMAP_HSIC_PORT1_RESET_GPIO) || \ + defined(CONFIG_OMAP_HSIC_PORT2_RESET_GPIO) || \ + defined(CONFIG_OMAP_HSIC_PORT3_RESET_GPIO) +static inline void omap_ehci_hsic_reset(int port, int on, int delay) +{ + /*printf("omap_ehci_hsic_reset: port %d, reset %s, delay %d\n", port, on ? "On" : "Off", delay);*/ + +#ifdef CONFIG_OMAP_HSIC_PORT1_RESET_GPIO + if (1 == port) { + gpio_request(CONFIG_OMAP_HSIC_PORT1_RESET_GPIO, "USB HSIC1 reset"); + gpio_direction_output(CONFIG_OMAP_HSIC_PORT1_RESET_GPIO, !on); + udelay(delay); + } +#endif +#ifdef CONFIG_OMAP_HSIC_PORT2_RESET_GPIO + if (2 == port) { + gpio_request(CONFIG_OMAP_HSIC_PORT2_RESET_GPIO, "USB HSIC2 reset"); + gpio_direction_output(CONFIG_OMAP_HSIC_PORT2_RESET_GPIO, !on); + udelay(delay); + } +#endif +#ifdef CONFIG_OMAP_HSIC_PORT3_RESET_GPIO + if (3 == port) { + gpio_request(CONFIG_OMAP_HSIC_PORT3_RESET_GPIO, "USB HSIC3 reset"); + gpio_direction_output(CONFIG_OMAP_HSIC_PORT3_RESET_GPIO, !on); + udelay(delay); + } +#endif +} +#else +#define omap_ehci_hsic_reset(port, on, delay) do {} while (0) +#endif + +#if defined(CONFIG_OMAP54XX) && \ + (defined(CONFIG_OMAP_HSIC_PORT1_RESET_GPIO) || \ + defined(CONFIG_OMAP_HSIC_PORT2_RESET_GPIO) || \ + defined(CONFIG_OMAP_HSIC_PORT3_RESET_GPIO)) +/* OMAP5: Reset HSIC devices upon applying port power for + * 'fail to connect' workaround. Called by ehci-hcd. + */ +inline void omap5_ehci_hsic_reset_device(int port_index) +{ + omap_ehci_hsic_reset(port_index, 1, 100); + omap_ehci_hsic_reset(port_index, 0, 0); +} +#else +inline void omap5_ehci_hsic_reset_device(int port_index) {} +#endif + /* Reset is needed otherwise the kernel-driver will throw an error. */ int omap_ehci_hcd_stop(void) { debug("Resetting OMAP EHCI\n"); +#ifdef CONFIG_OMAP_HSIC_PORT1_RESET_GPIO + omap_ehci_hsic_reset(1, 1, 0); +#endif +#ifdef CONFIG_OMAP_HSIC_PORT2_RESET_GPIO + omap_ehci_hsic_reset(2, 1, 0); +#endif +#ifdef CONFIG_OMAP_HSIC_PORT3_RESET_GPIO + omap_ehci_hsic_reset(3, 1, 0); +#endif omap_ehci_phy_reset(1, 0); if (omap_uhh_reset() < 0) @@ -168,7 +232,7 @@ int omap_ehci_hcd_init(struct omap_usbhs_board_data *usbhs_pdata, if (ret < 0) return ret; - /* Put the PHY in RESET */ + /* Put the PHYs (if any) in RESET */ omap_ehci_phy_reset(1, 10); ret = omap_uhh_reset(); @@ -209,11 +273,10 @@ int omap_ehci_hcd_init(struct omap_usbhs_board_data *usbhs_pdata, else setbits_le32(®, OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS); } else if (rev == OMAP_USBHS_REV2) { + /* Clear port mode fields for PHY mode */ clrsetbits_le32(®, (OMAP_P1_MODE_CLEAR | OMAP_P2_MODE_CLEAR), OMAP4_UHH_HOSTCONFIG_APP_START_CLK); - /* Clear port mode fields for PHY mode*/ - if (is_ehci_hsic_mode(usbhs_pdata->port_mode[0])) setbits_le32(®, OMAP_P1_MODE_HSIC); @@ -227,10 +290,16 @@ int omap_ehci_hcd_init(struct omap_usbhs_board_data *usbhs_pdata, debug("OMAP UHH_REVISION 0x%x\n", rev); writel(reg, &uhh->hostconfig); - for (i = 0; i < OMAP_HS_USB_PORTS; i++) - if (is_ehci_hsic_mode(usbhs_pdata->port_mode[i])) + /* OMAP5 HSIC devices (if any) shall be reset again by the + * ehci-hcd driver upon applying port power. See driver patch. + */ + for (i = 0; i < OMAP_HS_USB_PORTS; i++) { + if (is_ehci_hsic_mode(usbhs_pdata->port_mode[i])) { omap_usbhs_hsic_init(i); - + omap_ehci_hsic_reset(i + 1, 0, 0); /* Release reset on HSIC port */ + } + } + /* Release ULPI PHY reset and let PLL lock */ omap_ehci_phy_reset(0, 10); /* diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index d090f0a..9e0230b 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -256,4 +256,13 @@ struct QH { int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor); int ehci_hcd_stop(int index); +/* OMAP5: Reset HSIC devices upon applying port power for + * 'fail to connect' workaround (ehci-omap.c) + */ +#ifndef CONFIG_USB_EHCI_OMAP +static inline void omap5_ehci_hsic_reset_device(int port_index) {} +#else +inline void omap5_ehci_hsic_reset_device(int port_index); +#endif + #endif /* USB_EHCI_H */ -- 1.7.9.5 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot