102 lines
3.1 KiB
Diff
102 lines
3.1 KiB
Diff
|
From f59dcab176293b646e1358144c93c58c3cda2813 Mon Sep 17 00:00:00 2001
|
||
|
From: Felipe Balbi <felipe.balbi@linux.intel.com>
|
||
|
Date: Fri, 11 Mar 2016 10:51:52 +0200
|
||
|
Subject: usb: dwc3: core: improve reset sequence
|
||
|
|
||
|
According to Synopsys Databook, we shouldn't be
|
||
|
relying on GCTL.CORESOFTRESET bit as that's only for
|
||
|
debugging purposes. Instead, let's use DCTL.CSFTRST
|
||
|
if we're OTG or PERIPHERAL mode.
|
||
|
|
||
|
Host side block will be reset by XHCI driver if
|
||
|
necessary. Note that this reduces amount of time
|
||
|
spent on dwc3_probe() by a long margin.
|
||
|
|
||
|
We're still gonna wait for reset to finish for a
|
||
|
long time (default to 1ms max), but tests show that
|
||
|
the reset polling loop executed at most 19 times
|
||
|
(modprobe dwc3 && modprobe -r dwc3 executed 1000
|
||
|
times in a row).
|
||
|
|
||
|
Suggested-by: Mian Yousaf Kaukab <yousaf.kaukab@intel.com>
|
||
|
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
|
||
|
---
|
||
|
drivers/usb/dwc3/core.c | 48 ++++++++++++++++++------------------------------
|
||
|
1 file changed, 18 insertions(+), 30 deletions(-)
|
||
|
|
||
|
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
|
||
|
index 17fd814..fa20f5a9 100644
|
||
|
--- a/drivers/usb/dwc3/core.c
|
||
|
+++ b/drivers/usb/dwc3/core.c
|
||
|
@@ -67,23 +67,9 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
|
||
|
static int dwc3_core_soft_reset(struct dwc3 *dwc)
|
||
|
{
|
||
|
u32 reg;
|
||
|
+ int retries = 1000;
|
||
|
int ret;
|
||
|
|
||
|
- /* Before Resetting PHY, put Core in Reset */
|
||
|
- reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||
|
- reg |= DWC3_GCTL_CORESOFTRESET;
|
||
|
- dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||
|
-
|
||
|
- /* Assert USB3 PHY reset */
|
||
|
- reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||
|
- reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
|
||
|
- dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
|
||
|
-
|
||
|
- /* Assert USB2 PHY reset */
|
||
|
- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||
|
- reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
|
||
|
- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||
|
-
|
||
|
usb_phy_init(dwc->usb2_phy);
|
||
|
usb_phy_init(dwc->usb3_phy);
|
||
|
ret = phy_init(dwc->usb2_generic_phy);
|
||
|
@@ -95,26 +81,28 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
|
||
|
phy_exit(dwc->usb2_generic_phy);
|
||
|
return ret;
|
||
|
}
|
||
|
- mdelay(100);
|
||
|
|
||
|
- /* Clear USB3 PHY reset */
|
||
|
- reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
|
||
|
- reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
|
||
|
- dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
|
||
|
+ /*
|
||
|
+ * We're resetting only the device side because, if we're in host mode,
|
||
|
+ * XHCI driver will reset the host block. If dwc3 was configured for
|
||
|
+ * host-only mode, then we can return early.
|
||
|
+ */
|
||
|
+ if (dwc->dr_mode == USB_DR_MODE_HOST)
|
||
|
+ return 0;
|
||
|
|
||
|
- /* Clear USB2 PHY reset */
|
||
|
- reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
|
||
|
- reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
|
||
|
- dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
|
||
|
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||
|
+ reg |= DWC3_DCTL_CSFTRST;
|
||
|
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
|
||
|
|
||
|
- mdelay(100);
|
||
|
+ do {
|
||
|
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
|
||
|
+ if (!(reg & DWC3_DCTL_CSFTRST))
|
||
|
+ return 0;
|
||
|
|
||
|
- /* After PHYs are stable we can take Core out of reset state */
|
||
|
- reg = dwc3_readl(dwc->regs, DWC3_GCTL);
|
||
|
- reg &= ~DWC3_GCTL_CORESOFTRESET;
|
||
|
- dwc3_writel(dwc->regs, DWC3_GCTL, reg);
|
||
|
+ udelay(1);
|
||
|
+ } while (--retries);
|
||
|
|
||
|
- return 0;
|
||
|
+ return -ETIMEDOUT;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
--
|
||
|
cgit v0.12
|