@@ -158,6 +158,9 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy)
158158 dwc -> current_dr_role = mode ;
159159}
160160
161+ static void dwc3_core_exit (struct dwc3 * dwc );
162+ static int dwc3_core_init_for_resume (struct dwc3 * dwc );
163+
161164static void __dwc3_set_mode (struct work_struct * work )
162165{
163166 struct dwc3 * dwc = work_to_dwc (work );
@@ -177,7 +180,7 @@ static void __dwc3_set_mode(struct work_struct *work)
177180 if (dwc -> current_dr_role == DWC3_GCTL_PRTCAP_OTG )
178181 dwc3_otg_update (dwc , 0 );
179182
180- if (!desired_dr_role )
183+ if (!desired_dr_role && ! dwc -> role_switch_reset_quirk )
181184 goto out ;
182185
183186 if (desired_dr_role == dwc -> current_dr_role )
@@ -205,13 +208,32 @@ static void __dwc3_set_mode(struct work_struct *work)
205208 break ;
206209 }
207210
211+ if (dwc -> role_switch_reset_quirk ) {
212+ if (dwc -> current_dr_role ) {
213+ dwc -> current_dr_role = 0 ;
214+ dwc3_core_exit (dwc );
215+ }
216+
217+ if (desired_dr_role ) {
218+ ret = dwc3_core_init_for_resume (dwc );
219+ if (ret ) {
220+ dev_err (dwc -> dev ,
221+ "failed to reinitialize core\n" );
222+ goto out ;
223+ }
224+ } else {
225+ goto out ;
226+ }
227+ }
228+
208229 /*
209230 * When current_dr_role is not set, there's no role switching.
210231 * Only perform GCTL.CoreSoftReset when there's DRD role switching.
211232 */
212- if (dwc -> current_dr_role && ((DWC3_IP_IS (DWC3 ) ||
233+ if (dwc -> role_switch_reset_quirk ||
234+ (dwc -> current_dr_role && ((DWC3_IP_IS (DWC3 ) ||
213235 DWC3_VER_IS_PRIOR (DWC31 , 190 A )) &&
214- desired_dr_role != DWC3_GCTL_PRTCAP_OTG )) {
236+ desired_dr_role != DWC3_GCTL_PRTCAP_OTG ))) {
215237 reg = dwc3_readl (dwc -> regs , DWC3_GCTL );
216238 reg |= DWC3_GCTL_CORESOFTRESET ;
217239 dwc3_writel (dwc -> regs , DWC3_GCTL , reg );
@@ -1372,6 +1394,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
13721394 if (ret )
13731395 goto err_exit_phy ;
13741396
1397+ if (dwc -> role_switch_reset_quirk )
1398+ dwc3_enable_susphy (dwc , true);
1399+
13751400 dwc3_core_setup_global_control (dwc );
13761401 dwc3_core_num_eps (dwc );
13771402
@@ -1635,6 +1660,18 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
16351660 ret = dwc3_drd_init (dwc );
16361661 if (ret )
16371662 return dev_err_probe (dev , ret , "failed to initialize dual-role\n" );
1663+
1664+ /*
1665+ * If the role switch reset quirk is required the first role
1666+ * switch notification will initialize the core such that we
1667+ * have to shut it down here. Make sure that the __dwc3_set_mode
1668+ * queued by dwc3_drd_init has completed before since it
1669+ * may still try to access MMIO.
1670+ */
1671+ if (dwc -> role_switch_reset_quirk ) {
1672+ flush_work (& dwc -> drd_work );
1673+ dwc3_core_exit (dwc );
1674+ }
16381675 break ;
16391676 default :
16401677 dev_err (dev , "Unsupported mode of operation %d\n" , dwc -> dr_mode );
@@ -2223,6 +2260,23 @@ int dwc3_core_probe(const struct dwc3_probe_data *data)
22232260 goto err_put_psy ;
22242261 }
22252262
2263+ if (dev -> of_node ) {
2264+ if (of_device_is_compatible (dev -> of_node , "apple,dwc3" ) ||
2265+ of_device_is_compatible (dev -> of_node , "apple,t8103-dwc3" )) {
2266+ if (!IS_ENABLED (CONFIG_USB_ROLE_SWITCH ) ||
2267+ !IS_ENABLED (CONFIG_USB_DWC3_DUAL_ROLE )) {
2268+ dev_err (dev ,
2269+ "Apple DWC3 requires role switch support.\n"
2270+ );
2271+ ret = - EINVAL ;
2272+ goto err_put_psy ;
2273+ }
2274+
2275+ dwc -> dr_mode = USB_DR_MODE_OTG ;
2276+ dwc -> role_switch_reset_quirk = true;
2277+ }
2278+ }
2279+
22262280 ret = reset_control_deassert (dwc -> reset );
22272281 if (ret )
22282282 goto err_put_psy ;
@@ -2391,7 +2445,6 @@ static void dwc3_remove(struct platform_device *pdev)
23912445 dwc3_core_remove (platform_get_drvdata (pdev ));
23922446}
23932447
2394- #ifdef CONFIG_PM
23952448static int dwc3_core_init_for_resume (struct dwc3 * dwc )
23962449{
23972450 int ret ;
@@ -2418,6 +2471,7 @@ static int dwc3_core_init_for_resume(struct dwc3 *dwc)
24182471 return ret ;
24192472}
24202473
2474+ #ifdef CONFIG_PM
24212475static int dwc3_suspend_common (struct dwc3 * dwc , pm_message_t msg )
24222476{
24232477 u32 reg ;
@@ -2779,6 +2833,10 @@ static const struct of_device_id of_dwc3_match[] = {
27792833 {
27802834 .compatible = "synopsys,dwc3"
27812835 },
2836+ /* downstream forwards compatible for upstream dt-bindings */
2837+ {
2838+ .compatible = "apple,t8103-dwc3"
2839+ },
27822840 { },
27832841};
27842842MODULE_DEVICE_TABLE (of , of_dwc3_match );
0 commit comments