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 40e0a0c221b..27345cd04da 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -106,6 +106,33 @@ int xhci_halt(struct xhci_hcd *xhci)  }  /* + * Set the run bit and wait for the host to be running. + */ +int xhci_start(struct xhci_hcd *xhci) +{ +	u32 temp; +	int ret; + +	temp = xhci_readl(xhci, &xhci->op_regs->command); +	temp |= (CMD_RUN); +	xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n", +			temp); +	xhci_writel(xhci, temp, &xhci->op_regs->command); + +	/* +	 * Wait for the HCHalted Status bit to be 0 to indicate the host is +	 * running. +	 */ +	ret = handshake(xhci, &xhci->op_regs->status, +			STS_HALT, 0, XHCI_MAX_HALT_USEC); +	if (ret == -ETIMEDOUT) +		xhci_err(xhci, "Host took too long to start, " +				"waited %u microseconds.\n", +				XHCI_MAX_HALT_USEC); +	return ret; +} + +/*   * Reset a halted HC, and set the internal HC state to HC_STATE_HALT.   *   * This resets pipelines, timers, counters, state machines, etc. @@ -116,6 +143,7 @@ int xhci_reset(struct xhci_hcd *xhci)  {  	u32 command;  	u32 state; +	int ret;  	state = xhci_readl(xhci, &xhci->op_regs->status);  	if ((state & STS_HALT) == 0) { @@ -130,7 +158,17 @@ int xhci_reset(struct xhci_hcd *xhci)  	/* XXX: Why does EHCI set this here?  Shouldn't other code do this? */  	xhci_to_hcd(xhci)->state = HC_STATE_HALT; -	return handshake(xhci, &xhci->op_regs->command, CMD_RESET, 0, 250 * 1000); +	ret = handshake(xhci, &xhci->op_regs->command, +			CMD_RESET, 0, 250 * 1000); +	if (ret) +		return ret; + +	xhci_dbg(xhci, "Wait for controller to be ready for doorbell rings\n"); +	/* +	 * xHCI cannot write to any doorbells or operational registers other +	 * than status until the "Controller Not Ready" flag is cleared. +	 */ +	return handshake(xhci, &xhci->op_regs->status, STS_CNR, 0, 250 * 1000);  } @@ -448,17 +486,20 @@ int xhci_run(struct usb_hcd *hcd)  	if (NUM_TEST_NOOPS > 0)  		doorbell = xhci_setup_one_noop(xhci); +	if (xhci->quirks & XHCI_NEC_HOST) +		xhci_queue_vendor_command(xhci, 0, 0, 0, +				TRB_TYPE(TRB_NEC_GET_FW)); + +	if (xhci_start(xhci)) { +		xhci_halt(xhci); +		return -ENODEV; +	} -	temp = xhci_readl(xhci, &xhci->op_regs->command); -	temp |= (CMD_RUN); -	xhci_dbg(xhci, "// Turn on HC, cmd = 0x%x.\n", -			temp); -	xhci_writel(xhci, temp, &xhci->op_regs->command); -	/* Flush PCI posted writes */ -	temp = xhci_readl(xhci, &xhci->op_regs->command);  	xhci_dbg(xhci, "// @%p = 0x%x\n", &xhci->op_regs->command, temp);  	if (doorbell)  		(*doorbell)(xhci); +	if (xhci->quirks & XHCI_NEC_HOST) +		xhci_ring_cmd_db(xhci);  	xhci_dbg(xhci, "Finished xhci_run\n");  	return 0;  |