aboutsummaryrefslogtreecommitdiff
path: root/payloads/libpayload/drivers/usb/ohci_rh.c
diff options
context:
space:
mode:
authorNico Huber <nico.huber@secunet.com>2012-05-21 14:46:26 +0200
committerStefan Reinauer <stefan.reinauer@coreboot.org>2012-06-07 23:49:02 +0200
commitafe86c0b74cc7f5dcaefc34155daf299e8377353 (patch)
tree398d5b1caf5cbdd81f3b3764420343dabc52a455 /payloads/libpayload/drivers/usb/ohci_rh.c
parent5e3428ea2093e028c7f976b69032b1882e10e6ca (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.c50
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