+// SPDX-License-Identifier: GPL-2.0+
/*
* Most of this source has been derived from the Linux USB
* project:
*
* Adapted for U-Boot:
* (C) Copyright 2001 Denis Peter, MPL AG Switzerland
- *
- * SPDX-License-Identifier: GPL-2.0+
*/
/****************************************************************************
#include <common.h>
#include <command.h>
#include <dm.h>
+#include <env.h>
#include <errno.h>
+#include <log.h>
+#include <malloc.h>
#include <memalign.h>
#include <asm/processor.h>
#include <asm/unaligned.h>
#include <linux/ctype.h>
+#include <linux/delay.h>
#include <linux/list.h>
#include <asm/byteorder.h>
#ifdef CONFIG_SANDBOX
#endif
#include <asm/unaligned.h>
-DECLARE_GLOBAL_DATA_PTR;
-
#include <usb.h>
#define USB_BUFSIZ 512
#define HUB_SHORT_RESET_TIME 20
#define HUB_LONG_RESET_TIME 200
+#define HUB_DEBOUNCE_TIMEOUT CONFIG_USB_HUB_DEBOUNCE_TIMEOUT
+
#define PORT_OVERCURRENT_MAX_SCAN_COUNT 3
struct usb_device_scan {
return hdev->descriptor.bDeviceProtocol == 3;
}
-#ifdef CONFIG_DM_USB
+#if CONFIG_IS_ENABLED(DM_USB)
bool usb_hub_is_root_hub(struct udevice *hub)
{
if (device_get_uclass_id(hub->parent) != UCLASS_USB_HUB)
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
data, sizeof(struct usb_port_status), USB_CNTL_TIMEOUT);
-#ifdef CONFIG_DM_USB
+#if CONFIG_IS_ENABLED(DM_USB)
if (ret < 0)
return ret;
if (!usb_hub_is_root_hub(dev->dev) && usb_hub_is_superspeed(dev)) {
struct usb_port_status *status = (struct usb_port_status *)data;
- u16 tmp = (status->wPortStatus) & USB_SS_PORT_STAT_MASK;
+ u16 tmp = le16_to_cpu(status->wPortStatus) &
+ USB_SS_PORT_STAT_MASK;
if (status->wPortStatus & USB_SS_PORT_STAT_POWER)
tmp |= USB_PORT_STAT_POWER;
USB_SS_PORT_STAT_SPEED_5GBPS)
tmp |= USB_PORT_STAT_SUPER_SPEED;
- status->wPortStatus = tmp;
+ status->wPortStatus = cpu_to_le16(tmp);
}
#endif
int i;
struct usb_device *dev;
unsigned pgood_delay = hub->desc.bPwrOn2PwrGood * 2;
- const char *env;
+ const char __maybe_unused *env;
dev = hub->pusb_dev;
debug("enabling power on all ports\n");
for (i = 0; i < dev->maxchild; i++) {
+ if (usb_hub_is_superspeed(dev)) {
+ usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_RESET);
+ debug("Reset : port %d returns %lX\n", i + 1, dev->status);
+ }
usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
- debug("port %d returns %lX\n", i + 1, dev->status);
+ debug("PowerOn : port %d returns %lX\n", i + 1, dev->status);
}
#ifdef CONFIG_SANDBOX
* but allow this time to be increased via env variable as some
* devices break the spec and require longer warm-up times
*/
+#if CONFIG_IS_ENABLED(ENV_SUPPORT)
env = env_get("usb_pgood_delay");
if (env)
pgood_delay = max(pgood_delay,
(unsigned)simple_strtol(env, NULL, 0));
+#endif
debug("pgood_delay=%dms\n", pgood_delay);
/*
* will be done based on this value in the USB port loop in
* usb_hub_configure() later.
*/
- hub->connect_timeout = hub->query_delay + 1000;
+ hub->connect_timeout = hub->query_delay + HUB_DEBOUNCE_TIMEOUT;
debug("devnum=%d poweron: query_delay=%d connect_timeout=%d\n",
dev->devnum, max(100, (int)pgood_delay),
- max(100, (int)pgood_delay) + 1000);
+ max(100, (int)pgood_delay) + HUB_DEBOUNCE_TIMEOUT);
}
-#ifndef CONFIG_DM_USB
+#if !CONFIG_IS_ENABLED(DM_USB)
static struct usb_hub_device hub_dev[USB_MAX_HUB];
static int usb_hub_index;
#define MAX_TRIES 5
-static inline char *portspeed(int portstatus)
+static inline const char *portspeed(int portstatus)
{
- char *speed_str;
-
switch (portstatus & USB_PORT_STAT_SPEED_MASK) {
case USB_PORT_STAT_SUPER_SPEED:
- speed_str = "5 Gb/s";
- break;
+ return "5 Gb/s";
case USB_PORT_STAT_HIGH_SPEED:
- speed_str = "480 Mb/s";
- break;
+ return "480 Mb/s";
case USB_PORT_STAT_LOW_SPEED:
- speed_str = "1.5 Mb/s";
- break;
+ return "1.5 Mb/s";
default:
- speed_str = "12 Mb/s";
- break;
+ return "12 Mb/s";
}
-
- return speed_str;
}
/**
unsigned short portstatus, portchange;
int delay = HUB_SHORT_RESET_TIME; /* start with short reset delay */
-#ifdef CONFIG_DM_USB
+#if CONFIG_IS_ENABLED(DM_USB)
debug("%s: resetting '%s' port %d...\n", __func__, dev->dev->name,
port + 1);
#else
break;
}
-#ifdef CONFIG_DM_USB
+ /*
+ * USB 2.0 7.1.7.5: devices must be able to accept a SetAddress()
+ * request (refer to Section 11.24.2 and Section 9.4 respectively)
+ * after the reset recovery time 10 ms
+ */
+ mdelay(10);
+
+#if CONFIG_IS_ENABLED(DM_USB)
struct udevice *child;
ret = usb_scan_device(dev->dev, port + 1, speed, &child);
if (portchange & USB_PORT_STAT_C_ENABLE) {
debug("port %d enable change, status %x\n", i + 1, portstatus);
usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE);
- /*
- * The following hack causes a ghost device problem
- * to Faraday EHCI
- */
-#ifndef CONFIG_USB_EHCI_FARADAY
/*
* EM interference sometimes causes bad shielded USB
* devices to be shutdown by the hub, this hack enables
i + 1);
usb_hub_port_connect_change(dev, i);
}
-#endif
}
if (portstatus & USB_PORT_STAT_SUSPEND) {
{
struct usb_hub_device *hub;
-#ifndef CONFIG_DM_USB
+#if !CONFIG_IS_ENABLED(DM_USB)
/* "allocate" Hub device */
hub = usb_hub_allocate();
#else
short hubCharacteristics;
struct usb_hub_descriptor *descriptor;
struct usb_hub_device *hub;
- __maybe_unused struct usb_hub_status *hubsts;
+ struct usb_hub_status *hubsts;
int ret;
hub = usb_get_hub_device(dev);
return ret;
}
-#ifdef DEBUG
hubsts = (struct usb_hub_status *)buffer;
-#endif
debug("get_hub_status returned status %X, change %X\n",
le16_to_cpu(hubsts->wHubStatus),
(le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \
"" : "no ");
-#ifdef CONFIG_DM_USB
+#if CONFIG_IS_ENABLED(DM_USB)
/*
* Update USB host controller's internal representation of this hub
* after the hub descriptor is fetched.
return ret;
}
-#ifdef CONFIG_DM_USB
+#if CONFIG_IS_ENABLED(DM_USB)
int usb_hub_scan(struct udevice *hub)
{
struct usb_device *udev = dev_get_parent_priv(hub);
.post_bind = dm_scan_fdt_dev,
.post_probe = usb_hub_post_probe,
.child_pre_probe = usb_child_pre_probe,
- .per_child_auto_alloc_size = sizeof(struct usb_device),
- .per_child_platdata_auto_alloc_size = sizeof(struct usb_dev_platdata),
- .per_device_auto_alloc_size = sizeof(struct usb_hub_device),
+ .per_child_auto = sizeof(struct usb_device),
+ .per_child_plat_auto = sizeof(struct usb_dev_plat),
+ .per_device_auto = sizeof(struct usb_hub_device),
};
static const struct usb_device_id hub_id_table[] = {