@@ -143,6 +143,9 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
143143 dwc -> current_dr_role = mode ;
144144}
145145
146+ static void dwc3_core_exit (struct dwc3 * dwc );
147+ static int dwc3_core_init_for_resume (struct dwc3 * dwc );
148+
146149static void __dwc3_set_mode (struct work_struct * work )
147150{
148151 struct dwc3 * dwc = work_to_dwc (work );
@@ -162,7 +165,7 @@ static void __dwc3_set_mode(struct work_struct *work)
162165 if (dwc -> current_dr_role == DWC3_GCTL_PRTCAP_OTG )
163166 dwc3_otg_update (dwc , 0 );
164167
165- if (!desired_dr_role )
168+ if (!desired_dr_role && ! dwc -> role_switch_reset_quirk )
166169 goto out ;
167170
168171 if (desired_dr_role == dwc -> current_dr_role )
@@ -190,13 +193,32 @@ static void __dwc3_set_mode(struct work_struct *work)
190193 break ;
191194 }
192195
196+ if (dwc -> role_switch_reset_quirk ) {
197+ if (dwc -> current_dr_role ) {
198+ dwc -> current_dr_role = 0 ;
199+ dwc3_core_exit (dwc );
200+ }
201+
202+ if (desired_dr_role ) {
203+ ret = dwc3_core_init_for_resume (dwc );
204+ if (ret ) {
205+ dev_err (dwc -> dev ,
206+ "failed to reinitialize core\n" );
207+ goto out ;
208+ }
209+ } else {
210+ goto out ;
211+ }
212+ }
213+
193214 /*
194215 * When current_dr_role is not set, there's no role switching.
195216 * Only perform GCTL.CoreSoftReset when there's DRD role switching.
196217 */
197- if (dwc -> current_dr_role && ((DWC3_IP_IS (DWC3 ) ||
218+ if (dwc -> role_switch_reset_quirk ||
219+ (dwc -> current_dr_role && ((DWC3_IP_IS (DWC3 ) ||
198220 DWC3_VER_IS_PRIOR (DWC31 , 190 A )) &&
199- desired_dr_role != DWC3_GCTL_PRTCAP_OTG )) {
221+ desired_dr_role != DWC3_GCTL_PRTCAP_OTG ))) {
200222 reg = dwc3_readl (dwc -> regs , DWC3_GCTL );
201223 reg |= DWC3_GCTL_CORESOFTRESET ;
202224 dwc3_writel (dwc -> regs , DWC3_GCTL , reg );
@@ -1355,6 +1377,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
13551377 if (ret )
13561378 goto err_exit_phy ;
13571379
1380+ if (dwc -> role_switch_reset_quirk )
1381+ dwc3_enable_susphy (dwc , true);
1382+
13581383 dwc3_core_setup_global_control (dwc );
13591384 dwc3_core_num_eps (dwc );
13601385
@@ -1594,6 +1619,18 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
15941619 ret = dwc3_drd_init (dwc );
15951620 if (ret )
15961621 return dev_err_probe (dev , ret , "failed to initialize dual-role\n" );
1622+
1623+ /*
1624+ * If the role switch reset quirk is required the first role
1625+ * switch notification will initialize the core such that we
1626+ * have to shut it down here. Make sure that the __dwc3_set_mode
1627+ * queued by dwc3_drd_init has completed before since it
1628+ * may still try to access MMIO.
1629+ */
1630+ if (dwc -> role_switch_reset_quirk ) {
1631+ flush_work (& dwc -> drd_work );
1632+ dwc3_core_exit (dwc );
1633+ }
15971634 break ;
15981635 default :
15991636 dev_err (dev , "Unsupported mode of operation %d\n" , dwc -> dr_mode );
@@ -2171,6 +2208,22 @@ static int dwc3_probe(struct platform_device *pdev)
21712208 if (ret )
21722209 goto err_put_psy ;
21732210
2211+ if (dev -> of_node ) {
2212+ if (of_device_is_compatible (dev -> of_node , "apple,dwc3" )) {
2213+ if (!IS_ENABLED (CONFIG_USB_ROLE_SWITCH ) ||
2214+ !IS_ENABLED (CONFIG_USB_DWC3_DUAL_ROLE )) {
2215+ dev_err (dev ,
2216+ "Apple DWC3 requires role switch support.\n"
2217+ );
2218+ ret = - EINVAL ;
2219+ goto err_put_psy ;
2220+ }
2221+
2222+ dwc -> dr_mode = USB_DR_MODE_OTG ;
2223+ dwc -> role_switch_reset_quirk = true;
2224+ }
2225+ }
2226+
21742227 ret = reset_control_deassert (dwc -> reset );
21752228 if (ret )
21762229 goto err_put_psy ;
@@ -2310,7 +2363,6 @@ static void dwc3_remove(struct platform_device *pdev)
23102363 power_supply_put (dwc -> usb_psy );
23112364}
23122365
2313- #ifdef CONFIG_PM
23142366static int dwc3_core_init_for_resume (struct dwc3 * dwc )
23152367{
23162368 int ret ;
@@ -2337,6 +2389,7 @@ static int dwc3_core_init_for_resume(struct dwc3 *dwc)
23372389 return ret ;
23382390}
23392391
2392+ #ifdef CONFIG_PM
23402393static int dwc3_suspend_common (struct dwc3 * dwc , pm_message_t msg )
23412394{
23422395 u32 reg ;
0 commit comments