Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 6d73572

Browse files
Thinh Nguyengregkh
authored andcommitted
usb: dwc3: core: Prevent phy suspend during init
GUSB3PIPECTL.SUSPENDENABLE and GUSB2PHYCFG.SUSPHY should be cleared during initialization. Suspend during initialization can result in undefined behavior due to clock synchronization failure, which often seen as core soft reset timeout. The programming guide recommended these bits to be cleared during initialization for DWC_usb3.0 version 1.94 and above (along with DWC_usb31 and DWC_usb32). The current check in the driver does not account if it's set by default setting from coreConsultant. This is especially the case for DRD when switching mode to ensure the phy clocks are available to change mode. Depending on the platforms/design, some may be affected more than others. This is noted in the DWC_usb3x programming guide under the above registers. Let's just disable them during driver load and mode switching. Restore them when the controller initialization completes. Note that some platforms workaround this issue by disabling phy suspend through "snps,dis_u3_susphy_quirk" and "snps,dis_u2_susphy_quirk" when they should not need to. Cc: [email protected] Fixes: 9ba3aca ("usb: dwc3: Disable phy suspend after power-on reset") Signed-off-by: Thinh Nguyen <[email protected]> Link: https://lore.kernel.org/r/20da4e5a0c4678c9587d3da23f83bdd6d77353e9.1713394973.git.Thinh.Nguyen@synopsys.com Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 4a237d5 commit 6d73572

File tree

4 files changed

+68
-52
lines changed

4 files changed

+68
-52
lines changed

drivers/usb/dwc3/core.c

Lines changed: 38 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,27 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
104104
return 0;
105105
}
106106

107+
void dwc3_enable_susphy(struct dwc3 *dwc, bool enable)
108+
{
109+
u32 reg;
110+
111+
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
112+
if (enable && !dwc->dis_u3_susphy_quirk)
113+
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
114+
else
115+
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
116+
117+
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
118+
119+
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
120+
if (enable && !dwc->dis_u2_susphy_quirk)
121+
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
122+
else
123+
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
124+
125+
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
126+
}
127+
107128
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
108129
{
109130
u32 reg;
@@ -585,11 +606,8 @@ static int dwc3_core_ulpi_init(struct dwc3 *dwc)
585606
*/
586607
static int dwc3_phy_setup(struct dwc3 *dwc)
587608
{
588-
unsigned int hw_mode;
589609
u32 reg;
590610

591-
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
592-
593611
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
594612

595613
/*
@@ -599,21 +617,16 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
599617
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
600618

601619
/*
602-
* Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
603-
* to '0' during coreConsultant configuration. So default value
604-
* will be '0' when the core is reset. Application needs to set it
605-
* to '1' after the core initialization is completed.
606-
*/
607-
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
608-
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
609-
610-
/*
611-
* For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be cleared after
612-
* power-on reset, and it can be set after core initialization, which is
613-
* after device soft-reset during initialization.
620+
* Above DWC_usb3.0 1.94a, it is recommended to set
621+
* DWC3_GUSB3PIPECTL_SUSPHY to '0' during coreConsultant configuration.
622+
* So default value will be '0' when the core is reset. Application
623+
* needs to set it to '1' after the core initialization is completed.
624+
*
625+
* Similarly for DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be
626+
* cleared after power-on reset, and it can be set after core
627+
* initialization.
614628
*/
615-
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
616-
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
629+
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
617630

618631
if (dwc->u2ss_inp3_quirk)
619632
reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
@@ -639,9 +652,6 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
639652
if (dwc->tx_de_emphasis_quirk)
640653
reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
641654

642-
if (dwc->dis_u3_susphy_quirk)
643-
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
644-
645655
if (dwc->dis_del_phy_power_chg_quirk)
646656
reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
647657

@@ -689,24 +699,15 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
689699
}
690700

691701
/*
692-
* Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
693-
* '0' during coreConsultant configuration. So default value will
694-
* be '0' when the core is reset. Application needs to set it to
695-
* '1' after the core initialization is completed.
696-
*/
697-
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
698-
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
699-
700-
/*
701-
* For DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared after
702-
* power-on reset, and it can be set after core initialization, which is
703-
* after device soft-reset during initialization.
702+
* Above DWC_usb3.0 1.94a, it is recommended to set
703+
* DWC3_GUSB2PHYCFG_SUSPHY to '0' during coreConsultant configuration.
704+
* So default value will be '0' when the core is reset. Application
705+
* needs to set it to '1' after the core initialization is completed.
706+
*
707+
* Similarly for DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared
708+
* after power-on reset, and it can be set after core initialization.
704709
*/
705-
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
706-
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
707-
708-
if (dwc->dis_u2_susphy_quirk)
709-
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
710+
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
710711

711712
if (dwc->dis_enblslpm_quirk)
712713
reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
@@ -1227,21 +1228,6 @@ static int dwc3_core_init(struct dwc3 *dwc)
12271228
if (ret)
12281229
goto err_exit_phy;
12291230

1230-
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD &&
1231-
!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) {
1232-
if (!dwc->dis_u3_susphy_quirk) {
1233-
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
1234-
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
1235-
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
1236-
}
1237-
1238-
if (!dwc->dis_u2_susphy_quirk) {
1239-
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
1240-
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
1241-
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
1242-
}
1243-
}
1244-
12451231
dwc3_core_setup_global_control(dwc);
12461232
dwc3_core_num_eps(dwc);
12471233

drivers/usb/dwc3/core.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1580,6 +1580,7 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc);
15801580
void dwc3_event_buffers_cleanup(struct dwc3 *dwc);
15811581

15821582
int dwc3_core_soft_reset(struct dwc3 *dwc);
1583+
void dwc3_enable_susphy(struct dwc3 *dwc, bool enable);
15831584

15841585
#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
15851586
int dwc3_host_init(struct dwc3 *dwc);

drivers/usb/dwc3/gadget.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2924,6 +2924,7 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
29242924
dwc3_ep0_out_start(dwc);
29252925

29262926
dwc3_gadget_enable_irq(dwc);
2927+
dwc3_enable_susphy(dwc, true);
29272928

29282929
return 0;
29292930

@@ -4690,6 +4691,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
46904691
if (!dwc->gadget)
46914692
return;
46924693

4694+
dwc3_enable_susphy(dwc, false);
46934695
usb_del_gadget(dwc->gadget);
46944696
dwc3_gadget_free_endpoints(dwc);
46954697
usb_put_gadget(dwc->gadget);

drivers/usb/dwc3/host.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@
1010
#include <linux/irq.h>
1111
#include <linux/of.h>
1212
#include <linux/platform_device.h>
13+
#include <linux/usb.h>
14+
#include <linux/usb/hcd.h>
1315

1416
#include "../host/xhci-port.h"
1517
#include "../host/xhci-ext-caps.h"
1618
#include "../host/xhci-caps.h"
19+
#include "../host/xhci-plat.h"
1720
#include "core.h"
1821

1922
#define XHCI_HCSPARAMS1 0x4
@@ -57,6 +60,24 @@ static void dwc3_power_off_all_roothub_ports(struct dwc3 *dwc)
5760
}
5861
}
5962

63+
static void dwc3_xhci_plat_start(struct usb_hcd *hcd)
64+
{
65+
struct platform_device *pdev;
66+
struct dwc3 *dwc;
67+
68+
if (!usb_hcd_is_primary_hcd(hcd))
69+
return;
70+
71+
pdev = to_platform_device(hcd->self.controller);
72+
dwc = dev_get_drvdata(pdev->dev.parent);
73+
74+
dwc3_enable_susphy(dwc, true);
75+
}
76+
77+
static const struct xhci_plat_priv dwc3_xhci_plat_quirk = {
78+
.plat_start = dwc3_xhci_plat_start,
79+
};
80+
6081
static void dwc3_host_fill_xhci_irq_res(struct dwc3 *dwc,
6182
int irq, char *name)
6283
{
@@ -167,6 +188,11 @@ int dwc3_host_init(struct dwc3 *dwc)
167188
}
168189
}
169190

191+
ret = platform_device_add_data(xhci, &dwc3_xhci_plat_quirk,
192+
sizeof(struct xhci_plat_priv));
193+
if (ret)
194+
goto err;
195+
170196
ret = platform_device_add(xhci);
171197
if (ret) {
172198
dev_err(dwc->dev, "failed to register xHCI device\n");
@@ -192,6 +218,7 @@ void dwc3_host_exit(struct dwc3 *dwc)
192218
if (dwc->sys_wakeup)
193219
device_init_wakeup(&dwc->xhci->dev, false);
194220

221+
dwc3_enable_susphy(dwc, false);
195222
platform_device_unregister(dwc->xhci);
196223
dwc->xhci = NULL;
197224
}

0 commit comments

Comments
 (0)