diff options
author | Nico Huber <nico.huber@secunet.com> | 2012-05-21 14:46:26 +0200 |
---|---|---|
committer | Stefan Reinauer <stefan.reinauer@coreboot.org> | 2012-06-07 23:49:02 +0200 |
commit | afe86c0b74cc7f5dcaefc34155daf299e8377353 (patch) | |
tree | 398d5b1caf5cbdd81f3b3764420343dabc52a455 /payloads/libpayload/drivers/usb/ohci_rh.c | |
parent | 5e3428ea2093e028c7f976b69032b1882e10e6ca (diff) |
libpayload: Add timeouts in the OHCI USB driver
We should always have some timeout when we wait for the hardware. This adds
missing timeouts and a more standard compliant port reset to the OHCI driver.
Change-Id: I2cfcb1039fd12f291e88dcb8b74d41cb5bb2315e
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: http://review.coreboot.org/1076
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'payloads/libpayload/drivers/usb/ohci_rh.c')
-rw-r--r-- | payloads/libpayload/drivers/usb/ohci_rh.c | 50 |
1 files changed, 40 insertions, 10 deletions
diff --git a/payloads/libpayload/drivers/usb/ohci_rh.c b/payloads/libpayload/drivers/usb/ohci_rh.c index 5cf7ee8376..ac92f45a46 100644 --- a/payloads/libpayload/drivers/usb/ohci_rh.c +++ b/payloads/libpayload/drivers/usb/ohci_rh.c @@ -43,15 +43,40 @@ typedef struct { static void ohci_rh_enable_port (usbdev_t *dev, int port) { - if (!(OHCI_INST(dev->controller)->opreg->HcRhPortStatus[port] & CurrentConnectStatus)) - return; - - OHCI_INST (dev->controller)->opreg->HcRhPortStatus[port] = SetPortEnable; // enable port - mdelay(10); - while (!(OHCI_INST (dev->controller)->opreg->HcRhPortStatus[port] & PortEnableStatus)) mdelay(1); - OHCI_INST (dev->controller)->opreg->HcRhPortStatus[port] = SetPortReset; // reset port - while (OHCI_INST (dev->controller)->opreg->HcRhPortStatus[port] & PortResetStatus) mdelay(1); - OHCI_INST (dev->controller)->opreg->HcRhPortStatus[port] = PortResetStatusChange; + /* Reset RH port should hold 50ms with pulses of at least 10ms and + * gaps of at most 3ms (usb20 spec 7.1.7.5). + * After reset, the port will be enabled automatically (ohci spec + * 7.4.4). + */ + int delay = 100; /* 100 * 500us == 50ms */ + while (delay > 0) { + if (!(OHCI_INST(dev->controller)->opreg->HcRhPortStatus[port] + & CurrentConnectStatus)) + return; + + /* start reset */ + OHCI_INST (dev->controller)->opreg->HcRhPortStatus[port] = + SetPortReset; + int timeout = 200; /* timeout after 200 * 500us == 100ms */ + while ((OHCI_INST (dev->controller)->opreg->HcRhPortStatus[port] + & PortResetStatus) + && timeout--) { + udelay(500); delay--; + } + if (OHCI_INST (dev->controller)->opreg->HcRhPortStatus[port] + & PortResetStatus) { + debug("Warning: root-hub port reset timed out.\n"); + break; + } + if ((200-timeout) < 20) + debug("Warning: port reset too short: %dms; " + "should be at least 10ms.\n", + (200-timeout)/2); + /* clear reset status change */ + OHCI_INST (dev->controller)->opreg->HcRhPortStatus[port] = + PortResetStatusChange; + debug ("rh port reset finished after %dms.\n", (200-timeout)/2); + } } /* disable root hub */ @@ -59,7 +84,12 @@ static void ohci_rh_disable_port (usbdev_t *dev, int port) { OHCI_INST (dev->controller)->opreg->HcRhPortStatus[port] = ClearPortEnable; // disable port - while (OHCI_INST (dev->controller)->opreg->HcRhPortStatus[port] & PortEnableStatus) mdelay(1); + int timeout = 50; /* timeout after 50 * 100us == 5ms */ + while ((OHCI_INST (dev->controller)->opreg->HcRhPortStatus[port] + & PortEnableStatus) + && timeout--) { + udelay(100); + } } static void |