@@ -131,11 +131,24 @@ void dwc3_enable_susphy(struct dwc3 *dwc, bool enable)
131
131
}
132
132
}
133
133
134
- void dwc3_set_prtcap (struct dwc3 * dwc , u32 mode )
134
+ void dwc3_set_prtcap (struct dwc3 * dwc , u32 mode , bool ignore_susphy )
135
135
{
136
+ unsigned int hw_mode ;
136
137
u32 reg ;
137
138
138
139
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
+
139
152
reg &= ~(DWC3_GCTL_PRTCAPDIR (DWC3_GCTL_PRTCAP_OTG ));
140
153
reg |= DWC3_GCTL_PRTCAPDIR (mode );
141
154
dwc3_writel (dwc -> regs , DWC3_GCTL , reg );
@@ -216,7 +229,7 @@ static void __dwc3_set_mode(struct work_struct *work)
216
229
217
230
spin_lock_irqsave (& dwc -> lock , flags );
218
231
219
- dwc3_set_prtcap (dwc , desired_dr_role );
232
+ dwc3_set_prtcap (dwc , desired_dr_role , false );
220
233
221
234
spin_unlock_irqrestore (& dwc -> lock , flags );
222
235
@@ -658,16 +671,7 @@ static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index)
658
671
*/
659
672
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX ;
660
673
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. */
671
675
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY ;
672
676
673
677
if (dwc -> u2ss_inp3_quirk )
@@ -747,15 +751,7 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index)
747
751
break ;
748
752
}
749
753
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. */
759
755
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY ;
760
756
761
757
if (dwc -> dis_enblslpm_quirk )
@@ -830,6 +826,25 @@ static int dwc3_phy_init(struct dwc3 *dwc)
830
826
goto err_exit_usb3_phy ;
831
827
}
832
828
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 , 194 A ))
846
+ dwc3_enable_susphy (dwc , true);
847
+
833
848
return 0 ;
834
849
835
850
err_exit_usb3_phy :
@@ -1588,7 +1603,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
1588
1603
1589
1604
switch (dwc -> dr_mode ) {
1590
1605
case USB_DR_MODE_PERIPHERAL :
1591
- dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_DEVICE );
1606
+ dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_DEVICE , false );
1592
1607
1593
1608
if (dwc -> usb2_phy )
1594
1609
otg_set_vbus (dwc -> usb2_phy -> otg , false);
@@ -1600,7 +1615,7 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
1600
1615
return dev_err_probe (dev , ret , "failed to initialize gadget\n" );
1601
1616
break ;
1602
1617
case USB_DR_MODE_HOST :
1603
- dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_HOST );
1618
+ dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_HOST , false );
1604
1619
1605
1620
if (dwc -> usb2_phy )
1606
1621
otg_set_vbus (dwc -> usb2_phy -> otg , true);
@@ -1645,7 +1660,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
1645
1660
}
1646
1661
1647
1662
/* 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 );
1649
1664
}
1650
1665
1651
1666
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)
2453
2468
if (ret )
2454
2469
return ret ;
2455
2470
2456
- dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_DEVICE );
2471
+ dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_DEVICE , true );
2457
2472
dwc3_gadget_resume (dwc );
2458
2473
break ;
2459
2474
case DWC3_GCTL_PRTCAP_HOST :
2460
2475
if (!PMSG_IS_AUTO (msg ) && !device_may_wakeup (dwc -> dev )) {
2461
2476
ret = dwc3_core_init_for_resume (dwc );
2462
2477
if (ret )
2463
2478
return ret ;
2464
- dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_HOST );
2479
+ dwc3_set_prtcap (dwc , DWC3_GCTL_PRTCAP_HOST , true );
2465
2480
break ;
2466
2481
}
2467
2482
/* Restore GUSB2PHYCFG bits that were modified in suspend */
@@ -2490,7 +2505,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
2490
2505
if (ret )
2491
2506
return ret ;
2492
2507
2493
- dwc3_set_prtcap (dwc , dwc -> current_dr_role );
2508
+ dwc3_set_prtcap (dwc , dwc -> current_dr_role , true );
2494
2509
2495
2510
dwc3_otg_init (dwc );
2496
2511
if (dwc -> current_otg_role == DWC3_OTG_ROLE_HOST ) {
0 commit comments