From 6ad580141ff343ae523bf4fde1c622accf4617bb Mon Sep 17 00:00:00 2001 From: William Wu Date: Tue, 30 Mar 2021 11:15:03 +0800 Subject: [PATCH] usb: xhci: fix u2 bus suspend for Rockchip SNPS 3.0 xHC Rockchip SNPS xHC 3.0 set USB 2.0 PHY enter suspend mode from DWC3 core if the suspend conditions are valid (as per DWC3 controller databook 6.3.46 GUSB2PHYCFG register bit6). In this case, it needs to set the bus_suspended bit for USB 2.0, so that in xhci_bus_resume, it can set the xHC link state to XDEV_RESUME and send USB resume signal to USB 2.0 device. Test on RK3568 USB 3.0 Host interface with USB 2.0 Camera or USB 2.0 HUB which support USB auto suspend. Without this patch, the xHC fails to send USB resume signal on the USB bus to wakeup the USB 2.0 devices, and cause xHC died. Change-Id: Icb5a553d71a5f3144d77f8d5a5132892a5795285 Signed-off-by: William Wu --- drivers/usb/host/xhci-hub.c | 14 ++++++++++++++ drivers/usb/host/xhci-plat.c | 4 ++++ drivers/usb/host/xhci.h | 1 + 3 files changed, 19 insertions(+) diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index e6e8bed11aea..c8018cd8e4fe 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -1568,7 +1568,21 @@ retry: t2 &= ~PORT_PLS_MASK; t2 |= PORT_LINK_STROBE | XDEV_U3; set_bit(port_index, &bus_state->bus_suspended); + } else if ((xhci->quirks & XHCI_U2_BROKEN_SUSPEND) && + (hcd->speed < HCD_USB3) && + (t1 & PORT_PLS_MASK) == XDEV_U3) { + /* + * Rockchip SNPS xHC 3.0 set USB 2.0 PHY enter + * suspend mode from DWC3 core if the suspend + * conditions are valid. In this case, it need + * to set the bus_suspended bit for USB 2.0, so + * that in xhci_bus_resume, it can set the xHC + * link state to XDEV_RESUME and send USB resume + * signal to USB 2.0 device. + */ + set_bit(port_index, &bus_state->bus_suspended); } + /* USB core sets remote wake mask for USB 3.0 hubs, * including the USB 3.0 roothub, but only if CONFIG_PM * is enabled, so also enable remote wake here. diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c index 09dceed14f82..688b968f1bdc 100644 --- a/drivers/usb/host/xhci-plat.c +++ b/drivers/usb/host/xhci-plat.c @@ -301,6 +301,10 @@ static int xhci_plat_probe(struct platform_device *pdev) "xhci-warm-reset-on-suspend")) xhci->quirks |= XHCI_WARM_RESET_ON_SUSPEND; + if (device_property_read_bool(tmpdev, + "xhci-u2-broken-suspend")) + xhci->quirks |= XHCI_U2_BROKEN_SUSPEND; + device_property_read_u32(tmpdev, "imod-interval-ns", &xhci->imod_interval); } diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 56a618616323..301217641765 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1889,6 +1889,7 @@ struct xhci_hcd { #define XHCI_DIS_AUTOSUSPEND BIT_ULL(37) #define XHCI_DISABLE_SPARSE BIT_ULL(38) #define XHCI_WARM_RESET_ON_SUSPEND BIT_ULL(39) +#define XHCI_U2_BROKEN_SUSPEND BIT_ULL(40) unsigned int num_active_eps; unsigned int limit_active_eps;