04d35437b1b638b49bd5271bed5b15e66eaaa997
[openwrt/openwrt.git] / target / linux / bcm53xx / patches-4.1 / 820-xhci-add-Broadcom-specific-fake-doorbell.patch
1 From 9cc14ca0aae53c16d10ffea49848ac61a5015562 Mon Sep 17 00:00:00 2001
2 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
3 Date: Sun, 21 Jun 2015 11:10:49 +0200
4 Subject: [PATCH] xhci: add Broadcom specific fake doorbell
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 This fixes problem with controller seeing devices only in some small
10 percentage of cold boots.
11
12 Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
13 ---
14 drivers/usb/host/xhci.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++
15 1 file changed, 62 insertions(+)
16
17 --- a/drivers/usb/host/xhci.c
18 +++ b/drivers/usb/host/xhci.c
19 @@ -121,6 +121,64 @@ int xhci_halt(struct xhci_hcd *xhci)
20 return ret;
21 }
22
23 +#ifdef CONFIG_ARCH_BCM_5301X
24 +int xhci_fake_doorbell(struct xhci_hcd *xhci, int slot_id)
25 +{
26 + unsigned int temp1, ret;
27 +
28 + /* alloc a virt device for slot */
29 + if (!xhci_alloc_virt_device(xhci, slot_id, 0, GFP_NOIO)) {
30 + xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
31 + return 1;
32 + }
33 +
34 + /* ring fake doorbell for slot_id ep 0 */
35 + xhci_ring_ep_doorbell(xhci, slot_id, 0, 0);
36 + mdelay(1);
37 +
38 + /* read the status register to check if HSE is set or not? */
39 + temp1 = readl(&xhci->op_regs->status);
40 + xhci_dbg(xhci, "op reg status = %x\n",temp1);
41 +
42 + /* clear HSE if set */
43 + if(temp1 & STS_FATAL) {
44 + xhci_dbg(xhci, "HSE problem detected\n");
45 + temp1 &= ~(0x1fff);
46 + temp1 |= STS_FATAL;
47 + xhci_dbg(xhci, "temp1=%x\n",temp1);
48 + writel(temp1, &xhci->op_regs->status);
49 + mdelay(1);
50 + temp1 = readl(&xhci->op_regs->status);
51 + xhci_dbg(xhci, "After clear op reg status=%x\n", temp1);
52 + }
53 +
54 + /* Free virt device */
55 + xhci_free_virt_device(xhci, slot_id);
56 +
57 + /* Run the controller if needed */
58 + temp1 = readl(&xhci->op_regs->command);
59 + if (temp1 & CMD_RUN)
60 + return 0;
61 + temp1 |= (CMD_RUN);
62 +
63 + writel(temp1, &xhci->op_regs->command);
64 + /*
65 + * Wait for the HCHalted Status bit to be 0 to indicate the host is running.
66 + */
67 + ret = xhci_handshake(&xhci->op_regs->status,
68 + STS_HALT, 0, XHCI_MAX_HALT_USEC);
69 +
70 + if (ret == -ETIMEDOUT) {
71 + xhci_err(xhci, "Host took too long to start, "
72 + "waited %u microseconds.\n",
73 + XHCI_MAX_HALT_USEC);
74 + return 1;
75 + }
76 +
77 + return 0;
78 +}
79 +#endif /* CONFIG_ARCH_BCM_5301X */
80 +
81 /*
82 * Set the run bit and wait for the host to be running.
83 */
84 @@ -145,6 +203,10 @@ static int xhci_start(struct xhci_hcd *x
85 xhci_err(xhci, "Host took too long to start, "
86 "waited %u microseconds.\n",
87 XHCI_MAX_HALT_USEC);
88 +#ifdef CONFIG_ARCH_BCM_5301X
89 + xhci_fake_doorbell(xhci, 1);
90 +#endif /* CONFIG_ARCH_BCM_5301X */
91 +
92 if (!ret)
93 xhci->xhc_state &= ~XHCI_STATE_HALTED;
94 return ret;