usb: dwc3: Disable phy suspend after power-on reset
authorThinh Nguyen <Thinh.Nguyen@synopsys.com>
Fri, 9 Aug 2019 19:15:52 +0000 (12:15 -0700)
committerFelipe Balbi <felipe.balbi@linux.intel.com>
Tue, 22 Oct 2019 07:26:45 +0000 (10:26 +0300)
For DRD controllers, the programming guide recommended that
GUSB3PIPECTL.SUSPENDABLE and GUSB2PHYCFG.SUSPHY to be cleared after
power-on reset and only set after the controller initialization is
completed. This can be done after device soft-reset in dwc3_core_init().
This patch makes sure to clear GUSB3PIPECTL.SUSPENDABLE and
GUSB2PHYCFG.SUSPHY before core initialization and only set them after
the device soft-reset is completed.

Reference: DWC_usb3 3.30a and DWC_usb31 1.90a programming guide section
1.2.49 and 1.2.45

Signed-off-by: Thinh Nguyen <thinhn@synopsys.com>
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
drivers/usb/dwc3/core.c

index 999ce5e..2991e50 100644 (file)
@@ -567,8 +567,11 @@ static int dwc3_core_ulpi_init(struct dwc3 *dwc)
  */
 static int dwc3_phy_setup(struct dwc3 *dwc)
 {
+       unsigned int hw_mode;
        u32 reg;
 
+       hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
+
        reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
 
        /*
@@ -586,6 +589,14 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
        if (dwc->revision > DWC3_REVISION_194A)
                reg |= DWC3_GUSB3PIPECTL_SUSPHY;
 
+       /*
+        * For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be cleared after
+        * power-on reset, and it can be set after core initialization, which is
+        * after device soft-reset during initialization.
+        */
+       if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
+               reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+
        if (dwc->u2ss_inp3_quirk)
                reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
 
@@ -669,6 +680,14 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
        if (dwc->revision > DWC3_REVISION_194A)
                reg |= DWC3_GUSB2PHYCFG_SUSPHY;
 
+       /*
+        * For DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared after
+        * power-on reset, and it can be set after core initialization, which is
+        * after device soft-reset during initialization.
+        */
+       if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
+               reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+
        if (dwc->dis_u2_susphy_quirk)
                reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
 
@@ -903,9 +922,12 @@ static void dwc3_set_incr_burst_type(struct dwc3 *dwc)
  */
 static int dwc3_core_init(struct dwc3 *dwc)
 {
+       unsigned int            hw_mode;
        u32                     reg;
        int                     ret;
 
+       hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
+
        /*
         * Write Linux Version Code to our GUID register so it's easy to figure
         * out which kernel version a bug was found.
@@ -941,6 +963,21 @@ static int dwc3_core_init(struct dwc3 *dwc)
        if (ret)
                goto err0a;
 
+       if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD &&
+           dwc->revision > DWC3_REVISION_194A) {
+               if (!dwc->dis_u3_susphy_quirk) {
+                       reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+                       reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+                       dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+               }
+
+               if (!dwc->dis_u2_susphy_quirk) {
+                       reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+                       reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+                       dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+               }
+       }
+
        dwc3_core_setup_global_control(dwc);
        dwc3_core_num_eps(dwc);