OpenWrt – Blame information for rev 3
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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 |
||
4 | |||
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. |
||
10 | |||
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 |
||
13 | it on BCM4708 family. |
||
14 | --- |
||
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(-) |
||
19 | |||
20 | --- a/drivers/usb/host/xhci-plat.c |
||
21 | +++ b/drivers/usb/host/xhci-plat.c |
||
22 | @@ -67,12 +67,18 @@ static int xhci_priv_resume_quirk(struct |
||
23 | |||
24 | static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci) |
||
25 | { |
||
26 | + struct platform_device *pdev = to_platform_device(dev); |
||
27 | + struct device_node *node = pdev->dev.of_node; |
||
28 | + |
||
29 | /* |
||
30 | * As of now platform drivers don't provide MSI support so we ensure |
||
31 | * here that the generic code does not try to make a pci_dev from our |
||
32 | * dev struct in order to setup MSI |
||
33 | */ |
||
34 | xhci->quirks |= XHCI_PLAT; |
||
35 | + |
||
36 | + if (node && of_machine_is_compatible("brcm,bcm4708")) |
||
37 | + xhci->quirks |= XHCI_FAKE_DOORBELL; |
||
38 | } |
||
39 | |||
40 | /* called during probe() after chip reset completes */ |
||
41 | --- a/drivers/usb/host/xhci.c |
||
42 | +++ b/drivers/usb/host/xhci.c |
||
3 | office | 43 | @@ -153,6 +153,49 @@ int xhci_start(struct xhci_hcd *xhci) |
1 | office | 44 | return ret; |
45 | } |
||
46 | |||
47 | +/** |
||
48 | + * xhci_fake_doorbell - Perform a fake doorbell on a specified slot |
||
49 | + * |
||
50 | + * Some controllers require a fake doorbell to start correctly. Without that |
||
51 | + * they simply don't detect any devices. |
||
52 | + */ |
||
53 | +static int xhci_fake_doorbell(struct xhci_hcd *xhci, int slot_id) |
||
54 | +{ |
||
55 | + u32 temp; |
||
56 | + |
||
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"); |
||
60 | + return -ENOMEM; |
||
61 | + } |
||
62 | + |
||
63 | + /* Ring fake doorbell for slot_id ep 0 */ |
||
64 | + xhci_ring_ep_doorbell(xhci, slot_id, 0, 0); |
||
65 | + usleep_range(1000, 1500); |
||
66 | + |
||
67 | + /* Read the status to check if HSE is set or not */ |
||
68 | + temp = readl(&xhci->op_regs->status); |
||
69 | + |
||
70 | + /* Clear HSE if set */ |
||
71 | + if (temp & STS_FATAL) { |
||
72 | + xhci_dbg(xhci, "HSE problem detected, status: 0x%08x\n", temp); |
||
73 | + temp &= ~0x1fff; |
||
74 | + temp |= STS_FATAL; |
||
75 | + writel(temp, &xhci->op_regs->status); |
||
76 | + usleep_range(1000, 1500); |
||
77 | + readl(&xhci->op_regs->status); |
||
78 | + } |
||
79 | + |
||
80 | + /* Free virt device */ |
||
81 | + xhci_free_virt_device(xhci, slot_id); |
||
82 | + |
||
83 | + /* We're done if controller is already running */ |
||
84 | + if (readl(&xhci->op_regs->command) & CMD_RUN) |
||
85 | + return 0; |
||
86 | + |
||
87 | + return xhci_start(xhci); |
||
88 | +} |
||
89 | + |
||
90 | /* |
||
91 | * Reset a halted HC. |
||
92 | * |
||
3 | office | 93 | @@ -536,10 +579,20 @@ static int xhci_init(struct usb_hcd *hcd |
1 | office | 94 | |
95 | static int xhci_run_finished(struct xhci_hcd *xhci) |
||
96 | { |
||
97 | - if (xhci_start(xhci)) { |
||
98 | - xhci_halt(xhci); |
||
99 | - return -ENODEV; |
||
100 | + int err; |
||
101 | + |
||
102 | + err = xhci_start(xhci); |
||
103 | + if (err) { |
||
104 | + err = -ENODEV; |
||
105 | + goto err_halt; |
||
106 | } |
||
107 | + |
||
108 | + if (xhci->quirks & XHCI_FAKE_DOORBELL) { |
||
109 | + err = xhci_fake_doorbell(xhci, 1); |
||
110 | + if (err) |
||
111 | + goto err_halt; |
||
112 | + } |
||
113 | + |
||
114 | xhci->shared_hcd->state = HC_STATE_RUNNING; |
||
115 | xhci->cmd_ring_state = CMD_RING_STATE_RUNNING; |
||
116 | |||
3 | office | 117 | @@ -549,6 +602,10 @@ static int xhci_run_finished(struct xhci |
1 | office | 118 | xhci_dbg_trace(xhci, trace_xhci_dbg_init, |
119 | "Finished xhci_run for USB3 roothub"); |
||
120 | return 0; |
||
121 | + |
||
122 | +err_halt: |
||
123 | + xhci_halt(xhci); |
||
124 | + return err; |
||
125 | } |
||
126 | |||
127 | /* |
||
128 | --- a/drivers/usb/host/xhci.h |
||
129 | +++ b/drivers/usb/host/xhci.h |
||
3 | office | 130 | @@ -1835,6 +1835,7 @@ struct xhci_hcd { |
131 | #define XHCI_LIMIT_ENDPOINT_INTERVAL_7 (1 << 26) |
||
132 | #define XHCI_U2_DISABLE_WAKE (1 << 27) |
||
133 | #define XHCI_ASMEDIA_MODIFY_FLOWCONTROL (1 << 28) |
||
134 | +#define XHCI_FAKE_DOORBELL (1 << 29) |
||
135 | #define XHCI_SUSPEND_DELAY (1 << 30) |
||
1 | office | 136 | |
137 | unsigned int num_active_eps; |