diff options
Diffstat (limited to 'drivers/usb/host/xhci.c')
| -rw-r--r-- | drivers/usb/host/xhci.c | 57 |
1 files changed, 49 insertions, 8 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 40e0a0c221b8..27345cd04da0 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c | |||
| @@ -106,6 +106,33 @@ int xhci_halt(struct xhci_hcd *xhci) | |||
| 106 | } | 106 | } |
| 107 | 107 | ||
| 108 | /* | 108 | /* |
| 109 | * Set the run bit and wait for the host to be running. | ||
| 110 | */ | ||
| 111 | int xhci_start(struct xhci_hcd *xhci) | ||
| 112 | { | ||
| 113 | u32 temp; | ||
| 114 | int ret; | ||
| 115 | |||
| 116 | temp = xhci_readl(xhci, &xhci->op_regs->command); | ||
| 117 | temp |= (CMD_RUN); | ||
| 118 | xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n", | ||
| 119 | temp); | ||
| 120 | xhci_writel(xhci, temp, &xhci->op_regs->command); | ||
| 121 | |||
| 122 | /* | ||
| 123 | * Wait for the HCHalted Status bit to be 0 to indicate the host is | ||
| 124 | * running. | ||
| 125 | */ | ||
| 126 | ret = handshake(xhci, &xhci->op_regs->status, | ||
| 127 | STS_HALT, 0, XHCI_MAX_HALT_USEC); | ||
| 128 | if (ret == -ETIMEDOUT) | ||
| 129 | xhci_err(xhci, "Host took too long to start, " | ||
| 130 | "waited %u microseconds.\n", | ||
| 131 | XHCI_MAX_HALT_USEC); | ||
| 132 | return ret; | ||
| 133 | } | ||
| 134 | |||
| 135 | /* | ||
| 109 | * Reset a halted HC, and set the internal HC state to HC_STATE_HALT. | 136 | * Reset a halted HC, and set the internal HC state to HC_STATE_HALT. |
| 110 | * | 137 | * |
| 111 | * This resets pipelines, timers, counters, state machines, etc. | 138 | * This resets pipelines, timers, counters, state machines, etc. |
| @@ -116,6 +143,7 @@ int xhci_reset(struct xhci_hcd *xhci) | |||
| 116 | { | 143 | { |
| 117 | u32 command; | 144 | u32 command; |
| 118 | u32 state; | 145 | u32 state; |
| 146 | int ret; | ||
| 119 | 147 | ||
| 120 | state = xhci_readl(xhci, &xhci->op_regs->status); | 148 | state = xhci_readl(xhci, &xhci->op_regs->status); |
| 121 | if ((state & STS_HALT) == 0) { | 149 | if ((state & STS_HALT) == 0) { |
| @@ -130,7 +158,17 @@ int xhci_reset(struct xhci_hcd *xhci) | |||
| 130 | /* XXX: Why does EHCI set this here? Shouldn't other code do this? */ | 158 | /* XXX: Why does EHCI set this here? Shouldn't other code do this? */ |
| 131 | xhci_to_hcd(xhci)->state = HC_STATE_HALT; | 159 | xhci_to_hcd(xhci)->state = HC_STATE_HALT; |
| 132 | 160 | ||
| 133 | return handshake(xhci, &xhci->op_regs->command, CMD_RESET, 0, 250 * 1000); | 161 | ret = handshake(xhci, &xhci->op_regs->command, |
| 162 | CMD_RESET, 0, 250 * 1000); | ||
| 163 | if (ret) | ||
| 164 | return ret; | ||
| 165 | |||
| 166 | xhci_dbg(xhci, "Wait for controller to be ready for doorbell rings\n"); | ||
| 167 | /* | ||
| 168 | * xHCI cannot write to any doorbells or operational registers other | ||
| 169 | * than status until the "Controller Not Ready" flag is cleared. | ||
| 170 | */ | ||
| 171 | return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000); | ||
| 134 | } | 172 | } |
| 135 | 173 | ||
| 136 | 174 | ||
| @@ -448,17 +486,20 @@ int xhci_run(struct usb_hcd *hcd) | |||
| 448 | 486 | ||
| 449 | if (NUM_TEST_NOOPS > 0) | 487 | if (NUM_TEST_NOOPS > 0) |
| 450 | doorbell = xhci_setup_one_noop(xhci); | 488 | doorbell = xhci_setup_one_noop(xhci); |
| 489 | if (xhci->quirks & XHCI_NEC_HOST) | ||
| 490 | xhci_queue_vendor_command(xhci, 0, 0, 0, | ||
| 491 | TRB_TYPE(TRB_NEC_GET_FW)); | ||
| 492 | |||
| 493 | if (xhci_start(xhci)) { | ||
| 494 | xhci_halt(xhci); | ||
| 495 | return -ENODEV; | ||
| 496 | } | ||
| 451 | 497 | ||
| 452 | temp = xhci_readl(xhci, &xhci->op_regs->command); | ||
| 453 | temp |= (CMD_RUN); | ||
| 454 | xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n", | ||
| 455 | temp); | ||
| 456 | xhci_writel(xhci, temp, &xhci->op_regs->command); | ||
| 457 | /* Flush PCI posted writes */ | ||
| 458 | temp = xhci_readl(xhci, &xhci->op_regs->command); | ||
| 459 | xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp); | 498 | xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp); |
| 460 | if (doorbell) | 499 | if (doorbell) |
| 461 | (*doorbell)(xhci); | 500 | (*doorbell)(xhci); |
| 501 | if (xhci->quirks & XHCI_NEC_HOST) | ||
| 502 | xhci_ring_cmd_db(xhci); | ||
| 462 | 503 | ||
| 463 | xhci_dbg(xhci, "Finished xhci_run\n"); | 504 | xhci_dbg(xhci, "Finished xhci_run\n"); |
| 464 | return 0; | 505 | return 0; |
