1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Apple Silicon DWC3 Glue driver
4 * Copyright (C) The Asahi Linux Contributors
5 *
6 * Based on:
7 * - dwc3-qcom.c Copyright (c) 2018, The Linux Foundation. All rights reserved.
8 * - dwc3-of-simple.c Copyright (c) 2015 Texas Instruments Incorporated - https://www.ti.com
9 */
10
11 #include <linux/of.h>
12 #include <linux/module.h>
13 #include <linux/mutex.h>
14 #include <linux/platform_device.h>
15 #include <linux/reset.h>
16
17 #include "glue.h"
18
19 /*
20 * This platform requires a very specific sequence of operations to bring up dwc3 and its USB3 PHY:
21 *
22 * 1) The PHY itself has to be brought up; for this we need to know the mode (USB3,
23 * USB3+DisplayPort, USB4, etc) and the lane orientation. This happens through typec_mux_set.
24 * 2) DWC3 has to be brought up but we must not touch the gadget area or start xhci yet.
25 * 3) The PHY bring-up has to be finalized and dwc3's PIPE interface has to be switched to the
26 * USB3 PHY, this is done inside phy_set_mode.
27 * 4) We can now initialize xhci or gadget mode.
28 *
29 * We can switch 1 and 2 but 3 has to happen after (1 and 2) and 4 has to happen after 3.
30 *
31 * And then to bring this all down again:
32 *
33 * 1) DWC3 has to exit host or gadget mode and must no longer touch those registers
34 * 2) The PHY has to switch dwc3's PIPE interface back to the dummy backend
35 * 3) The PHY itself can be shut down, this happens from typec_mux_set
36 *
37 * We also can't transition the PHY from one mode to another while dwc3 is up and running (this is
38 * slightly wrong, some transitions are possible, others aren't but because we have no documentation
39 * for this I'd rather play it safe).
40 *
41 * After both the PHY and dwc3 are initialized we will only ever see a single "new device connected"
42 * event. If we just keep them running only the first device plugged in will ever work. XHCI's port
43 * status register actually does show the correct state but no interrupt ever comes in. In gadget
44 * mode we don't even get a USBDisconnected event and everything looks like there's still something
45 * connected on the other end.
46 * This can be partially explained because the USB2 D+/D- lines are connected through a stateful
47 * eUSB2 repeater which in turn is controlled by a variant of the TI TPS6598x USB PD chip which
48 * resets the repeater out-of-band everytime the CC lines are (dis)connected. This then requires a
49 * PHY reset to make sure the PHY and the eUSB2 repeater state are synchronized again.
50 *
51 * And to make this all extra fun: If we get the order of some of this wrong either the port is just
52 * broken until a phy+dwc3 reset, or it's broken until a full SoC reset (likely because we can't
53 * reset some parts of the PHY), or some watchdog kicks in after a few seconds and forces a full SoC
54 * reset (mostly seen this with USB4/Thunderbolt but there's clearly some watchdog that hates
55 * invalid states).
56 *
57 * Hence there's really no good way to keep dwc3 fully up and running after we disconnect a cable
58 * because then we can't shut down the PHY anymore. And if we kept the PHY running in whatever mode
59 * it was until the next cable is connected we'd need to tear it all down and bring it back up again
60 * anyway to detect and use the next device.
61 *
62 * Instead, we just shut down everything when a cable is disconnected and transition to
63 * DWC3_APPLE_NO_CABLE.
64 * During initial probe we don't have any information about the connected cable and can't bring up
65 * the PHY properly and thus also can't fully bring up dwc3. Instead, we just keep everything off
66 * and defer the first dwc3 probe until we get the first cable connected event. Until then we stay
67 * in DWC3_APPLE_PROBE_PENDING.
68 * Once a cable is connected we then keep track of the controller mode here by transitioning to
69 * DWC3_APPLE_HOST or DWC3_APPLE_DEVICE.
70 */
71 enum dwc3_apple_state {
72 DWC3_APPLE_PROBE_PENDING, /* Before first cable connection, dwc3_core_probe not called */
73 DWC3_APPLE_NO_CABLE, /* No cable connected, dwc3 suspended after dwc3_core_exit */
74 DWC3_APPLE_HOST, /* Cable connected, dwc3 in host mode */
75 DWC3_APPLE_DEVICE, /* Cable connected, dwc3 in device mode */
76 };
77
78 /**
79 * struct dwc3_apple - Apple-specific DWC3 USB controller
80 * @dwc: Core DWC3 structure
81 * @dev: Pointer to the device structure
82 * @mmio_resource: Resource to be passed to dwc3_core_probe
83 * @apple_regs: Apple-specific DWC3 registers
84 * @reset: Reset control
85 * @role_sw: USB role switch
86 * @lock: Mutex for synchronizing access
87 * @state: Current state of the controller, see documentation for the enum for details
88 */
89 struct dwc3_apple {
90 struct dwc3 dwc;
91
92 struct device *dev;
93 struct resource *mmio_resource;
94 void __iomem *apple_regs;
95
96 struct reset_control *reset;
97 struct usb_role_switch *role_sw;
98
99 struct mutex lock;
100
101 enum dwc3_apple_state state;
102 };
103
104 #define to_dwc3_apple(d) container_of((d), struct dwc3_apple, dwc)
105
106 /*
107 * Apple Silicon dwc3 vendor-specific registers
108 *
109 * These registers were identified by tracing XNU's memory access patterns and correlating them with
110 * debug output over serial to determine their names. We don't exactly know what these do but
111 * without these USB3 devices sometimes don't work.
112 */
113 #define APPLE_DWC3_REGS_START 0xcd00
114 #define APPLE_DWC3_REGS_END 0xcdff
115
116 #define APPLE_DWC3_CIO_LFPS_OFFSET 0xcd38
117 #define APPLE_DWC3_CIO_LFPS_OFFSET_VALUE 0xf800f80
118
119 #define APPLE_DWC3_CIO_BW_NGT_OFFSET 0xcd3c
120 #define APPLE_DWC3_CIO_BW_NGT_OFFSET_VALUE 0xfc00fc0
121
122 #define APPLE_DWC3_CIO_LINK_TIMER 0xcd40
123 #define APPLE_DWC3_CIO_PENDING_HP_TIMER GENMASK(23, 16)
124 #define APPLE_DWC3_CIO_PENDING_HP_TIMER_VALUE 0x14
125 #define APPLE_DWC3_CIO_PM_LC_TIMER GENMASK(15, 8)
126 #define APPLE_DWC3_CIO_PM_LC_TIMER_VALUE 0xa
127 #define APPLE_DWC3_CIO_PM_ENTRY_TIMER GENMASK(7, 0)
128 #define APPLE_DWC3_CIO_PM_ENTRY_TIMER_VALUE 0x10
129
dwc3_apple_writel(struct dwc3_apple * appledwc,u32 offset,u32 value)130 static inline void dwc3_apple_writel(struct dwc3_apple *appledwc, u32 offset, u32 value)
131 {
132 writel(value, appledwc->apple_regs + offset - APPLE_DWC3_REGS_START);
133 }
134
dwc3_apple_readl(struct dwc3_apple * appledwc,u32 offset)135 static inline u32 dwc3_apple_readl(struct dwc3_apple *appledwc, u32 offset)
136 {
137 return readl(appledwc->apple_regs + offset - APPLE_DWC3_REGS_START);
138 }
139
dwc3_apple_mask(struct dwc3_apple * appledwc,u32 offset,u32 mask,u32 value)140 static inline void dwc3_apple_mask(struct dwc3_apple *appledwc, u32 offset, u32 mask, u32 value)
141 {
142 u32 reg;
143
144 reg = dwc3_apple_readl(appledwc, offset);
145 reg &= ~mask;
146 reg |= value;
147 dwc3_apple_writel(appledwc, offset, reg);
148 }
149
dwc3_apple_setup_cio(struct dwc3_apple * appledwc)150 static void dwc3_apple_setup_cio(struct dwc3_apple *appledwc)
151 {
152 dwc3_apple_writel(appledwc, APPLE_DWC3_CIO_LFPS_OFFSET, APPLE_DWC3_CIO_LFPS_OFFSET_VALUE);
153 dwc3_apple_writel(appledwc, APPLE_DWC3_CIO_BW_NGT_OFFSET,
154 APPLE_DWC3_CIO_BW_NGT_OFFSET_VALUE);
155 dwc3_apple_mask(appledwc, APPLE_DWC3_CIO_LINK_TIMER, APPLE_DWC3_CIO_PENDING_HP_TIMER,
156 FIELD_PREP(APPLE_DWC3_CIO_PENDING_HP_TIMER,
157 APPLE_DWC3_CIO_PENDING_HP_TIMER_VALUE));
158 dwc3_apple_mask(appledwc, APPLE_DWC3_CIO_LINK_TIMER, APPLE_DWC3_CIO_PM_LC_TIMER,
159 FIELD_PREP(APPLE_DWC3_CIO_PM_LC_TIMER, APPLE_DWC3_CIO_PM_LC_TIMER_VALUE));
160 dwc3_apple_mask(appledwc, APPLE_DWC3_CIO_LINK_TIMER, APPLE_DWC3_CIO_PM_ENTRY_TIMER,
161 FIELD_PREP(APPLE_DWC3_CIO_PM_ENTRY_TIMER,
162 APPLE_DWC3_CIO_PM_ENTRY_TIMER_VALUE));
163 }
164
dwc3_apple_set_ptrcap(struct dwc3_apple * appledwc,u32 mode)165 static void dwc3_apple_set_ptrcap(struct dwc3_apple *appledwc, u32 mode)
166 {
167 guard(spinlock_irqsave)(&appledwc->dwc.lock);
168 dwc3_set_prtcap(&appledwc->dwc, mode, false);
169 }
170
dwc3_apple_core_probe(struct dwc3_apple * appledwc)171 static int dwc3_apple_core_probe(struct dwc3_apple *appledwc)
172 {
173 struct dwc3_probe_data probe_data = {};
174 int ret;
175
176 lockdep_assert_held(&appledwc->lock);
177 WARN_ON_ONCE(appledwc->state != DWC3_APPLE_PROBE_PENDING);
178
179 appledwc->dwc.dev = appledwc->dev;
180 probe_data.dwc = &appledwc->dwc;
181 probe_data.res = appledwc->mmio_resource;
182 probe_data.ignore_clocks_and_resets = true;
183 probe_data.skip_core_init_mode = true;
184 probe_data.properties = DWC3_DEFAULT_PROPERTIES;
185
186 ret = dwc3_core_probe(&probe_data);
187 if (ret)
188 return ret;
189
190 appledwc->state = DWC3_APPLE_NO_CABLE;
191 return 0;
192 }
193
dwc3_apple_core_init(struct dwc3_apple * appledwc)194 static int dwc3_apple_core_init(struct dwc3_apple *appledwc)
195 {
196 int ret;
197
198 lockdep_assert_held(&appledwc->lock);
199
200 switch (appledwc->state) {
201 case DWC3_APPLE_PROBE_PENDING:
202 ret = dwc3_apple_core_probe(appledwc);
203 if (ret)
204 dev_err(appledwc->dev, "Failed to probe DWC3 Core, err=%d\n", ret);
205 break;
206 case DWC3_APPLE_NO_CABLE:
207 ret = dwc3_core_init(&appledwc->dwc);
208 if (ret)
209 dev_err(appledwc->dev, "Failed to initialize DWC3 Core, err=%d\n", ret);
210 break;
211 default:
212 /* Unreachable unless there's a bug in this driver */
213 WARN_ON_ONCE(1);
214 ret = -EINVAL;
215 break;
216 }
217
218 return ret;
219 }
220
dwc3_apple_phy_set_mode(struct dwc3_apple * appledwc,enum phy_mode mode)221 static void dwc3_apple_phy_set_mode(struct dwc3_apple *appledwc, enum phy_mode mode)
222 {
223 lockdep_assert_held(&appledwc->lock);
224
225 /*
226 * This platform requires SUSPHY to be enabled here already in order to properly configure
227 * the PHY and switch dwc3's PIPE interface to USB3 PHY.
228 */
229 dwc3_enable_susphy(&appledwc->dwc, true);
230 phy_set_mode(appledwc->dwc.usb2_generic_phy[0], mode);
231 phy_set_mode(appledwc->dwc.usb3_generic_phy[0], mode);
232 }
233
dwc3_apple_init(struct dwc3_apple * appledwc,enum dwc3_apple_state state)234 static int dwc3_apple_init(struct dwc3_apple *appledwc, enum dwc3_apple_state state)
235 {
236 int ret, ret_reset;
237
238 lockdep_assert_held(&appledwc->lock);
239
240 ret = reset_control_deassert(appledwc->reset);
241 if (ret) {
242 dev_err(appledwc->dev, "Failed to deassert reset, err=%d\n", ret);
243 return ret;
244 }
245
246 ret = dwc3_apple_core_init(appledwc);
247 if (ret)
248 goto reset_assert;
249
250 /*
251 * Now that the core is initialized and already went through dwc3_core_soft_reset we can
252 * configure some unknown Apple-specific settings and then bring up xhci or gadget mode.
253 */
254 dwc3_apple_setup_cio(appledwc);
255
256 switch (state) {
257 case DWC3_APPLE_HOST:
258 appledwc->dwc.dr_mode = USB_DR_MODE_HOST;
259 dwc3_apple_set_ptrcap(appledwc, DWC3_GCTL_PRTCAP_HOST);
260 dwc3_apple_phy_set_mode(appledwc, PHY_MODE_USB_HOST);
261 ret = dwc3_host_init(&appledwc->dwc);
262 if (ret) {
263 dev_err(appledwc->dev, "Failed to initialize host, ret=%d\n", ret);
264 goto core_exit;
265 }
266
267 break;
268 case DWC3_APPLE_DEVICE:
269 appledwc->dwc.dr_mode = USB_DR_MODE_PERIPHERAL;
270 dwc3_apple_set_ptrcap(appledwc, DWC3_GCTL_PRTCAP_DEVICE);
271 dwc3_apple_phy_set_mode(appledwc, PHY_MODE_USB_DEVICE);
272 ret = dwc3_gadget_init(&appledwc->dwc);
273 if (ret) {
274 dev_err(appledwc->dev, "Failed to initialize gadget, ret=%d\n", ret);
275 goto core_exit;
276 }
277 break;
278 default:
279 /* Unreachable unless there's a bug in this driver */
280 WARN_ON_ONCE(1);
281 ret = -EINVAL;
282 goto core_exit;
283 }
284
285 appledwc->state = state;
286 return 0;
287
288 core_exit:
289 dwc3_core_exit(&appledwc->dwc);
290 reset_assert:
291 ret_reset = reset_control_assert(appledwc->reset);
292 if (ret_reset)
293 dev_warn(appledwc->dev, "Failed to assert reset, err=%d\n", ret_reset);
294
295 return ret;
296 }
297
dwc3_apple_exit(struct dwc3_apple * appledwc)298 static int dwc3_apple_exit(struct dwc3_apple *appledwc)
299 {
300 int ret = 0;
301
302 lockdep_assert_held(&appledwc->lock);
303
304 switch (appledwc->state) {
305 case DWC3_APPLE_PROBE_PENDING:
306 case DWC3_APPLE_NO_CABLE:
307 /* Nothing to do if we're already off */
308 return 0;
309 case DWC3_APPLE_DEVICE:
310 dwc3_gadget_exit(&appledwc->dwc);
311 break;
312 case DWC3_APPLE_HOST:
313 dwc3_host_exit(&appledwc->dwc);
314 break;
315 }
316
317 /*
318 * This platform requires SUSPHY to be enabled in order to properly power down the PHY
319 * and switch dwc3's PIPE interface back to a dummy PHY (i.e. no USB3 support and USB2 via
320 * a different PHY connected through ULPI).
321 */
322 dwc3_enable_susphy(&appledwc->dwc, true);
323 dwc3_core_exit(&appledwc->dwc);
324 appledwc->state = DWC3_APPLE_NO_CABLE;
325
326 ret = reset_control_assert(appledwc->reset);
327 if (ret) {
328 dev_err(appledwc->dev, "Failed to assert reset, err=%d\n", ret);
329 return ret;
330 }
331
332 return 0;
333 }
334
dwc3_usb_role_switch_set(struct usb_role_switch * sw,enum usb_role role)335 static int dwc3_usb_role_switch_set(struct usb_role_switch *sw, enum usb_role role)
336 {
337 struct dwc3_apple *appledwc = usb_role_switch_get_drvdata(sw);
338 int ret;
339
340 guard(mutex)(&appledwc->lock);
341
342 /*
343 * We need to tear all of dwc3 down and re-initialize it every time a cable is
344 * connected or disconnected or when the mode changes. See the documentation for enum
345 * dwc3_apple_state for details.
346 */
347 ret = dwc3_apple_exit(appledwc);
348 if (ret)
349 return ret;
350
351 switch (role) {
352 case USB_ROLE_NONE:
353 /* Nothing to do if no cable is connected */
354 return 0;
355 case USB_ROLE_HOST:
356 return dwc3_apple_init(appledwc, DWC3_APPLE_HOST);
357 case USB_ROLE_DEVICE:
358 return dwc3_apple_init(appledwc, DWC3_APPLE_DEVICE);
359 default:
360 dev_err(appledwc->dev, "Invalid target role: %d\n", role);
361 return -EINVAL;
362 }
363 }
364
dwc3_usb_role_switch_get(struct usb_role_switch * sw)365 static enum usb_role dwc3_usb_role_switch_get(struct usb_role_switch *sw)
366 {
367 struct dwc3_apple *appledwc = usb_role_switch_get_drvdata(sw);
368
369 guard(mutex)(&appledwc->lock);
370
371 switch (appledwc->state) {
372 case DWC3_APPLE_HOST:
373 return USB_ROLE_HOST;
374 case DWC3_APPLE_DEVICE:
375 return USB_ROLE_DEVICE;
376 case DWC3_APPLE_NO_CABLE:
377 case DWC3_APPLE_PROBE_PENDING:
378 return USB_ROLE_NONE;
379 default:
380 /* Unreachable unless there's a bug in this driver */
381 dev_err(appledwc->dev, "Invalid internal state: %d\n", appledwc->state);
382 return USB_ROLE_NONE;
383 }
384 }
385
dwc3_apple_setup_role_switch(struct dwc3_apple * appledwc)386 static int dwc3_apple_setup_role_switch(struct dwc3_apple *appledwc)
387 {
388 struct usb_role_switch_desc dwc3_role_switch = { NULL };
389
390 dwc3_role_switch.fwnode = dev_fwnode(appledwc->dev);
391 dwc3_role_switch.set = dwc3_usb_role_switch_set;
392 dwc3_role_switch.get = dwc3_usb_role_switch_get;
393 dwc3_role_switch.driver_data = appledwc;
394 appledwc->role_sw = usb_role_switch_register(appledwc->dev, &dwc3_role_switch);
395 if (IS_ERR(appledwc->role_sw))
396 return PTR_ERR(appledwc->role_sw);
397
398 return 0;
399 }
400
dwc3_apple_probe(struct platform_device * pdev)401 static int dwc3_apple_probe(struct platform_device *pdev)
402 {
403 struct device *dev = &pdev->dev;
404 struct dwc3_apple *appledwc;
405 int ret;
406
407 appledwc = devm_kzalloc(&pdev->dev, sizeof(*appledwc), GFP_KERNEL);
408 if (!appledwc)
409 return -ENOMEM;
410
411 appledwc->dev = &pdev->dev;
412 mutex_init(&appledwc->lock);
413
414 appledwc->reset = devm_reset_control_get_exclusive(dev, NULL);
415 if (IS_ERR(appledwc->reset))
416 return dev_err_probe(&pdev->dev, PTR_ERR(appledwc->reset),
417 "Failed to get reset control\n");
418
419 ret = reset_control_assert(appledwc->reset);
420 if (ret) {
421 dev_err(&pdev->dev, "Failed to assert reset, err=%d\n", ret);
422 return ret;
423 }
424
425 appledwc->mmio_resource = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dwc3-core");
426 if (!appledwc->mmio_resource) {
427 dev_err(dev, "Failed to get DWC3 MMIO\n");
428 return -EINVAL;
429 }
430
431 appledwc->apple_regs = devm_platform_ioremap_resource_byname(pdev, "dwc3-apple");
432 if (IS_ERR(appledwc->apple_regs))
433 return dev_err_probe(dev, PTR_ERR(appledwc->apple_regs),
434 "Failed to map Apple-specific MMIO\n");
435
436 /*
437 * On this platform, DWC3 can only be brought up after parts of the PHY have been
438 * initialized with knowledge of the target mode and cable orientation from typec_set_mux.
439 * Since this has not happened here we cannot setup DWC3 yet and instead defer this until
440 * the first cable is connected. See the documentation for enum dwc3_apple_state for
441 * details.
442 */
443 appledwc->state = DWC3_APPLE_PROBE_PENDING;
444 ret = dwc3_apple_setup_role_switch(appledwc);
445 if (ret)
446 return dev_err_probe(&pdev->dev, ret, "Failed to setup role switch\n");
447
448 return 0;
449 }
450
dwc3_apple_remove(struct platform_device * pdev)451 static void dwc3_apple_remove(struct platform_device *pdev)
452 {
453 struct dwc3 *dwc = platform_get_drvdata(pdev);
454 struct dwc3_apple *appledwc = to_dwc3_apple(dwc);
455
456 guard(mutex)(&appledwc->lock);
457
458 usb_role_switch_unregister(appledwc->role_sw);
459
460 /*
461 * If we're still in DWC3_APPLE_PROBE_PENDING we never got any cable connected event and
462 * dwc3_core_probe was never called and there's hence no need to call dwc3_core_remove.
463 * dwc3_apple_exit can be called unconditionally because it checks the state itself.
464 */
465 dwc3_apple_exit(appledwc);
466 if (appledwc->state != DWC3_APPLE_PROBE_PENDING)
467 dwc3_core_remove(&appledwc->dwc);
468 }
469
470 static const struct of_device_id dwc3_apple_of_match[] = {
471 { .compatible = "apple,t8103-dwc3" },
472 {}
473 };
474 MODULE_DEVICE_TABLE(of, dwc3_apple_of_match);
475
476 static struct platform_driver dwc3_apple_driver = {
477 .probe = dwc3_apple_probe,
478 .remove = dwc3_apple_remove,
479 .driver = {
480 .name = "dwc3-apple",
481 .of_match_table = dwc3_apple_of_match,
482 },
483 };
484
485 module_platform_driver(dwc3_apple_driver);
486
487 MODULE_LICENSE("GPL");
488 MODULE_AUTHOR("Sven Peter <sven@kernel.org>");
489 MODULE_DESCRIPTION("DesignWare DWC3 Apple Silicon Glue Driver");
490