[PATCH 1/1] ehci-mxc: Fix mx31 OTG host initialisation
Daniel Mack
daniel at caiaq.de
Mon May 10 14:35:09 EDT 2010
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.
Given that things are wired up correctly on the board, yes. Many boards
don't, as they copy-pasted the schematics which got it wrong.
Anyway, if it helps you, it should go in. Some commenty below ...
> Signed-off-by: Philippe Rétornaz <philippe.retornaz at epfl.ch>
> ---
> 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. */
> + 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);
> + }
Please use a #defined value rather than the 10000 magic. Also, use
cpu_relax() instead of the 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;
> + }
This seems to be done all over the place. Wouldn't a static inline
function simplify the code a lot here?
Daniel
> + /* 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;
> + }
> + }
> +
> /* 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
>
More information about the linux-arm-kernel
mailing list