1 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
2 Date: Sat, 1 Oct 2016 22:54:48 +0200
3 Subject: [PATCH] usb: xhci: add support for performing fake doorbell
5 Broadcom's Northstar XHCI controllers seem to need a special start
6 procedure to work correctly. There isn't any official documentation of
7 this, the problem is that controller doesn't detect any connected
8 devices with default setup. Moreover connecting USB device to controller
9 that doesn't run properly can cause SoC's watchdog issues.
11 A workaround that was successfully tested on multiple devices is to
12 perform a fake doorbell. This patch adds code for doing this and enables
15 drivers/usb/host/xhci-plat.c | 6 +++++
16 drivers/usb/host/xhci.c | 63 +++++++++++++++++++++++++++++++++++++++++---
17 drivers/usb/host/xhci.h | 1 +
18 3 files changed, 67 insertions(+), 3 deletions(-)
20 --- a/drivers/usb/host/xhci-plat.c
21 +++ b/drivers/usb/host/xhci-plat.c
22 @@ -87,6 +87,8 @@ static int xhci_priv_resume_quirk(struct
23 static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
25 struct xhci_plat_priv *priv = xhci_to_priv(xhci);
26 + struct platform_device*pdev = to_platform_device(dev);
27 + struct device_node *node = pdev->dev.of_node;
30 * As of now platform drivers don't provide MSI support so we ensure
31 @@ -94,6 +96,9 @@ static void xhci_plat_quirks(struct devi
32 * dev struct in order to setup MSI
34 xhci->quirks |= XHCI_PLAT | priv->quirks;
36 + if (node && of_machine_is_compatible("brcm,bcm4708"))
37 + xhci->quirks |= XHCI_FAKE_DOORBELL;
40 /* called during probe() after chip reset completes */
41 --- a/drivers/usb/host/xhci.c
42 +++ b/drivers/usb/host/xhci.c
43 @@ -156,6 +156,49 @@ int xhci_start(struct xhci_hcd *xhci)
48 + * xhci_fake_doorbell - Perform a fake doorbell on a specified slot
50 + * Some controllers require a fake doorbell to start correctly. Without that
51 + * they simply don't detect any devices.
53 +static int xhci_fake_doorbell(struct xhci_hcd *xhci, int slot_id)
57 + /* Alloc a virt device for that slot */
58 + if (!xhci_alloc_virt_device(xhci, slot_id, NULL, GFP_NOIO)) {
59 + xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
63 + /* Ring fake doorbell for slot_id ep 0 */
64 + xhci_ring_ep_doorbell(xhci, slot_id, 0, 0);
65 + usleep_range(1000, 1500);
67 + /* Read the status to check if HSE is set or not */
68 + temp = readl(&xhci->op_regs->status);
70 + /* Clear HSE if set */
71 + if (temp & STS_FATAL) {
72 + xhci_dbg(xhci, "HSE problem detected, status: 0x%08x\n", temp);
75 + writel(temp, &xhci->op_regs->status);
76 + usleep_range(1000, 1500);
77 + readl(&xhci->op_regs->status);
80 + /* Free virt device */
81 + xhci_free_virt_device(xhci, slot_id);
83 + /* We're done if controller is already running */
84 + if (readl(&xhci->op_regs->command) & CMD_RUN)
87 + return xhci_start(xhci);
93 @@ -608,10 +651,20 @@ static int xhci_init(struct usb_hcd *hcd
95 static int xhci_run_finished(struct xhci_hcd *xhci)
97 - if (xhci_start(xhci)) {
102 + err = xhci_start(xhci);
108 + if (xhci->quirks & XHCI_FAKE_DOORBELL) {
109 + err = xhci_fake_doorbell(xhci, 1);
114 xhci->shared_hcd->state = HC_STATE_RUNNING;
115 xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
117 @@ -621,6 +674,10 @@ static int xhci_run_finished(struct xhci
118 xhci_dbg_trace(xhci, trace_xhci_dbg_init,
119 "Finished xhci_run for USB3 roothub");
128 --- a/drivers/usb/host/xhci.h
129 +++ b/drivers/usb/host/xhci.h
130 @@ -1880,6 +1880,7 @@ struct xhci_hcd {
131 #define XHCI_DISABLE_SPARSE BIT_ULL(38)
132 #define XHCI_SG_TRB_CACHE_SIZE_QUIRK BIT_ULL(39)
133 #define XHCI_NO_SOFT_RETRY BIT_ULL(40)
134 +#define XHCI_FAKE_DOORBELL BIT_ULL(41)
136 unsigned int num_active_eps;
137 unsigned int limit_active_eps;