From 9cc14ca0aae53c16d10ffea49848ac61a5015562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 21 Jun 2015 11:10:49 +0200 Subject: [PATCH] xhci: add Broadcom specific fake doorbell MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes problem with controller seeing devices only in some small percentage of cold boots. Signed-off-by: Rafał Miłecki --- drivers/usb/host/xhci.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -122,6 +122,64 @@ int xhci_halt(struct xhci_hcd *xhci) return ret; } +#ifdef CONFIG_ARCH_BCM_5301X +int xhci_fake_doorbell(struct xhci_hcd *xhci, int slot_id) +{ + unsigned int temp1, ret; + + /* alloc a virt device for slot */ + if (!xhci_alloc_virt_device(xhci, slot_id, 0, GFP_NOIO)) { + xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n"); + return 1; + } + + /* ring fake doorbell for slot_id ep 0 */ + xhci_ring_ep_doorbell(xhci, slot_id, 0, 0); + mdelay(1); + + /* read the status register to check if HSE is set or not? */ + temp1 = readl(&xhci->op_regs->status); + xhci_dbg(xhci, "op reg status = %x\n",temp1); + + /* clear HSE if set */ + if(temp1 & STS_FATAL) { + xhci_dbg(xhci, "HSE problem detected\n"); + temp1 &= ~(0x1fff); + temp1 |= STS_FATAL; + xhci_dbg(xhci, "temp1=%x\n",temp1); + writel(temp1, &xhci->op_regs->status); + mdelay(1); + temp1 = readl(&xhci->op_regs->status); + xhci_dbg(xhci, "After clear op reg status=%x\n", temp1); + } + + /* Free virt device */ + xhci_free_virt_device(xhci, slot_id); + + /* Run the controller if needed */ + temp1 = readl(&xhci->op_regs->command); + if (temp1 & CMD_RUN) + return 0; + temp1 |= (CMD_RUN); + + writel(temp1, &xhci->op_regs->command); + /* + * Wait for the HCHalted Status bit to be 0 to indicate the host is running. + */ + ret = xhci_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 1; + } + + return 0; +} +#endif /* CONFIG_ARCH_BCM_5301X */ + /* * Set the run bit and wait for the host to be running. */ @@ -146,6 +204,10 @@ static int xhci_start(struct xhci_hcd *x xhci_err(xhci, "Host took too long to start, " "waited %u microseconds.\n", XHCI_MAX_HALT_USEC); +#ifdef CONFIG_ARCH_BCM_5301X + xhci_fake_doorbell(xhci, 1); +#endif /* CONFIG_ARCH_BCM_5301X */ + if (!ret) xhci->xhc_state &= ~(XHCI_STATE_HALTED | XHCI_STATE_DYING);