1f1ba13f8SMasahiro Yamada /*
2f1ba13f8SMasahiro Yamada * STiH407 family DWC3 specific Glue layer
3f1ba13f8SMasahiro Yamada *
4f1ba13f8SMasahiro Yamada * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
5f1ba13f8SMasahiro Yamada * Author(s): Patrice Chotard, <patrice.chotard@st.com> for STMicroelectronics.
6f1ba13f8SMasahiro Yamada *
7f1ba13f8SMasahiro Yamada * SPDX-License-Identifier: GPL-2.0+
8f1ba13f8SMasahiro Yamada */
9f1ba13f8SMasahiro Yamada
10f1ba13f8SMasahiro Yamada #include <common.h>
11f1ba13f8SMasahiro Yamada #include <asm/io.h>
12f1ba13f8SMasahiro Yamada #include <dm.h>
13f1ba13f8SMasahiro Yamada #include <errno.h>
14f1ba13f8SMasahiro Yamada #include <dm/lists.h>
15f1ba13f8SMasahiro Yamada #include <regmap.h>
16f1ba13f8SMasahiro Yamada #include <reset-uclass.h>
17f1ba13f8SMasahiro Yamada #include <syscon.h>
18f1ba13f8SMasahiro Yamada #include <usb.h>
19f1ba13f8SMasahiro Yamada
20f1ba13f8SMasahiro Yamada #include <linux/usb/dwc3.h>
21f1ba13f8SMasahiro Yamada #include <linux/usb/otg.h>
22f1ba13f8SMasahiro Yamada #include <dwc3-sti-glue.h>
23f1ba13f8SMasahiro Yamada
24f1ba13f8SMasahiro Yamada DECLARE_GLOBAL_DATA_PTR;
25f1ba13f8SMasahiro Yamada
26f1ba13f8SMasahiro Yamada /*
27f1ba13f8SMasahiro Yamada * struct sti_dwc3_glue_platdata - dwc3 STi glue driver private structure
28f1ba13f8SMasahiro Yamada * @syscfg_base: addr for the glue syscfg
29f1ba13f8SMasahiro Yamada * @glue_base: addr for the glue registers
30f1ba13f8SMasahiro Yamada * @syscfg_offset: usb syscfg control offset
31f1ba13f8SMasahiro Yamada * @powerdown_ctl: rest controller for powerdown signal
32f1ba13f8SMasahiro Yamada * @softreset_ctl: reset controller for softreset signal
33f1ba13f8SMasahiro Yamada * @mode: drd static host/device config
34f1ba13f8SMasahiro Yamada */
35f1ba13f8SMasahiro Yamada struct sti_dwc3_glue_platdata {
36f1ba13f8SMasahiro Yamada phys_addr_t syscfg_base;
37f1ba13f8SMasahiro Yamada phys_addr_t glue_base;
38f1ba13f8SMasahiro Yamada phys_addr_t syscfg_offset;
39f1ba13f8SMasahiro Yamada struct reset_ctl powerdown_ctl;
40f1ba13f8SMasahiro Yamada struct reset_ctl softreset_ctl;
41f1ba13f8SMasahiro Yamada enum usb_dr_mode mode;
42f1ba13f8SMasahiro Yamada };
43f1ba13f8SMasahiro Yamada
sti_dwc3_glue_drd_init(struct sti_dwc3_glue_platdata * plat)44f1ba13f8SMasahiro Yamada static int sti_dwc3_glue_drd_init(struct sti_dwc3_glue_platdata *plat)
45f1ba13f8SMasahiro Yamada {
46f1ba13f8SMasahiro Yamada unsigned long val;
47f1ba13f8SMasahiro Yamada
48f1ba13f8SMasahiro Yamada val = readl(plat->syscfg_base + plat->syscfg_offset);
49f1ba13f8SMasahiro Yamada
50f1ba13f8SMasahiro Yamada val &= USB3_CONTROL_MASK;
51f1ba13f8SMasahiro Yamada
52f1ba13f8SMasahiro Yamada switch (plat->mode) {
53f1ba13f8SMasahiro Yamada case USB_DR_MODE_PERIPHERAL:
54f1ba13f8SMasahiro Yamada val &= ~(USB3_DELAY_VBUSVALID
55f1ba13f8SMasahiro Yamada | USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3)
56f1ba13f8SMasahiro Yamada | USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2
57f1ba13f8SMasahiro Yamada | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2);
58f1ba13f8SMasahiro Yamada
59f1ba13f8SMasahiro Yamada val |= USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID;
60f1ba13f8SMasahiro Yamada break;
61f1ba13f8SMasahiro Yamada
62f1ba13f8SMasahiro Yamada case USB_DR_MODE_HOST:
63f1ba13f8SMasahiro Yamada val &= ~(USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID
64f1ba13f8SMasahiro Yamada | USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3)
65f1ba13f8SMasahiro Yamada | USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2
66f1ba13f8SMasahiro Yamada | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2);
67f1ba13f8SMasahiro Yamada
68f1ba13f8SMasahiro Yamada val |= USB3_DELAY_VBUSVALID;
69f1ba13f8SMasahiro Yamada break;
70f1ba13f8SMasahiro Yamada
71f1ba13f8SMasahiro Yamada default:
72f1ba13f8SMasahiro Yamada pr_err("Unsupported mode of operation %d\n", plat->mode);
73f1ba13f8SMasahiro Yamada return -EINVAL;
74f1ba13f8SMasahiro Yamada }
75f1ba13f8SMasahiro Yamada writel(val, plat->syscfg_base + plat->syscfg_offset);
76f1ba13f8SMasahiro Yamada
77f1ba13f8SMasahiro Yamada return 0;
78f1ba13f8SMasahiro Yamada }
79f1ba13f8SMasahiro Yamada
sti_dwc3_glue_init(struct sti_dwc3_glue_platdata * plat)80f1ba13f8SMasahiro Yamada static void sti_dwc3_glue_init(struct sti_dwc3_glue_platdata *plat)
81f1ba13f8SMasahiro Yamada {
82f1ba13f8SMasahiro Yamada unsigned long reg;
83f1ba13f8SMasahiro Yamada
84f1ba13f8SMasahiro Yamada reg = readl(plat->glue_base + CLKRST_CTRL);
85f1ba13f8SMasahiro Yamada
86f1ba13f8SMasahiro Yamada reg |= AUX_CLK_EN | EXT_CFG_RESET_N | XHCI_REVISION;
87f1ba13f8SMasahiro Yamada reg &= ~SW_PIPEW_RESET_N;
88f1ba13f8SMasahiro Yamada
89f1ba13f8SMasahiro Yamada writel(reg, plat->glue_base + CLKRST_CTRL);
90f1ba13f8SMasahiro Yamada
91f1ba13f8SMasahiro Yamada /* configure mux for vbus, powerpresent and bvalid signals */
92f1ba13f8SMasahiro Yamada reg = readl(plat->glue_base + USB2_VBUS_MNGMNT_SEL1);
93f1ba13f8SMasahiro Yamada
94f1ba13f8SMasahiro Yamada reg |= SEL_OVERRIDE_VBUSVALID(USB2_VBUS_UTMIOTG) |
95f1ba13f8SMasahiro Yamada SEL_OVERRIDE_POWERPRESENT(USB2_VBUS_UTMIOTG) |
96f1ba13f8SMasahiro Yamada SEL_OVERRIDE_BVALID(USB2_VBUS_UTMIOTG);
97f1ba13f8SMasahiro Yamada
98f1ba13f8SMasahiro Yamada writel(reg, plat->glue_base + USB2_VBUS_MNGMNT_SEL1);
99f1ba13f8SMasahiro Yamada
100f1ba13f8SMasahiro Yamada setbits_le32(plat->glue_base + CLKRST_CTRL, SW_PIPEW_RESET_N);
101f1ba13f8SMasahiro Yamada }
102f1ba13f8SMasahiro Yamada
sti_dwc3_glue_ofdata_to_platdata(struct udevice * dev)103f1ba13f8SMasahiro Yamada static int sti_dwc3_glue_ofdata_to_platdata(struct udevice *dev)
104f1ba13f8SMasahiro Yamada {
105f1ba13f8SMasahiro Yamada struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev);
106f1ba13f8SMasahiro Yamada struct udevice *syscon;
107f1ba13f8SMasahiro Yamada struct regmap *regmap;
108f1ba13f8SMasahiro Yamada int ret;
109f1ba13f8SMasahiro Yamada u32 reg[4];
110f1ba13f8SMasahiro Yamada
111*ef78966dSKever Yang ret = ofnode_read_u32_array(dev->node, "reg", reg, ARRAY_SIZE(reg));
112f1ba13f8SMasahiro Yamada if (ret) {
113f1ba13f8SMasahiro Yamada pr_err("unable to find st,stih407-dwc3 reg property(%d)\n", ret);
114f1ba13f8SMasahiro Yamada return ret;
115f1ba13f8SMasahiro Yamada }
116f1ba13f8SMasahiro Yamada
117f1ba13f8SMasahiro Yamada plat->glue_base = reg[0];
118f1ba13f8SMasahiro Yamada plat->syscfg_offset = reg[2];
119f1ba13f8SMasahiro Yamada
120f1ba13f8SMasahiro Yamada /* get corresponding syscon phandle */
121f1ba13f8SMasahiro Yamada ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev, "st,syscfg",
122f1ba13f8SMasahiro Yamada &syscon);
123f1ba13f8SMasahiro Yamada if (ret) {
124f1ba13f8SMasahiro Yamada pr_err("unable to find syscon device (%d)\n", ret);
125f1ba13f8SMasahiro Yamada return ret;
126f1ba13f8SMasahiro Yamada }
127f1ba13f8SMasahiro Yamada
128f1ba13f8SMasahiro Yamada /* get syscfg-reg base address */
129f1ba13f8SMasahiro Yamada regmap = syscon_get_regmap(syscon);
130f1ba13f8SMasahiro Yamada if (!regmap) {
131f1ba13f8SMasahiro Yamada pr_err("unable to find regmap\n");
132f1ba13f8SMasahiro Yamada return -ENODEV;
133f1ba13f8SMasahiro Yamada }
134f1ba13f8SMasahiro Yamada plat->syscfg_base = regmap->base;
135f1ba13f8SMasahiro Yamada
136f1ba13f8SMasahiro Yamada /* get powerdown reset */
137f1ba13f8SMasahiro Yamada ret = reset_get_by_name(dev, "powerdown", &plat->powerdown_ctl);
138f1ba13f8SMasahiro Yamada if (ret) {
139f1ba13f8SMasahiro Yamada pr_err("can't get powerdown reset for %s (%d)", dev->name, ret);
140f1ba13f8SMasahiro Yamada return ret;
141f1ba13f8SMasahiro Yamada }
142f1ba13f8SMasahiro Yamada
143f1ba13f8SMasahiro Yamada /* get softreset reset */
144f1ba13f8SMasahiro Yamada ret = reset_get_by_name(dev, "softreset", &plat->softreset_ctl);
145f1ba13f8SMasahiro Yamada if (ret)
146f1ba13f8SMasahiro Yamada pr_err("can't get soft reset for %s (%d)", dev->name, ret);
147f1ba13f8SMasahiro Yamada
148f1ba13f8SMasahiro Yamada return ret;
149f1ba13f8SMasahiro Yamada };
150f1ba13f8SMasahiro Yamada
sti_dwc3_glue_bind(struct udevice * dev)151f1ba13f8SMasahiro Yamada static int sti_dwc3_glue_bind(struct udevice *dev)
152f1ba13f8SMasahiro Yamada {
153f1ba13f8SMasahiro Yamada struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev);
154*ef78966dSKever Yang ofnode node, dwc3_node;
155f1ba13f8SMasahiro Yamada
156*ef78966dSKever Yang /* Find snps,dwc3 node from subnode */
157*ef78966dSKever Yang ofnode_for_each_subnode(node, dev->node) {
158*ef78966dSKever Yang if (ofnode_device_is_compatible(node, "snps,dwc3"))
159*ef78966dSKever Yang dwc3_node = node;
160f1ba13f8SMasahiro Yamada }
161f1ba13f8SMasahiro Yamada
162*ef78966dSKever Yang if (!ofnode_valid(node)) {
163f1ba13f8SMasahiro Yamada pr_err("Can't find dwc3 subnode for %s\n", dev->name);
164f1ba13f8SMasahiro Yamada return -ENODEV;
165f1ba13f8SMasahiro Yamada }
166f1ba13f8SMasahiro Yamada
167f1ba13f8SMasahiro Yamada /* retrieve the DWC3 dual role mode */
168f1ba13f8SMasahiro Yamada plat->mode = usb_get_dr_mode(dwc3_node);
169f1ba13f8SMasahiro Yamada if (plat->mode == USB_DR_MODE_UNKNOWN)
170f1ba13f8SMasahiro Yamada /* by default set dual role mode to HOST */
171f1ba13f8SMasahiro Yamada plat->mode = USB_DR_MODE_HOST;
172f1ba13f8SMasahiro Yamada
173f1ba13f8SMasahiro Yamada return dm_scan_fdt_dev(dev);
174f1ba13f8SMasahiro Yamada }
175f1ba13f8SMasahiro Yamada
sti_dwc3_glue_probe(struct udevice * dev)176f1ba13f8SMasahiro Yamada static int sti_dwc3_glue_probe(struct udevice *dev)
177f1ba13f8SMasahiro Yamada {
178f1ba13f8SMasahiro Yamada struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev);
179f1ba13f8SMasahiro Yamada int ret;
180f1ba13f8SMasahiro Yamada
181f1ba13f8SMasahiro Yamada /* deassert both powerdown and softreset */
182f1ba13f8SMasahiro Yamada ret = reset_deassert(&plat->powerdown_ctl);
183f1ba13f8SMasahiro Yamada if (ret < 0) {
184f1ba13f8SMasahiro Yamada pr_err("DWC3 powerdown reset deassert failed: %d", ret);
185f1ba13f8SMasahiro Yamada return ret;
186f1ba13f8SMasahiro Yamada }
187f1ba13f8SMasahiro Yamada
188f1ba13f8SMasahiro Yamada ret = reset_deassert(&plat->softreset_ctl);
189f1ba13f8SMasahiro Yamada if (ret < 0) {
190f1ba13f8SMasahiro Yamada pr_err("DWC3 soft reset deassert failed: %d", ret);
191f1ba13f8SMasahiro Yamada goto softreset_err;
192f1ba13f8SMasahiro Yamada }
193f1ba13f8SMasahiro Yamada
194f1ba13f8SMasahiro Yamada ret = sti_dwc3_glue_drd_init(plat);
195f1ba13f8SMasahiro Yamada if (ret)
196f1ba13f8SMasahiro Yamada goto init_err;
197f1ba13f8SMasahiro Yamada
198f1ba13f8SMasahiro Yamada sti_dwc3_glue_init(plat);
199f1ba13f8SMasahiro Yamada
200f1ba13f8SMasahiro Yamada return 0;
201f1ba13f8SMasahiro Yamada
202f1ba13f8SMasahiro Yamada init_err:
203f1ba13f8SMasahiro Yamada ret = reset_assert(&plat->softreset_ctl);
204f1ba13f8SMasahiro Yamada if (ret < 0) {
205f1ba13f8SMasahiro Yamada pr_err("DWC3 soft reset deassert failed: %d", ret);
206f1ba13f8SMasahiro Yamada return ret;
207f1ba13f8SMasahiro Yamada }
208f1ba13f8SMasahiro Yamada
209f1ba13f8SMasahiro Yamada softreset_err:
210f1ba13f8SMasahiro Yamada ret = reset_assert(&plat->powerdown_ctl);
211f1ba13f8SMasahiro Yamada if (ret < 0)
212f1ba13f8SMasahiro Yamada pr_err("DWC3 powerdown reset deassert failed: %d", ret);
213f1ba13f8SMasahiro Yamada
214f1ba13f8SMasahiro Yamada return ret;
215f1ba13f8SMasahiro Yamada }
216f1ba13f8SMasahiro Yamada
sti_dwc3_glue_remove(struct udevice * dev)217f1ba13f8SMasahiro Yamada static int sti_dwc3_glue_remove(struct udevice *dev)
218f1ba13f8SMasahiro Yamada {
219f1ba13f8SMasahiro Yamada struct sti_dwc3_glue_platdata *plat = dev_get_platdata(dev);
220f1ba13f8SMasahiro Yamada int ret;
221f1ba13f8SMasahiro Yamada
222f1ba13f8SMasahiro Yamada /* assert both powerdown and softreset */
223f1ba13f8SMasahiro Yamada ret = reset_assert(&plat->powerdown_ctl);
224f1ba13f8SMasahiro Yamada if (ret < 0) {
225f1ba13f8SMasahiro Yamada pr_err("DWC3 powerdown reset deassert failed: %d", ret);
226f1ba13f8SMasahiro Yamada return ret;
227f1ba13f8SMasahiro Yamada }
228f1ba13f8SMasahiro Yamada
229f1ba13f8SMasahiro Yamada ret = reset_assert(&plat->softreset_ctl);
230f1ba13f8SMasahiro Yamada if (ret < 0)
231f1ba13f8SMasahiro Yamada pr_err("DWC3 soft reset deassert failed: %d", ret);
232f1ba13f8SMasahiro Yamada
233f1ba13f8SMasahiro Yamada return ret;
234f1ba13f8SMasahiro Yamada }
235f1ba13f8SMasahiro Yamada
236f1ba13f8SMasahiro Yamada static const struct udevice_id sti_dwc3_glue_ids[] = {
237f1ba13f8SMasahiro Yamada { .compatible = "st,stih407-dwc3" },
238f1ba13f8SMasahiro Yamada { }
239f1ba13f8SMasahiro Yamada };
240f1ba13f8SMasahiro Yamada
241f1ba13f8SMasahiro Yamada U_BOOT_DRIVER(dwc3_sti_glue) = {
242f1ba13f8SMasahiro Yamada .name = "dwc3_sti_glue",
243f1ba13f8SMasahiro Yamada .id = UCLASS_MISC,
244f1ba13f8SMasahiro Yamada .of_match = sti_dwc3_glue_ids,
245f1ba13f8SMasahiro Yamada .ofdata_to_platdata = sti_dwc3_glue_ofdata_to_platdata,
246f1ba13f8SMasahiro Yamada .probe = sti_dwc3_glue_probe,
247f1ba13f8SMasahiro Yamada .remove = sti_dwc3_glue_remove,
248f1ba13f8SMasahiro Yamada .bind = sti_dwc3_glue_bind,
249f1ba13f8SMasahiro Yamada .platdata_auto_alloc_size = sizeof(struct sti_dwc3_glue_platdata),
250f1ba13f8SMasahiro Yamada .flags = DM_FLAG_ALLOC_PRIV_DMA,
251f1ba13f8SMasahiro Yamada };
252