Skip to content

Commit d3e9888

Browse files
committed
Merge branch 'bits/040-dwc3' into asahi-wip
2 parents 032dd35 + 49b1418 commit d3e9888

6 files changed

Lines changed: 188 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 <[email protected]>
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: 109 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -105,27 +105,6 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
105105
return 0;
106106
}
107107

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

120+
static void dwc3_core_exit(struct dwc3 *dwc);
121+
static int dwc3_core_init_for_resume(struct dwc3 *dwc);
122+
141123
static void __dwc3_set_mode(struct work_struct *work)
142124
{
143125
struct dwc3 *dwc = work_to_dwc(work);
@@ -157,7 +139,7 @@ static void __dwc3_set_mode(struct work_struct *work)
157139
if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_OTG)
158140
dwc3_otg_update(dwc, 0);
159141

160-
if (!desired_dr_role)
142+
if (!desired_dr_role && !dwc->role_switch_reset_quirk)
161143
goto out;
162144

163145
if (desired_dr_role == dwc->current_dr_role)
@@ -185,13 +167,32 @@ static void __dwc3_set_mode(struct work_struct *work)
185167
break;
186168
}
187169

170+
if (dwc->role_switch_reset_quirk) {
171+
if (dwc->current_dr_role) {
172+
dwc->current_dr_role = 0;
173+
dwc3_core_exit(dwc);
174+
}
175+
176+
if (desired_dr_role) {
177+
ret = dwc3_core_init_for_resume(dwc);
178+
if (ret) {
179+
dev_err(dwc->dev,
180+
"failed to reinitialize core\n");
181+
goto out;
182+
}
183+
} else {
184+
goto out;
185+
}
186+
}
187+
188188
/*
189189
* When current_dr_role is not set, there's no role switching.
190190
* Only perform GCTL.CoreSoftReset when there's DRD role switching.
191191
*/
192-
if (dwc->current_dr_role && ((DWC3_IP_IS(DWC3) ||
192+
if (dwc->role_switch_reset_quirk ||
193+
(dwc->current_dr_role && ((DWC3_IP_IS(DWC3) ||
193194
DWC3_VER_IS_PRIOR(DWC31, 190A)) &&
194-
desired_dr_role != DWC3_GCTL_PRTCAP_OTG)) {
195+
desired_dr_role != DWC3_GCTL_PRTCAP_OTG))) {
195196
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
196197
reg |= DWC3_GCTL_CORESOFTRESET;
197198
dwc3_writel(dwc->regs, DWC3_GCTL, reg);
@@ -625,8 +626,11 @@ static int dwc3_core_ulpi_init(struct dwc3 *dwc)
625626

626627
static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index)
627628
{
629+
unsigned int hw_mode;
628630
u32 reg;
629631

632+
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
633+
630634
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(index));
631635

632636
/*
@@ -636,16 +640,21 @@ static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index)
636640
reg &= ~DWC3_GUSB3PIPECTL_UX_EXIT_PX;
637641

638642
/*
639-
* Above DWC_usb3.0 1.94a, it is recommended to set
640-
* DWC3_GUSB3PIPECTL_SUSPHY to '0' during coreConsultant configuration.
641-
* So default value will be '0' when the core is reset. Application
642-
* needs to set it to '1' after the core initialization is completed.
643-
*
644-
* Similarly for DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be
645-
* cleared after power-on reset, and it can be set after core
646-
* initialization.
643+
* Above 1.94a, it is recommended to set DWC3_GUSB3PIPECTL_SUSPHY
644+
* to '0' during coreConsultant configuration. So default value
645+
* will be '0' when the core is reset. Application needs to set it
646+
* to '1' after the core initialization is completed.
647+
*/
648+
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
649+
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
650+
651+
/*
652+
* For DRD controllers, GUSB3PIPECTL.SUSPENDENABLE must be cleared after
653+
* power-on reset, and it can be set after core initialization, which is
654+
* after device soft-reset during initialization.
647655
*/
648-
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
656+
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
657+
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
649658

650659
if (dwc->u2ss_inp3_quirk)
651660
reg |= DWC3_GUSB3PIPECTL_U2SSINP3OK;
@@ -671,6 +680,9 @@ static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index)
671680
if (dwc->tx_de_emphasis_quirk)
672681
reg |= DWC3_GUSB3PIPECTL_TX_DEEPH(dwc->tx_de_emphasis);
673682

683+
if (dwc->dis_u3_susphy_quirk)
684+
reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
685+
674686
if (dwc->dis_del_phy_power_chg_quirk)
675687
reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
676688

@@ -681,8 +693,11 @@ static int dwc3_ss_phy_setup(struct dwc3 *dwc, int index)
681693

682694
static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index)
683695
{
696+
unsigned int hw_mode;
684697
u32 reg;
685698

699+
hw_mode = DWC3_GHWPARAMS0_MODE(dwc->hwparams.hwparams0);
700+
686701
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(index));
687702

688703
/* Select the HS PHY interface */
@@ -725,15 +740,24 @@ static int dwc3_hs_phy_setup(struct dwc3 *dwc, int index)
725740
}
726741

727742
/*
728-
* Above DWC_usb3.0 1.94a, it is recommended to set
729-
* DWC3_GUSB2PHYCFG_SUSPHY to '0' during coreConsultant configuration.
730-
* So default value will be '0' when the core is reset. Application
731-
* needs to set it to '1' after the core initialization is completed.
732-
*
733-
* Similarly for DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared
734-
* after power-on reset, and it can be set after core initialization.
743+
* Above 1.94a, it is recommended to set DWC3_GUSB2PHYCFG_SUSPHY to
744+
* '0' during coreConsultant configuration. So default value will
745+
* be '0' when the core is reset. Application needs to set it to
746+
* '1' after the core initialization is completed.
747+
*/
748+
if (!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A))
749+
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
750+
751+
/*
752+
* For DRD controllers, GUSB2PHYCFG.SUSPHY must be cleared after
753+
* power-on reset, and it can be set after core initialization, which is
754+
* after device soft-reset during initialization.
735755
*/
736-
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
756+
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD)
757+
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
758+
759+
if (dwc->dis_u2_susphy_quirk)
760+
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
737761

738762
if (dwc->dis_enblslpm_quirk)
739763
reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
@@ -1332,6 +1356,21 @@ static int dwc3_core_init(struct dwc3 *dwc)
13321356
if (ret)
13331357
goto err_exit_phy;
13341358

1359+
if (hw_mode == DWC3_GHWPARAMS0_MODE_DRD &&
1360+
!DWC3_VER_IS_WITHIN(DWC3, ANY, 194A)) {
1361+
if (!dwc->dis_u3_susphy_quirk) {
1362+
reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
1363+
reg |= DWC3_GUSB3PIPECTL_SUSPHY;
1364+
dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
1365+
}
1366+
1367+
if (!dwc->dis_u2_susphy_quirk) {
1368+
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
1369+
reg |= DWC3_GUSB2PHYCFG_SUSPHY;
1370+
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
1371+
}
1372+
}
1373+
13351374
dwc3_core_setup_global_control(dwc);
13361375
dwc3_core_num_eps(dwc);
13371376

@@ -1554,6 +1593,18 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
15541593
ret = dwc3_drd_init(dwc);
15551594
if (ret)
15561595
return dev_err_probe(dev, ret, "failed to initialize dual-role\n");
1596+
1597+
/*
1598+
* If the role switch reset quirk is required the first role
1599+
* switch notification will initialize the core such that we
1600+
* have to shut it down here. Make sure that the __dwc3_set_mode
1601+
* queued by dwc3_drd_init has completed before since it
1602+
* may still try to access MMIO.
1603+
*/
1604+
if (dwc->role_switch_reset_quirk) {
1605+
flush_work(&dwc->drd_work);
1606+
dwc3_core_exit(dwc);
1607+
}
15571608
break;
15581609
default:
15591610
dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
@@ -2108,6 +2159,22 @@ static int dwc3_probe(struct platform_device *pdev)
21082159
if (ret)
21092160
goto err_put_psy;
21102161

2162+
if (dev->of_node) {
2163+
if (of_device_is_compatible(dev->of_node, "apple,dwc3")) {
2164+
if (!IS_ENABLED(CONFIG_USB_ROLE_SWITCH) ||
2165+
!IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)) {
2166+
dev_err(dev,
2167+
"Apple DWC3 requires role switch support.\n"
2168+
);
2169+
ret = -EINVAL;
2170+
goto err_put_psy;
2171+
}
2172+
2173+
dwc->dr_mode = USB_DR_MODE_OTG;
2174+
dwc->role_switch_reset_quirk = true;
2175+
}
2176+
}
2177+
21112178
ret = reset_control_deassert(dwc->reset);
21122179
if (ret)
21132180
goto err_put_psy;
@@ -2247,7 +2314,6 @@ static void dwc3_remove(struct platform_device *pdev)
22472314
power_supply_put(dwc->usb_psy);
22482315
}
22492316

2250-
#ifdef CONFIG_PM
22512317
static int dwc3_core_init_for_resume(struct dwc3 *dwc)
22522318
{
22532319
int ret;
@@ -2274,6 +2340,7 @@ static int dwc3_core_init_for_resume(struct dwc3 *dwc)
22742340
return ret;
22752341
}
22762342

2343+
#ifdef CONFIG_PM
22772344
static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
22782345
{
22792346
u32 reg;

drivers/usb/dwc3/core.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1145,6 +1145,7 @@ struct dwc3_scratchpad_array {
11451145
* @sys_wakeup: set if the device may do system wakeup.
11461146
* @wakeup_configured: set if the device is configured for remote wakeup.
11471147
* @suspended: set to track suspend event due to U3/L2.
1148+
* @role_switch_reset_quirk: set to force reinitialization after any role switch
11481149
* @imod_interval: set the interrupt moderation interval in 250ns
11491150
* increments or 0 to disable.
11501151
* @max_cfg_eps: current max number of IN eps used across all USB configs.
@@ -1374,6 +1375,8 @@ struct dwc3 {
13741375
unsigned wakeup_configured:1;
13751376
unsigned suspended:1;
13761377

1378+
unsigned role_switch_reset_quirk:1;
1379+
13771380
u16 imod_interval;
13781381

13791382
int max_cfg_eps;
@@ -1592,7 +1595,6 @@ int dwc3_event_buffers_setup(struct dwc3 *dwc);
15921595
void dwc3_event_buffers_cleanup(struct dwc3 *dwc);
15931596

15941597
int dwc3_core_soft_reset(struct dwc3 *dwc);
1595-
void dwc3_enable_susphy(struct dwc3 *dwc, bool enable);
15961598

15971599
#if IS_ENABLED(CONFIG_USB_DWC3_HOST) || IS_ENABLED(CONFIG_USB_DWC3_DUAL_ROLE)
15981600
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
@@ -464,6 +464,9 @@ static int dwc3_usb_role_switch_set(struct usb_role_switch *sw,
464464
break;
465465
}
466466

467+
if (dwc->role_switch_reset_quirk && role == USB_ROLE_NONE)
468+
mode = 0;
469+
467470
dwc3_set_mode(dwc, mode);
468471
return 0;
469472
}
@@ -492,6 +495,10 @@ static enum usb_role dwc3_usb_role_switch_get(struct usb_role_switch *sw)
492495
role = USB_ROLE_DEVICE;
493496
break;
494497
}
498+
499+
if (dwc->role_switch_reset_quirk && !dwc->current_dr_role)
500+
role = USB_ROLE_NONE;
501+
495502
spin_unlock_irqrestore(&dwc->lock, flags);
496503
return role;
497504
}
@@ -502,7 +509,9 @@ static int dwc3_setup_role_switch(struct dwc3 *dwc)
502509
u32 mode;
503510

504511
dwc->role_switch_default_mode = usb_get_role_switch_default_mode(dwc->dev);
505-
if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) {
512+
if (dwc->role_switch_reset_quirk) {
513+
mode = 0;
514+
} else if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) {
506515
mode = DWC3_GCTL_PRTCAP_HOST;
507516
} else {
508517
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)