[PATCH 1/2] usb: dwc3: wait for the port to leave RxDetect before xHCI reset
From: Xu Yang
Date: Fri Nov 06 2026 - 06:31:28 EST
From: Xu Yang <xu.yang_2@xxxxxxx>
When the host controller loses power during system suspend, the port
state is not retained. After power is restored, the port starts in the
Disconnected (RxDetect) state instead of its previous Enabled (U3)
state.
After the controller is switched back to host mode, testing on an i.MX8/9
SoC shows that it takes about 2 ms for the port to leave RxDetect and
enter Polling. If xHCI is reset while the port is still in RxDetect, the
port does not issue a Warm Reset.
This prevents the link from recovering because the USB3 device may
still be in U3. Once the port enters Polling, it sends LFPS.Polling, but
the device does not respond as expected. After three Polling attempts,
each taking about 360 ms (tPollingLFPSTimeout), the controller reports
the device as disconnected.
If xHCI is reset after the port has entered Polling, the port issues a
Warm Reset and the link recovers quickly after the device responds.
Add a 2 ms delay through the xHCI resume quirk before resetting xHCI.
This allows the port to leave RxDetect so that a Warm Reset can be
issued, avoiding an unnecessary device disconnect during system
resume.
Signed-off-by: Xu Yang <xu.yang_2@xxxxxxx>
---
drivers/usb/dwc3/host.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index c5674161b2b0..465c170df12c 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -78,8 +78,29 @@ static void dwc3_xhci_plat_start(struct usb_hcd *hcd)
dwc3_enable_susphy(dwc, true);
}
+static int dwc3_xhci_resume_quirk(struct usb_hcd *hcd)
+{
+ struct platform_device *pdev;
+ struct dwc3 *dwc;
+
+ pdev = to_platform_device(hcd->self.controller);
+ dwc = dev_get_drvdata(pdev->dev.parent);
+
+ if (dwc->needs_full_reinit) {
+ /*
+ * The port needs some time to leave RxDetect after host mode
+ * is restored. Delay the xHCI reset until the port can enter
+ * Polling, allowing a Warm Reset to recover the USB3 link.
+ */
+ usleep_range(2000, 2500);
+ }
+
+ return 0;
+}
+
static const struct xhci_plat_priv dwc3_xhci_plat_quirk = {
.plat_start = dwc3_xhci_plat_start,
+ .resume_quirk = dwc3_xhci_resume_quirk,
};
static void dwc3_host_fill_xhci_irq_res(struct dwc3 *dwc,
--
2.34.1