UPSTREAM: usb: dwc2: Avoid double-reset at boot time
authorJacob Chen <jacob2.chen@rock-chips.com>
Tue, 16 Aug 2016 01:10:43 +0000 (09:10 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Thu, 18 Aug 2016 10:48:46 +0000 (18:48 +0800)
In (usb: dwc2: reset dwc2 core before dwc2_get_hwparams()) we added an
extra reset to the probe path for the dwc2 USB controllers.  This
allowed proper detection of parameters even if the firmware had already
used the USB part.

Unfortunately, this extra reset is quite slow and is affecting boot
speed.  We can avoid the double-reset by skipping the extra reset that
would happen just after the one we added.  Logic that explains why this
is safe:

* As of the CL mentioned above, we now always call dwc2_core_reset() in
  dwc2_driver_probe() before dwc2_hcd_init().

* The only caller of dwc2_hcd_init() is dwc2_driver_probe(), so we're
  guaranteed that dwc2_core_reset() was called before dwc2_hdc_init().

* dwc2_hdc_init() is the only caller that passes an irq other than -1 to
  dwc2_core_init().  Thus if dwc2_core_init() is called with an irq
  other than -1 we're guaranteed that dwc2_core_reset was called before
  dwc2_core_init().

...this allows us to remove the dwc2_core_reset() in dwc2_core_init() if
irq is not < 0.

Note that since "irq" wasn't used in the function dwc2_core_init()
anyway and since select_phy was always set at exactly the same times we
could avoid the reset, we remove "irq" and rename "select_phy" to
"initial_setup" and adjust the callers accordingly.

Change-Id: Id3b085ddc9d35baca140fc8a502fca74dcfd01b5
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Jacob Chen <jacob2.chen@rock-chips.com>
(cherry picked from commit 0fe239bc190453fe82252c6d41a74e685730cd93)

drivers/usb/dwc2/core.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/hcd.c

index bb2ab81145dbb6d076f5457920069be7587a87cf..e75adac676022330256d02a3b596b4ac40e753d6 100644 (file)
@@ -765,11 +765,10 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
  * dwc2_core_init() - Initializes the DWC_otg controller registers and
  * prepares the core for device mode or host mode operation
  *
- * @hsotg:      Programming view of the DWC_otg controller
- * @select_phy: If true then also set the Phy type
- * @irq:        If >= 0, the irq to register
+ * @hsotg:         Programming view of the DWC_otg controller
+ * @initial_setup: If true then this is the first init for this instance.
  */
-int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
+int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup)
 {
        u32 usbcfg, otgctl;
        int retval;
@@ -791,18 +790,26 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
 
        dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
 
-       /* Reset the Controller */
-       retval = dwc2_core_reset(hsotg);
-       if (retval) {
-               dev_err(hsotg->dev, "%s(): Reset failed, aborting\n",
-                               __func__);
-               return retval;
+       /*
+        * Reset the Controller
+        *
+        * We only need to reset the controller if this is a re-init.
+        * For the first init we know for sure that earlier code reset us (it
+        * needed to in order to properly detect various parameters).
+        */
+       if (!initial_setup) {
+               retval = dwc2_core_reset(hsotg);
+               if (retval) {
+                       dev_err(hsotg->dev, "%s(): Reset failed, aborting\n",
+                                       __func__);
+                       return retval;
+               }
        }
 
        /*
         * This needs to happen in FS mode before any other programming occurs
         */
-       retval = dwc2_phy_init(hsotg, select_phy);
+       retval = dwc2_phy_init(hsotg, initial_setup);
        if (retval)
                return retval;
 
index b99cc9c75918a01181f2ed8073271b5fe367528f..907da681930a850949963e0bcc0c658c92838b49 100644 (file)
@@ -929,7 +929,7 @@ extern void dwc2_read_packet(struct dwc2_hsotg *hsotg, u8 *dest, u16 bytes);
 extern void dwc2_flush_tx_fifo(struct dwc2_hsotg *hsotg, const int num);
 extern void dwc2_flush_rx_fifo(struct dwc2_hsotg *hsotg);
 
-extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq);
+extern int dwc2_core_init(struct dwc2_hsotg *hsotg, bool initial_setup);
 extern void dwc2_enable_global_interrupts(struct dwc2_hsotg *hcd);
 extern void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd);
 
index 571c21727ff9f5cb8c774eeb1178cfc55e8e88b4..1224ce2742a54c48b99c1ca327f504854f7e2cce 100644 (file)
@@ -1382,7 +1382,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
                        dev_err(hsotg->dev,
                                "Connection id status change timed out\n");
                hsotg->op_state = OTG_STATE_B_PERIPHERAL;
-               dwc2_core_init(hsotg, false, -1);
+               dwc2_core_init(hsotg, false);
                dwc2_enable_global_interrupts(hsotg);
                spin_lock_irqsave(&hsotg->lock, flags);
                dwc2_hsotg_core_init_disconnected(hsotg, false);
@@ -1405,7 +1405,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
                hsotg->op_state = OTG_STATE_A_HOST;
 
                /* Initialize the Core for Host mode */
-               dwc2_core_init(hsotg, false, -1);
+               dwc2_core_init(hsotg, false);
                dwc2_enable_global_interrupts(hsotg);
                dwc2_hcd_start(hsotg);
        }
@@ -3054,7 +3054,7 @@ int dwc2_hcd_init(struct dwc2_hsotg *hsotg, int irq)
        dwc2_disable_global_interrupts(hsotg);
 
        /* Initialize the DWC_otg core, and select the Phy type */
-       retval = dwc2_core_init(hsotg, true, irq);
+       retval = dwc2_core_init(hsotg, true);
        if (retval)
                goto error2;