Hi Fabrice

On 12/12/22 11:44, Fabrice Gasnier wrote:
> The main issue the driver addresses is that a USB hub needs to be
> powered before it can be discovered. This is often solved by using
> "regulator-always-on".
> 
> This driver is inspired by the Linux v6.1 driver. It only enables (or
> disables) the hub vdd (3v3) supply, so it can be enumerated.
> Scanning of the device tree is done in a similar manner to the sandbox,
> by the usb-uclass. DT part looks like:
> 
> &usbh_ehci {
>       ...
>       #address-cells = <1>;
>       #size-cells = <0>;
>       hub@1 {
>               compatible = "usb424,2514";
>               reg = <1>;
>               vdd-supply = <&v3v3>;
>       };
> };
> 
> When the bus gets probed, the driver is automatically probed/removed from
> the bus tree, as an example on stm32:
> STM32MP> usb start
> starting USB...
> STM32MP> dm tree
>  Class     Index  Probed  Driver                Name
> -----------------------------------------------------------
>  usb           0  [ + ]   ehci_generic          |   |-- usb@5800d000
>  usb_hub       0  [ + ]   usb_onboard_hub       |   |   `-- hub@1
>  usb_hub       1  [ + ]   usb_hub               |   |       `-- usb_hub
> 
> STM32MP> usb tree
> USB device tree:
>   1  Hub (480 Mb/s, 0mA)
>   |  u-boot EHCI Host Controller
>   |
>   +-2  Hub (480 Mb/s, 2mA)
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasn...@foss.st.com>
> ---
> 
>  common/Makefile               |  1 +
>  common/usb_onboard_hub.c      | 62 +++++++++++++++++++++++++++++++++++
>  drivers/usb/Kconfig           | 10 ++++++
>  drivers/usb/host/usb-uclass.c | 16 +++++----
>  4 files changed, 83 insertions(+), 6 deletions(-)
>  create mode 100644 common/usb_onboard_hub.c
> 
> diff --git a/common/Makefile b/common/Makefile
> index 20addfb244c2..7789aab484fd 100644
> --- a/common/Makefile
> +++ b/common/Makefile
> @@ -26,6 +26,7 @@ obj-$(CONFIG_PHYLIB) += miiphyutil.o
>  obj-$(CONFIG_USB_HOST) += usb.o usb_hub.o
>  obj-$(CONFIG_USB_GADGET) += usb.o usb_hub.o
>  obj-$(CONFIG_USB_STORAGE) += usb_storage.o
> +obj-$(CONFIG_USB_ONBOARD_HUB) += usb_onboard_hub.o
>  
>  # others
>  obj-$(CONFIG_CONSOLE_MUX) += iomux.o
> diff --git a/common/usb_onboard_hub.c b/common/usb_onboard_hub.c
> new file mode 100644
> index 000000000000..89e18a2ddad6
> --- /dev/null
> +++ b/common/usb_onboard_hub.c
> @@ -0,0 +1,62 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Driver for onboard USB hubs
> + *
> + * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
> + *
> + * Mostly inspired by Linux kernel v6.1 onboard_usb_hub driver
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <dm/device_compat.h>
> +#include <power/regulator.h>
> +
> +struct onboard_hub {
> +     struct udevice *vdd;
> +};
> +
> +static int usb_onboard_hub_probe(struct udevice *dev)
> +{
> +     struct onboard_hub *hub = dev_get_priv(dev);
> +     int ret;
> +
> +     ret = device_get_supply_regulator(dev, "vdd-supply", &hub->vdd);
> +     if (ret) {
> +             dev_err(dev, "can't get vdd-supply: %d\n", ret);
> +             return ret;
> +     }
> +
> +     ret = regulator_set_enable_if_allowed(hub->vdd, true);
> +     if (ret)
> +             dev_err(dev, "can't enable vdd-supply: %d\n", ret);
> +
> +     return ret;
> +}
> +
> +static int usb_onboard_hub_remove(struct udevice *dev)
> +{
> +     struct onboard_hub *hub = dev_get_priv(dev);
> +     int ret;
> +
> +     ret = regulator_set_enable_if_allowed(hub->vdd, false);
> +     if (ret)
> +             dev_err(dev, "can't disable vdd-supply: %d\n", ret);
> +
> +     return ret;
> +}
> +
> +static const struct udevice_id usb_onboard_hub_ids[] = {
> +     /* Use generic usbVID,PID dt-bindings (usb-device.yaml) */
> +     { .compatible = "usb424,2514" }, /* USB2514B USB 2.0 */
> +     { }
> +};
> +
> +U_BOOT_DRIVER(usb_onboard_hub) = {
> +     .name   = "usb_onboard_hub",
> +     .id     = UCLASS_USB_HUB,
> +     .probe = usb_onboard_hub_probe,
> +     .remove = usb_onboard_hub_remove,
> +     .of_match = usb_onboard_hub_ids,
> +     .priv_auto = sizeof(struct onboard_hub),
> +};
> diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
> index 3afb45d5ccb2..d10ee6853d40 100644
> --- a/drivers/usb/Kconfig
> +++ b/drivers/usb/Kconfig
> @@ -106,6 +106,16 @@ config USB_KEYBOARD
>         Say Y here if you want to use a USB keyboard for U-Boot command line
>         input.
>  
> +config USB_ONBOARD_HUB
> +     bool "Onboard USB hub support"
> +     depends on DM_USB
> +     ---help---
> +       Say Y here if you want to support discrete onboard USB hubs that
> +       don't require an additional control bus for initialization, but
> +       need some non-trivial form of initialization, such as enabling a
> +       power regulator. An example for such a hub is the Microchip
> +       USB2514B.
> +
>  if USB_KEYBOARD
>  
>  config USB_KEYBOARD_FN_KEYS
> diff --git a/drivers/usb/host/usb-uclass.c b/drivers/usb/host/usb-uclass.c
> index 060f3441df0c..f5dc93ffee39 100644
> --- a/drivers/usb/host/usb-uclass.c
> +++ b/drivers/usb/host/usb-uclass.c
> @@ -271,19 +271,23 @@ int usb_init(void)
>               /* init low_level USB */
>               printf("Bus %s: ", bus->name);
>  
> -#ifdef CONFIG_SANDBOX
>               /*
>                * For Sandbox, we need scan the device tree each time when we
>                * start the USB stack, in order to re-create the emulated USB
>                * devices and bind drivers for them before we actually do the
>                * driver probe.
> +              *
> +              * For USB onboard HUB, we need to do some non-trivial init
> +              * like enabling a power regulator, before enumeration.
>                */
> -             ret = dm_scan_fdt_dev(bus);
> -             if (ret) {
> -                     printf("Sandbox USB device scan failed (%d)\n", ret);
> -                     continue;
> +             if (IS_ENABLED(CONFIG_SANDBOX) ||
> +                 IS_ENABLED(CONFIG_USB_ONBOARD_HUB)) {
> +                     ret = dm_scan_fdt_dev(bus);
> +                     if (ret) {
> +                             printf("USB device scan from fdt failed (%d)", 
> ret);
> +                             continue;
> +                     }
>               }
> -#endif
>  
>               ret = device_probe(bus);
>               if (ret == -ENODEV) {   /* No such device. */

Reviewed-by: Patrice Chotard <patrice.chot...@foss.st.com>

Thanks
Patrice

Reply via email to