mediatek: Add support for Xiaomi Redmi Router AX6S
[openwrt/openwrt.git] / target / linux / bcm4908 / patches-5.4 / 084-v5.6-0007-phy-usb-Add-support-for-new-Synopsys-USB-controller-.patch
1 From 4e5b9c9a73b32d28759225a40d30848393a8f1fd Mon Sep 17 00:00:00 2001
2 From: Al Cooper <alcooperx@gmail.com>
3 Date: Fri, 3 Jan 2020 13:18:05 -0500
4 Subject: [PATCH] phy: usb: Add support for new Synopsys USB controller on the
5 7216
6
7 The 7216 has the new USB XHCI controller from Synopsys. While
8 this new controller and the PHY are similar to the STB versions,
9 the major differences are:
10
11 - Many of the registers and fields in the CTRL block have been
12 removed or changed.
13 - A new set of Synopsys control registers, BCHP_USB_XHCI_GBL, were
14 added.
15 - MDIO functionality has been replaced with direct access registers
16 in the BCHP_USB_XHCI_GBL block.
17 - Power up PHY defaults that had to be changed by MDIO in previous
18 chips will now power up with the correct defaults.
19
20 A new init module was created for this new Synopsys USB controller.
21 A new compatible string was added and the driver will dispatch
22 into one of two init modules based on it. A "reg-names" field was
23 added so the driver can more easily get optional registers.
24 A DT bindings document was also added for this driver.
25
26 Signed-off-by: Al Cooper <alcooperx@gmail.com>
27 Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
28 Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
29 ---
30 drivers/phy/broadcom/Makefile | 2 +-
31 .../phy/broadcom/phy-brcm-usb-init-synopsys.c | 171 ++++++++++++++++++
32 drivers/phy/broadcom/phy-brcm-usb-init.h | 2 +
33 drivers/phy/broadcom/phy-brcm-usb.c | 70 +++++--
34 4 files changed, 227 insertions(+), 18 deletions(-)
35 create mode 100644 drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c
36
37 --- a/drivers/phy/broadcom/Makefile
38 +++ b/drivers/phy/broadcom/Makefile
39 @@ -8,7 +8,7 @@ obj-$(CONFIG_PHY_NS2_USB_DRD) += phy-bc
40 obj-$(CONFIG_PHY_BRCM_SATA) += phy-brcm-sata.o
41 obj-$(CONFIG_PHY_BRCM_USB) += phy-brcm-usb-dvr.o
42
43 -phy-brcm-usb-dvr-objs := phy-brcm-usb.o phy-brcm-usb-init.o
44 +phy-brcm-usb-dvr-objs := phy-brcm-usb.o phy-brcm-usb-init.o phy-brcm-usb-init-synopsys.o
45
46 obj-$(CONFIG_PHY_BCM_SR_PCIE) += phy-bcm-sr-pcie.o
47 obj-$(CONFIG_PHY_BCM_SR_USB) += phy-bcm-sr-usb.o
48 --- /dev/null
49 +++ b/drivers/phy/broadcom/phy-brcm-usb-init-synopsys.c
50 @@ -0,0 +1,171 @@
51 +// SPDX-License-Identifier: GPL-2.0
52 +/* Copyright (c) 2018, Broadcom */
53 +
54 +/*
55 + * This module contains USB PHY initialization for power up and S3 resume
56 + * for newer Synopsys based USB hardware first used on the bcm7216.
57 + */
58 +
59 +#include <linux/delay.h>
60 +#include <linux/io.h>
61 +
62 +#include <linux/soc/brcmstb/brcmstb.h>
63 +#include "phy-brcm-usb-init.h"
64 +
65 +/* Register definitions for the USB CTRL block */
66 +#define USB_CTRL_SETUP 0x00
67 +#define USB_CTRL_SETUP_STRAP_IPP_SEL_MASK 0x02000000
68 +#define USB_CTRL_SETUP_SCB2_EN_MASK 0x00008000
69 +#define USB_CTRL_SETUP_SCB1_EN_MASK 0x00004000
70 +#define USB_CTRL_SETUP_SOFT_SHUTDOWN_MASK 0x00000200
71 +#define USB_CTRL_SETUP_IPP_MASK 0x00000020
72 +#define USB_CTRL_SETUP_IOC_MASK 0x00000010
73 +#define USB_CTRL_USB_PM 0x04
74 +#define USB_CTRL_USB_PM_USB_PWRDN_MASK 0x80000000
75 +#define USB_CTRL_USB_PM_SOFT_RESET_MASK 0x40000000
76 +#define USB_CTRL_USB_PM_BDC_SOFT_RESETB_MASK 0x00800000
77 +#define USB_CTRL_USB_PM_XHC_SOFT_RESETB_MASK 0x00400000
78 +#define USB_CTRL_USB_PM_STATUS 0x08
79 +#define USB_CTRL_USB_DEVICE_CTL1 0x10
80 +#define USB_CTRL_USB_DEVICE_CTL1_PORT_MODE_MASK 0x00000003
81 +
82 +
83 +static void xhci_soft_reset(struct brcm_usb_init_params *params,
84 + int on_off)
85 +{
86 + void __iomem *ctrl = params->ctrl_regs;
87 +
88 + /* Assert reset */
89 + if (on_off)
90 + USB_CTRL_UNSET(ctrl, USB_PM, XHC_SOFT_RESETB);
91 + /* De-assert reset */
92 + else
93 + USB_CTRL_SET(ctrl, USB_PM, XHC_SOFT_RESETB);
94 +}
95 +
96 +static void usb_init_ipp(struct brcm_usb_init_params *params)
97 +{
98 + void __iomem *ctrl = params->ctrl_regs;
99 + u32 reg;
100 + u32 orig_reg;
101 +
102 + pr_debug("%s\n", __func__);
103 +
104 + orig_reg = reg = brcm_usb_readl(USB_CTRL_REG(ctrl, SETUP));
105 + if (params->ipp != 2)
106 + /* override ipp strap pin (if it exits) */
107 + reg &= ~(USB_CTRL_MASK(SETUP, STRAP_IPP_SEL));
108 +
109 + /* Override the default OC and PP polarity */
110 + reg &= ~(USB_CTRL_MASK(SETUP, IPP) | USB_CTRL_MASK(SETUP, IOC));
111 + if (params->ioc)
112 + reg |= USB_CTRL_MASK(SETUP, IOC);
113 + if (params->ipp == 1)
114 + reg |= USB_CTRL_MASK(SETUP, IPP);
115 + brcm_usb_writel(reg, USB_CTRL_REG(ctrl, SETUP));
116 +
117 + /*
118 + * If we're changing IPP, make sure power is off long enough
119 + * to turn off any connected devices.
120 + */
121 + if ((reg ^ orig_reg) & USB_CTRL_MASK(SETUP, IPP))
122 + msleep(50);
123 +}
124 +
125 +static void usb_init_common(struct brcm_usb_init_params *params)
126 +{
127 + u32 reg;
128 + void __iomem *ctrl = params->ctrl_regs;
129 +
130 + pr_debug("%s\n", __func__);
131 +
132 + USB_CTRL_UNSET(ctrl, USB_PM, USB_PWRDN);
133 + /* 1 millisecond - for USB clocks to settle down */
134 + usleep_range(1000, 2000);
135 +
136 + if (USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE)) {
137 + reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
138 + reg &= ~USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
139 + reg |= params->mode;
140 + brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
141 + }
142 + switch (params->mode) {
143 + case USB_CTLR_MODE_HOST:
144 + USB_CTRL_UNSET(ctrl, USB_PM, BDC_SOFT_RESETB);
145 + break;
146 + default:
147 + USB_CTRL_UNSET(ctrl, USB_PM, BDC_SOFT_RESETB);
148 + USB_CTRL_SET(ctrl, USB_PM, BDC_SOFT_RESETB);
149 + break;
150 + }
151 +}
152 +
153 +static void usb_init_xhci(struct brcm_usb_init_params *params)
154 +{
155 + pr_debug("%s\n", __func__);
156 +
157 + xhci_soft_reset(params, 0);
158 +}
159 +
160 +static void usb_uninit_common(struct brcm_usb_init_params *params)
161 +{
162 + void __iomem *ctrl = params->ctrl_regs;
163 +
164 + pr_debug("%s\n", __func__);
165 +
166 + USB_CTRL_SET(ctrl, USB_PM, USB_PWRDN);
167 +
168 +}
169 +
170 +static void usb_uninit_xhci(struct brcm_usb_init_params *params)
171 +{
172 +
173 + pr_debug("%s\n", __func__);
174 +
175 + xhci_soft_reset(params, 1);
176 +}
177 +
178 +static int usb_get_dual_select(struct brcm_usb_init_params *params)
179 +{
180 + void __iomem *ctrl = params->ctrl_regs;
181 + u32 reg = 0;
182 +
183 + pr_debug("%s\n", __func__);
184 +
185 + reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
186 + reg &= USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
187 + return reg;
188 +}
189 +
190 +static void usb_set_dual_select(struct brcm_usb_init_params *params, int mode)
191 +{
192 + void __iomem *ctrl = params->ctrl_regs;
193 + u32 reg;
194 +
195 + pr_debug("%s\n", __func__);
196 +
197 + reg = brcm_usb_readl(USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
198 + reg &= ~USB_CTRL_MASK(USB_DEVICE_CTL1, PORT_MODE);
199 + reg |= mode;
200 + brcm_usb_writel(reg, USB_CTRL_REG(ctrl, USB_DEVICE_CTL1));
201 +}
202 +
203 +
204 +static const struct brcm_usb_init_ops bcm7216_ops = {
205 + .init_ipp = usb_init_ipp,
206 + .init_common = usb_init_common,
207 + .init_xhci = usb_init_xhci,
208 + .uninit_common = usb_uninit_common,
209 + .uninit_xhci = usb_uninit_xhci,
210 + .get_dual_select = usb_get_dual_select,
211 + .set_dual_select = usb_set_dual_select,
212 +};
213 +
214 +void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params)
215 +{
216 +
217 + pr_debug("%s\n", __func__);
218 +
219 + params->family_name = "7216";
220 + params->ops = &bcm7216_ops;
221 +}
222 --- a/drivers/phy/broadcom/phy-brcm-usb-init.h
223 +++ b/drivers/phy/broadcom/phy-brcm-usb-init.h
224 @@ -43,6 +43,7 @@ struct brcm_usb_init_ops {
225 struct brcm_usb_init_params {
226 void __iomem *ctrl_regs;
227 void __iomem *xhci_ec_regs;
228 + void __iomem *xhci_gbl_regs;
229 int ioc;
230 int ipp;
231 int mode;
232 @@ -55,6 +56,7 @@ struct brcm_usb_init_params {
233 };
234
235 void brcm_usb_dvr_init_7445(struct brcm_usb_init_params *params);
236 +void brcm_usb_dvr_init_7216(struct brcm_usb_init_params *params);
237
238 static inline u32 brcm_usb_readl(void __iomem *addr)
239 {
240 --- a/drivers/phy/broadcom/phy-brcm-usb.c
241 +++ b/drivers/phy/broadcom/phy-brcm-usb.c
242 @@ -241,6 +241,15 @@ static const struct attribute_group brcm
243 .attrs = brcm_usb_phy_attrs,
244 };
245
246 +static const struct of_device_id brcm_usb_dt_ids[] = {
247 + {
248 + .compatible = "brcm,bcm7216-usb-phy",
249 + .data = &brcm_usb_dvr_init_7216,
250 + },
251 + { .compatible = "brcm,brcmstb-usb-phy" },
252 + { /* sentinel */ }
253 +};
254 +
255 static int brcm_usb_phy_dvr_init(struct platform_device *pdev,
256 struct brcm_usb_phy_data *priv,
257 struct device_node *dn)
258 @@ -316,13 +325,16 @@ static int brcm_usb_phy_dvr_init(struct
259
260 static int brcm_usb_phy_probe(struct platform_device *pdev)
261 {
262 - struct resource *res;
263 + struct resource *res_ctrl;
264 + struct resource *res_xhciec = NULL;
265 + struct resource *res_xhcigbl = NULL;
266 struct device *dev = &pdev->dev;
267 struct brcm_usb_phy_data *priv;
268 struct phy_provider *phy_provider;
269 struct device_node *dn = pdev->dev.of_node;
270 int err;
271 const char *mode;
272 + const struct of_device_id *match;
273
274 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
275 if (!priv)
276 @@ -331,30 +343,59 @@ static int brcm_usb_phy_probe(struct pla
277
278 priv->ini.family_id = brcmstb_get_family_id();
279 priv->ini.product_id = brcmstb_get_product_id();
280 - brcm_usb_dvr_init_7445(&priv->ini);
281 +
282 + match = of_match_node(brcm_usb_dt_ids, dev->of_node);
283 + if (match && match->data) {
284 + void (*dvr_init)(struct brcm_usb_init_params *params);
285 +
286 + dvr_init = match->data;
287 + (*dvr_init)(&priv->ini);
288 + } else {
289 + brcm_usb_dvr_init_7445(&priv->ini);
290 + }
291 +
292 dev_dbg(dev, "Best mapping table is for %s\n",
293 priv->ini.family_name);
294 - res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
295 - if (!res) {
296 - dev_err(dev, "can't get USB_CTRL base address\n");
297 - return -EINVAL;
298 +
299 + /* Newer DT node has reg-names. xhci_ec and xhci_gbl are optional. */
300 + res_ctrl = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl");
301 + if (res_ctrl != NULL) {
302 + res_xhciec = platform_get_resource_byname(pdev,
303 + IORESOURCE_MEM,
304 + "xhci_ec");
305 + res_xhcigbl = platform_get_resource_byname(pdev,
306 + IORESOURCE_MEM,
307 + "xhci_gbl");
308 + } else {
309 + /* Older DT node without reg-names, use index */
310 + res_ctrl = platform_get_resource(pdev, IORESOURCE_MEM, 0);
311 + if (res_ctrl == NULL) {
312 + dev_err(dev, "can't get CTRL base address\n");
313 + return -EINVAL;
314 + }
315 + res_xhciec = platform_get_resource(pdev, IORESOURCE_MEM, 1);
316 }
317 - priv->ini.ctrl_regs = devm_ioremap_resource(dev, res);
318 + priv->ini.ctrl_regs = devm_ioremap_resource(dev, res_ctrl);
319 if (IS_ERR(priv->ini.ctrl_regs)) {
320 dev_err(dev, "can't map CTRL register space\n");
321 return -EINVAL;
322 }
323 -
324 - /* The XHCI EC registers are optional */
325 - res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
326 - if (res) {
327 + if (res_xhciec) {
328 priv->ini.xhci_ec_regs =
329 - devm_ioremap_resource(dev, res);
330 + devm_ioremap_resource(dev, res_xhciec);
331 if (IS_ERR(priv->ini.xhci_ec_regs)) {
332 dev_err(dev, "can't map XHCI EC register space\n");
333 return -EINVAL;
334 }
335 }
336 + if (res_xhcigbl) {
337 + priv->ini.xhci_gbl_regs =
338 + devm_ioremap_resource(dev, res_xhcigbl);
339 + if (IS_ERR(priv->ini.xhci_gbl_regs)) {
340 + dev_err(dev, "can't map XHCI Global register space\n");
341 + return -EINVAL;
342 + }
343 + }
344
345 of_property_read_u32(dn, "brcm,ipp", &priv->ini.ipp);
346 of_property_read_u32(dn, "brcm,ioc", &priv->ini.ioc);
347 @@ -480,11 +521,6 @@ static const struct dev_pm_ops brcm_usb_
348 SET_LATE_SYSTEM_SLEEP_PM_OPS(brcm_usb_phy_suspend, brcm_usb_phy_resume)
349 };
350
351 -static const struct of_device_id brcm_usb_dt_ids[] = {
352 - { .compatible = "brcm,brcmstb-usb-phy" },
353 - { /* sentinel */ }
354 -};
355 -
356 MODULE_DEVICE_TABLE(of, brcm_usb_dt_ids);
357
358 static struct platform_driver brcm_usb_driver = {