summaryrefslogtreecommitdiff
path: root/board/theobroma-systems
diff options
context:
space:
mode:
authorPhilipp Tomsich <philipp.tomsich@theobroma-systems.com>2017-11-22 17:15:18 +0100
committerPhilipp Tomsich <philipp.tomsich@theobroma-systems.com>2017-11-30 22:55:27 +0100
commit614539d4f79669413e3336f349c487b605f2bb6b (patch)
tree1dd186de3ce447c42976fc358728d07b60d17ad0 /board/theobroma-systems
parentfd1f80aab654adaa06d1293487bacdcd5958d799 (diff)
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/theobroma-systems')
-rw-r--r--board/theobroma-systems/puma_rk3399/puma-rk3399.c70
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, &regname);
+ 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, &regulator);
+ 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);
+}