+++ /dev/null
-From f88359e1588b85cf0e8209ab7d6620085f3441d9 Mon Sep 17 00:00:00 2001
-From: Yu Chen <chenyu56@huawei.com>
-Date: Thu, 15 Apr 2021 15:20:30 -0700
-Subject: usb: dwc3: core: Do core softreset when switch mode
-
-From: Yu Chen <chenyu56@huawei.com>
-
-commit f88359e1588b85cf0e8209ab7d6620085f3441d9 upstream.
-
-From: John Stultz <john.stultz@linaro.org>
-
-According to the programming guide, to switch mode for DRD controller,
-the driver needs to do the following.
-
-To switch from device to host:
-1. Reset controller with GCTL.CoreSoftReset
-2. Set GCTL.PrtCapDir(host mode)
-3. Reset the host with USBCMD.HCRESET
-4. Then follow up with the initializing host registers sequence
-
-To switch from host to device:
-1. Reset controller with GCTL.CoreSoftReset
-2. Set GCTL.PrtCapDir(device mode)
-3. Reset the device with DCTL.CSftRst
-4. Then follow up with the initializing registers sequence
-
-Currently we're missing step 1) to do GCTL.CoreSoftReset and step 3) of
-switching from host to device. John Stult reported a lockup issue seen
-with HiKey960 platform without these steps[1]. Similar issue is observed
-with Ferry's testing platform[2].
-
-So, apply the required steps along with some fixes to Yu Chen's and John
-Stultz's version. The main fixes to their versions are the missing wait
-for clocks synchronization before clearing GCTL.CoreSoftReset and only
-apply DCTL.CSftRst when switching from host to device.
-
-[1] https://lore.kernel.org/linux-usb/20210108015115.27920-1-john.stultz@linaro.org/
-[2] https://lore.kernel.org/linux-usb/0ba7a6ba-e6a7-9cd4-0695-64fc927e01f1@gmail.com/
-
-Fixes: 41ce1456e1db ("usb: dwc3: core: make dwc3_set_mode() work properly")
-Cc: Andy Shevchenko <andy.shevchenko@gmail.com>
-Cc: Ferry Toth <fntoth@gmail.com>
-Cc: Wesley Cheng <wcheng@codeaurora.org>
-Cc: <stable@vger.kernel.org>
-Tested-by: John Stultz <john.stultz@linaro.org>
-Tested-by: Wesley Cheng <wcheng@codeaurora.org>
-Signed-off-by: Yu Chen <chenyu56@huawei.com>
-Signed-off-by: John Stultz <john.stultz@linaro.org>
-Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
-Link: https://lore.kernel.org/r/374440f8dcd4f06c02c2caf4b1efde86774e02d9.1618521663.git.Thinh.Nguyen@synopsys.com
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-Signed-off-by: Hardik Gohil <hgohil@mvista.com>
-Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
----
- drivers/usb/dwc3/core.c | 25 +++++++++++++++++++++++++
- drivers/usb/dwc3/core.h | 5 +++++
- 2 files changed, 30 insertions(+)
-
---- a/drivers/usb/dwc3/core.c
-+++ b/drivers/usb/dwc3/core.c
-@@ -122,6 +122,8 @@ static void __dwc3_set_mode(struct work_
- if (dwc->dr_mode != USB_DR_MODE_OTG)
- return;
-
-+ mutex_lock(&dwc->mutex);
-+
- pm_runtime_get_sync(dwc->dev);
-
- if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG)
-@@ -155,6 +157,25 @@ static void __dwc3_set_mode(struct work_
- break;
- }
-
-+ /* For DRD host or device mode only */
-+ if (dwc->desired_dr_role != DWC3_GCTL_PRTCAP_OTG) {
-+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
-+ reg |= DWC3_GCTL_CORESOFTRESET;
-+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
-+
-+ /*
-+ * Wait for internal clocks to synchronized. DWC_usb31 and
-+ * DWC_usb32 may need at least 50ms (less for DWC_usb3). To
-+ * keep it consistent across different IPs, let's wait up to
-+ * 100ms before clearing GCTL.CORESOFTRESET.
-+ */
-+ msleep(100);
-+
-+ reg = dwc3_readl(dwc->regs, DWC3_GCTL);
-+ reg &= ~DWC3_GCTL_CORESOFTRESET;
-+ dwc3_writel(dwc->regs, DWC3_GCTL, reg);
-+ }
-+
- spin_lock_irqsave(&dwc->lock, flags);
-
- dwc3_set_prtcap(dwc, dwc->desired_dr_role);
-@@ -179,6 +200,8 @@ static void __dwc3_set_mode(struct work_
- }
- break;
- case DWC3_GCTL_PRTCAP_DEVICE:
-+ dwc3_core_soft_reset(dwc);
-+
- dwc3_event_buffers_setup(dwc);
-
- if (dwc->usb2_phy)
-@@ -201,6 +224,7 @@ static void __dwc3_set_mode(struct work_
- out:
- pm_runtime_mark_last_busy(dwc->dev);
- pm_runtime_put_autosuspend(dwc->dev);
-+ mutex_unlock(&dwc->mutex);
- }
-
- void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
-@@ -1511,6 +1535,7 @@ static int dwc3_probe(struct platform_de
- dwc3_cache_hwparams(dwc);
-
- spin_lock_init(&dwc->lock);
-+ mutex_init(&dwc->mutex);
-
- pm_runtime_get_noresume(dev);
- pm_runtime_set_active(dev);
---- a/drivers/usb/dwc3/core.h
-+++ b/drivers/usb/dwc3/core.h
-@@ -13,6 +13,7 @@
-
- #include <linux/device.h>
- #include <linux/spinlock.h>
-+#include <linux/mutex.h>
- #include <linux/ioport.h>
- #include <linux/list.h>
- #include <linux/bitops.h>
-@@ -929,6 +930,7 @@ struct dwc3_scratchpad_array {
- * @scratch_addr: dma address of scratchbuf
- * @ep0_in_setup: one control transfer is completed and enter setup phase
- * @lock: for synchronizing
-+ * @mutex: for mode switching
- * @dev: pointer to our struct device
- * @sysdev: pointer to the DMA-capable device
- * @xhci: pointer to our xHCI child
-@@ -1061,6 +1063,9 @@ struct dwc3 {
- /* device lock */
- spinlock_t lock;
-
-+ /* mode switching lock */
-+ struct mutex mutex;
-+
- struct device *dev;
- struct device *sysdev;
-