blob: 11cc080c2368456d2d2fe4cae88086663592d4ba [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001From 4e5b9c9a73b32d28759225a40d30848393a8f1fd Mon Sep 17 00:00:00 2001
2From: Al Cooper <alcooperx@gmail.com>
3Date: Fri, 3 Jan 2020 13:18:05 -0500
4Subject: [PATCH] phy: usb: Add support for new Synopsys USB controller on the
5 7216
6
7The 7216 has the new USB XHCI controller from Synopsys. While
8this new controller and the PHY are similar to the STB versions,
9the 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
20A new init module was created for this new Synopsys USB controller.
21A new compatible string was added and the driver will dispatch
22into one of two init modules based on it. A "reg-names" field was
23added so the driver can more easily get optional registers.
24A DT bindings document was also added for this driver.
25
26Signed-off-by: Al Cooper <alcooperx@gmail.com>
27Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
28Signed-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 = {