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 <thi...@synopsys.com>
---
 drivers/usb/dwc3/core.c | 37 +++++++++++++++++++++++++++++++++++++
 1 file changed, 37 insertions(+)

diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 252c397860ef..edbc3709f28e 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -568,8 +568,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));
 
        /*
@@ -587,6 +590,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;
 
@@ -670,6 +681,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;
 
@@ -905,9 +924,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.
@@ -943,6 +965,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);
 
-- 
2.11.0

Reply via email to