Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: 0ec946d32ef7 ("usb: dwc3: Add Apple Silicon DWC3 glue layer driver")
Cc: stable <stable@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>
Link: https://patch.msgid.link/20260109-dwc3-apple-usb2phy-fix-v2-1-ab6b041e3b26@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Sven Peter and committed by
Greg Kroah-Hartman
c4380ee3 2740ac33

+33 -15
+33 -15
drivers/usb/dwc3/dwc3-apple.c
··· 218 218 return ret; 219 219 } 220 220 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 - 234 221 static int dwc3_apple_init(struct dwc3_apple *appledwc, enum dwc3_apple_state state) 235 222 { 236 223 int ret, ret_reset; 237 224 238 225 lockdep_assert_held(&appledwc->lock); 226 + 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 + } 239 245 240 246 ret = reset_control_deassert(appledwc->reset); 241 247 if (ret) { ··· 263 257 case DWC3_APPLE_HOST: 264 258 appledwc->dwc.dr_mode = USB_DR_MODE_HOST; 265 259 dwc3_apple_set_ptrcap(appledwc, DWC3_GCTL_PRTCAP_HOST); 266 - dwc3_apple_phy_set_mode(appledwc, PHY_MODE_USB_HOST); 260 + /* 261 + * This platform requires SUSPHY to be enabled here already in order to properly 262 + * configure the PHY and switch dwc3's PIPE interface to USB3 PHY. The USB2 PHY 263 + * has already been configured to the correct mode earlier. 264 + */ 265 + dwc3_enable_susphy(&appledwc->dwc, true); 266 + phy_set_mode(appledwc->dwc.usb3_generic_phy[0], PHY_MODE_USB_HOST); 267 267 ret = dwc3_host_init(&appledwc->dwc); 268 268 if (ret) { 269 269 dev_err(appledwc->dev, "Failed to initialize host, ret=%d\n", ret); ··· 280 268 case DWC3_APPLE_DEVICE: 281 269 appledwc->dwc.dr_mode = USB_DR_MODE_PERIPHERAL; 282 270 dwc3_apple_set_ptrcap(appledwc, DWC3_GCTL_PRTCAP_DEVICE); 283 - dwc3_apple_phy_set_mode(appledwc, PHY_MODE_USB_DEVICE); 271 + /* 272 + * This platform requires SUSPHY to be enabled here already in order to properly 273 + * configure the PHY and switch dwc3's PIPE interface to USB3 PHY. The USB2 PHY 274 + * has already been configured to the correct mode earlier. 275 + */ 276 + dwc3_enable_susphy(&appledwc->dwc, true); 277 + phy_set_mode(appledwc->dwc.usb3_generic_phy[0], PHY_MODE_USB_DEVICE); 284 278 ret = dwc3_gadget_init(&appledwc->dwc); 285 279 if (ret) { 286 280 dev_err(appledwc->dev, "Failed to initialize gadget, ret=%d\n", ret);