@@ -156,6 +156,9 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy)
156156 dwc -> current_dr_role = mode ;
157157}
158158
159+ static void dwc3_core_exit (struct dwc3 * dwc );
160+ static int dwc3_core_init_for_resume (struct dwc3 * dwc );
161+
159162static void __dwc3_set_mode (struct work_struct * work )
160163{
161164 struct dwc3 * dwc = work_to_dwc (work );
@@ -175,7 +178,7 @@ static void __dwc3_set_mode(struct work_struct *work)
175178 if (dwc -> current_dr_role == DWC3_GCTL_PRTCAP_OTG )
176179 dwc3_otg_update (dwc , 0 );
177180
178- if (!desired_dr_role )
181+ if (!desired_dr_role && ! dwc -> role_switch_reset_quirk )
179182 goto out ;
180183
181184 if (desired_dr_role == dwc -> current_dr_role )
@@ -203,13 +206,32 @@ static void __dwc3_set_mode(struct work_struct *work)
203206 break ;
204207 }
205208
209+ if (dwc -> role_switch_reset_quirk ) {
210+ if (dwc -> current_dr_role ) {
211+ dwc -> current_dr_role = 0 ;
212+ dwc3_core_exit (dwc );
213+ }
214+
215+ if (desired_dr_role ) {
216+ ret = dwc3_core_init_for_resume (dwc );
217+ if (ret ) {
218+ dev_err (dwc -> dev ,
219+ "failed to reinitialize core\n" );
220+ goto out ;
221+ }
222+ } else {
223+ goto out ;
224+ }
225+ }
226+
206227 /*
207228 * When current_dr_role is not set, there's no role switching.
208229 * Only perform GCTL.CoreSoftReset when there's DRD role switching.
209230 */
210- if (dwc -> current_dr_role && ((DWC3_IP_IS (DWC3 ) ||
231+ if (dwc -> role_switch_reset_quirk ||
232+ (dwc -> current_dr_role && ((DWC3_IP_IS (DWC3 ) ||
211233 DWC3_VER_IS_PRIOR (DWC31 , 190 A )) &&
212- desired_dr_role != DWC3_GCTL_PRTCAP_OTG )) {
234+ desired_dr_role != DWC3_GCTL_PRTCAP_OTG ))) {
213235 reg = dwc3_readl (dwc -> regs , DWC3_GCTL );
214236 reg |= DWC3_GCTL_CORESOFTRESET ;
215237 dwc3_writel (dwc -> regs , DWC3_GCTL , reg );
@@ -1370,6 +1392,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
13701392 if (ret )
13711393 goto err_exit_phy ;
13721394
1395+ if (dwc -> role_switch_reset_quirk )
1396+ dwc3_enable_susphy (dwc , true);
1397+
13731398 dwc3_core_setup_global_control (dwc );
13741399 dwc3_core_num_eps (dwc );
13751400
@@ -1613,6 +1638,18 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
16131638 ret = dwc3_drd_init (dwc );
16141639 if (ret )
16151640 return dev_err_probe (dev , ret , "failed to initialize dual-role\n" );
1641+
1642+ /*
1643+ * If the role switch reset quirk is required the first role
1644+ * switch notification will initialize the core such that we
1645+ * have to shut it down here. Make sure that the __dwc3_set_mode
1646+ * queued by dwc3_drd_init has completed before since it
1647+ * may still try to access MMIO.
1648+ */
1649+ if (dwc -> role_switch_reset_quirk ) {
1650+ flush_work (& dwc -> drd_work );
1651+ dwc3_core_exit (dwc );
1652+ }
16161653 break ;
16171654 default :
16181655 dev_err (dev , "Unsupported mode of operation %d\n" , dwc -> dr_mode );
@@ -2198,6 +2235,23 @@ static int dwc3_probe(struct platform_device *pdev)
21982235 if (ret )
21992236 goto err_put_psy ;
22002237
2238+ if (dev -> of_node ) {
2239+ if (of_device_is_compatible (dev -> of_node , "apple,dwc3" )) {
2240+ if (!IS_ENABLED (CONFIG_USB_ROLE_SWITCH ) ||
2241+ !IS_ENABLED (CONFIG_USB_DWC3_DUAL_ROLE )) {
2242+ dev_err (dev ,
2243+ "Apple DWC3 requires role switch support.\n"
2244+ );
2245+ ret = - EINVAL ;
2246+ goto err_put_psy ;
2247+ }
2248+
2249+ dwc -> dr_mode = USB_DR_MODE_OTG ;
2250+ dwc -> role_switch_reset_quirk = true;
2251+ dwc -> no_early_roothub_poweroff = true;
2252+ }
2253+ }
2254+
22012255 ret = reset_control_deassert (dwc -> reset );
22022256 if (ret )
22032257 goto err_put_psy ;
@@ -2337,7 +2391,6 @@ static void dwc3_remove(struct platform_device *pdev)
23372391 power_supply_put (dwc -> usb_psy );
23382392}
23392393
2340- #ifdef CONFIG_PM
23412394static int dwc3_core_init_for_resume (struct dwc3 * dwc )
23422395{
23432396 int ret ;
@@ -2364,6 +2417,7 @@ static int dwc3_core_init_for_resume(struct dwc3 *dwc)
23642417 return ret ;
23652418}
23662419
2420+ #ifdef CONFIG_PM
23672421static int dwc3_suspend_common (struct dwc3 * dwc , pm_message_t msg )
23682422{
23692423 u32 reg ;
0 commit comments