diff options
author | Philipp Tomsich <philipp.tomsich@theobroma-systems.com> | 2017-11-22 17:15:18 +0100 |
---|---|---|
committer | Philipp Tomsich <philipp.tomsich@theobroma-systems.com> | 2017-11-30 22:55:27 +0100 |
commit | 614539d4f79669413e3336f349c487b605f2bb6b (patch) | |
tree | 1dd186de3ce447c42976fc358728d07b60d17ad0 /board | |
parent | fd1f80aab654adaa06d1293487bacdcd5958d799 (diff) | |
download | u-boot-614539d4f79669413e3336f349c487b605f2bb6b.tar.gz u-boot-614539d4f79669413e3336f349c487b605f2bb6b.tar.xz u-boot-614539d4f79669413e3336f349c487b605f2bb6b.zip |
rockchip: rk3399-puma: implement usb_hub_reset_devices for puma-rk3399
For some versions of the RK3399-Q7 (at least revisions v1.1 and v1.2
are affected), we need to turn on the power for the port connected to
the on-module USB hub only when the device is probed for the first
time to ensure that the hub does not enter a low-power mode (that
U-Boot's USB stack can't deal with).
Note that this is needed for U-Boot only, as Linux eventually manages
to attach the hub even when it has entered into its low-power state
(when the hub wakes up the next time) after a few seconds.
Signed-off-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
Tested-by: Jakob Unterwurzacher <jakob.unterwurzacher@theobroma-systems.com>
Diffstat (limited to 'board')
-rw-r--r-- | board/theobroma-systems/puma_rk3399/puma-rk3399.c | 70 |
1 files changed, 69 insertions, 1 deletions
diff --git a/board/theobroma-systems/puma_rk3399/puma-rk3399.c b/board/theobroma-systems/puma_rk3399/puma-rk3399.c index 2b4988e2d2..7f2dd65d44 100644 --- a/board/theobroma-systems/puma_rk3399/puma-rk3399.c +++ b/board/theobroma-systems/puma_rk3399/puma-rk3399.c @@ -7,12 +7,13 @@ #include <common.h> #include <dm.h> #include <misc.h> +#include <spl.h> +#include <usb.h> #include <dm/pinctrl.h> #include <dm/uclass-internal.h> #include <asm/setup.h> #include <asm/arch/periph.h> #include <power/regulator.h> -#include <spl.h> #include <u-boot/sha256.h> DECLARE_GLOBAL_DATA_PTR; @@ -158,3 +159,70 @@ void get_board_serial(struct tag_serialnr *serialnr) serialnr->low = (u32)(serial & 0xffffffff); } #endif + +/** + * Switch power at an external regulator (for our root hub). + * + * @param ctrl pointer to the xHCI controller + * @param port port number as in the control message (one-based) + * @param enable boolean indicating whether to enable or disable power + * @return returns 0 on success, an error-code on failure + */ +static int board_usb_port_power_set(struct udevice *dev, int port, + bool enable) +{ +#if CONFIG_IS_ENABLED(OF_CONTROL) && CONFIG_IS_ENABLED(DM_REGULATOR) + /* We start counting ports at 0, while USB counts from 1. */ + int index = port - 1; + const char *regname = NULL; + struct udevice *regulator; + const char *prop = "tsd,usb-port-power"; + int ret; + + debug("%s: ctrl '%s' port %d enable %s\n", __func__, + dev_read_name(dev), port, enable ? "true" : "false"); + + ret = dev_read_string_index(dev, prop, index, ®name); + if (ret < 0) { + debug("%s: ctrl '%s' port %d: no entry in '%s'\n", + __func__, dev_read_name(dev), port, prop); + return ret; + } + + ret = regulator_get_by_platname(regname, ®ulator); + if (ret) { + debug("%s: ctrl '%s' port %d: could not get regulator '%s'\n", + __func__, dev_read_name(dev), port, regname); + return ret; + } + + regulator_set_enable(regulator, enable); + return 0; +#else + return -ENOTSUPP; +#endif +} + +void usb_hub_reset_devices(struct usb_hub_device *hub, int port) +{ + struct udevice *dev = hub->pusb_dev->dev; + struct udevice *ctrl; + + /* We are only interested in our root-hubs */ + if (usb_hub_is_root_hub(dev) == false) + return; + + ctrl = usb_get_bus(dev); + if (!ctrl) { + debug("%s: could not retrieve ctrl for hub\n", __func__); + return; + } + + /* + * To work around an incompatibility between the single-threaded + * USB stack in U-Boot and (a strange low-power mode of) the USB + * hub we have on-module, we need to delay powering on the hub + * until the first time the port is probed. + */ + board_usb_port_power_set(ctrl, port, true); +} |