diff options
author | Venkat Moganty <vmoganty@nvidia.com> | 2012-01-19 11:34:22 +0530 |
---|---|---|
committer | Rohan Somvanshi <rsomvanshi@nvidia.com> | 2012-01-24 10:59:32 -0800 |
commit | 005f572bd229c4072cc618b74847edeba65faf33 (patch) | |
tree | fe352aa8bffa315d51d388bd3299a911c06d5644 /drivers/usb/host | |
parent | 65ab9647d93da8dce3ea14922a6095bbcf64efcd (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 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/ehci-hcd.c | 3 | ||||
-rw-r--r-- | drivers/usb/host/ehci-tegra.c | 62 | ||||
-rw-r--r-- | drivers/usb/host/ehci.h | 1 |
3 files changed, 58 insertions, 8 deletions
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index ab94b512e0ea..1a534c70ea6e 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -906,6 +906,9 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd) ehci->reset_done[i] = jiffies + msecs_to_jiffies(25); ehci_dbg (ehci, "port %d remote wakeup\n", i + 1); mod_timer(&hcd->rh_timer, ehci->reset_done[i]); +#ifdef CONFIG_USB_EHCI_TEGRA + ehci->controller_remote_wakeup = true; +#endif } } diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c index 917796c20d8a..1dbfc4aa1981 100644 --- a/drivers/usb/host/ehci-tegra.c +++ b/drivers/usb/host/ehci-tegra.c @@ -167,11 +167,14 @@ static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd) struct ehci_regs __iomem *hw = ehci->regs; struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); u32 val; + irqreturn_t irq_status; + bool pmc_remote_wakeup = false; if ((tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) && (tegra->ehci->has_hostpc)) { /* check if there is any remote wake event */ if (tegra_usb_phy_is_remotewake_detected(tegra->phy)) { + pmc_remote_wakeup = true; spin_lock (&ehci->lock); usb_hcd_resume_root_hub(hcd); spin_unlock (&ehci->lock); @@ -196,7 +199,21 @@ static irqreturn_t tegra_ehci_irq (struct usb_hcd *hcd) } spin_unlock(&ehci->lock); } - return ehci_irq(hcd); + + irq_status = ehci_irq(hcd); + + if (pmc_remote_wakeup) { + ehci->controller_remote_wakeup = false; + } + + if (ehci->controller_remote_wakeup) { + ehci->controller_remote_wakeup = false; + /* disable interrupts */ + ehci_writel(ehci, 0, &ehci->regs->intr_enable); + tegra_usb_phy_preresume(tegra->phy, true); + tegra->port_resuming = 1; + } + return irq_status; } static int tegra_ehci_hub_control( @@ -219,6 +236,7 @@ static int tegra_ehci_hub_control( unsigned selector; struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); bool hsic = false; + bool do_post_resume = false; if (!tegra->host_resumed) { if (buf) @@ -244,13 +262,18 @@ static int tegra_ehci_hub_control( } else if (typeReq == GetPortStatus) { temp = ehci_readl(ehci, status_reg); if (tegra->port_resuming && !(temp & PORT_SUSPEND) && - time_after_eq(jiffies, ehci->reset_done[wIndex-1])) { - /* Resume completed, re-enable disconnect detection */ - tegra->port_resuming = 0; + time_after_eq(jiffies, ehci->reset_done[wIndex-1])) { clear_bit((wIndex & 0xff) - 1, &ehci->suspended_ports); ehci->reset_done[wIndex-1] = 0; + do_post_resume = true; + } else if (tegra->port_resuming && (temp & PORT_RESUME) && + time_after_eq(jiffies, ehci->reset_done[wIndex-1]) ) { + do_post_resume = true; + } + + if (do_post_resume) { + tegra->port_resuming = 0; tegra_usb_phy_postresume(tegra->phy, false); -#ifndef CONFIG_ARCH_TEGRA_2x_SOC if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) { ehci->command |= CMD_RUN; /* @@ -259,9 +282,11 @@ static int tegra_ehci_hub_control( */ ehci_writel(ehci, ehci->command, &ehci->regs->command); + /* Now we can safely re-enable irqs */ + ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); } -#endif } + } else if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) { temp = ehci_readl(ehci, status_reg); if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) { @@ -286,6 +311,13 @@ static int tegra_ehci_hub_control( set_bit((wIndex & 0xff) - 1, &ehci->suspended_ports); + if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) { + /* Disable RUN bit. */ + ehci->command &= ~CMD_RUN; + ehci_writel(ehci, ehci->command, + &ehci->regs->command); + } + tegra_usb_phy_postsuspend(tegra->phy, false); goto done; @@ -318,6 +350,15 @@ static int tegra_ehci_hub_control( tegra->port_resuming = 1; + if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) { + /* disable interrupts */ + ehci_writel(ehci, 0, &ehci->regs->intr_enable); + /* Disable RUN bit. */ + ehci->command &= ~CMD_RUN; + ehci_writel(ehci, ehci->command, + &ehci->regs->command); + } + /* Disable disconnect detection during port resume */ tegra_usb_phy_preresume(tegra->phy, false); #ifndef CONFIG_ARCH_TEGRA_2x_SOC @@ -509,6 +550,7 @@ static int tegra_usb_resume(struct usb_hcd *hcd, bool is_dpd) unsigned long val; bool hsic; bool null_ulpi; + bool utmip_remote_wakeup = false; null_ulpi = (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_NULL_ULPI); hsic = (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_HSIC); @@ -547,8 +589,7 @@ static int tegra_usb_resume(struct usb_hcd *hcd, bool is_dpd) if ((tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_UTMIP) && (tegra->ehci->has_hostpc) && (tegra->phy->remote_wakeup)) { - ehci->command |= CMD_RUN; - ehci_writel(ehci, ehci->command, &ehci->regs->command); + utmip_remote_wakeup = true; } /* Check if the phy resume from LP0. When the phy resume from LP0 @@ -611,6 +652,10 @@ static int tegra_usb_resume(struct usb_hcd *hcd, bool is_dpd) } tegra_ehci_phy_restore_end(tegra->phy); + if (utmip_remote_wakeup) { + ehci->command |= CMD_RUN; + ehci_writel(ehci, ehci->command, &ehci->regs->command); + } return 0; restart: @@ -709,6 +754,7 @@ static int tegra_ehci_setup(struct usb_hcd *hcd) return retval; ehci->sbrn = 0x20; + ehci->controller_remote_wakeup = false; if (tegra->phy->usb_phy_type == TEGRA_USB_PHY_TYPE_NULL_ULPI) { tegra_ehci_pre_reset(tegra->phy, false); diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 7f0e828631ed..e897262c6a60 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -142,6 +142,7 @@ struct ehci_hcd { /* one per controller */ unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */ #ifdef CONFIG_USB_EHCI_TEGRA unsigned controller_resets_phy:1; + unsigned controller_remote_wakeup:1; #endif /* required for usb32 quirk */ |