ipq806x: switch to upstream usb driver and backport fixes
[oweals/openwrt.git] / target / linux / ipq806x / patches-4.4 / 096-06-usb-dwc3-core-improve-reset-sequence.patch
1 From f59dcab176293b646e1358144c93c58c3cda2813 Mon Sep 17 00:00:00 2001
2 From: Felipe Balbi <felipe.balbi@linux.intel.com>
3 Date: Fri, 11 Mar 2016 10:51:52 +0200
4 Subject: usb: dwc3: core: improve reset sequence
5
6 According to Synopsys Databook, we shouldn't be
7 relying on GCTL.CORESOFTRESET bit as that's only for
8 debugging purposes. Instead, let's use DCTL.CSFTRST
9 if we're OTG or PERIPHERAL mode.
10
11 Host side block will be reset by XHCI driver if
12 necessary. Note that this reduces amount of time
13 spent on dwc3_probe() by a long margin.
14
15 We're still gonna wait for reset to finish for a
16 long time (default to 1ms max), but tests show that
17 the reset polling loop executed at most 19 times
18 (modprobe dwc3 && modprobe -r dwc3 executed 1000
19 times in a row).
20
21 Suggested-by: Mian Yousaf Kaukab <yousaf.kaukab@intel.com>
22 Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
23 ---
24  drivers/usb/dwc3/core.c | 48 ++++++++++++++++++------------------------------
25  1 file changed, 18 insertions(+), 30 deletions(-)
26
27 diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
28 index 17fd814..fa20f5a9 100644
29 --- a/drivers/usb/dwc3/core.c
30 +++ b/drivers/usb/dwc3/core.c
31 @@ -67,23 +67,9 @@ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
32  static int dwc3_core_soft_reset(struct dwc3 *dwc)
33  {
34         u32             reg;
35 +       int             retries = 1000;
36         int             ret;
37  
38 -       /* Before Resetting PHY, put Core in Reset */
39 -       reg = dwc3_readl(dwc->regs, DWC3_GCTL);
40 -       reg |= DWC3_GCTL_CORESOFTRESET;
41 -       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
42 -
43 -       /* Assert USB3 PHY reset */
44 -       reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
45 -       reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
46 -       dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
47 -
48 -       /* Assert USB2 PHY reset */
49 -       reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
50 -       reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
51 -       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
52 -
53         usb_phy_init(dwc->usb2_phy);
54         usb_phy_init(dwc->usb3_phy);
55         ret = phy_init(dwc->usb2_generic_phy);
56 @@ -95,26 +81,28 @@ static int dwc3_core_soft_reset(struct dwc3 *dwc)
57                 phy_exit(dwc->usb2_generic_phy);
58                 return ret;
59         }
60 -       mdelay(100);
61  
62 -       /* Clear USB3 PHY reset */
63 -       reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
64 -       reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
65 -       dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
66 +       /*
67 +        * We're resetting only the device side because, if we're in host mode,
68 +        * XHCI driver will reset the host block. If dwc3 was configured for
69 +        * host-only mode, then we can return early.
70 +        */
71 +       if (dwc->dr_mode == USB_DR_MODE_HOST)
72 +               return 0;
73  
74 -       /* Clear USB2 PHY reset */
75 -       reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
76 -       reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
77 -       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
78 +       reg = dwc3_readl(dwc->regs, DWC3_DCTL);
79 +       reg |= DWC3_DCTL_CSFTRST;
80 +       dwc3_writel(dwc->regs, DWC3_DCTL, reg);
81  
82 -       mdelay(100);
83 +       do {
84 +               reg = dwc3_readl(dwc->regs, DWC3_DCTL);
85 +               if (!(reg & DWC3_DCTL_CSFTRST))
86 +                       return 0;
87  
88 -       /* After PHYs are stable we can take Core out of reset state */
89 -       reg = dwc3_readl(dwc->regs, DWC3_GCTL);
90 -       reg &= ~DWC3_GCTL_CORESOFTRESET;
91 -       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
92 +               udelay(1);
93 +       } while (--retries);
94  
95 -       return 0;
96 +       return -ETIMEDOUT;
97  }
98  
99  /**
100 -- 
101 cgit v0.12