kernel: bump 5.4 to 5.4.24
[oweals/openwrt.git] / target / linux / bcm53xx / patches-5.4 / 180-usb-xhci-add-support-for-performing-fake-doorbell.patch
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,6 +67,8 @@ static int xhci_priv_resume_quirk(struct
23  static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
24  {
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;
28  
29         /*
30          * As of now platform drivers don't provide MSI support so we ensure
31 @@ -74,6 +76,9 @@ static void xhci_plat_quirks(struct devi
32          * dev struct in order to setup MSI
33          */
34         xhci->quirks |= XHCI_PLAT | priv->quirks;
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
43 @@ -156,6 +156,49 @@ int xhci_start(struct xhci_hcd *xhci)
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   *
93 @@ -604,10 +647,20 @@ static int xhci_init(struct usb_hcd *hcd
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  
117 @@ -617,6 +670,10 @@ static int xhci_run_finished(struct xhci
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
130 @@ -1872,6 +1872,7 @@ struct xhci_hcd {
131  #define XHCI_DEFAULT_PM_RUNTIME_ALLOW  BIT_ULL(33)
132  #define XHCI_RESET_PLL_ON_DISCONNECT   BIT_ULL(34)
133  #define XHCI_SNPS_BROKEN_SUSPEND    BIT_ULL(35)
134 +#define XHCI_FAKE_DOORBELL     BIT_ULL(36)
135  
136         unsigned int            num_active_eps;
137         unsigned int            limit_active_eps;