summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/usb_phy.c
diff options
context:
space:
mode:
authorVenkat Moganty <vmoganty@nvidia.com>2012-01-19 11:34:22 +0530
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-01-24 10:59:32 -0800
commit005f572bd229c4072cc618b74847edeba65faf33 (patch)
treefe352aa8bffa315d51d388bd3299a911c06d5644 /arch/arm/mach-tegra/usb_phy.c
parent65ab9647d93da8dce3ea14922a6095bbcf64efcd (diff)
tegra: usb: host: Fix remote wakeup issues on UTMI
Add WAR to fix 2LS voilation during usb remote resume. Bug 880538 Reviewed-on: http://git-master/r/75845 Change-Id: I552c9e657776f67c263ef750a7786c796dc785cb Signed-off-by: Venkat Moganty <vmoganty@nvidia.com> Signed-off-by: Varun Wadekar <vwadekar@nvidia.com> Reviewed-on: http://git-master/r/76822 Reviewed-by: Automatic_Commit_Validation_User
Diffstat (limited to 'arch/arm/mach-tegra/usb_phy.c')
-rw-r--r--arch/arm/mach-tegra/usb_phy.c134
1 files changed, 89 insertions, 45 deletions
diff --git a/arch/arm/mach-tegra/usb_phy.c b/arch/arm/mach-tegra/usb_phy.c
index 5eab7ccd3dc8..8820a2626282 100644
--- a/arch/arm/mach-tegra/usb_phy.c
+++ b/arch/arm/mach-tegra/usb_phy.c
@@ -1414,27 +1414,45 @@ static void utmip_phy_disable_pmc_bus_ctrl(struct tegra_usb_phy *phy)
#endif
}
-static int utmi_phy_preresume(struct tegra_usb_phy *phy, bool is_dpd)
+static void utmi_phy_enable_obs_bus(struct tegra_usb_phy *phy,
+ enum tegra_usb_phy_port_speed port_speed)
{
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
unsigned long val;
void __iomem *base = phy->regs;
- val = readl(base + UTMIP_TX_CFG0);
- val |= UTMIP_HS_DISCON_DISABLE;
- writel(val, base + UTMIP_TX_CFG0);
-#else
- utmip_phy_disable_pmc_bus_ctrl(phy);
-#endif
- return 0;
+ /* (2LS WAR)is not required for LS and FS devices and is only for HS */
+ if (port_speed != TEGRA_USB_PHY_PORT_SPEED_HIGH) {
+ /* do not enable the OBS bus */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
+ writel(val, base + UTMIP_MISC_CFG0);
+ return;
+ }
+ /* Force DP/DM pulldown active for Host mode */
+ val = readl(base + UTMIP_MISC_CFG0);
+ val |= FORCE_PULLDN_DM | FORCE_PULLDN_DP |
+ COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS;
+ writel(val, base + UTMIP_MISC_CFG0);
+ val = readl(base + UTMIP_MISC_CFG0);
+ val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
+ if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
+ else
+ val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(1);
+
+ val = readl(base + UTMIP_MISC_CFG0);
+ val |= UTMIP_DPDM_OBSERVE;
+ writel(val, base + UTMIP_MISC_CFG0);
+ udelay(10);
}
-static int utmi_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd)
+static void utmi_phy_disable_obs_bus(struct tegra_usb_phy *phy)
{
unsigned long val;
void __iomem *base = phy->regs;
-#ifndef CONFIG_ARCH_TEGRA_2x_SOC
/* check if OBS bus is already enabled */
val = readl(base + UTMIP_MISC_CFG0);
if (val & UTMIP_DPDM_OBSERVE) {
@@ -1458,11 +1476,65 @@ static int utmi_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd)
COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS);
writel(val, base + UTMIP_MISC_CFG0);
}
+}
+
+
+static int utmi_phy_preresume(struct tegra_usb_phy *phy, bool remote_wakeup)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ enum tegra_usb_phy_port_speed port_speed;
+
+ val = readl(base + UTMIP_TX_CFG0);
+ val |= UTMIP_HS_DISCON_DISABLE;
+ writel(val, base + UTMIP_TX_CFG0);
+
+ port_speed = (readl(base + USB_PORTSC1) >> 26) & 0x3;
+ utmi_phy_enable_obs_bus(phy, port_speed);
+
+#else
+ unsigned long val;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->instance;
+ void __iomem *base = phy->regs;
+ enum tegra_usb_phy_port_speed port_speed;
+
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ if (val & UTMIP_MASTER_ENABLE(inst)) {
+ if (!remote_wakeup)
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+ } else {
+ port_speed = (readl(base + HOSTPC1_DEVLC) >> 25) &
+ HOSTPC1_DEVLC_PSPD_MASK;
+ utmi_phy_enable_obs_bus(phy, port_speed);
+ }
+#endif
+
+ return 0;
+}
+
+static int utmi_phy_postresume(struct tegra_usb_phy *phy, bool is_dpd)
+{
+ unsigned long val;
+ void __iomem *base = phy->regs;
+ void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
+ unsigned int inst = phy->instance;
+
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ val = readl(pmc_base + PMC_SLEEP_CFG);
+ /* if PMC is not disabled by now then disable it */
+ if (val & UTMIP_MASTER_ENABLE(inst)) {
+ utmip_phy_disable_pmc_bus_ctrl(phy);
+ }
#else
val = readl(base + UTMIP_TX_CFG0);
val &= ~UTMIP_HS_DISCON_DISABLE;
writel(val, base + UTMIP_TX_CFG0);
#endif
+
+ utmi_phy_disable_obs_bus(phy);
+
return 0;
}
@@ -1476,7 +1548,7 @@ static int uhsic_phy_postsuspend(struct tegra_usb_phy *phy, bool is_dpd)
return 0;
}
-static int uhsic_phy_preresume(struct tegra_usb_phy *phy, bool is_dpd)
+static int uhsic_phy_preresume(struct tegra_usb_phy *phy, bool remote_wakeup)
{
struct tegra_uhsic_config *uhsic_config = phy->config;
@@ -1524,7 +1596,6 @@ static void utmi_phy_restore_start(struct tegra_usb_phy *phy,
udelay(10);
#else
unsigned long val;
- void __iomem *base = phy->regs;
void __iomem *pmc_base = IO_ADDRESS(TEGRA_PMC_BASE);
int inst = phy->instance;
@@ -1538,34 +1609,7 @@ static void utmi_phy_restore_start(struct tegra_usb_phy *phy,
utmip_phy_disable_pmc_bus_ctrl(phy);
}
}
-
- /* (2LS WAR)is not required for LS and FS devices and is only for HS */
- if ((port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) ||
- (port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL)) {
- /* do not enable the OBS bus */
- val = readl(base + UTMIP_MISC_CFG0);
- val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
- writel(val, base + UTMIP_MISC_CFG0);
- return;
- }
- /* Force DP/DM pulldown active for Host mode */
- val = readl(base + UTMIP_MISC_CFG0);
- val |= FORCE_PULLDN_DM | FORCE_PULLDN_DP |
- COMB_TERMS | ALWAYS_FREE_RUNNING_TERMS;
- writel(val, base + UTMIP_MISC_CFG0);
- val = readl(base + UTMIP_MISC_CFG0);
- val &= ~UTMIP_DPDM_OBSERVE_SEL(~0);
- if (port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW)
- val |= UTMIP_DPDM_OBSERVE_SEL_FS_J;
- else
- val |= UTMIP_DPDM_OBSERVE_SEL_FS_K;
- writel(val, base + UTMIP_MISC_CFG0);
- udelay(1);
-
- val = readl(base + UTMIP_MISC_CFG0);
- val |= UTMIP_DPDM_OBSERVE;
- writel(val, base + UTMIP_MISC_CFG0);
- udelay(10);
+ utmi_phy_enable_obs_bus(phy, port_speed);
#endif
}
@@ -1597,10 +1641,10 @@ static void utmi_phy_restore_end(struct tegra_usb_phy *phy)
}
wait_time_us--;
} while (!(val & USB_PORTSC1_RESUME));
- /* disable PMC master control */
- utmip_phy_disable_pmc_bus_ctrl(phy);
/* wait for 25 ms to port resume complete */
msleep(25);
+ /* disable PMC master control */
+ utmip_phy_disable_pmc_bus_ctrl(phy);
/* Clear PCI and SRI bits to avoid an interrupt upon resume */
val = readl(base + USB_USBSTS);
@@ -2481,7 +2525,7 @@ void tegra_usb_phy_power_off(struct tegra_usb_phy *phy, bool is_dpd)
phy->power_on = false;
}
-void tegra_usb_phy_preresume(struct tegra_usb_phy *phy, bool is_dpd)
+void tegra_usb_phy_preresume(struct tegra_usb_phy *phy, bool remote_wakeup)
{
const tegra_phy_fp preresume[] = {
utmi_phy_preresume,
@@ -2491,7 +2535,7 @@ void tegra_usb_phy_preresume(struct tegra_usb_phy *phy, bool is_dpd)
};
if (preresume[phy->usb_phy_type])
- preresume[phy->usb_phy_type](phy, is_dpd);
+ preresume[phy->usb_phy_type](phy, remote_wakeup);
}
void tegra_usb_phy_postsuspend(struct tegra_usb_phy *phy, bool is_dpd)