X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=drivers%2Fusb%2Fhost%2Fehci-hcd.c;h=17187caed4827841615bf2f3a66b915bb291a131;hb=eb63218b9b95a59baa8b241f3a88e4415dabf833;hp=fdad739724eacb545817ebaf8128bdba96a82c91;hpb=8bc3603675f7bf4dfa4eb6bdaf2aa0a8ddce9fa6;p=oweals%2Fu-boot.git diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index fdad739724..17187caed4 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -36,6 +36,12 @@ #define CONFIG_USB_MAX_CONTROLLER_COUNT 1 #endif +/* + * EHCI spec page 20 says that the HC may take up to 16 uFrames (= 4ms) to halt. + * Let's time out after 8 to have a little safety margin on top of that. + */ +#define HCHALT_TIMEOUT (8 * 1000) + static struct ehci_ctrl ehcic[CONFIG_USB_MAX_CONTROLLER_COUNT]; #define ALIGN_END_ADDR(type, ptr, size) \ @@ -190,6 +196,39 @@ out: return ret; } +static int ehci_shutdown(struct ehci_ctrl *ctrl) +{ + int i, ret = 0; + uint32_t cmd, reg; + + if (!ctrl || !ctrl->hcor) + return -EINVAL; + + cmd = ehci_readl(&ctrl->hcor->or_usbcmd); + cmd &= ~(CMD_PSE | CMD_ASE); + ehci_writel(&ctrl->hcor->or_usbcmd, cmd); + ret = handshake(&ctrl->hcor->or_usbsts, STS_ASS | STS_PSS, 0, + 100 * 1000); + + if (!ret) { + for (i = 0; i < CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS; i++) { + reg = ehci_readl(&ctrl->hcor->or_portsc[i]); + reg |= EHCI_PS_SUSP; + ehci_writel(&ctrl->hcor->or_portsc[i], reg); + } + + cmd &= ~CMD_RUN; + ehci_writel(&ctrl->hcor->or_usbcmd, cmd); + ret = handshake(&ctrl->hcor->or_usbsts, STS_HALT, STS_HALT, + HCHALT_TIMEOUT); + } + + if (ret) + puts("EHCI failed to shut down host controller.\n"); + + return ret; +} + static int ehci_td_buffer(struct qTD *td, void *buf, size_t sz) { uint32_t delta, next; @@ -808,6 +847,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer, } break; case USB_PORT_FEAT_TEST: + ehci_shutdown(ctrl); reg &= ~(0xf << 16); reg |= ((le16_to_cpu(req->index) >> 8) & 0xf) << 16; ehci_writel(status_reg, reg); @@ -878,31 +918,37 @@ unknown: int usb_lowlevel_stop(int index) { + ehci_shutdown(&ehcic[index]); return ehci_hcd_stop(index); } -int usb_lowlevel_init(int index, void **controller) +int usb_lowlevel_init(int index, enum usb_init_type init, void **controller) { uint32_t reg; uint32_t cmd; struct QH *qh_list; struct QH *periodic; int i; + int rc; - if (ehci_hcd_init(index, &ehcic[index].hccr, &ehcic[index].hcor)) - return -1; + rc = ehci_hcd_init(index, init, &ehcic[index].hccr, &ehcic[index].hcor); + if (rc) + return rc; + if (init == USB_INIT_DEVICE) + goto done; /* EHCI spec section 4.1 */ if (ehci_reset(index)) return -1; #if defined(CONFIG_EHCI_HCD_INIT_AFTER_RESET) - if (ehci_hcd_init(index, &ehcic[index].hccr, &ehcic[index].hcor)) - return -1; + rc = ehci_hcd_init(index, init, &ehcic[index].hccr, &ehcic[index].hcor); + if (rc) + return rc; #endif /* Set the high address word (aka segment) for 64-bit controller */ if (ehci_readl(&ehcic[index].hccr->cr_hccparams) & 1) - ehci_writel(ehcic[index].hcor->or_ctrldssegment, 0); + ehci_writel(&ehcic[index].hcor->or_ctrldssegment, 0); qh_list = &ehcic[index].qh_list; @@ -999,7 +1045,7 @@ int usb_lowlevel_init(int index, void **controller) printf("USB EHCI %x.%02x\n", reg >> 8, reg & 0xff); ehcic[index].rootdev = 0; - +done: *controller = &ehcic[index]; return 0; }