1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
From 9cc14ca0aae53c16d10ffea49848ac61a5015562 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
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 <zajec5@gmail.com>
---
drivers/usb/host/xhci.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 62 insertions(+)
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -121,6 +121,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->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.
*/
@@ -145,6 +203,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;
return ret;
|