@@ -125,11 +125,24 @@ void dwc3_enable_susphy(struct dwc3 *dwc, bool enable)
125
125
dwc3_writel (dwc -> regs , DWC3_GUSB2PHYCFG (0 ), reg );
126
126
}
127
127
128
- void dwc3_set_prtcap (struct dwc3 * dwc , u32 mode )
128
+ void dwc3_set_prtcap (struct dwc3 * dwc , u32 mode , bool ignore_susphy )
129
129
{
130
+ unsigned int hw_mode ;
130
131
u32 reg ;
131
132
132
133
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
+
133
146
reg &= ~(DWC3_GCTL_PRTCAPDIR (DWC3_GCTL_PRTCAP_OTG ));
134
147
reg |= DWC3_GCTL_PRTCAPDIR (mode );
135
148
dwc3_writel (dwc -> regs , DWC3_GCTL , reg );
@@ -209,7 +222,7 @@ static void __dwc3_set_mode(struct work_struct *work)
209
222
210
223
spin_lock_irqsave (& dwc -> lock , flags );
211
224
212
- dwc3_set_prtcap (dwc , desired_dr_role );
225
+ dwc3_set_prtcap (dwc , desired_dr_role , false );
213
226
214
227
spin_unlock_irqrestore (& dwc -> lock , flags );
215
228
@@ -646,16 +659,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
646
659
*/
647
660
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX ;
648
661
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. */
659
663
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY ;
660
664
661
665
if (dwc -> u2ss_inp3_quirk )
@@ -728,15 +732,7 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
728
732
break ;
729
733
}
730
734
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. */
740
736
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY ;
741
737
742
738
if (dwc -> dis_enblslpm_quirk )
@@ -777,6 +773,25 @@ static int dwc3_phy_init(struct dwc3 *dwc)
777
773
if (ret < 0 )
778
774
goto err_exit_usb2_phy ;
779
775
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 , 194 A ))
793
+ dwc3_enable_susphy (dwc , true);
794
+
780
795
return 0 ;
781
796
782
797
err_exit_usb2_phy :
@@ -1447,7 +1462,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
1447
1462
1448
1463
switch (dwc -> dr_mode ) {
1449
1464
case USB_DR_MODE_PERIPHERAL :
1450
- dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_DEVICE );
1465
+ dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_DEVICE , false );
1451
1466
1452
1467
if (dwc -> usb2_phy )
1453
1468
otg_set_vbus (dwc -> usb2_phy -> otg , false);
@@ -1459,7 +1474,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
1459
1474
return dev_err_probe (dev , ret , "failed to initialize gadget\n" );
1460
1475
break ;
1461
1476
case USB_DR_MODE_HOST :
1462
- dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_HOST );
1477
+ dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_HOST , false );
1463
1478
1464
1479
if (dwc -> usb2_phy )
1465
1480
otg_set_vbus (dwc -> usb2_phy -> otg , true);
@@ -1502,7 +1517,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
1502
1517
}
1503
1518
1504
1519
/* 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 );
1506
1521
}
1507
1522
1508
1523
static void dwc3_get_properties (struct dwc3 * dwc )
@@ -2206,15 +2221,15 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
2206
2221
if (ret )
2207
2222
return ret ;
2208
2223
2209
- dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_DEVICE );
2224
+ dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_DEVICE , true );
2210
2225
dwc3_gadget_resume (dwc );
2211
2226
break ;
2212
2227
case DWC3_GCTL_PRTCAP_HOST :
2213
2228
if (!PMSG_IS_AUTO (msg ) && !device_may_wakeup (dwc -> dev )) {
2214
2229
ret = dwc3_core_init_for_resume (dwc );
2215
2230
if (ret )
2216
2231
return ret ;
2217
- dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_HOST );
2232
+ dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_HOST , true );
2218
2233
break ;
2219
2234
}
2220
2235
/* Restore GUSB2PHYCFG bits that were modified in suspend */
@@ -2239,7 +2254,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
2239
2254
if (ret )
2240
2255
return ret ;
2241
2256
2242
- dwc3_set_prtcap (dwc , dwc -> current_dr_role );
2257
+ dwc3_set_prtcap (dwc , dwc -> current_dr_role , true );
2243
2258
2244
2259
dwc3_otg_init (dwc );
2245
2260
if (dwc -> current_otg_role == DWC3_OTG_ROLE_HOST ) {
0 commit comments