usb: dwc2: Update Core Reset programming flow.
authorMinas Harutyunyan <Minas.Harutyunyan@synopsys.com>
Thu, 21 May 2020 06:05:44 +0000 (10:05 +0400)
committerFelipe Balbi <balbi@kernel.org>
Mon, 25 May 2020 08:09:44 +0000 (11:09 +0300)
Starting from core version 4.20a Core Reset flow is changed.
Introduced new bit in GRSTCTL register - GRSTCTL_CSFTRST_DONE.
Core Reset new programming flow steps are follow:
1. Set GRSTCTL_CSFTRST bit.
2. Wait for bit GRSTCTL_CSFTRST_DONE is set.
3. Clear GRSTCTL_CSFTRST and GRSTCTL_CSFTRST_DONE bits.

Check core version functionality separated from dwc2_get_hwparams() to
new dwc2_check_core_version() function because Core Reset flow depend
on SNPSID.

Signed-off-by: Minas Harutyunyan <hminas@synopsys.com>
Signed-off-by: Felipe Balbi <balbi@kernel.org>
drivers/usb/dwc2/core.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/hw.h
drivers/usb/dwc2/params.c
drivers/usb/dwc2/platform.c

index 78a4925aa118545fdf1c981128d2c55c91bb2d5c..fec17a2d2447dd5a863bf37fc940832737501c0c 100644 (file)
@@ -524,10 +524,25 @@ int dwc2_core_reset(struct dwc2_hsotg *hsotg, bool skip_wait)
        greset |= GRSTCTL_CSFTRST;
        dwc2_writel(hsotg, greset, GRSTCTL);
 
-       if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL, GRSTCTL_CSFTRST, 10000)) {
-               dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL GRSTCTL_CSFTRST\n",
-                        __func__);
-               return -EBUSY;
+       if ((hsotg->hw_params.snpsid & DWC2_CORE_REV_MASK) <
+               (DWC2_CORE_REV_4_20a & DWC2_CORE_REV_MASK)) {
+               if (dwc2_hsotg_wait_bit_clear(hsotg, GRSTCTL,
+                                             GRSTCTL_CSFTRST, 10000)) {
+                       dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST\n",
+                                __func__);
+                       return -EBUSY;
+               }
+       } else {
+               if (dwc2_hsotg_wait_bit_set(hsotg, GRSTCTL,
+                                           GRSTCTL_CSFTRST_DONE, 10000)) {
+                       dev_warn(hsotg->dev, "%s: HANG! Soft Reset timeout GRSTCTL_CSFTRST_DONE\n",
+                                __func__);
+                       return -EBUSY;
+               }
+               greset = dwc2_readl(hsotg, GRSTCTL);
+               greset &= ~GRSTCTL_CSFTRST;
+               greset |= GRSTCTL_CSFTRST_DONE;
+               dwc2_writel(hsotg, greset, GRSTCTL);
        }
 
        /* Wait for AHB master IDLE state */
index 668d1ad646a4acc60034be648985fa1fc84eb819..132d687f1590db8d7e2df011f78589b70ae886c1 100644 (file)
@@ -1103,8 +1103,10 @@ struct dwc2_hsotg {
 #define DWC2_CORE_REV_3_00a    0x4f54300a
 #define DWC2_CORE_REV_3_10a    0x4f54310a
 #define DWC2_CORE_REV_4_00a    0x4f54400a
+#define DWC2_CORE_REV_4_20a    0x4f54420a
 #define DWC2_FS_IOT_REV_1_00a  0x5531100a
 #define DWC2_HS_IOT_REV_1_00a  0x5532100a
+#define DWC2_CORE_REV_MASK     0x0000ffff
 
        /* DWC OTG HW Core ID */
 #define DWC2_OTG_ID            0x4f540000
@@ -1309,6 +1311,8 @@ void dwc2_force_dr_mode(struct dwc2_hsotg *hsotg);
 
 bool dwc2_is_controller_alive(struct dwc2_hsotg *hsotg);
 
+int dwc2_check_core_version(struct dwc2_hsotg *hsotg);
+
 /*
  * Common core Functions.
  * The following functions support managing the DWC_otg controller in either
index 864b76a0b954d720415e71ee9822186401de6d41..c3d6dde2aca45cd28ae5a67b3a358e9a8e5fa05b 100644 (file)
 #define GRSTCTL                                HSOTG_REG(0x010)
 #define GRSTCTL_AHBIDLE                        BIT(31)
 #define GRSTCTL_DMAREQ                 BIT(30)
+#define GRSTCTL_CSFTRST_DONE           BIT(29)
 #define GRSTCTL_TXFNUM_MASK            (0x1f << 6)
 #define GRSTCTL_TXFNUM_SHIFT           6
 #define GRSTCTL_TXFNUM_LIMIT           0x1f
index 8ccc83f7eb3fcfe1b4b511734a8ff90e1e54b0eb..ce736d67c7c34ee9aa9696255132cbcab7eba6aa 100644 (file)
@@ -782,25 +782,6 @@ int dwc2_get_hwparams(struct dwc2_hsotg *hsotg)
        u32 hwcfg1, hwcfg2, hwcfg3, hwcfg4;
        u32 grxfsiz;
 
-       /*
-        * Attempt to ensure this device is really a DWC_otg Controller.
-        * Read and verify the GSNPSID register contents. The value should be
-        * 0x45f4xxxx, 0x5531xxxx or 0x5532xxxx
-        */
-
-       hw->snpsid = dwc2_readl(hsotg, GSNPSID);
-       if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID &&
-           (hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID &&
-           (hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_IOT_ID) {
-               dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n",
-                       hw->snpsid);
-               return -ENODEV;
-       }
-
-       dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n",
-               hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
-               hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
-
        hwcfg1 = dwc2_readl(hsotg, GHWCFG1);
        hwcfg2 = dwc2_readl(hsotg, GHWCFG2);
        hwcfg3 = dwc2_readl(hsotg, GHWCFG3);
index 69972750e161252e676e0f3b749194cf2bc31bf5..e571c8ae65ec01913ca2ffb81c5b7e78788c29f9 100644 (file)
@@ -362,6 +362,37 @@ static bool dwc2_check_core_endianness(struct dwc2_hsotg *hsotg)
        return true;
 }
 
+/**
+ * Check core version
+ *
+ * @hsotg: Programming view of the DWC_otg controller
+ *
+ */
+int dwc2_check_core_version(struct dwc2_hsotg *hsotg)
+{
+       struct dwc2_hw_params *hw = &hsotg->hw_params;
+
+       /*
+        * Attempt to ensure this device is really a DWC_otg Controller.
+        * Read and verify the GSNPSID register contents. The value should be
+        * 0x45f4xxxx, 0x5531xxxx or 0x5532xxxx
+        */
+
+       hw->snpsid = dwc2_readl(hsotg, GSNPSID);
+       if ((hw->snpsid & GSNPSID_ID_MASK) != DWC2_OTG_ID &&
+           (hw->snpsid & GSNPSID_ID_MASK) != DWC2_FS_IOT_ID &&
+           (hw->snpsid & GSNPSID_ID_MASK) != DWC2_HS_IOT_ID) {
+               dev_err(hsotg->dev, "Bad value for GSNPSID: 0x%08x\n",
+                       hw->snpsid);
+               return -ENODEV;
+       }
+
+       dev_dbg(hsotg->dev, "Core Release: %1x.%1x%1x%1x (snpsid=%x)\n",
+               hw->snpsid >> 12 & 0xf, hw->snpsid >> 8 & 0xf,
+               hw->snpsid >> 4 & 0xf, hw->snpsid & 0xf, hw->snpsid);
+       return 0;
+}
+
 /**
  * dwc2_driver_probe() - Called when the DWC_otg core is bound to the DWC_otg
  * driver
@@ -444,6 +475,14 @@ static int dwc2_driver_probe(struct platform_device *dev)
                of_property_read_bool(dev->dev.of_node,
                                      "snps,need-phy-for-wake");
 
+       /*
+        * Before performing any core related operations
+        * check core version.
+        */
+       retval = dwc2_check_core_version(hsotg);
+       if (retval)
+               goto error;
+
        /*
         * Reset before dwc2_get_hwparams() then it could get power-on real
         * reset value form registers.