Re: [PATCH 1/1] ehci-mxc: Fix mx31 OTG host initialisation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



See the comments below.

On 05/11/2010 08:39 AM, Sascha Hauer wrote:
On Mon, May 10, 2010 at 08:13:40PM +0200, Philippe Rétornaz wrote:
On mx31 the OTG host initialisation fail if you need to have
an ULPI transfert to initialize the PHY.

In order to be able to communicate with the PHY a complete reset
of the usb host is needed. After the PHY initialization the host
usb configuration registers need to be rewritten to avoid a host
controller lockup.

Signed-off-by: Philippe Rétornaz<philippe.retornaz@xxxxxxx>
---
  drivers/usb/host/ehci-mxc.c |   68 +++++++++++++++++++++++++++++++++++++++++++
  1 files changed, 68 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index 544ccfd..39d28da 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -29,6 +29,11 @@
  #define PORTSC_OFFSET		0x184
  #define USBMODE_OFFSET		0x1a8
  #define USBMODE_CM_HOST		3
+#define USBCMD_OFFSET		0x140
+#define USBCMD_RS		(1<<  0)
+#define USBCMD_RST		(1<<  1)
+#define USBSTS_OFFSET		0x144
+#define USBSTS_HCH		(1<<  12)

  struct ehci_mxc_priv {
  	struct clk *usbclk, *ahbclk;
@@ -120,6 +125,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
  	int irq, ret, temp;
  	struct ehci_mxc_priv *priv;
  	struct device *dev =&pdev->dev;
+	int i;

  	dev_info(&pdev->dev, "initializing i.MX USB Controller\n");

@@ -204,6 +210,51 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
  	if (ret<  0)
  		goto err_init;

+	/* i.Mx31 OTG host has a bug, if you don't do a reset, then ULPI
+	 * transfert timeout. */

s/transfert/transfers/
Same below.

+	if (cpu_is_mx31()&&  pdev->id == 0) {
+		/* Wait for the controller to go idle */
+		for (i = 0; i<  10000; i++) {
+			if (readl(hcd->regs + USBSTS_OFFSET)&  USBSTS_HCH)
+				break;
+			udelay(1);
+		}
+		if (i == 10000) {
+			dev_err(dev, "Timeout while stopping USB controller\n");
+			goto err_init;
+		}
+
+		/* Stop the usb controller */
+		temp = readl(hcd->regs + USBCMD_OFFSET);
+		writel(temp&  (~USBCMD_RS), hcd->regs + USBCMD_OFFSET);
+
+		for (i = 0; i<  10000; i++) {
+			if (!(readl(hcd->regs + USBCMD_OFFSET)&  USBCMD_RS))
+				break;
+			udelay(1);
+		}
+
+		if (i == 10000) {
+			dev_err(dev, "Timeout while stopping USB controller\n");
+			goto err_init;
+		}
+
+		/* Reset the usb controller */
+		temp = readl(hcd->regs + USBCMD_OFFSET);
+		writel(temp | USBCMD_RST, hcd->regs + USBCMD_OFFSET);
+
+		for (i = 0; i<  10000; i++) {
+			if (!(readl(hcd->regs + USBCMD_OFFSET)&  USBCMD_RST))
+				break;
+			udelay(1);
+		}
+
+		if (i == 10000) {
+			dev_err(dev, "Timeout while reseting USB controller\n");
+			goto err_init;
+		}
+	}

You add the resetting of the controller after setting up USBMODE/PORTSC
setup. Wouldn't it be possible to change the order so that we do not
have to do it twice?

It has to be tested, but if it works the code would then be clearer.

Also, I think the whole reset functionality should be a seperate
function. I can imagine we'll need it elsewhere or on different SoCs in
which case the if clause above gets complicated.

I also think most of the things could be implemented as functions for a better readability (reset, and as Mark suggested a static inline function for the delay).

Val


Sascha


+
  	/* Initialize the transceiver */
  	if (pdata->otg) {
  		pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
@@ -213,6 +264,23 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
  			dev_err(dev, "unable to enable vbus on transceiver\n");
  	}

+	/* i.Mx31 OTG host has a bug, if you do an ULPI transfert then the host
+	 * controller stay busy. Rewriting the register is enough to make it
+	 * working */
+	if (cpu_is_mx31()&&  pdev->id == 0) {
+		/* set USBMODE to host mode */
+		temp = readl(hcd->regs + USBMODE_OFFSET);
+		writel(temp | USBMODE_CM_HOST, hcd->regs + USBMODE_OFFSET);
+
+		/* set up the PORTSCx register */
+		writel(pdata->portsc, hcd->regs + PORTSC_OFFSET);
+
+		/* setup USBCONTROL. */
+		ret = mxc_initialize_usb_hw(pdev->id, pdata->flags);
+		if (ret<  0)
+			goto err_init;
+	}
+
  	priv->hcd = hcd;
  	platform_set_drvdata(pdev, priv);

--
1.6.3.3





--
Valentin Longchamp, PhD Student, EPFL-STI-LSRO1
valentin.longchamp@xxxxxxx, Phone: +41216937827
http://people.epfl.ch/valentin.longchamp
MEB3494, Station 9, CH-1015 Lausanne
--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux