Skip to content

Commit ca76e69

Browse files
svenpeter42jannau
authored andcommitted
usb: dwc3: apple: Set USB2 PHY mode before dwc3 init
Now that the upstream code has been getting broader test coverage by our users we occasionally see issues with USB2 devices plugged in during boot. Before Linux is running, the USB2 PHY has usually been running in device mode and it turns out that sometimes host->device or device->host transitions don't work. The root cause: If the role inside the USB2 PHY is re-configured when it has already been powered on or when dwc3 has already enabled the ULPI interface the new configuration sometimes doesn't take affect until dwc3 is reset again. Fix this rare issue by configuring the role much earlier. Note that the USB3 PHY does not suffer from this issue and actually requires dwc3 to be up before the correct role can be configured there. Reported-by: James Calligeros <jcalligeros99@gmail.com> Reported-by: Janne Grunau <j@jannau.net> Fixes: 0ec946d ("usb: dwc3: Add Apple Silicon DWC3 glue layer driver") Cc: stable@vger.kernel.org Tested-by: Janne Grunau <j@jannau.net> Reviewed-by: Janne Grunau <j@jannau.net> Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com> Signed-off-by: Sven Peter <sven@kernel.org>
1 parent 481d2c4 commit ca76e69

1 file changed

Lines changed: 33 additions & 15 deletions

File tree

drivers/usb/dwc3/dwc3-apple.c

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -218,25 +218,31 @@ static int dwc3_apple_core_init(struct dwc3_apple *appledwc)
218218
return ret;
219219
}
220220

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-
234221
static int dwc3_apple_init(struct dwc3_apple *appledwc, enum dwc3_apple_state state)
235222
{
236223
int ret, ret_reset;
237224

238225
lockdep_assert_held(&appledwc->lock);
239226

227+
/*
228+
* The USB2 PHY on this platform must be configured for host or device mode while it is
229+
* still powered off and before dwc3 tries to access it. Otherwise, the new configuration
230+
* will sometimes only take affect after the *next* time dwc3 is brought up which causes
231+
* the connected device to just not work.
232+
* The USB3 PHY must be configured later after dwc3 has already been initialized.
233+
*/
234+
switch (state) {
235+
case DWC3_APPLE_HOST:
236+
phy_set_mode(appledwc->dwc.usb2_generic_phy[0], PHY_MODE_USB_HOST);
237+
break;
238+
case DWC3_APPLE_DEVICE:
239+
phy_set_mode(appledwc->dwc.usb2_generic_phy[0], PHY_MODE_USB_DEVICE);
240+
break;
241+
default:
242+
/* Unreachable unless there's a bug in this driver */
243+
return -EINVAL;
244+
}
245+
240246
ret = reset_control_deassert(appledwc->reset);
241247
if (ret) {
242248
dev_err(appledwc->dev, "Failed to deassert reset, err=%d\n", ret);
@@ -257,7 +263,13 @@ static int dwc3_apple_init(struct dwc3_apple *appledwc, enum dwc3_apple_state st
257263
case DWC3_APPLE_HOST:
258264
appledwc->dwc.dr_mode = USB_DR_MODE_HOST;
259265
dwc3_apple_set_ptrcap(appledwc, DWC3_GCTL_PRTCAP_HOST);
260-
dwc3_apple_phy_set_mode(appledwc, PHY_MODE_USB_HOST);
266+
/*
267+
* This platform requires SUSPHY to be enabled here already in order to properly
268+
* configure the PHY and switch dwc3's PIPE interface to USB3 PHY. The USB2 PHY
269+
* has already been configured to the correct mode earlier.
270+
*/
271+
dwc3_enable_susphy(&appledwc->dwc, true);
272+
phy_set_mode(appledwc->dwc.usb3_generic_phy[0], PHY_MODE_USB_HOST);
261273
ret = dwc3_host_init(&appledwc->dwc);
262274
if (ret) {
263275
dev_err(appledwc->dev, "Failed to initialize host, ret=%d\n", ret);
@@ -268,7 +280,13 @@ static int dwc3_apple_init(struct dwc3_apple *appledwc, enum dwc3_apple_state st
268280
case DWC3_APPLE_DEVICE:
269281
appledwc->dwc.dr_mode = USB_DR_MODE_PERIPHERAL;
270282
dwc3_apple_set_ptrcap(appledwc, DWC3_GCTL_PRTCAP_DEVICE);
271-
dwc3_apple_phy_set_mode(appledwc, PHY_MODE_USB_DEVICE);
283+
/*
284+
* This platform requires SUSPHY to be enabled here already in order to properly
285+
* configure the PHY and switch dwc3's PIPE interface to USB3 PHY. The USB2 PHY
286+
* has already been configured to the correct mode earlier.
287+
*/
288+
dwc3_enable_susphy(&appledwc->dwc, true);
289+
phy_set_mode(appledwc->dwc.usb3_generic_phy[0], PHY_MODE_USB_DEVICE);
272290
ret = dwc3_gadget_init(&appledwc->dwc);
273291
if (ret) {
274292
dev_err(appledwc->dev, "Failed to initialize gadget, ret=%d\n", ret);

0 commit comments

Comments
 (0)