mirror of
https://git.codelinaro.org/clo/qsdk/oss/boot/u-boot-2016.git
synced 2026-03-01 17:36:03 +01:00
Merge "usb: hub: Translate USB 3.0 hub port status into old version"
This commit is contained in:
commit
315f1e32fa
7 changed files with 154 additions and 16 deletions
112
common/usb_hub.c
112
common/usb_hub.c
|
|
@ -46,9 +46,6 @@ DECLARE_GLOBAL_DATA_PTR;
|
|||
|
||||
#define USB_BUFSIZ 512
|
||||
|
||||
/* TODO(sjg@chromium.org): Remove this when CONFIG_DM_USB is defined */
|
||||
static struct usb_hub_device hub_dev[USB_MAX_HUB];
|
||||
static int usb_hub_index;
|
||||
|
||||
__weak void usb_hub_reset_devices(int port)
|
||||
{
|
||||
|
|
@ -68,6 +65,16 @@ bool usb_hub_is_root_hub(struct udevice *hub)
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int usb_set_hub_depth(struct usb_device *dev, int depth)
|
||||
{
|
||||
if (depth < 0 || depth > 4)
|
||||
return -EINVAL;
|
||||
|
||||
return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
|
||||
USB_REQ_SET_HUB_DEPTH, USB_DIR_OUT | USB_RT_HUB,
|
||||
depth, 0, NULL, 0, USB_CNTL_TIMEOUT);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
|
||||
|
|
@ -105,9 +112,40 @@ static int usb_get_hub_status(struct usb_device *dev, void *data)
|
|||
|
||||
int usb_get_port_status(struct usb_device *dev, int port, void *data)
|
||||
{
|
||||
return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
|
||||
int ret;
|
||||
|
||||
ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
|
||||
USB_REQ_GET_STATUS, USB_DIR_IN | USB_RT_PORT, 0, port,
|
||||
data, sizeof(struct usb_hub_status), USB_CNTL_TIMEOUT);
|
||||
|
||||
#ifdef CONFIG_DM_USB
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Translate the USB 3.0 hub port status field into the old version
|
||||
* that U-Boot understands. Do this only when the hub is not root hub.
|
||||
* For root hub, the port status field has already been translated
|
||||
* in the host controller driver (see xhci_submit_root() in xhci.c).
|
||||
*
|
||||
* Note: this only supports driver model.
|
||||
*/
|
||||
|
||||
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;
|
||||
|
||||
if (status->wPortStatus & USB_SS_PORT_STAT_POWER)
|
||||
tmp |= USB_PORT_STAT_POWER;
|
||||
if ((status->wPortStatus & USB_SS_PORT_STAT_SPEED) ==
|
||||
USB_SS_PORT_STAT_SPEED_5GBPS)
|
||||
tmp |= USB_PORT_STAT_SUPER_SPEED;
|
||||
|
||||
status->wPortStatus = tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -140,6 +178,10 @@ static void usb_hub_power_on(struct usb_hub_device *hub)
|
|||
mdelay(pgood_delay + 1000);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_DM_USB
|
||||
static struct usb_hub_device hub_dev[USB_MAX_HUB];
|
||||
static int usb_hub_index;
|
||||
|
||||
void usb_hub_reset(void)
|
||||
{
|
||||
usb_hub_index = 0;
|
||||
|
|
@ -153,6 +195,7 @@ static struct usb_hub_device *usb_hub_allocate(void)
|
|||
printf("ERROR: USB_MAX_HUB (%d) reached\n", USB_MAX_HUB);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define MAX_TRIES 5
|
||||
|
||||
|
|
@ -351,6 +394,20 @@ int usb_hub_port_connect_change(struct usb_device *dev, int port)
|
|||
}
|
||||
|
||||
|
||||
static struct usb_hub_device *usb_get_hub_device(struct usb_device *dev)
|
||||
{
|
||||
struct usb_hub_device *hub;
|
||||
|
||||
#ifndef CONFIG_DM_USB
|
||||
/* "allocate" Hub device */
|
||||
hub = usb_hub_allocate();
|
||||
#else
|
||||
hub = dev_get_uclass_priv(dev->dev);
|
||||
#endif
|
||||
|
||||
return hub;
|
||||
}
|
||||
|
||||
static int usb_hub_configure(struct usb_device *dev)
|
||||
{
|
||||
int i, length;
|
||||
|
|
@ -362,11 +419,11 @@ static int usb_hub_configure(struct usb_device *dev)
|
|||
__maybe_unused struct usb_hub_status *hubsts;
|
||||
int ret;
|
||||
|
||||
/* "allocate" Hub device */
|
||||
hub = usb_hub_allocate();
|
||||
hub = usb_get_hub_device(dev);
|
||||
if (hub == NULL)
|
||||
return -ENOMEM;
|
||||
hub->pusb_dev = dev;
|
||||
|
||||
/* Get the the hub descriptor */
|
||||
ret = usb_get_hub_descriptor(dev, buffer, 4);
|
||||
if (ret < 0) {
|
||||
|
|
@ -476,6 +533,48 @@ static int usb_hub_configure(struct usb_device *dev)
|
|||
debug("%sover-current condition exists\n",
|
||||
(le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \
|
||||
"" : "no ");
|
||||
|
||||
#ifdef CONFIG_DM_USB
|
||||
/*
|
||||
* A maximum of seven tiers are allowed in a USB topology, and the
|
||||
* root hub occupies the first tier. The last tier ends with a normal
|
||||
* USB device. USB 3.0 hubs use a 20-bit field called 'route string'
|
||||
* to route packets to the designated downstream port. The hub uses a
|
||||
* hub depth value multiplied by four as an offset into the 'route
|
||||
* string' to locate the bits it uses to determine the downstream
|
||||
* port number.
|
||||
*/
|
||||
if (usb_hub_is_root_hub(dev->dev)) {
|
||||
hub->hub_depth = -1;
|
||||
} else {
|
||||
struct udevice *hdev;
|
||||
int depth = 0;
|
||||
|
||||
hdev = dev->dev->parent;
|
||||
while (!usb_hub_is_root_hub(hdev)) {
|
||||
depth++;
|
||||
hdev = hdev->parent;
|
||||
}
|
||||
|
||||
hub->hub_depth = depth;
|
||||
|
||||
if (usb_hub_is_superspeed(dev)) {
|
||||
debug("set hub (%p) depth to %d\n", dev, depth);
|
||||
/*
|
||||
* This request sets the value that the hub uses to
|
||||
* determine the index into the 'route string index'
|
||||
* for this hub.
|
||||
*/
|
||||
ret = usb_set_hub_depth(dev, depth);
|
||||
if (ret < 0) {
|
||||
debug("%s: failed to set hub depth (%lX)\n",
|
||||
__func__, dev->status);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
usb_hub_power_on(hub);
|
||||
|
||||
/*
|
||||
|
|
@ -677,6 +776,7 @@ UCLASS_DRIVER(usb_hub) = {
|
|||
.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),
|
||||
};
|
||||
|
||||
static const struct usb_device_id hub_id_table[] = {
|
||||
|
|
|
|||
|
|
@ -174,7 +174,6 @@ int usb_stop(void)
|
|||
#ifdef CONFIG_USB_STORAGE
|
||||
usb_stor_reset();
|
||||
#endif
|
||||
usb_hub_reset();
|
||||
uc_priv->companion_device_count = 0;
|
||||
usb_started = 0;
|
||||
|
||||
|
|
@ -227,7 +226,6 @@ int usb_init(void)
|
|||
int ret;
|
||||
|
||||
asynch_allowed = 1;
|
||||
usb_hub_reset();
|
||||
|
||||
ret = uclass_get(UCLASS_USB, &uc);
|
||||
if (ret)
|
||||
|
|
|
|||
|
|
@ -626,14 +626,21 @@ void xhci_slot_copy(struct xhci_ctrl *ctrl, struct xhci_container_ctx *in_ctx,
|
|||
* @param udev pointer to the Device Data Structure
|
||||
* @return returns negative value on failure else 0 on success
|
||||
*/
|
||||
void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, int slot_id,
|
||||
int speed, int hop_portnr)
|
||||
void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
|
||||
struct usb_device *udev, int hop_portnr)
|
||||
{
|
||||
struct xhci_virt_device *virt_dev;
|
||||
struct xhci_ep_ctx *ep0_ctx;
|
||||
struct xhci_slot_ctx *slot_ctx;
|
||||
u32 port_num = 0;
|
||||
u64 trb_64 = 0;
|
||||
int slot_id = udev->slot_id;
|
||||
int speed = udev->speed;
|
||||
int route = 0;
|
||||
#ifdef CONFIG_DM_USB
|
||||
struct usb_device *dev = udev;
|
||||
struct usb_hub_device *hub;
|
||||
#endif
|
||||
|
||||
virt_dev = ctrl->devs[slot_id];
|
||||
|
||||
|
|
@ -644,7 +651,32 @@ void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, int slot_id,
|
|||
slot_ctx = xhci_get_slot_ctx(ctrl, virt_dev->in_ctx);
|
||||
|
||||
/* Only the control endpoint is valid - one endpoint context */
|
||||
slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | 0);
|
||||
slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1));
|
||||
|
||||
#ifdef CONFIG_DM_USB
|
||||
/* Calculate the route string for this device */
|
||||
port_num = dev->portnr;
|
||||
while (!usb_hub_is_root_hub(dev->dev)) {
|
||||
hub = dev_get_uclass_priv(dev->dev);
|
||||
/*
|
||||
* Each hub in the topology is expected to have no more than
|
||||
* 15 ports in order for the route string of a device to be
|
||||
* unique. SuperSpeed hubs are restricted to only having 15
|
||||
* ports, but FS/LS/HS hubs are not. The xHCI specification
|
||||
* says that if the port number the device is greater than 15,
|
||||
* that portion of the route string shall be set to 15.
|
||||
*/
|
||||
if (port_num > 15)
|
||||
port_num = 15;
|
||||
route |= port_num << (hub->hub_depth * 4);
|
||||
dev = dev_get_parent_priv(dev->dev);
|
||||
port_num = dev->portnr;
|
||||
dev = dev_get_parent_priv(dev->dev->parent);
|
||||
}
|
||||
|
||||
debug("route string %x\n", route);
|
||||
#endif
|
||||
slot_ctx->dev_info |= route;
|
||||
|
||||
switch (speed) {
|
||||
case USB_SPEED_SUPER:
|
||||
|
|
|
|||
|
|
@ -415,8 +415,7 @@ static int xhci_address_device(struct usb_device *udev, int root_portnr)
|
|||
* so setting up the slot context.
|
||||
*/
|
||||
debug("Setting up addressable devices %p\n", ctrl->dcbaa);
|
||||
xhci_setup_addressable_virt_dev(ctrl, udev->slot_id, udev->speed,
|
||||
root_portnr);
|
||||
xhci_setup_addressable_virt_dev(ctrl, udev, root_portnr);
|
||||
|
||||
ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx);
|
||||
ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
|
||||
|
|
|
|||
|
|
@ -1244,8 +1244,8 @@ void xhci_endpoint_copy(struct xhci_ctrl *ctrl,
|
|||
void xhci_slot_copy(struct xhci_ctrl *ctrl,
|
||||
struct xhci_container_ctx *in_ctx,
|
||||
struct xhci_container_ctx *out_ctx);
|
||||
void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl, int slot_id,
|
||||
int speed, int hop_portnr);
|
||||
void xhci_setup_addressable_virt_dev(struct xhci_ctrl *ctrl,
|
||||
struct usb_device *udev, int hop_portnr);
|
||||
void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr,
|
||||
u32 slot_id, u32 ep_index, trb_type cmd);
|
||||
void xhci_acknowledge_event(struct xhci_ctrl *ctrl);
|
||||
|
|
|
|||
|
|
@ -566,6 +566,7 @@ struct usb_hub_descriptor {
|
|||
struct usb_hub_device {
|
||||
struct usb_device *pusb_dev;
|
||||
struct usb_hub_descriptor desc;
|
||||
int hub_depth; /* USB 3.0 hub depth */
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DM_USB
|
||||
|
|
|
|||
|
|
@ -262,12 +262,17 @@
|
|||
|
||||
/*
|
||||
* Changes to wPortStatus bit field in USB 3.0
|
||||
* See USB 3.0 spec Table 10-11
|
||||
* See USB 3.0 spec Table 10-10
|
||||
*/
|
||||
#define USB_SS_PORT_STAT_LINK_STATE 0x01e0
|
||||
#define USB_SS_PORT_STAT_POWER 0x0200
|
||||
#define USB_SS_PORT_STAT_SPEED 0x1c00
|
||||
#define USB_SS_PORT_STAT_SPEED_5GBPS 0x0000
|
||||
/* Bits that are the same from USB 2.0 */
|
||||
#define USB_SS_PORT_STAT_MASK (USB_PORT_STAT_CONNECTION | \
|
||||
USB_PORT_STAT_ENABLE | \
|
||||
USB_PORT_STAT_OVERCURRENT | \
|
||||
USB_PORT_STAT_RESET)
|
||||
|
||||
/* wPortChange bits */
|
||||
#define USB_PORT_STAT_C_CONNECTION 0x0001
|
||||
|
|
@ -301,6 +306,9 @@
|
|||
/* Mask for wIndex in get/set port feature */
|
||||
#define USB_HUB_PORT_MASK 0xf
|
||||
|
||||
/* Hub class request codes */
|
||||
#define USB_REQ_SET_HUB_DEPTH 0x0c
|
||||
|
||||
/*
|
||||
* CBI style
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue