@@ -159,6 +159,9 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode, bool ignore_susphy)
159159 dwc -> current_dr_role = mode ;
160160}
161161
162+ static void dwc3_core_exit (struct dwc3 * dwc );
163+ static int dwc3_core_init_for_resume (struct dwc3 * dwc );
164+
162165static void __dwc3_set_mode (struct work_struct * work )
163166{
164167 struct dwc3 * dwc = work_to_dwc (work );
@@ -178,7 +181,7 @@ static void __dwc3_set_mode(struct work_struct *work)
178181 if (dwc -> current_dr_role == DWC3_GCTL_PRTCAP_OTG )
179182 dwc3_otg_update (dwc , 0 );
180183
181- if (!desired_dr_role )
184+ if (!desired_dr_role && ! dwc -> role_switch_reset_quirk )
182185 goto out ;
183186
184187 if (desired_dr_role == dwc -> current_dr_role )
@@ -206,13 +209,32 @@ static void __dwc3_set_mode(struct work_struct *work)
206209 break ;
207210 }
208211
212+ if (dwc -> role_switch_reset_quirk ) {
213+ if (dwc -> current_dr_role ) {
214+ dwc -> current_dr_role = 0 ;
215+ dwc3_core_exit (dwc );
216+ }
217+
218+ if (desired_dr_role ) {
219+ ret = dwc3_core_init_for_resume (dwc );
220+ if (ret ) {
221+ dev_err (dwc -> dev ,
222+ "failed to reinitialize core\n" );
223+ goto out ;
224+ }
225+ } else {
226+ goto out ;
227+ }
228+ }
229+
209230 /*
210231 * When current_dr_role is not set, there's no role switching.
211232 * Only perform GCTL.CoreSoftReset when there's DRD role switching.
212233 */
213- if (dwc -> current_dr_role && ((DWC3_IP_IS (DWC3 ) ||
234+ if (dwc -> role_switch_reset_quirk ||
235+ (dwc -> current_dr_role && ((DWC3_IP_IS (DWC3 ) ||
214236 DWC3_VER_IS_PRIOR (DWC31 , 190 A )) &&
215- desired_dr_role != DWC3_GCTL_PRTCAP_OTG )) {
237+ desired_dr_role != DWC3_GCTL_PRTCAP_OTG ))) {
216238 reg = dwc3_readl (dwc -> regs , DWC3_GCTL );
217239 reg |= DWC3_GCTL_CORESOFTRESET ;
218240 dwc3_writel (dwc -> regs , DWC3_GCTL , reg );
@@ -1373,6 +1395,9 @@ static int dwc3_core_init(struct dwc3 *dwc)
13731395 if (ret )
13741396 goto err_exit_phy ;
13751397
1398+ if (dwc -> role_switch_reset_quirk )
1399+ dwc3_enable_susphy (dwc , true);
1400+
13761401 dwc3_core_setup_global_control (dwc );
13771402 dwc3_core_num_eps (dwc );
13781403
@@ -1636,6 +1661,18 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
16361661 ret = dwc3_drd_init (dwc );
16371662 if (ret )
16381663 return dev_err_probe (dev , ret , "failed to initialize dual-role\n" );
1664+
1665+ /*
1666+ * If the role switch reset quirk is required the first role
1667+ * switch notification will initialize the core such that we
1668+ * have to shut it down here. Make sure that the __dwc3_set_mode
1669+ * queued by dwc3_drd_init has completed before since it
1670+ * may still try to access MMIO.
1671+ */
1672+ if (dwc -> role_switch_reset_quirk ) {
1673+ flush_work (& dwc -> drd_work );
1674+ dwc3_core_exit (dwc );
1675+ }
16391676 break ;
16401677 default :
16411678 dev_err (dev , "Unsupported mode of operation %d\n" , dwc -> dr_mode );
@@ -2224,6 +2261,23 @@ int dwc3_core_probe(const struct dwc3_probe_data *data)
22242261 goto err_put_psy ;
22252262 }
22262263
2264+ if (dev -> of_node ) {
2265+ if (of_device_is_compatible (dev -> of_node , "apple,dwc3" ) ||
2266+ of_device_is_compatible (dev -> of_node , "apple,t8103-dwc3" )) {
2267+ if (!IS_ENABLED (CONFIG_USB_ROLE_SWITCH ) ||
2268+ !IS_ENABLED (CONFIG_USB_DWC3_DUAL_ROLE )) {
2269+ dev_err (dev ,
2270+ "Apple DWC3 requires role switch support.\n"
2271+ );
2272+ ret = - EINVAL ;
2273+ goto err_put_psy ;
2274+ }
2275+
2276+ dwc -> dr_mode = USB_DR_MODE_OTG ;
2277+ dwc -> role_switch_reset_quirk = true;
2278+ }
2279+ }
2280+
22272281 ret = reset_control_deassert (dwc -> reset );
22282282 if (ret )
22292283 goto err_put_psy ;
@@ -2392,7 +2446,6 @@ static void dwc3_remove(struct platform_device *pdev)
23922446 dwc3_core_remove (platform_get_drvdata (pdev ));
23932447}
23942448
2395- #ifdef CONFIG_PM
23962449static int dwc3_core_init_for_resume (struct dwc3 * dwc )
23972450{
23982451 int ret ;
@@ -2419,6 +2472,7 @@ static int dwc3_core_init_for_resume(struct dwc3 *dwc)
24192472 return ret ;
24202473}
24212474
2475+ #ifdef CONFIG_PM
24222476static int dwc3_suspend_common (struct dwc3 * dwc , pm_message_t msg )
24232477{
24242478 u32 reg ;
@@ -2780,6 +2834,10 @@ static const struct of_device_id of_dwc3_match[] = {
27802834 {
27812835 .compatible = "synopsys,dwc3"
27822836 },
2837+ /* downstream forwards compatible for upstream dt-bindings */
2838+ {
2839+ .compatible = "apple,t8103-dwc3"
2840+ },
27832841 { },
27842842};
27852843MODULE_DEVICE_TABLE (of , of_dwc3_match );
0 commit comments