Skip to content

Commit 3e88cbe

Browse files
committed
Merge branch 'bits/040-dwc3' into asahi-wip
2 parents 21deacb + f1ba4d9 commit 3e88cbe

6 files changed

Lines changed: 146 additions & 7 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+
};

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2397,6 +2397,7 @@ F: Documentation/devicetree/bindings/power/reset/apple,smc-reboot.yaml
23972397
F: Documentation/devicetree/bindings/pwm/apple,s5l-fpwm.yaml
23982398
F: Documentation/devicetree/bindings/spi/apple,spi.yaml
23992399
F: Documentation/devicetree/bindings/spmi/apple,spmi.yaml
2400+
F: Documentation/devicetree/bindings/usb/apple,dwc3.yaml
24002401
F: Documentation/devicetree/bindings/watchdog/apple,wdt.yaml
24012402
F: arch/arm64/boot/dts/apple/
24022403
F: drivers/bluetooth/hci_bcm4377.c

drivers/usb/dwc3/core.c

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
162165
static 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, 190A)) &&
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
23962449
static 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
24222476
static 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
};
27852843
MODULE_DEVICE_TABLE(of, of_dwc3_match);

drivers/usb/dwc3/core.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,6 +1154,7 @@ struct dwc3_scratchpad_array {
11541154
* @suspended: set to track suspend event due to U3/L2.
11551155
* @susphy_state: state of DWC3_GUSB2PHYCFG_SUSPHY + DWC3_GUSB3PIPECTL_SUSPHY
11561156
* before PM suspend.
1157+
* @role_switch_reset_quirk: set to force reinitialization after any role switch
11571158
* @imod_interval: set the interrupt moderation interval in 250ns
11581159
* increments or 0 to disable.
11591160
* @max_cfg_eps: current max number of IN eps used across all USB configs.
@@ -1392,6 +1393,8 @@ struct dwc3 {
13921393
unsigned suspended:1;
13931394
unsigned susphy_state:1;
13941395

1396+
unsigned role_switch_reset_quirk:1;
1397+
13951398
u16 imod_interval;
13961399

13971400
int max_cfg_eps;

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/host.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ static void dwc3_power_off_all_roothub_ports(struct dwc3 *dwc)
3737

3838
/* xhci regs are not mapped yet, do it temporarily here */
3939
if (dwc->xhci_resources[0].start) {
40-
xhci_regs = ioremap(dwc->xhci_resources[0].start, DWC3_XHCI_REGS_END);
40+
if (dwc->xhci_resources[0].flags & IORESOURCE_MEM_NONPOSTED)
41+
xhci_regs = ioremap_np(dwc->xhci_resources[0].start, DWC3_XHCI_REGS_END);
42+
else
43+
xhci_regs = ioremap(dwc->xhci_resources[0].start, DWC3_XHCI_REGS_END);
4144
if (!xhci_regs) {
4245
dev_err(dwc->dev, "Failed to ioremap xhci_regs\n");
4346
return;
@@ -223,7 +226,8 @@ void dwc3_host_exit(struct dwc3 *dwc)
223226
if (dwc->sys_wakeup)
224227
device_init_wakeup(&dwc->xhci->dev, false);
225228

226-
dwc3_enable_susphy(dwc, false);
229+
if (!dwc->role_switch_reset_quirk)
230+
dwc3_enable_susphy(dwc, false);
227231
platform_device_unregister(dwc->xhci);
228232
dwc->xhci = NULL;
229233
}

0 commit comments

Comments
 (0)