summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorVivek Gautam <gautam.vivek@samsung.com>2013-04-12 16:34:35 +0530
committerMarek Vasut <marex@denx.de>2013-05-05 23:54:22 +0200
commit020bbcb76b5be0d5406d2ae7c26dbdb013ead812 (patch)
tree514516d7255a259dd155edef84af0ae610fc174e /common
parent605bd75af565011aa46e6d80a32e2aa03aff8159 (diff)
usb: hub: Power-cycle on root-hub ports
XHCI ports are powered on after a H/W reset, however EHCI ports are not. So disabling and re-enabling power on all ports invariably. Signed-off-by: Amar <amarendra.xt@samsung.com> Signed-off-by: Vivek Gautam <gautam.vivek@samsung.com>
Diffstat (limited to 'common')
-rw-r--r--common/usb_hub.c34
1 files changed, 34 insertions, 0 deletions
diff --git a/common/usb_hub.c b/common/usb_hub.c
index f2a02854fa..e4f4e3cd32 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -100,11 +100,45 @@ 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 */
debug("enabling power on all ports\n");
for (i = 0; i < dev->maxchild; i++) {
+ /*
+ * Power-cycle the ports here: aka,
+ * turning them off and turning on again.
+ */
+ 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);
+
+ 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;
+ }
+
usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
debug("port %d returns %lX\n", i + 1, dev->status);
}