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

Commit 55cef59

Browse files
roychl666Treehugger Robot
authored andcommitted
BACKPORT: FROMLIST: usb: dwc3: Set SUSPENDENABLE soon after phy init
After phy initialization, some phy operations can only be executed while in lower P states. Ensure GUSB3PIPECTL.SUSPENDENABLE and GUSB2PHYCFG.SUSPHY are set soon after initialization to avoid blocking phy ops. Previously the SUSPENDENABLE bits are only set after the controller initialization, which may not happen right away if there's no gadget driver or xhci driver bound. Revise this to clear SUSPENDENABLE bits only when there's mode switching (change in GCTL.PRTCAPDIR). Fixes: 6d73572 ("usb: dwc3: core: Prevent phy suspend during init") Cc: [email protected] Signed-off-by: Thinh Nguyen <[email protected]> Bug: 374242909 Bug: 359966146 Test: gadget enumeration Link: https://lore.kernel.org/linux-usb/633aef0afee7d56d2316f7cc3e1b2a6d518a8cc9.1738280911.git.Thinh.Nguyen@synopsys.com/ Change-Id: Ib2cb7c6f0f5c7082fa18155403633e36f589ebbc Signed-off-by: Roy Luo <[email protected]>
1 parent a47cc5b commit 55cef59

File tree

3 files changed

+45
-30
lines changed

3 files changed

+45
-30
lines changed

drivers/usb/dwc3/core.c

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -125,11 +125,24 @@ void dwc3_enable_susphy(struct dwc3 *dwc, bool enable)
125125
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
126126
}
127127

128-
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
128+
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy)
129129
{
130+
unsigned int hw_mode;
130131
u32 reg;
131132

132133
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
134+
135+
/*
136+
* For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE and
137+
* GUSB2PHYCFG.SUSPHY should be cleared during mode switching,
138+
* and they can be set after core initialization.
139+
*/
140+
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
141+
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && !ignore_susphy) {
142+
if (DWC3_GCTL_PRTCAP(reg) != mode)
143+
dwc3_enable_susphy(dwc, false);
144+
}
145+
133146
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
134147
reg |= DWC3_GCTL_PRTCAPDIR(mode);
135148
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
@@ -209,7 +222,7 @@ static void __dwc3_set_mode(struct work_struct *work)
209222

210223
spin_lock_irqsave(&dwc->lock, flags);
211224

212-
dwc3_set_prtcap(dwc, desired_dr_role);
225+
dwc3_set_prtcap(dwc, desired_dr_role, false);
213226

214227
spin_unlock_irqrestore(&dwc->lock, flags);
215228

@@ -646,16 +659,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
646659
*/
647660
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
648661

649-
/*
650-
* Above DWC_usb3.0 1.94a, it is recommended to set
651-
* DWC3_GUSB3PIPECTL_SUSPHY to '0' during coreConsultant configuration.
652-
* So default value will be '0' when the core is reset. Application
653-
* needs to set it to '1' after the core initialization is completed.
654-
*
655-
* Similarly for DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be
656-
* cleared after power-on reset, and it can be set after core
657-
* initialization.
658-
*/
662+
/* Ensure the GUSB3PIPECTL.SUSPENDENABLE is cleared prior to phy init. */
659663
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
660664

661665
if (dwc->u2ss_inp3_quirk)
@@ -728,15 +732,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
728732
break;
729733
}
730734

731-
/*
732-
* Above DWC_usb3.0 1.94a, it is recommended to set
733-
* DWC3_GUSB2PHYCFG_SUSPHY to '0' during coreConsultant configuration.
734-
* So default value will be '0' when the core is reset. Application
735-
* needs to set it to '1' after the core initialization is completed.
736-
*
737-
* Similarly for DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared
738-
* after power-on reset, and it can be set after core initialization.
739-
*/
735+
/* Ensure the GUSB2PHYCFG.SUSPHY is cleared prior to phy init. */
740736
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
741737

742738
if (dwc->dis_enblslpm_quirk)
@@ -777,6 +773,25 @@ static int dwc3_phy_init(struct dwc3 *dwc)
777773
if (ret < 0)
778774
goto err_exit_usb2_phy;
779775

776+
/*
777+
* Above DWC_usb3.0 1.94a, it is recommended to set
778+
* DWC3_GUSB3PIPECTL_SUSPHY and DWC3_GUSB2PHYCFG_SUSPHY to '0' during
779+
* coreConsultant configuration. So default value will be '0' when the
780+
* core is reset. Application needs to set it to '1' after the core
781+
* initialization is completed.
782+
*
783+
* Certain phy requires to be in P0 power state during initialization.
784+
* Make sure GUSB3PIPECTL.SUSPENDENABLE and GUSB2PHYCFG.SUSPHY are clear
785+
* prior to phy init to maintain in the P0 state.
786+
*
787+
* After phy initialization, some phy operations can only be executed
788+
* while in lower P states. Ensure GUSB3PIPECTL.SUSPENDENABLE and
789+
* GUSB2PHYCFG.SUSPHY are set soon after initialization to avoid
790+
* blocking phy ops.
791+
*/
792+
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
793+
dwc3_enable_susphy(dwc, true);
794+
780795
return 0;
781796

782797
err_exit_usb2_phy:
@@ -1447,7 +1462,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
14471462

14481463
switch (dwc->dr_mode) {
14491464
case USB_DR_MODE_PERIPHERAL:
1450-
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
1465+
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, false);
14511466

14521467
if (dwc->usb2_phy)
14531468
otg_set_vbus(dwc->usb2_phy->otg, false);
@@ -1459,7 +1474,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
14591474
return dev_err_probe(dev, ret, "failed to initialize gadget\n");
14601475
break;
14611476
case USB_DR_MODE_HOST:
1462-
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
1477+
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST, false);
14631478

14641479
if (dwc->usb2_phy)
14651480
otg_set_vbus(dwc->usb2_phy->otg, true);
@@ -1502,7 +1517,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
15021517
}
15031518

15041519
/* de-assert DRVVBUS for HOST and OTG mode */
1505-
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
1520+
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, true);
15061521
}
15071522

15081523
static void dwc3_get_properties(struct dwc3 *dwc)
@@ -2206,15 +2221,15 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
22062221
if (ret)
22072222
return ret;
22082223

2209-
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
2224+
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, true);
22102225
dwc3_gadget_resume(dwc);
22112226
break;
22122227
case DWC3_GCTL_PRTCAP_HOST:
22132228
if (!PMSG_IS_AUTO(msg) && !device_may_wakeup(dwc->dev)) {
22142229
ret = dwc3_core_init_for_resume(dwc);
22152230
if (ret)
22162231
return ret;
2217-
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
2232+
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST, true);
22182233
break;
22192234
}
22202235
/* Restore GUSB2PHYCFG bits that were modified in suspend */
@@ -2239,7 +2254,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
22392254
if (ret)
22402255
return ret;
22412256

2242-
dwc3_set_prtcap(dwc, dwc->current_dr_role);
2257+
dwc3_set_prtcap(dwc, dwc->current_dr_role, true);
22432258

22442259
dwc3_otg_init(dwc);
22452260
if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) {

drivers/usb/dwc3/core.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1549,7 +1549,7 @@ struct dwc3_gadget_ep_cmd_params {
15491549
#define DWC3_HAS_OTG BIT(3)
15501550

15511551
/* prototypes */
1552-
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode);
1552+
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy);
15531553
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
15541554
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
15551555

drivers/usb/dwc3/drd.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ void dwc3_otg_init(struct dwc3 *dwc)
173173
* block "Initialize GCTL for OTG operation".
174174
*/
175175
/* GCTL.PrtCapDir=2'b11 */
176-
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
176+
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG, true);
177177
/* GUSB2PHYCFG0.SusPHY=0 */
178178
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
179179
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
@@ -553,7 +553,7 @@ int dwc3_drd_init(struct dwc3 *dwc)
553553

554554
dwc3_drd_update(dwc);
555555
} else {
556-
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
556+
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG, true);
557557

558558
/* use OTG block to get ID event */
559559
irq = dwc3_otg_get_irq(dwc);

0 commit comments

Comments
 (0)