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-msm.c b/drivers/usb/dwc3/dwc3-msm.c
index 9c9c923..934ddc4 100644
--- a/drivers/usb/dwc3/dwc3-msm.c
+++ b/drivers/usb/dwc3/dwc3-msm.c
@@ -860,6 +860,10 @@
 	struct dwc3_ep *dep = to_dwc3_ep(ep);
 	struct usb_ep_ops *new_ep_ops;
 
+	dwc3_msm_event_buffer_config(dwc3_msm_read_reg(context->base,
+			DWC3_GEVNTADRLO(0)),
+			dwc3_msm_read_reg(context->base, DWC3_GEVNTSIZ(0)));
+
 	/* Save original ep ops for future restore*/
 	if (context->original_ep_ops[dep->number]) {
 		dev_err(context->dev,
@@ -1262,6 +1266,11 @@
 
 	/* Reinitialize QSCRATCH registers after block reset */
 	dwc3_msm_qscratch_reg_init(mdwc);
+
+	/* Reset the DBM */
+	dwc3_msm_dbm_soft_reset(1);
+	usleep_range(1000, 1200);
+	dwc3_msm_dbm_soft_reset(0);
 }
 
 static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
@@ -2261,15 +2270,6 @@
 			dev_err(&pdev->dev, "Failed to vote for bus scaling\n");
 	}
 
-	/* Reset the DBM */
-	dwc3_msm_dbm_soft_reset(1);
-	usleep_range(1000, 1200);
-	dwc3_msm_dbm_soft_reset(0);
-
-	dwc3_msm_event_buffer_config(dwc3_msm_read_reg(msm->base,
-							DWC3_GEVNTADRLO(0)),
-				dwc3_msm_read_reg(msm->base, DWC3_GEVNTSIZ(0)));
-
 	msm->otg_xceiv = usb_get_transceiver();
 	if (msm->otg_xceiv) {
 		msm->charger.start_detection = dwc3_start_chg_det;
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 {