]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 22 Apr 2025 08:38:12 +0000 (10:38 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 22 Apr 2025 08:38:12 +0000 (10:38 +0200)
added patches:
usb-dwc3-core-do-core-softreset-when-switch-mode.patch
usb-dwc3-support-continuous-runtime-pm-with-dual-role.patch

queue-5.4/series
queue-5.4/usb-dwc3-core-do-core-softreset-when-switch-mode.patch [new file with mode: 0644]
queue-5.4/usb-dwc3-support-continuous-runtime-pm-with-dual-role.patch [new file with mode: 0644]

index f83dfc768ca2bd97b83002fbd1be3d99ff6dff3f..8ad521b61684bcc47b4e94fc7fae622256e3dd75 100644 (file)
@@ -113,3 +113,5 @@ powerpc-prom_init-use-ffreestanding-to-avoid-a-reference-to-bcmp.patch
 tcp-dccp-don-t-use-timer_pending-in-reqsk_queue_unlink.patch
 misc-pci_endpoint_test-avoid-issue-of-interrupts-remaining-after-request_irq-error.patch
 misc-pci_endpoint_test-fix-irq_type-to-convey-the-correct-type.patch
+usb-dwc3-support-continuous-runtime-pm-with-dual-role.patch
+usb-dwc3-core-do-core-softreset-when-switch-mode.patch
diff --git a/queue-5.4/usb-dwc3-core-do-core-softreset-when-switch-mode.patch b/queue-5.4/usb-dwc3-core-do-core-softreset-when-switch-mode.patch
new file mode 100644 (file)
index 0000000..8aef6e7
--- /dev/null
@@ -0,0 +1,148 @@
+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;
diff --git a/queue-5.4/usb-dwc3-support-continuous-runtime-pm-with-dual-role.patch b/queue-5.4/usb-dwc3-support-continuous-runtime-pm-with-dual-role.patch
new file mode 100644 (file)
index 0000000..790927b
--- /dev/null
@@ -0,0 +1,56 @@
+From c2cd3452d5f8b66d49a73138fba5baadd5b489bd Mon Sep 17 00:00:00 2001
+From: Martin Kepplinger <martin.kepplinger@puri.sm>
+Date: Thu, 19 Mar 2020 11:02:07 +0100
+Subject: usb: dwc3: support continuous runtime PM with dual role
+
+From: Martin Kepplinger <martin.kepplinger@puri.sm>
+
+commit c2cd3452d5f8b66d49a73138fba5baadd5b489bd upstream.
+
+The DRD module calls dwc3_set_mode() on role switches, i.e. when a device is
+being plugged in. In order to support continuous runtime power management when
+plugging in / unplugging a cable, we need to call pm_runtime_get_sync() in
+this path.
+
+Signed-off-by: Martin Kepplinger <martin.kepplinger@puri.sm>
+Signed-off-by: Felipe Balbi <balbi@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/usb/dwc3/core.c |   11 ++++++++---
+ 1 file changed, 8 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/dwc3/core.c
++++ b/drivers/usb/dwc3/core.c
+@@ -122,17 +122,19 @@ static void __dwc3_set_mode(struct work_
+       if (dwc->dr_mode != USB_DR_MODE_OTG)
+               return;
++      pm_runtime_get_sync(dwc->dev);
++
+       if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG)
+               dwc3_otg_update(dwc, 0);
+       if (!dwc->desired_dr_role)
+-              return;
++              goto out;
+       if (dwc->desired_dr_role == dwc->current_dr_role)
+-              return;
++              goto out;
+       if (dwc->desired_dr_role == DWC3_GCTL_PRTCAP_OTG && dwc->edev)
+-              return;
++              goto out;
+       switch (dwc->current_dr_role) {
+       case DWC3_GCTL_PRTCAP_HOST:
+@@ -196,6 +198,9 @@ static void __dwc3_set_mode(struct work_
+               break;
+       }
++out:
++      pm_runtime_mark_last_busy(dwc->dev);
++      pm_runtime_put_autosuspend(dwc->dev);
+ }
+ void dwc3_set_mode(struct dwc3 *dwc, u32 mode)