Skip to content

Commit cc5bfc4

Browse files
Thinh Nguyengregkh
authored andcommitted
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: stable <stable@kernel.org> Signed-off-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Link: https://lore.kernel.org/r/633aef0afee7d56d2316f7cc3e1b2a6d518a8cc9.1738280911.git.Thinh.Nguyen@synopsys.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 2b66ef8 commit cc5bfc4

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
@@ -131,11 +131,24 @@ void dwc3_enable_susphy(struct dwc3 *dwc, bool enable)
131131
}
132132
}
133133

134-
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
134+
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy)
135135
{
136+
unsigned int hw_mode;
136137
u32 reg;
137138

138139
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
140+
141+
/*
142+
* For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE and
143+
* GUSB2PHYCFG.SUSPHY should be cleared during mode switching,
144+
* and they can be set after core initialization.
145+
*/
146+
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
147+
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD && !ignore_susphy) {
148+
if (DWC3_GCTL_PRTCAP(reg) != mode)
149+
dwc3_enable_susphy(dwc, false);
150+
}
151+
139152
reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
140153
reg |= DWC3_GCTL_PRTCAPDIR(mode);
141154
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
@@ -216,7 +229,7 @@ static void __dwc3_set_mode(struct work_struct *work)
216229

217230
spin_lock_irqsave(&dwc->lock, flags);
218231

219-
dwc3_set_prtcap(dwc, desired_dr_role);
232+
dwc3_set_prtcap(dwc, desired_dr_role, false);
220233

221234
spin_unlock_irqrestore(&dwc->lock, flags);
222235

@@ -658,16 +671,7 @@ static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index)
658671
*/
659672
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
660673

661-
/*
662-
* Above DWC_usb3.0 1.94a, it is recommended to set
663-
* DWC3_GUSB3PIPECTL_SUSPHY to '0' during coreConsultant configuration.
664-
* So default value will be '0' when the core is reset. Application
665-
* needs to set it to '1' after the core initialization is completed.
666-
*
667-
* Similarly for DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be
668-
* cleared after power-on reset, and it can be set after core
669-
* initialization.
670-
*/
674+
/* Ensure the GUSB3PIPECTL.SUSPENDENABLE is cleared prior to phy init. */
671675
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
672676

673677
if (dwc->u2ss_inp3_quirk)
@@ -747,15 +751,7 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index)
747751
break;
748752
}
749753

750-
/*
751-
* Above DWC_usb3.0 1.94a, it is recommended to set
752-
* DWC3_GUSB2PHYCFG_SUSPHY to '0' during coreConsultant configuration.
753-
* So default value will be '0' when the core is reset. Application
754-
* needs to set it to '1' after the core initialization is completed.
755-
*
756-
* Similarly for DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared
757-
* after power-on reset, and it can be set after core initialization.
758-
*/
754+
/* Ensure the GUSB2PHYCFG.SUSPHY is cleared prior to phy init. */
759755
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
760756

761757
if (dwc->dis_enblslpm_quirk)
@@ -830,6 +826,25 @@ static int dwc3_phy_init(struct dwc3 *dwc)
830826
goto err_exit_usb3_phy;
831827
}
832828

829+
/*
830+
* Above DWC_usb3.0 1.94a, it is recommended to set
831+
* DWC3_GUSB3PIPECTL_SUSPHY and DWC3_GUSB2PHYCFG_SUSPHY to '0' during
832+
* coreConsultant configuration. So default value will be '0' when the
833+
* core is reset. Application needs to set it to '1' after the core
834+
* initialization is completed.
835+
*
836+
* Certain phy requires to be in P0 power state during initialization.
837+
* Make sure GUSB3PIPECTL.SUSPENDENABLE and GUSB2PHYCFG.SUSPHY are clear
838+
* prior to phy init to maintain in the P0 state.
839+
*
840+
* After phy initialization, some phy operations can only be executed
841+
* while in lower P states. Ensure GUSB3PIPECTL.SUSPENDENABLE and
842+
* GUSB2PHYCFG.SUSPHY are set soon after initialization to avoid
843+
* blocking phy ops.
844+
*/
845+
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
846+
dwc3_enable_susphy(dwc, true);
847+
833848
return 0;
834849

835850
err_exit_usb3_phy:
@@ -1588,7 +1603,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
15881603

15891604
switch (dwc->dr_mode) {
15901605
case USB_DR_MODE_PERIPHERAL:
1591-
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
1606+
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, false);
15921607

15931608
if (dwc->usb2_phy)
15941609
otg_set_vbus(dwc->usb2_phy->otg, false);
@@ -1600,7 +1615,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
16001615
return dev_err_probe(dev, ret, "failed to initialize gadget\n");
16011616
break;
16021617
case USB_DR_MODE_HOST:
1603-
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
1618+
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST, false);
16041619

16051620
if (dwc->usb2_phy)
16061621
otg_set_vbus(dwc->usb2_phy->otg, true);
@@ -1645,7 +1660,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
16451660
}
16461661

16471662
/* de-assert DRVVBUS for HOST and OTG mode */
1648-
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
1663+
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, true);
16491664
}
16501665

16511666
static void dwc3_get_software_properties(struct dwc3 *dwc)
@@ -2453,15 +2468,15 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
24532468
if (ret)
24542469
return ret;
24552470

2456-
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE);
2471+
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_DEVICE, true);
24572472
dwc3_gadget_resume(dwc);
24582473
break;
24592474
case DWC3_GCTL_PRTCAP_HOST:
24602475
if (!PMSG_IS_AUTO(msg) && !device_may_wakeup(dwc->dev)) {
24612476
ret = dwc3_core_init_for_resume(dwc);
24622477
if (ret)
24632478
return ret;
2464-
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST);
2479+
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST, true);
24652480
break;
24662481
}
24672482
/* Restore GUSB2PHYCFG bits that were modified in suspend */
@@ -2490,7 +2505,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
24902505
if (ret)
24912506
return ret;
24922507

2493-
dwc3_set_prtcap(dwc, dwc->current_dr_role);
2508+
dwc3_set_prtcap(dwc, dwc->current_dr_role, true);
24942509

24952510
dwc3_otg_init(dwc);
24962511
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
@@ -1558,7 +1558,7 @@ struct dwc3_gadget_ep_cmd_params {
15581558
#define DWC3_HAS_OTG BIT(3)
15591559

15601560
/* prototypes */
1561-
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode);
1561+
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy);
15621562
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
15631563
u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type);
15641564

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;
@@ -556,7 +556,7 @@ int dwc3_drd_init(struct dwc3 *dwc)
556556

557557
dwc3_drd_update(dwc);
558558
} else {
559-
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
559+
dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG, true);
560560

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

0 commit comments

Comments
 (0)