All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH] OMAP4/5: Add USB EHCI support
@ 2013-04-01 14:41 Lubomir Popov
  0 siblings, 0 replies; only message in thread
From: Lubomir Popov @ 2013-04-01 14:41 UTC (permalink / raw)
  To: u-boot

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 <lpopov@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.raja@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(&reg, OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS);
 	} else if (rev == OMAP_USBHS_REV2) {
+		/* Clear port mode fields for PHY mode */
 		clrsetbits_le32(&reg, (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(&reg, 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

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2013-04-01 14:41 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-04-01 14:41 [U-Boot] [PATCH] OMAP4/5: Add USB EHCI support Lubomir Popov

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.