Merge "usb: hub: Translate USB 3.0 hub port status into old version"

This commit is contained in:
Linux Build Service Account 2018-06-08 07:56:44 -07:00 committed by Gerrit - the friendly Code Review server
commit 315f1e32fa
7 changed files with 154 additions and 16 deletions

View file

@ -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[] = {

View file

@ -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)

View file

@ -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:

View file

@ -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);

View file

@ -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);

View file

@ -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

View file

@ -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
*/