From: Lukasz Czechowski Date: Tue, 22 Jul 2025 09:55:35 +0000 (+0200) Subject: usb: onboard-hub: Set the reset gpio pin before freeing X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=42a025412d737cd57874b81de8c8f49fea538c8b;p=thirdparty%2Fu-boot.git usb: onboard-hub: Set the reset gpio pin before freeing In the usb_onboard_hub_remove, the reset gpio, if available, is freed. The pin state however, remains unchanged, as set in the usb_onboard_hub_reset. The hub is then left enabled. During second onboard hub probing, the hub is initially enabled (reset pin in state "0"), and then it is being reset by the reset function (transition to "1" and then to "0"). Because of this, the hub first disconnects from root hub, and then it connects again. When the devices are being discovered in the usb_scan_port in the usb_hub driver, initially there is the USB_PORT_STAT_CONNECTION bit not set in portstatus, but USB_PORT_STAT_C_CONNECTION set in portchange data (which is because disconnect event occurred first). In this condition, the driver does not wait for devices to appear. This can cause the hub (and all child devices) to be not enumerated when rescanning on "usb reset" command. To fix this, set the reset gpio to active in usb_onboard_hub_remove, to put the hub into reset state. However, in case the hub reset pin is by default held in high state by HW before U-Boot takes over, in which case the USB hub is active, then during the first probe it gets reset and we might get into the same issue of the hub being not enumerated. Reviewed-by: Quentin Schulz Signed-off-by: Lukasz Czechowski --- diff --git a/common/usb_onboard_hub.c b/common/usb_onboard_hub.c index c6379192fe8..046831d0966 100644 --- a/common/usb_onboard_hub.c +++ b/common/usb_onboard_hub.c @@ -211,6 +211,13 @@ static int usb_onboard_hub_remove(struct udevice *dev) struct onboard_hub *hub = dev_get_priv(dev); int ret = 0; + if (hub->reset_gpio) { + ret = dm_gpio_set_value(hub->reset_gpio, 1); + if (ret) + dev_err(dev, "can't set gpio %s: %d\n", hub->reset_gpio->dev->name, + ret); + } + if (hub->vdd) { ret = regulator_set_enable_if_allowed(hub->vdd, false); if (ret)