usb: dwc2: Avoid double-reset at boot time
authorDouglas Anderson <dianders@chromium.org>
Thu, 17 Dec 2015 19:14:40 +0000 (11:14 -0800)
committerFelipe Balbi <balbi@ti.com>
Tue, 22 Dec 2015 17:52:08 +0000 (11:52 -0600)
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.

Signed-off-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: John Youn <johnyoun@synopsys.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/dwc2/core.c
drivers/usb/dwc2/core.h
drivers/usb/dwc2/hcd.c

index 0a584ecb233f88ea9b5a8eeb38730e237e268ac8..af12778b0e96ed7aca7113347b79c7fdefc30eb6 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 d1d855af63e676b6bb6138aff3f5269174e5afbe..cbece3a68c30edc6f2848caf1ace801bb6ce3f79 100644 (file)
@@ -918,7 +918,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 880b549f737aea5419e71211dc4be8edfef631b3..8847c72e55f676213624012a80f92aa206d04115 100644 (file)
@@ -1420,7 +1420,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);
@@ -1443,7 +1443,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);
        }
@@ -3120,7 +3120,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;