USB: dwc3_otg: Reset hardware before starting peripheral

USB endpoints can be configured either in DBM or non-DBM mode.
DBM mode is used for BAM to BAM uses case e.g. QDSS, and
non-DBM mode is used for normal device use.
Once an endpoint is configured DBM mode mode, hardware has
to be RESET and re-initialized if endpoint has to be used in
non-DBM mode e.g. changing USB composition from QDSS to non-QDSS.

Currently hardware is RESET as part of moving from host to
peripheral mode. Move this RESET from stop_host to start_peripheral.
Additionally, user is required to reconnect USB cable for RESET to
take place.

CRs-Fixed: 432474
Change-Id: I12fe7d8a2523ba02f454e01191275fc71c3f0091
Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
diff --git a/drivers/usb/dwc3/dwc3_otg.c b/drivers/usb/dwc3/dwc3_otg.c
index 361aa32..eb879e3 100644
--- a/drivers/usb/dwc3/dwc3_otg.c
+++ b/drivers/usb/dwc3/dwc3_otg.c
@@ -179,16 +179,6 @@
 			return ret;
 		}
 		dwc3_otg_notify_host_mode(otg, on);
-
-		/* Do block reset for Host <-> peripheral switching to work */
-		if (ext_xceiv && ext_xceiv->otg_capability &&
-						ext_xceiv->ext_block_reset)
-			ext_xceiv->ext_block_reset();
-
-		/* re-init core and OTG register as XHCI reset clears it */
-		dwc3_post_host_reset_core_init(dwc);
-		if (ext_xceiv && !ext_xceiv->otg_capability)
-			dwc3_otg_reset(dotg);
 	}
 
 	return 0;
@@ -235,6 +225,8 @@
 static int dwc3_otg_start_peripheral(struct usb_otg *otg, int on)
 {
 	struct dwc3_otg *dotg = container_of(otg, struct dwc3_otg, otg);
+	struct dwc3_ext_xceiv *ext_xceiv = dotg->ext_xceiv;
+	struct dwc3 *dwc = dotg->dwc;
 
 	if (!otg->gadget)
 		return -EINVAL;
@@ -242,6 +234,22 @@
 	if (on) {
 		dev_dbg(otg->phy->dev, "%s: turn on gadget %s\n",
 					__func__, otg->gadget->name);
+
+		/*
+		 * Hardware reset is required to support below scenarios:
+		 * 1. Host <-> peripheral switching
+		 * 2. Once an endpoint is configured in DBM (BAM) mode, it
+		 * can be unconfigured only after RESET
+		 */
+		if (ext_xceiv && ext_xceiv->otg_capability &&
+						ext_xceiv->ext_block_reset)
+			ext_xceiv->ext_block_reset();
+
+		/* re-init core and OTG registers as block reset clears these */
+		dwc3_post_host_reset_core_init(dwc);
+		if (ext_xceiv && !ext_xceiv->otg_capability)
+			dwc3_otg_reset(dotg);
+
 		dwc3_otg_set_peripheral_regs(dotg);
 		usb_gadget_vbus_connect(otg->gadget);
 	} else {