From: Lubomir Popov <lpopov@mm-sol.com>
To: u-boot@lists.denx.de
Subject: [U-Boot] [RFC PATCH 1/2] ARM: OMAP4/5: Add alternative method for HSIC USB devices reset
Date: Thu, 19 Dec 2013 16:54:27 +0200 [thread overview]
Message-ID: <52B308A3.6050500@mm-sol.com> (raw)
Add option for individual reset of HSIC-connected USB devices by the
ehci-hcd.c driver upon applying port power, with per-device configurable
reset hold and delay times. This may replace the reset functionality via
usb_hub.c and board file (which does not work on some boards).
Make HSIC work on all OMAP543x-ES1.0 ports.
Signed-off-by: Lubomir Popov <l-popov@ti.com>
---
drivers/usb/host/ehci-hcd.c | 15 ++++
drivers/usb/host/ehci-omap.c | 174 +++++++++++++++++++++++++++++++++++++-----
2 files changed, 170 insertions(+), 19 deletions(-)
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 8bd1eb8..47b4097 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -119,6 +119,12 @@ static struct descriptor {
#define ehci_is_TDI() (0)
#endif
+/* OMAP HSIC workaround option: */
+__weak void omap_ehci_hsic_reset_device(int port)
+{
+ return;
+}
+
int __ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
{
return PORTSC_PSPD(reg);
@@ -803,6 +809,15 @@ 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);
+ /*
+ * OMAP4/5: Reset device for 'fail to connect'
+ * workaround. Weak function, actual reset
+ * should happen in ehci-omap.c and only if we
+ * have defined HSIC devices (in the board file)
+ * that we want to reset at this moment.
+ */
+ omap_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 1b215c2..071739d 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -7,6 +7,13 @@
* Sunil Kumar <sunilsaini05@gmail.com>
* Shashi Ranjan <shashiranjanmca05@gmail.com>
*
+ * (C) Copyright 2013 Lubomir Popov, MM Solutions <lpopov@mm-sol.com>
+ * - Add option for individual reset of HSIC-connected USB devices by the
+ * ehci-hcd.c driver upon applying port power, with per-device configurable
+ * reset hold and delay times. This may replace the reset functionality via
+ * usb_hub.c and board file;
+ * - Make HSIC work on all OMAP5430-ES1.0 ports;
+ * - Add explanatory comments where appropriate.
*
* SPDX-License-Identifier: GPL-2.0+
*/
@@ -26,6 +33,8 @@ static struct omap_uhh *const uhh = (struct omap_uhh
*)OMAP_UHH_BASE;
static struct omap_usbtll *const usbtll = (struct omap_usbtll *)OMAP_USBTLL_BASE;
static struct omap_ehci *const ehci = (struct omap_ehci *)OMAP_EHCI_BASE;
+static struct omap_usbhs_board_data *usbhs_bdp = NULL;
+
static int omap_uhh_reset(void)
{
int timeout = 0;
@@ -106,7 +115,7 @@ static void omap_usbhs_hsic_init(int port)
writel(reg, &usbtll->channel_conf + port);
}
-#ifdef CONFIG_USB_ULPI
+#if defined(CONFIG_USB_ULPI) && defined(CONFIG_USB_ULPI_VIEWPORT_OMAP)
static void omap_ehci_soft_phy_reset(int port)
{
struct ulpi_viewport ulpi_vp;
@@ -158,10 +167,141 @@ static inline void omap_ehci_phy_reset(int on, int delay)
#define omap_ehci_phy_reset(on, delay) do {} while (0)
#endif
+/*
+ * Individual HSIC USB device reset to fix 'fail to connect' for some devices.
+ * Note that a HSIC-connected device is actually a permanently attached USB
+ * slave, while a PHY is just a hardware extension of the host port, and
+ * handling them in the same manner is not appropriate.
+ * In order to invoke this feature, define CONFIG_OMAP_HSIC_PORTx_RESET_GPIO
+ * in the board header (where x is the port number with HSIC-attached device
+ * that we want to reset via this method, and the value is the number of the
+ * particular GPIO) - the real functions shall then build and override the
+ * __weak dummy in ehci-hcd.c that is called upon applying port power. The
+ * active reset hold time, as well as the delay after release of reset, are
+ * configurable per device (port) via CONFIG_OMAP_PORTx_RST_HOLD_US and
+ * CONFIG_OMAP_PORTx_DLY_AFTER_US.
+ *
+ * Applicable to OMAP4/5 only (except for the OMAP4430, where HSIC is not
+ * functional). Valid HSIC ports are:
+ * OMAP4460/70: 1, 2
+ * OMAP5430: 1, 2, 3
+ * OMAP5432: 2, 3
+ */
+#if defined(CONFIG_OMAP_HSIC_PORT1_RESET_GPIO) || \
+ defined(CONFIG_OMAP_HSIC_PORT2_RESET_GPIO) || \
+ defined(CONFIG_OMAP_HSIC_PORT3_RESET_GPIO)
+/* Should not be called for non-HSIC ports */
+static void omap_ehci_hsic_reset(int port, int on, int delay)
+{
+ debug("HSIC device reset: port %d, reset %s, delay %d us\n",
+ port, on ? "On" : "Off", delay);
+#ifdef CONFIG_OMAP_HSIC_PORT1_RESET_GPIO
+ if (port == 1) {
+ gpio_request(CONFIG_OMAP_HSIC_PORT1_RESET_GPIO,
+ "USB HSIC1 Reset");
+ gpio_direction_output(CONFIG_OMAP_HSIC_PORT1_RESET_GPIO, !on);
+ }
+#endif
+#ifdef CONFIG_OMAP_HSIC_PORT2_RESET_GPIO
+ if (port == 2) {
+ gpio_request(CONFIG_OMAP_HSIC_PORT2_RESET_GPIO,
+ "USB HSIC2 Reset");
+ gpio_direction_output(CONFIG_OMAP_HSIC_PORT2_RESET_GPIO, !on);
+ }
+#endif
+#ifdef CONFIG_OMAP_HSIC_PORT3_RESET_GPIO
+ if (port == 3) {
+ gpio_request(CONFIG_OMAP_HSIC_PORT3_RESET_GPIO,
+ "USB HSIC3 Reset");
+ gpio_direction_output(CONFIG_OMAP_HSIC_PORT3_RESET_GPIO, !on);
+ }
+#endif
+ if (delay)
+ udelay(delay);
+}
+
+/*
+ * Called by ehci-hcd when setting the USB_PORT_FEAT_POWER feature
+ * (overrides __weak function in ehci-hcd.c)
+ */
+void omap_ehci_hsic_reset_device(int port)
+{
+ int rst_hold; /* Reset active hold time, us */
+ int dly_after; /* Delay after releasing reset, us */
+
+ if ((port <= 0) ||
+ !(usbhs_bdp) ||
+ !(is_ehci_hsic_mode(usbhs_bdp->port_mode[port-1])))
+ return;
+
+#ifdef CONFIG_OMAP_HSIC_PORT1_RESET_GPIO
+ if (port == 1) {
+#ifdef CONFIG_OMAP_PORT1_RST_HOLD_US
+ rst_hold = CONFIG_OMAP_PORT1_RST_HOLD_US;
+#else
+ rst_hold = 10; /* Provide a default hold time */
+#endif
+#ifdef CONFIG_OMAP_PORT1_DLY_AFTER_US
+ dly_after = CONFIG_OMAP_PORT1_DLY_AFTER_US;
+#else
+ dly_after = 0; /* No delay by default */
+#endif
+ }
+#endif
+
+#ifdef CONFIG_OMAP_HSIC_PORT2_RESET_GPIO
+ if (port == 2) {
+#ifdef CONFIG_OMAP_PORT2_RST_HOLD_US
+ rst_hold = CONFIG_OMAP_PORT2_RST_HOLD_US;
+#else
+ rst_hold = 10; /* Provide a default hold time */
+#endif
+#ifdef CONFIG_OMAP_PORT2_DLY_AFTER_US
+ dly_after = CONFIG_OMAP_PORT2_DLY_AFTER_US;
+#else
+ dly_after = 0; /* No delay by default */
+#endif
+ }
+#endif
+
+#ifdef CONFIG_OMAP_HSIC_PORT3_RESET_GPIO
+ if (port == 3) {
+#ifdef CONFIG_OMAP_PORT3_RST_HOLD_US
+ rst_hold = CONFIG_OMAP_PORT3_RST_HOLD_US;
+#else
+ rst_hold = 10; /* Provide a default hold time */
+#endif
+#ifdef CONFIG_OMAP_PORT3_DLY_AFTER_US
+ dly_after = CONFIG_OMAP_PORT3_DLY_AFTER_US;
+#else
+ dly_after = 0; /* No delay by default */
+#endif
+ }
+#endif
+ omap_ehci_hsic_reset(port, 1, rst_hold);
+ omap_ehci_hsic_reset(port, 0, dly_after);
+}
+
+#else
+/* No CONFIG_OMAP_HSIC_PORTx_RESET_GPIO defined */
+#define omap_ehci_hsic_reset(port, on, delay) do {} while (0)
+#endif
+
/* Reset is needed otherwise the kernel-driver will throw an error. */
int omap_ehci_hcd_stop(void)
{
debug("Resetting OMAP EHCI\n");
+ /* Put HSIC devices, if any, in RESET */
+#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
+ /* Reset PHYs, if any */
omap_ehci_phy_reset(1, 0);
if (omap_uhh_reset() < 0)
@@ -184,13 +324,15 @@ int omap_ehci_hcd_init(int index, struct
omap_usbhs_board_data *usbhs_pdata,
int ret;
unsigned int i, reg = 0, rev = 0;
- debug("Initializing OMAP EHCI\n");
+ debug("Initializing OMAP EHCI %d\n", index);
ret = board_usb_init(index, USB_INIT_HOST);
if (ret < 0)
return ret;
- /* Put the PHY in RESET */
+ usbhs_bdp = usbhs_pdata;
+
+ /* Put the PHYs, if any, in RESET */
omap_ehci_phy_reset(1, 10);
ret = omap_uhh_reset();
@@ -230,35 +372,28 @@ int omap_ehci_hcd_init(int index, struct
omap_usbhs_board_data *usbhs_pdata,
clrbits_le32(®, OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS);
else
setbits_le32(®, OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS);
- } else if (rev == OMAP_USBHS_REV2) {
-
- 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);
-
- if (is_ehci_hsic_mode(usbhs_pdata->port_mode[1]))
- setbits_le32(®, OMAP_P2_MODE_HSIC);
-
- } else if (rev == OMAP_USBHS_REV2_1) {
+ } else if ((rev == OMAP_USBHS_REV2) || (rev == OMAP_USBHS_REV2_1)) {
+ /*
+ * OMAP4 and OMAP5-ES1 UHH are R.2.0, OMAP5-ES2 - R.2.1
+ *
+ * Clear port mode fields for ULPI PHY mode. On OMAP4 the P3
+ * field is reserved, but clearing it does not harm.
+ */
clrsetbits_le32(®,
(OMAP_P1_MODE_CLEAR |
OMAP_P2_MODE_CLEAR |
OMAP_P3_MODE_CLEAR),
OMAP4_UHH_HOSTCONFIG_APP_START_CLK);
- /* Clear port mode fields for PHY mode */
-
+ /* Warning: HSIC mode for Port 1 not usable on OMAP5432 */
if (is_ehci_hsic_mode(usbhs_pdata->port_mode[0]))
setbits_le32(®, OMAP_P1_MODE_HSIC);
if (is_ehci_hsic_mode(usbhs_pdata->port_mode[1]))
setbits_le32(®, OMAP_P2_MODE_HSIC);
+ /* Warning: HSIC mode for Port 3 possible on OMAP5 only */
if (is_ehci_hsic_mode(usbhs_pdata->port_mode[2]))
setbits_le32(®, OMAP_P3_MODE_HSIC);
}
@@ -270,6 +405,7 @@ int omap_ehci_hcd_init(int index, struct
omap_usbhs_board_data *usbhs_pdata,
if (is_ehci_hsic_mode(usbhs_pdata->port_mode[i]))
omap_usbhs_hsic_init(i);
+ /* Release ULPI PHY reset and let PLL lock (may need more delay...) */
omap_ehci_phy_reset(0, 10);
/*
--
1.7.9.5
reply other threads:[~2013-12-19 14:54 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=52B308A3.6050500@mm-sol.com \
--to=lpopov@mm-sol.com \
--cc=u-boot@lists.denx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.