Skip to content

Commit a944c86

Browse files
committed
Merge branch 'bits/040-dwc3' into asahi-wip
2 parents dae45ad + 33ba28e commit a944c86

6 files changed

Lines changed: 185 additions & 74 deletions

File tree

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# SPDX-License-Identifier: GPL-2.0
2+
%YAML 1.2
3+
---
4+
$id: http://devicetree.org/schemas/usb/apple,dwc3.yaml#
5+
$schema: http://devicetree.org/meta-schemas/core.yaml#
6+
7+
title: Apple Silicon DWC3 USB controller
8+
9+
maintainers:
10+
- Sven Peter <sven@svenpeter.dev>
11+
12+
description:
13+
On Apple Silicon SoCs such as the M1 each Type-C port has a corresponding
14+
USB controller based on the Synopsys DesignWare USB3 controller.
15+
16+
The common content of this binding is defined in snps,dwc3.yaml.
17+
18+
allOf:
19+
- $ref: snps,dwc3.yaml#
20+
21+
select:
22+
properties:
23+
compatible:
24+
contains:
25+
const: apple,dwc3
26+
required:
27+
- compatible
28+
29+
properties:
30+
compatible:
31+
items:
32+
- enum:
33+
- apple,t8103-dwc3
34+
- apple,t6000-dwc3
35+
- const: apple,dwc3
36+
- const: snps,dwc3
37+
38+
reg:
39+
maxItems: 1
40+
41+
interrupts:
42+
maxItems: 1
43+
44+
unevaluatedProperties: false
45+
46+
required:
47+
- compatible
48+
- reg
49+
- interrupts
50+
51+
examples:
52+
- |
53+
#include <dt-bindings/interrupt-controller/apple-aic.h>
54+
#include <dt-bindings/interrupt-controller/irq.h>
55+
56+
usb@82280000 {
57+
compatible = "apple,t8103-dwc3", "apple,dwc3", "snps,dwc3";
58+
reg = <0x82280000 0x10000>;
59+
interrupts = <AIC_IRQ 777 IRQ_TYPE_LEVEL_HIGH>;
60+
61+
dr_mode = "otg";
62+
usb-role-switch;
63+
role-switch-default-mode = "host";
64+
};

drivers/usb/dwc3/core.c

Lines changed: 106 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -104,27 +104,6 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
104104
return 0;
105105
}
106106

107-
void dwc3_enable_susphy(struct dwc3 *dwc, bool enable)
108-
{
109-
u32 reg;
110-
111-
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
112-
if (enable && !dwc->dis_u3_susphy_quirk)
113-
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
114-
else
115-
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
116-
117-
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
118-
119-
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
120-
if (enable && !dwc->dis_u2_susphy_quirk)
121-
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
122-
else
123-
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
124-
125-
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
126-
}
127-
128107
void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
129108
{
130109
u32 reg;
@@ -137,6 +116,9 @@ void dwc3_set_prtcap(struct dwc3 *dwc, u32 mode)
137116
dwc->current_dr_role = mode;
138117
}
139118

119+
static void dwc3_core_exit(struct dwc3 *dwc);
120+
static int dwc3_core_init_for_resume(struct dwc3 *dwc);
121+
140122
static void __dwc3_set_mode(struct work_struct *work)
141123
{
142124
struct dwc3 *dwc = work_to_dwc(work);
@@ -155,7 +137,7 @@ static void __dwc3_set_mode(struct work_struct *work)
155137
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG)
156138
dwc3_otg_update(dwc, 0);
157139

158-
if (!desired_dr_role)
140+
if (!desired_dr_role && !dwc->role_switch_reset_quirk)
159141
goto out;
160142

161143
if (desired_dr_role == dwc->current_dr_role)
@@ -183,13 +165,32 @@ static void __dwc3_set_mode(struct work_struct *work)
183165
break;
184166
}
185167

168+
if (dwc->role_switch_reset_quirk) {
169+
if (dwc->current_dr_role) {
170+
dwc->current_dr_role = 0;
171+
dwc3_core_exit(dwc);
172+
}
173+
174+
if (desired_dr_role) {
175+
ret = dwc3_core_init_for_resume(dwc);
176+
if (ret) {
177+
dev_err(dwc->dev,
178+
"failed to reinitialize core\n");
179+
goto out;
180+
}
181+
} else {
182+
goto out;
183+
}
184+
}
185+
186186
/*
187187
* When current_dr_role is not set, there's no role switching.
188188
* Only perform GCTL.CoreSoftReset when there's DRD role switching.
189189
*/
190-
if (dwc->current_dr_role && ((DWC3_IP_IS(DWC3) ||
190+
if (dwc->role_switch_reset_quirk ||
191+
(dwc->current_dr_role && ((DWC3_IP_IS(DWC3) ||
191192
DWC3_VER_IS_PRIOR(DWC31, 190A)) &&
192-
desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) {
193+
desired_dr_role != DWC3_GCTL_PRTCAP_OTG))) {
193194
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
194195
reg |= DWC3_GCTL_CORESOFTRESET;
195196
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
@@ -606,8 +607,11 @@ static int dwc3_core_ulpi_init(struct dwc3 *dwc)
606607
*/
607608
static int dwc3_phy_setup(struct dwc3 *dwc)
608609
{
610+
unsigned int hw_mode;
609611
u32 reg;
610612

613+
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
614+
611615
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
612616

613617
/*
@@ -617,16 +621,21 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
617621
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
618622

619623
/*
620-
* Above DWC_usb3.0 1.94a, it is recommended to set
621-
* DWC3_GUSB3PIPECTL_SUSPHY to '0' during coreConsultant configuration.
622-
* So default value will be '0' when the core is reset. Application
623-
* needs to set it to '1' after the core initialization is completed.
624-
*
625-
* Similarly for DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be
626-
* cleared after power-on reset, and it can be set after core
627-
* initialization.
624+
* Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
625+
* to '0' during coreConsultant configuration. So default value
626+
* will be '0' when the core is reset. Application needs to set it
627+
* to '1' after the core initialization is completed.
628628
*/
629-
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
629+
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
630+
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
631+
632+
/*
633+
* For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be cleared after
634+
* power-on reset, and it can be set after core initialization, which is
635+
* after device soft-reset during initialization.
636+
*/
637+
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
638+
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
630639

631640
if (dwc->u2ss_inp3_quirk)
632641
reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
@@ -652,6 +661,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
652661
if (dwc->tx_de_emphasis_quirk)
653662
reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
654663

664+
if (dwc->dis_u3_susphy_quirk)
665+
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
666+
655667
if (dwc->dis_del_phy_power_chg_quirk)
656668
reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
657669

@@ -699,15 +711,24 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
699711
}
700712

701713
/*
702-
* Above DWC_usb3.0 1.94a, it is recommended to set
703-
* DWC3_GUSB2PHYCFG_SUSPHY to '0' during coreConsultant configuration.
704-
* So default value will be '0' when the core is reset. Application
705-
* needs to set it to '1' after the core initialization is completed.
706-
*
707-
* Similarly for DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared
708-
* after power-on reset, and it can be set after core initialization.
714+
* Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
715+
* '0' during coreConsultant configuration. So default value will
716+
* be '0' when the core is reset. Application needs to set it to
717+
* '1' after the core initialization is completed.
709718
*/
710-
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
719+
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
720+
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
721+
722+
/*
723+
* For DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared after
724+
* power-on reset, and it can be set after core initialization, which is
725+
* after device soft-reset during initialization.
726+
*/
727+
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
728+
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
729+
730+
if (dwc->dis_u2_susphy_quirk)
731+
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
711732

712733
if (dwc->dis_enblslpm_quirk)
713734
reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
@@ -1246,6 +1267,21 @@ static int dwc3_core_init(struct dwc3 *dwc)
12461267
if (ret)
12471268
goto err_exit_phy;
12481269

1270+
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD &&
1271+
!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) {
1272+
if (!dwc->dis_u3_susphy_quirk) {
1273+
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
1274+
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
1275+
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
1276+
}
1277+
1278+
if (!dwc->dis_u2_susphy_quirk) {
1279+
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
1280+
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
1281+
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
1282+
}
1283+
}
1284+
12491285
dwc3_core_setup_global_control(dwc);
12501286
dwc3_core_num_eps(dwc);
12511287

@@ -1444,6 +1480,18 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
14441480
ret = dwc3_drd_init(dwc);
14451481
if (ret)
14461482
return dev_err_probe(dev, ret, "failed to initialize dual-role\n");
1483+
1484+
/*
1485+
* If the role switch reset quirk is required the first role
1486+
* switch notification will initialize the core such that we
1487+
* have to shut it down here. Make sure that the __dwc3_set_mode
1488+
* queued by dwc3_drd_init has completed before since it
1489+
* may still try to access MMIO.
1490+
*/
1491+
if (dwc->role_switch_reset_quirk) {
1492+
flush_work(&dwc->drd_work);
1493+
dwc3_core_exit(dwc);
1494+
}
14471495
break;
14481496
default:
14491497
dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
@@ -1948,6 +1996,22 @@ static int dwc3_probe(struct platform_device *pdev)
19481996
if (ret)
19491997
goto err_put_psy;
19501998

1999+
if (dev->of_node) {
2000+
if (of_device_is_compatible(dev->of_node, "apple,dwc3")) {
2001+
if (!IS_ENABLED(CONFIG_USB_ROLE_SWITCH) ||
2002+
!IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) {
2003+
dev_err(dev,
2004+
"Apple DWC3 requires role switch support.\n"
2005+
);
2006+
ret = -EINVAL;
2007+
goto err_put_psy;
2008+
}
2009+
2010+
dwc->dr_mode = USB_DR_MODE_OTG;
2011+
dwc->role_switch_reset_quirk = true;
2012+
}
2013+
}
2014+
19512015
ret = reset_control_deassert(dwc->reset);
19522016
if (ret)
19532017
goto err_put_psy;
@@ -2073,7 +2137,6 @@ static void dwc3_remove(struct platform_device *pdev)
20732137
power_supply_put(dwc->usb_psy);
20742138
}
20752139

2076-
#ifdef CONFIG_PM
20772140
static int dwc3_core_init_for_resume(struct dwc3 *dwc)
20782141
{
20792142
int ret;
@@ -2100,6 +2163,7 @@ static int dwc3_core_init_for_resume(struct dwc3 *dwc)
21002163
return ret;
21012164
}
21022165

2166+
#ifdef CONFIG_PM
21032167
static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
21042168
{
21052169
u32 reg;

drivers/usb/dwc3/core.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1136,6 +1136,7 @@ struct dwc3_scratchpad_array {
11361136
* @sys_wakeup: set if the device may do system wakeup.
11371137
* @wakeup_configured: set if the device is configured for remote wakeup.
11381138
* @suspended: set to track suspend event due to U3/L2.
1139+
* @role_switch_reset_quirk: set to force reinitialization after any role switch
11391140
* @imod_interval: set the interrupt moderation interval in 250ns
11401141
* increments or 0 to disable.
11411142
* @max_cfg_eps: current max number of IN eps used across all USB configs.
@@ -1362,6 +1363,8 @@ struct dwc3 {
13621363
unsigned wakeup_configured:1;
13631364
unsigned suspended:1;
13641365

1366+
unsigned role_switch_reset_quirk:1;
1367+
13651368
u16 imod_interval;
13661369

13671370
int max_cfg_eps;
@@ -1580,7 +1583,6 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc);
15801583
void dwc3_event_buffers_cleanup(struct dwc3 *dwc);
15811584

15821585
int dwc3_core_soft_reset(struct dwc3 *dwc);
1583-
void dwc3_enable_susphy(struct dwc3 *dwc, bool enable);
15841586

15851587
#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
15861588
int dwc3_host_init(struct dwc3 *dwc);

drivers/usb/dwc3/drd.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,9 @@ static int dwc3_usb_role_switch_set(struct usb_role_switch *sw,
461461
break;
462462
}
463463

464+
if (dwc->role_switch_reset_quirk && role == USB_ROLE_NONE)
465+
mode = 0;
466+
464467
dwc3_set_mode(dwc, mode);
465468
return 0;
466469
}
@@ -489,6 +492,10 @@ static enum usb_role dwc3_usb_role_switch_get(struct usb_role_switch *sw)
489492
role = USB_ROLE_DEVICE;
490493
break;
491494
}
495+
496+
if (dwc->role_switch_reset_quirk && !dwc->current_dr_role)
497+
role = USB_ROLE_NONE;
498+
492499
spin_unlock_irqrestore(&dwc->lock, flags);
493500
return role;
494501
}
@@ -499,7 +506,9 @@ static int dwc3_setup_role_switch(struct dwc3 *dwc)
499506
u32 mode;
500507

501508
dwc->role_switch_default_mode = usb_get_role_switch_default_mode(dwc->dev);
502-
if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) {
509+
if (dwc->role_switch_reset_quirk) {
510+
mode = 0;
511+
} else if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) {
503512
mode = DWC3_GCTL_PRTCAP_HOST;
504513
} else {
505514
dwc->role_switch_default_mode = USB_DR_MODE_PERIPHERAL;

drivers/usb/dwc3/gadget.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2922,7 +2922,6 @@ static int __dwc3_gadget_start(struct dwc3 *dwc)
29222922
dwc3_ep0_out_start(dwc);
29232923

29242924
dwc3_gadget_enable_irq(dwc);
2925-
dwc3_enable_susphy(dwc, true);
29262925

29272926
return 0;
29282927

@@ -4689,7 +4688,6 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
46894688
if (!dwc->gadget)
46904689
return;
46914690

4692-
dwc3_enable_susphy(dwc, false);
46934691
usb_del_gadget(dwc->gadget);
46944692
dwc3_gadget_free_endpoints(dwc);
46954693
usb_put_gadget(dwc->gadget);

0 commit comments

Comments
 (0)