From a07bbdb6bd88bd0362607a43f31316383b0dbe3c Mon Sep 17 00:00:00 2001 From: Steve Lin Date: Wed, 21 Sep 2011 13:11:40 -0700 Subject: arm: tegra: usb: fix null ULPI init for LP0 Changing null ULPI init sequence to avoid phy register program issue when exiting LP0. Bug 863224 Bug 860900 Bug 800318 Reviewed-on: http://git-master/r/53256 (cherry picked from commit 0beea798107fbe276568c3d67a3857f359ff5f53) Change-Id: I2a7bdac4e3f517c56c1505312db83b6535e77c58 Reviewed-on: http://git-master/r/55036 Reviewed-by: Varun Colbert Tested-by: Varun Colbert --- arch/arm/mach-tegra/include/mach/usb_phy.h | 2 + arch/arm/mach-tegra/usb_phy.c | 97 +++++++++++++++++------------- 2 files changed, 58 insertions(+), 41 deletions(-) diff --git a/arch/arm/mach-tegra/include/mach/usb_phy.h b/arch/arm/mach-tegra/include/mach/usb_phy.h index d08e243238f5..0b794bb51964 100644 --- a/arch/arm/mach-tegra/include/mach/usb_phy.h +++ b/arch/arm/mach-tegra/include/mach/usb_phy.h @@ -125,6 +125,8 @@ void tegra_usb_phy_preresume(struct tegra_usb_phy *phy, bool is_dpd); void tegra_usb_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd); +void tegra_ehci_pre_reset(struct tegra_usb_phy *phy, bool is_dpd); + void tegra_ehci_post_reset(struct tegra_usb_phy *phy, bool is_dpd); void tegra_ehci_phy_restore_start(struct tegra_usb_phy *phy, diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c index b3bcab65d4b3..b5d1a2afa79e 100644 --- a/arch/arm/mach-tegra/usb_phy.c +++ b/arch/arm/mach-tegra/usb_phy.c @@ -1846,11 +1846,18 @@ static int null_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd) ulpi_phy_reset(base); +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + /* remove ULPI PADS CLKEN reset */ + val = readl(base + USB_SUSP_CTRL); + val &= ~ULPI_PADS_CLKEN_RESET; + writel(val, base + USB_SUSP_CTRL); + udelay(10); +#endif val = readl(base + ULPI_TIMING_CTRL_0); val |= ULPI_OUTPUT_PINMUX_BYP | ULPI_CLKOUT_PINMUX_BYP; writel(val, base + ULPI_TIMING_CTRL_0); - ulpi_set_host(base); + ulpi_set_tristate(false); if (config->pre_phy_on && config->pre_phy_on()) return -EAGAIN; @@ -1863,7 +1870,7 @@ static int null_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd) /* set timming parameters */ val = readl(base + ULPI_TIMING_CTRL_0); val |= ULPI_SHADOW_CLK_LOOPBACK_EN; - val |= ULPI_SHADOW_CLK_SEL; + val &= ~ULPI_SHADOW_CLK_SEL; val &= ~ULPI_LBK_PAD_EN; val |= ULPI_SHADOW_CLK_DELAY(config->trimmer->shadow_clk_delay); val |= ULPI_CLOCK_OUT_DELAY(config->trimmer->clock_out_delay); @@ -1874,7 +1881,11 @@ static int null_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd) udelay(10); /* start internal 60MHz clock */ - val = ULPIS2S_PLLU_MASTER_BLASTER60; + val = readl(base + ULPIS2S_CTRL); + val |= ULPIS2S_ENA; + val |= ULPIS2S_SUPPORT_DISCONNECT; + val |= ULPIS2S_SPARE((phy->mode == TEGRA_USB_PHY_MODE_HOST) ? 3 : 1); + val |= ULPIS2S_PLLU_MASTER_BLASTER60; writel(val, base + ULPIS2S_CTRL); /* select ULPI_CORE_CLK_SEL to SHADOW_CLK */ @@ -1883,57 +1894,43 @@ static int null_phy_power_on(struct tegra_usb_phy *phy, bool is_dpd) writel(val, base + ULPI_TIMING_CTRL_0); udelay(10); -#ifndef CONFIG_ARCH_TEGRA_2x_SOC - /* remove slave0 reset */ - val = readl(base + USB_SUSP_CTRL); - val &= ~ULPIS2S_SLV0_RESET; - writel(val, base + USB_SUSP_CTRL); - udelay(10); -#endif /* enable ULPI null phy clock - can't set the trimmers before this */ val = readl(base + ULPI_TIMING_CTRL_0); val |= ULPI_CLK_OUT_ENA; writel(val, base + ULPI_TIMING_CTRL_0); udelay(10); - /* set trimmers */ + if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, + USB_PHY_CLK_VALID)) { + pr_err("%s: timeout waiting for phy to stabilize\n", __func__); + return -ETIMEDOUT; + } + + /* set ULPI trimmers */ ulpi_set_trimmer(base, config->trimmer->data_trimmer, config->trimmer->stpdirnxt_trimmer, 1); + ulpi_set_host(base); + #ifndef CONFIG_ARCH_TEGRA_2x_SOC - /* remove various ULPIS2S resets */ + /* remove slave0 reset */ val = readl(base + USB_SUSP_CTRL); - val &= ~ULPIS2S_LINE_RESET; - val &= ~ULPIS2S_SLV1_RESET; - val &= ~ULPI_PADS_RESET; - val &= ~ULPI_PADS_CLKEN_RESET; + val &= ~ULPIS2S_SLV0_RESET; writel(val, base + USB_SUSP_CTRL); -#endif - val = readl(base + ULPIS2S_CTRL); - val |= ULPIS2S_ENA; - val |= ULPIS2S_SUPPORT_DISCONNECT; - val |= ULPIS2S_SPARE((phy->mode == TEGRA_USB_PHY_MODE_HOST)? 3 : 1); - writel(val, base + ULPIS2S_CTRL); - -#ifdef CONFIG_ARCH_TEGRA_2x_SOC + /* remove slave1 and line reset */ val = readl(base + USB_SUSP_CTRL); - val |= USB_SUSP_CLR; - writel(val, base + USB_SUSP_CTRL); - udelay(100); - val = readl(base + USB_SUSP_CTRL); - val &= ~USB_SUSP_CLR; + val &= ~ULPIS2S_SLV1_RESET; + val &= ~ULPIS2S_LINE_RESET; + + /* remove ULPI PADS reset */ + val &= ~ULPI_PADS_RESET; writel(val, base + USB_SUSP_CTRL); #endif - if (utmi_wait_register(base + USB_SUSP_CTRL, USB_PHY_CLK_VALID, - USB_PHY_CLK_VALID)) { - pr_err("%s: timeout waiting for phy to stabilize\n", __func__); - return -ETIMEDOUT; - } - val = readl(base + ULPI_TIMING_CTRL_0); val |= ULPI_CLK_PADOUT_ENA; writel(val, base + ULPI_TIMING_CTRL_0); + udelay(10); if (config->post_phy_on && config->post_phy_on()) @@ -1951,10 +1948,6 @@ static int null_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd) if (config->pre_phy_off && config->pre_phy_off()) return -EAGAIN; - val = readl(base + ULPI_TIMING_CTRL_0); - val &= ~ULPI_CLK_PADOUT_ENA; - writel(val, base + ULPI_TIMING_CTRL_0); - ulpi_set_tristate(true); if (config->post_phy_off && config->post_phy_off()) @@ -1963,7 +1956,7 @@ static int null_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd) return 0; } -static int null_phy_post_usbcmd_reset(struct tegra_usb_phy *phy, bool is_dpd) +static int null_phy_pre_usbcmd_reset(struct tegra_usb_phy *phy, bool is_dpd) { #ifndef CONFIG_ARCH_TEGRA_2x_SOC unsigned long val; @@ -1977,16 +1970,25 @@ static int null_phy_post_usbcmd_reset(struct tegra_usb_phy *phy, bool is_dpd) val |= ULPIS2S_SLV0_RESET; writel(val, base + USB_SUSP_CTRL); udelay(10); +#endif + return 0; +} + +static int null_phy_post_usbcmd_reset(struct tegra_usb_phy *phy, bool is_dpd) +{ +#ifndef CONFIG_ARCH_TEGRA_2x_SOC + unsigned long val; + void __iomem *base = phy->regs; /* remove slave0 reset */ val = readl(base + USB_SUSP_CTRL); val &= ~ULPIS2S_SLV0_RESET; writel(val, base + USB_SUSP_CTRL); - udelay(10); val = readl(base + ULPIS2S_CTRL); val &= ~ULPIS2S_SLV0_CLAMP_XMIT; writel(val, base + ULPIS2S_CTRL); + udelay(10); ulpi_set_host(base); #endif @@ -2402,6 +2404,19 @@ void tegra_usb_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd) postresume[phy->usb_phy_type](phy, is_dpd); } +void tegra_ehci_pre_reset(struct tegra_usb_phy *phy, bool is_dpd) +{ + const tegra_phy_fp pre_reset[] = { + NULL, + NULL, + null_phy_pre_usbcmd_reset, + NULL, + }; + + if (pre_reset[phy->usb_phy_type]) + pre_reset[phy->usb_phy_type](phy, is_dpd); +} + void tegra_ehci_post_reset(struct tegra_usb_phy *phy, bool is_dpd) { const tegra_phy_fp post_reset[] = { -- cgit v1.2.3