Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754625Ab0DUBIW (ORCPT ); Tue, 20 Apr 2010 21:08:22 -0400 Received: from buzzloop.caiaq.de ([212.112.241.133]:47679 "EHLO buzzloop.caiaq.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754190Ab0DUBIV (ORCPT ); Tue, 20 Apr 2010 21:08:21 -0400 Date: Wed, 21 Apr 2010 03:08:05 +0200 From: Daniel Mack To: Dinh.Nguyen@freescale.com Cc: linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux@arm.linux.org.uk, s.hauer@pengutronix.de, valentin.longchamp@epfl.ch, grant.likely@secretlab.ca, bryan.wu@canonical.com, amit.kucheria@canonical.com, Jun.Li@freescale.com, xiao-lizhang@freescale.com Subject: Re: [PATCHv6 2.6.34-rc5 4/5] mxc: Add generic USB HW initialization for MX51 Message-ID: <20100421010804.GO30801@buzzloop.caiaq.de> References: <1271805567-23068-1-git-send-email-Dinh.Nguyen@freescale.com> <1271805567-23068-2-git-send-email-Dinh.Nguyen@freescale.com> <1271805567-23068-3-git-send-email-Dinh.Nguyen@freescale.com> <1271805567-23068-4-git-send-email-Dinh.Nguyen@freescale.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <1271805567-23068-4-git-send-email-Dinh.Nguyen@freescale.com> User-Agent: Mutt/1.5.20 (2009-06-14) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 10897 Lines: 324 On Tue, Apr 20, 2010 at 06:19:26PM -0500, Dinh.Nguyen@freescale.com wrote: > This patch adds USB HW initializiation code to /plat-mxc/ehci.c. > -Stops and resets USB HW > -Sets some specific PHY settings > -Stop and restart the USB HW. > Renames mxc_set_usbcontrol to mxc_initialize_usb_hw. > The placing of the mxc_initialize_usb_hw needs to be before setting > the USBMODE register to host, since a reset and restart is done in > mxc_initialize_usb_hw. > Adds new register bit defines for the USB HW on Freescale > SoCs. > > This patch applies to 2.6.34-rc5. One more thing ... > diff --git a/arch/arm/plat-mxc/ehci.c b/arch/arm/plat-mxc/ehci.c > index cb0b638..f85ca3e 100644 > --- a/arch/arm/plat-mxc/ehci.c > +++ b/arch/arm/plat-mxc/ehci.c > @@ -1,5 +1,6 @@ > /* > * Copyright (c) 2009 Daniel Mack > + * Copyright (C) 2010 Freescale Semiconductor, Inc. > * > * This program is free software; you can redistribute it and/or modify it > * under the terms of the GNU General Public License as published by the > @@ -18,6 +19,7 @@ > > #include > #include > +#include > > #include > #include > @@ -50,7 +52,29 @@ > #define MX35_H1_TLL_BIT (1 << 5) > #define MX35_H1_USBTE_BIT (1 << 4) > > -int mxc_set_usbcontrol(int port, unsigned int flags) > +/* This function is a version of David Brownell's handshake function in > + * ehci-hcd.c. This function uses cpu_relax instead of udelay(). > + * > + * @addr: Address of register > + * @mask: bits to look at in result of read > + * @done: value of those bits when handshake succeeds > + * @timeout: timeout in count > + * > + * This function waits for certain bits in the HW to stick before moving > + * on and provides a timeout in the case where those bits do not stick. > + */ > +static inline int hw_handshake(u32 addr, u32 mask, int done, int timeout) > +{ > + while (--timeout && ((__raw_readl(addr) & mask) != done)) > + cpu_relax(); > + > + if (timeout) > + return 0; > + else > + return -ETIMEDOUT; > +} > + > +int mxc_intialize_usb_hw(int port, unsigned int flags) Typo - that should be named 'mxc_initialize_usb_hw' ^ Thanks, Daniel > { > unsigned int v; > #ifdef CONFIG_ARCH_MX3 > @@ -186,9 +210,130 @@ int mxc_set_usbcontrol(int port, unsigned int flags) > return 0; > } > #endif /* CONFIG_MACH_MX27 */ > +#ifdef CONFIG_ARCH_MX51 > + if (cpu_is_mx51()) { > + void __iomem *usb_base; > + u32 usbotg_base; > + u32 usbother_base; > + int ret = 0; > + > + usb_base = ioremap(MX51_OTG_BASE_ADDR, SZ_4K); > + > + switch (port) { > + case 0: /* OTG port */ > + usbotg_base = usb_base + USBOTG_OFFSET; > + break; > + case 1: /* Host 1 port */ > + usbotg_base = usb_base + USBH1_OFFSET; > + break; > + default: > + printk(KERN_ERR"%s no such port %d\n", __func__, port); > + ret = -ENOENT; > + goto error; > + } > + usbother_base = usb_base + USBOTHER_REGS_OFFSET; > + > + /* Stop then Reset */ > + v = __raw_readl(usbotg_base + USBCMD_OFFSET); > + v &= ~UCMD_RUN_STOP; > + __raw_writel(v, usbotg_base + USBCMD_OFFSET); > + ret = hw_handshake(usbotg_base + USBCMD_OFFSET, UCMD_RUN_STOP, 0, 500); > + if (ret) { > + printk(KERN_ERR "%s could not stop usb hardware\n", __func__); > + goto error; > + } > + > + v = __raw_readl(usbotg_base + USBCMD_OFFSET); > + v |= UCMD_RESET; > + __raw_writel(v, usbotg_base + USBCMD_OFFSET); > + ret = hw_handshake(usbotg_base + USBCMD_OFFSET, UCMD_RESET, 0, 500); > + if (ret) { > + printk(KERN_ERR "%s could not reset usb hardware\n", __func__); > + goto error; > + } > + > + switch (port) { > + case 0: /*OTG port */ > + if (flags & MXC_EHCI_INTERNAL_PHY) { > + v = __raw_readl(usbother_base + USB_PHY_CTR_FUNC_OFFSET); > + > + if (flags & MXC_EHCI_POWER_PINS_ENABLED) > + v |= (USB_UTMI_PHYCTRL_OC_DIS | UCTRL_OPM); /* OC/USBPWR is not used */ > + else > + v &= ~(USB_UTMI_PHYCTRL_OC_DIS | UCTRL_OPM); /* OC/USBPWR is used */ > + __raw_writel(v, usbother_base + USB_PHY_CTR_FUNC_OFFSET); > + > + v = __raw_readl(usbother_base + USBCTRL_OFFSET); > + if (flags & MXC_EHCI_WAKEUP_ENABLED) > + v |= UCTRL_OWIE;/* OTG wakeup enable */ > + else > + v &= ~UCTRL_OWIE;/* OTG wakeup disable */ > + __raw_writel(v, usbother_base + USBCTRL_OFFSET); > + } > + break; > + case 1: /* Host 1 */ > + /*Host ULPI */ > + v = __raw_readl(usbother_base + USBCTRL_OFFSET); > + if (flags & MXC_EHCI_WAKEUP_ENABLED) > + v &= ~(UCTRL_H1WIE | UCTRL_H1UIE);/* HOST1 wakeup/ULPI intr disable */ > + else > + v &= ~(UCTRL_H1WIE | UCTRL_H1UIE);/* HOST1 wakeup/ULPI intr disable */ > + > + if (flags & MXC_EHCI_POWER_PINS_ENABLED) > + v &= ~UCTRL_H1PM; /* HOST1 power mask used*/ > + else > + v |= UCTRL_H1PM; /* HOST1 power mask used*/ > + __raw_writel(v, usbother_base + USBCTRL_OFFSET); > + > + v = __raw_readl(usbother_base + USB_PHY_CTR_FUNC_OFFSET); > + if (flags & MXC_EHCI_POWER_PINS_ENABLED) > + v &= ~USB_UH1_OC_DIS; /* OC is used */ > + else > + v |= USB_UH1_OC_DIS; /* OC is not used */ > + __raw_writel(v, usbother_base + USB_PHY_CTR_FUNC_OFFSET); > + > + v = __raw_readl(usbotg_base + USBCMD_OFFSET); > + if (flags & MXC_EHCI_ITC_NO_THRESHOLD) > + /* Interrupt Threshold Control:Immediate (no threshold) */ > + v &= UCMD_ITC_NO_THRESHOLD; > + __raw_writel(v, usbotg_base + USBCMD_OFFSET); > + break; > + } > + > + /* need to reset the controller here so that the ID pin > + * is correctly detected. > + */ > + /* Stop then Reset */ > + v = __raw_readl(usbotg_base + USBCMD_OFFSET); > + v &= ~UCMD_RUN_STOP; > + __raw_writel(v, usbotg_base + USBCMD_OFFSET); > + ret = hw_handshake(usbotg_base + USBCMD_OFFSET, UCMD_RUN_STOP, 0, 500); > + if (ret) { > + printk(KERN_ERR "%s could not stop usb hardware\n", __func__); > + goto error; > + } > + > + v = __raw_readl(usbotg_base + USBCMD_OFFSET); > + v |= UCMD_RESET; > + __raw_writel(v, usbotg_base + USBCMD_OFFSET); > + ret = hw_handshake(usbotg_base + USBCMD_OFFSET, UCMD_RESET, 0, 500); > + if (ret) { > + printk(KERN_ERR "%s could not reset usb hardware\n", __func__); > + goto error; > + } > + > + /* allow controller to reset, and leave time for > + * the ULPI transceiver to reset too. > + */ > + msleep(100); > +error: > + iounmap(usb_base); > + return ret; > + } > +#endif > printk(KERN_WARNING > "%s() unable to setup USBCONTROL for this CPU\n", __func__); > return -EINVAL; > } > -EXPORT_SYMBOL(mxc_set_usbcontrol); > +EXPORT_SYMBOL(mxc_intialize_usb_hw); > > diff --git a/arch/arm/plat-mxc/include/mach/mxc_ehci.h b/arch/arm/plat-mxc/include/mach/mxc_ehci.h > index 4b9b836..42c4beb 100644 > --- a/arch/arm/plat-mxc/include/mach/mxc_ehci.h > +++ b/arch/arm/plat-mxc/include/mach/mxc_ehci.h > @@ -1,6 +1,30 @@ > #ifndef __INCLUDE_ASM_ARCH_MXC_EHCI_H > #define __INCLUDE_ASM_ARCH_MXC_EHCI_H > > +#define USBOTG_OFFSET 0 > +#define USBH1_OFFSET 0x200 > +#define USBH2_OFFSET 0x400 > +#define USBH3_OFFSET 0x600 > +#define USBOTHER_REGS_OFFSET 0x800 > + > +#define USBCMD_OFFSET 0x140 > + > +#define ULPI_VIEWPORT_OFFSET 0x170 > +#define PORTSC_OFFSET 0x184 > +#define USBMODE_OFFSET 0x1a8 > +#define USBMODE_CM_HOST 3 > + > +#define USBCTRL_OFFSET 0 > +#define USB_PHY_CTR_FUNC_OFFSET 0x8 > +#define USB_PHY_CTR_FUNC2_OFFSET 0xc > +#define USB_CTRL_1_OFFSET 0x10 > + > + > +/* USBCMD */ > +#define UCMD_RUN_STOP (1 << 0) /* controller run/stop */ > +#define UCMD_RESET (1 << 1) /* controller reset */ > +#define UCMD_ITC_NO_THRESHOLD (~(0xff << 16)) /* Interrupt Threshold Control */ > + > /* values for portsc field */ > #define MXC_EHCI_PHY_LOW_POWER_SUSPEND (1 << 23) > #define MXC_EHCI_FORCE_FS (1 << 24) > @@ -25,6 +49,38 @@ > #define MXC_EHCI_INTERNAL_PHY (1 << 7) > #define MXC_EHCI_IPPUE_DOWN (1 << 8) > #define MXC_EHCI_IPPUE_UP (1 << 9) > +#define MXC_EHCI_WAKEUP_ENABLED (1 << 10) > +#define MXC_EHCI_ITC_NO_THRESHOLD (1 << 11) > + > +/* USB_CTRL */ > +#define UCTRL_OUIE (1 << 28) /* OTG ULPI intr enable */ > +#define UCTRL_OWIE (1 << 27) /* OTG wakeup intr enable */ > +#define UCTRL_OBPVAL_RXDP (1 << 26) /* OTG RxDp status in bypass mode */ > +#define UCTRL_OBPVAL_RXDM (1 << 25) /* OTG RxDm status in bypass mode */ > +#define UCTRL_OPM (1 << 24) /* OTG power mask */ > +#define UCTRL_H1UIE (1 << 12) /* Host1 ULPI interrupt enable */ > +#define UCTRL_H1WIE (1 << 11) /* HOST1 wakeup intr enable */ > +#define UCTRL_H1PM (1 << 8) /* HOST1 power mask */ > + > +/* USB_PHY_CTRL_FUNC */ > +#define USB_UTMI_PHYCTRL_OC_DIS (1 << 8) /* OTG Disable Overcurrent Event */ > +#define USB_UH1_OC_DIS (1 << 5) /* UH1 Disable Overcurrent Event */ > + > +/* USB_CTRL_1 */ > +#define USB_CTRL_UH1_EXT_CLK_EN (1 << 25) > +#define USB_CTRL_UH2_EXT_CLK_EN (1 << 26) > + > +/* USB_PHY_CTRL_FUNC2*/ > +#define USB_UTMI_PHYCTRL2_PLLDIV_MASK 0x3 > +#define USB_UTMI_PHYCTRL2_PLLDIV_SHIFT 0 > +#define USB_UTMI_PHYCTRL2_HSDEVSEL_MASK 0x3 > +#define USB_UTMI_PHYCTRL2_HSDEVSEL_SHIFT 19 > + > +#ifdef CONFIG_ARCH_MX51 > +#define USB_PLLDIV_12_MHZ 0x00 > +#define USB_PLL_DIV_19_2_MHZ 0x01 > +#define USB_PLL_DIV_24_MHZ 0x02 > +#endif > > struct mxc_usbh_platform_data { > int (*init)(struct platform_device *pdev); > @@ -35,7 +91,7 @@ struct mxc_usbh_platform_data { > struct otg_transceiver *otg; > }; > > -int mxc_set_usbcontrol(int port, unsigned int flags); > +int mxc_intialize_usb_hw(int port, unsigned int flags); > > #endif /* __INCLUDE_ASM_ARCH_MXC_EHCI_H */ > > diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c > index ead59f4..7091b20 100644 > --- a/drivers/usb/host/ehci-mxc.c > +++ b/drivers/usb/host/ehci-mxc.c > @@ -191,6 +191,11 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) > clk_enable(priv->ahbclk); > } > > + /* setup specific usb hw */ > + ret = mxc_intialize_usb_hw(pdev->id, pdata->flags); > + if (ret < 0) > + goto err_init; > + > /* set USBMODE to host mode */ > temp = readl(hcd->regs + USBMODE_OFFSET); > writel(temp | USBMODE_CM_HOST, hcd->regs + USBMODE_OFFSET); > @@ -199,11 +204,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev) > writel(pdata->portsc, hcd->regs + PORTSC_OFFSET); > mdelay(10); > > - /* setup USBCONTROL. */ > - ret = mxc_set_usbcontrol(pdev->id, pdata->flags); > - if (ret < 0) > - goto err_init; > - > /* Initialize the transceiver */ > if (pdata->otg) { > pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET; > -- > 1.6.0.4 > -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/