diff options
Diffstat (limited to 'common/usb_hub.c')
-rw-r--r-- | common/usb_hub.c | 242 |
1 files changed, 143 insertions, 99 deletions
diff --git a/common/usb_hub.c b/common/usb_hub.c index b5eeb62..0d79ec3 100644 --- a/common/usb_hub.c +++ b/common/usb_hub.c @@ -53,17 +53,6 @@ #include <asm/4xx_pci.h> #endif -#ifdef DEBUG -#define USB_DEBUG 1 -#define USB_HUB_DEBUG 1 -#else -#define USB_DEBUG 0 -#define USB_HUB_DEBUG 0 -#endif - -#define USB_PRINTF(fmt, args...) debug_cond(USB_DEBUG, fmt, ##args) -#define USB_HUB_PRINTF(fmt, args...) debug_cond(USB_HUB_DEBUG, fmt, ##args) - #define USB_BUFSIZ 512 static struct usb_hub_device hub_dev[USB_MAX_HUB]; @@ -111,13 +100,52 @@ static void usb_hub_power_on(struct usb_hub_device *hub) int i; struct usb_device *dev; unsigned pgood_delay = hub->desc.bPwrOn2PwrGood * 2; + ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); + unsigned short portstatus; + int ret; dev = hub->pusb_dev; - /* Enable power to the ports */ - USB_HUB_PRINTF("enabling power on all ports\n"); + + /* + * Enable power to the ports: + * Here we Power-cycle the ports: aka, + * turning them off and turning on again. + */ + debug("enabling power on all ports\n"); + for (i = 0; i < dev->maxchild; i++) { + usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); + debug("port %d returns %lX\n", i + 1, dev->status); + } + + /* Wait at least 2*bPwrOn2PwrGood for PP to change */ + mdelay(pgood_delay); + + for (i = 0; i < dev->maxchild; i++) { + ret = usb_get_port_status(dev, i + 1, portsts); + if (ret < 0) { + debug("port %d: get_port_status failed\n", i + 1); + return; + } + + /* + * Check to confirm the state of Port Power: + * xHCI says "After modifying PP, s/w shall read + * PP and confirm that it has reached the desired state + * before modifying it again, undefined behavior may occur + * if this procedure is not followed". + * EHCI doesn't say anything like this, but no harm in keeping + * this. + */ + portstatus = le16_to_cpu(portsts->wPortStatus); + if (portstatus & (USB_PORT_STAT_POWER << 1)) { + debug("port %d: Port power change failed\n", i + 1); + return; + } + } + for (i = 0; i < dev->maxchild; i++) { usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); - USB_HUB_PRINTF("port %d returns %lX\n", i + 1, dev->status); + debug("port %d returns %lX\n", i + 1, dev->status); } /* Wait at least 100 msec for power to become stable */ @@ -142,12 +170,24 @@ static struct usb_hub_device *usb_hub_allocate(void) static inline char *portspeed(int portstatus) { - if (portstatus & (1 << USB_PORT_FEAT_HIGHSPEED)) - return "480 Mb/s"; - else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED)) - return "1.5 Mb/s"; - else - return "12 Mb/s"; + char *speed_str; + + switch (portstatus & USB_PORT_STAT_SPEED_MASK) { + case USB_PORT_STAT_SUPER_SPEED: + speed_str = "5 Gb/s"; + break; + case USB_PORT_STAT_HIGH_SPEED: + speed_str = "480 Mb/s"; + break; + case USB_PORT_STAT_LOW_SPEED: + speed_str = "1.5 Mb/s"; + break; + default: + speed_str = "12 Mb/s"; + break; + } + + return speed_str; } int hub_port_reset(struct usb_device *dev, int port, @@ -157,29 +197,28 @@ int hub_port_reset(struct usb_device *dev, int port, ALLOC_CACHE_ALIGN_BUFFER(struct usb_port_status, portsts, 1); unsigned short portstatus, portchange; - USB_HUB_PRINTF("hub_port_reset: resetting port %d...\n", port); + debug("hub_port_reset: resetting port %d...\n", port); for (tries = 0; tries < MAX_TRIES; tries++) { usb_set_port_feature(dev, port + 1, USB_PORT_FEAT_RESET); mdelay(200); if (usb_get_port_status(dev, port + 1, portsts) < 0) { - USB_HUB_PRINTF("get_port_status failed status %lX\n", - dev->status); + debug("get_port_status failed status %lX\n", + dev->status); return -1; } portstatus = le16_to_cpu(portsts->wPortStatus); portchange = le16_to_cpu(portsts->wPortChange); - USB_HUB_PRINTF("portstatus %x, change %x, %s\n", - portstatus, portchange, - portspeed(portstatus)); + debug("portstatus %x, change %x, %s\n", portstatus, portchange, + portspeed(portstatus)); - USB_HUB_PRINTF("STAT_C_CONNECTION = %d STAT_CONNECTION = %d" \ - " USB_PORT_STAT_ENABLE %d\n", - (portchange & USB_PORT_STAT_C_CONNECTION) ? 1 : 0, - (portstatus & USB_PORT_STAT_CONNECTION) ? 1 : 0, - (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0); + debug("STAT_C_CONNECTION = %d STAT_CONNECTION = %d" \ + " USB_PORT_STAT_ENABLE %d\n", + (portchange & USB_PORT_STAT_C_CONNECTION) ? 1 : 0, + (portstatus & USB_PORT_STAT_CONNECTION) ? 1 : 0, + (portstatus & USB_PORT_STAT_ENABLE) ? 1 : 0); if ((portchange & USB_PORT_STAT_C_CONNECTION) || !(portstatus & USB_PORT_STAT_CONNECTION)) @@ -192,9 +231,9 @@ int hub_port_reset(struct usb_device *dev, int port, } if (tries == MAX_TRIES) { - USB_HUB_PRINTF("Cannot enable port %i after %i retries, " \ - "disabling port.\n", port + 1, MAX_TRIES); - USB_HUB_PRINTF("Maybe the USB cable is bad?\n"); + debug("Cannot enable port %i after %i retries, " \ + "disabling port.\n", port + 1, MAX_TRIES); + debug("Maybe the USB cable is bad?\n"); return -1; } @@ -212,15 +251,15 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) /* Check status */ if (usb_get_port_status(dev, port + 1, portsts) < 0) { - USB_HUB_PRINTF("get_port_status failed\n"); + debug("get_port_status failed\n"); return; } portstatus = le16_to_cpu(portsts->wPortStatus); - USB_HUB_PRINTF("portstatus %x, change %x, %s\n", - portstatus, - le16_to_cpu(portsts->wPortChange), - portspeed(portstatus)); + debug("portstatus %x, change %x, %s\n", + portstatus, + le16_to_cpu(portsts->wPortChange), + portspeed(portstatus)); /* Clear the connection change status */ usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_C_CONNECTION); @@ -228,7 +267,7 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) /* Disconnect any existing devices under this port */ if (((!(portstatus & USB_PORT_STAT_CONNECTION)) && (!(portstatus & USB_PORT_STAT_ENABLE))) || (dev->children[port])) { - USB_HUB_PRINTF("usb_disconnect(&hub->children[port]);\n"); + debug("usb_disconnect(&hub->children[port]);\n"); /* Return now if nothing is connected */ if (!(portstatus & USB_PORT_STAT_CONNECTION)) return; @@ -246,12 +285,20 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) /* Allocate a new device struct for it */ usb = usb_alloc_new_device(dev->controller); - if (portstatus & USB_PORT_STAT_HIGH_SPEED) + switch (portstatus & USB_PORT_STAT_SPEED_MASK) { + case USB_PORT_STAT_SUPER_SPEED: + usb->speed = USB_SPEED_SUPER; + break; + case USB_PORT_STAT_HIGH_SPEED: usb->speed = USB_SPEED_HIGH; - else if (portstatus & USB_PORT_STAT_LOW_SPEED) + break; + case USB_PORT_STAT_LOW_SPEED: usb->speed = USB_SPEED_LOW; - else + break; + default: usb->speed = USB_SPEED_FULL; + break; + } dev->children[port] = usb; usb->parent = dev; @@ -261,7 +308,7 @@ void usb_hub_port_connect_change(struct usb_device *dev, int port) /* Woops, disable the port */ usb_free_device(); dev->children[port] = NULL; - USB_HUB_PRINTF("hub: disabling port %d\n", port + 1); + debug("hub: disabling port %d\n", port + 1); usb_clear_port_feature(dev, port + 1, USB_PORT_FEAT_ENABLE); } } @@ -275,9 +322,7 @@ static int usb_hub_configure(struct usb_device *dev) short hubCharacteristics; struct usb_hub_descriptor *descriptor; struct usb_hub_device *hub; -#ifdef USB_HUB_DEBUG - struct usb_hub_status *hubsts; -#endif + __maybe_unused struct usb_hub_status *hubsts; /* "allocate" Hub device */ hub = usb_hub_allocate(); @@ -286,8 +331,8 @@ static int usb_hub_configure(struct usb_device *dev) hub->pusb_dev = dev; /* Get the the hub descriptor */ if (usb_get_hub_descriptor(dev, buffer, 4) < 0) { - USB_HUB_PRINTF("usb_hub_configure: failed to get hub " \ - "descriptor, giving up %lX\n", dev->status); + debug("usb_hub_configure: failed to get hub " \ + "descriptor, giving up %lX\n", dev->status); return -1; } descriptor = (struct usb_hub_descriptor *)buffer; @@ -295,15 +340,14 @@ static int usb_hub_configure(struct usb_device *dev) /* silence compiler warning if USB_BUFSIZ is > 256 [= sizeof(char)] */ i = descriptor->bLength; if (i > USB_BUFSIZ) { - USB_HUB_PRINTF("usb_hub_configure: failed to get hub " \ - "descriptor - too long: %d\n", - descriptor->bLength); + debug("usb_hub_configure: failed to get hub " \ + "descriptor - too long: %d\n", descriptor->bLength); return -1; } if (usb_get_hub_descriptor(dev, buffer, descriptor->bLength) < 0) { - USB_HUB_PRINTF("usb_hub_configure: failed to get hub " \ - "descriptor 2nd giving up %lX\n", dev->status); + debug("usb_hub_configure: failed to get hub " \ + "descriptor 2nd giving up %lX\n", dev->status); return -1; } memcpy((unsigned char *)&hub->desc, buffer, descriptor->bLength); @@ -325,74 +369,75 @@ static int usb_hub_configure(struct usb_device *dev) hub->desc.PortPowerCtrlMask[i] = descriptor->PortPowerCtrlMask[i]; dev->maxchild = descriptor->bNbrPorts; - USB_HUB_PRINTF("%d ports detected\n", dev->maxchild); + debug("%d ports detected\n", dev->maxchild); hubCharacteristics = get_unaligned(&hub->desc.wHubCharacteristics); switch (hubCharacteristics & HUB_CHAR_LPSM) { case 0x00: - USB_HUB_PRINTF("ganged power switching\n"); + debug("ganged power switching\n"); break; case 0x01: - USB_HUB_PRINTF("individual port power switching\n"); + debug("individual port power switching\n"); break; case 0x02: case 0x03: - USB_HUB_PRINTF("unknown reserved power switching mode\n"); + debug("unknown reserved power switching mode\n"); break; } if (hubCharacteristics & HUB_CHAR_COMPOUND) - USB_HUB_PRINTF("part of a compound device\n"); + debug("part of a compound device\n"); else - USB_HUB_PRINTF("standalone hub\n"); + debug("standalone hub\n"); switch (hubCharacteristics & HUB_CHAR_OCPM) { case 0x00: - USB_HUB_PRINTF("global over-current protection\n"); + debug("global over-current protection\n"); break; case 0x08: - USB_HUB_PRINTF("individual port over-current protection\n"); + debug("individual port over-current protection\n"); break; case 0x10: case 0x18: - USB_HUB_PRINTF("no over-current protection\n"); + debug("no over-current protection\n"); break; } - USB_HUB_PRINTF("power on to power good time: %dms\n", - descriptor->bPwrOn2PwrGood * 2); - USB_HUB_PRINTF("hub controller current requirement: %dmA\n", - descriptor->bHubContrCurrent); + debug("power on to power good time: %dms\n", + descriptor->bPwrOn2PwrGood * 2); + debug("hub controller current requirement: %dmA\n", + descriptor->bHubContrCurrent); for (i = 0; i < dev->maxchild; i++) - USB_HUB_PRINTF("port %d is%s removable\n", i + 1, - hub->desc.DeviceRemovable[(i + 1) / 8] & \ - (1 << ((i + 1) % 8)) ? " not" : ""); + debug("port %d is%s removable\n", i + 1, + hub->desc.DeviceRemovable[(i + 1) / 8] & \ + (1 << ((i + 1) % 8)) ? " not" : ""); if (sizeof(struct usb_hub_status) > USB_BUFSIZ) { - USB_HUB_PRINTF("usb_hub_configure: failed to get Status - " \ - "too long: %d\n", descriptor->bLength); + debug("usb_hub_configure: failed to get Status - " \ + "too long: %d\n", descriptor->bLength); return -1; } if (usb_get_hub_status(dev, buffer) < 0) { - USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\n", - dev->status); + debug("usb_hub_configure: failed to get Status %lX\n", + dev->status); return -1; } -#ifdef USB_HUB_DEBUG +#ifdef DEBUG hubsts = (struct usb_hub_status *)buffer; #endif - USB_HUB_PRINTF("get_hub_status returned status %X, change %X\n", - le16_to_cpu(hubsts->wHubStatus), - le16_to_cpu(hubsts->wHubChange)); - USB_HUB_PRINTF("local power source is %s\n", - (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? \ - "lost (inactive)" : "good"); - USB_HUB_PRINTF("%sover-current condition exists\n", - (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \ - "" : "no "); + + debug("get_hub_status returned status %X, change %X\n", + le16_to_cpu(hubsts->wHubStatus), + le16_to_cpu(hubsts->wHubChange)); + debug("local power source is %s\n", + (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_LOCAL_POWER) ? \ + "lost (inactive)" : "good"); + debug("%sover-current condition exists\n", + (le16_to_cpu(hubsts->wHubStatus) & HUB_STATUS_OVERCURRENT) ? \ + "" : "no "); usb_hub_power_on(hub); for (i = 0; i < dev->maxchild; i++) { @@ -412,7 +457,7 @@ static int usb_hub_configure(struct usb_device *dev) do { ret = usb_get_port_status(dev, i + 1, portsts); if (ret < 0) { - USB_HUB_PRINTF("get_port_status failed\n"); + debug("get_port_status failed\n"); break; } @@ -423,22 +468,21 @@ static int usb_hub_configure(struct usb_device *dev) (portstatus & USB_PORT_STAT_CONNECTION)) break; - mdelay(100); } while (get_timer(start) < CONFIG_SYS_HZ * 10); if (ret < 0) continue; - USB_HUB_PRINTF("Port %d Status %X Change %X\n", - i + 1, portstatus, portchange); + debug("Port %d Status %X Change %X\n", + i + 1, portstatus, portchange); if (portchange & USB_PORT_STAT_C_CONNECTION) { - USB_HUB_PRINTF("port %d connection change\n", i + 1); + debug("port %d connection change\n", i + 1); usb_hub_port_connect_change(dev, i); } if (portchange & USB_PORT_STAT_C_ENABLE) { - USB_HUB_PRINTF("port %d enable change, status %x\n", - i + 1, portstatus); + debug("port %d enable change, status %x\n", + i + 1, portstatus); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_ENABLE); @@ -448,27 +492,27 @@ static int usb_hub_configure(struct usb_device *dev) if (!(portstatus & USB_PORT_STAT_ENABLE) && (portstatus & USB_PORT_STAT_CONNECTION) && ((dev->children[i]))) { - USB_HUB_PRINTF("already running port %i " \ - "disabled by hub (EMI?), " \ - "re-enabling...\n", i + 1); - usb_hub_port_connect_change(dev, i); + debug("already running port %i " \ + "disabled by hub (EMI?), " \ + "re-enabling...\n", i + 1); + usb_hub_port_connect_change(dev, i); } } if (portstatus & USB_PORT_STAT_SUSPEND) { - USB_HUB_PRINTF("port %d suspend change\n", i + 1); + debug("port %d suspend change\n", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_SUSPEND); } if (portchange & USB_PORT_STAT_C_OVERCURRENT) { - USB_HUB_PRINTF("port %d over-current change\n", i + 1); + debug("port %d over-current change\n", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_OVER_CURRENT); usb_hub_power_on(hub); } if (portchange & USB_PORT_STAT_C_RESET) { - USB_HUB_PRINTF("port %d reset change\n", i + 1); + debug("port %d reset change\n", i + 1); usb_clear_port_feature(dev, i + 1, USB_PORT_FEAT_C_RESET); } @@ -503,7 +547,7 @@ int usb_hub_probe(struct usb_device *dev, int ifnum) if ((ep->bmAttributes & 3) != 3) return 0; /* We found a hub */ - USB_HUB_PRINTF("USB hub found\n"); + debug("USB hub found\n"); ret = usb_hub_configure(dev); return ret; } |