blob: 2c5205df62cd17a3610215f81c78407d891520f5 [file] [log] [blame]
Patrick Delaunay22929e12018-10-26 09:02:52 +02001// SPDX-License-Identifier: GPL-2.0
Michal Simek49d67452018-05-18 13:15:06 +02002/*
3 * Generic DWC3 Glue layer
4 *
5 * Copyright (C) 2016 - 2018 Xilinx, Inc.
6 *
7 * Based on dwc3-omap.c.
8 */
9
10#include <common.h>
Simon Glass1eb69ae2019-11-14 12:57:39 -070011#include <cpu_func.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060012#include <log.h>
Michal Simek49d67452018-05-18 13:15:06 +020013#include <dm.h>
14#include <dm/device-internal.h>
15#include <dm/lists.h>
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010016#include <dwc3-uboot.h>
Michal Simek142d50f2022-03-09 10:05:45 +010017#include <generic-phy.h>
Simon Glasscd93d622020-05-10 11:40:13 -060018#include <linux/bitops.h>
Frank Wang5d422ab2020-05-26 11:34:31 +080019#include <linux/delay.h>
Michal Simek49d67452018-05-18 13:15:06 +020020#include <linux/usb/ch9.h>
21#include <linux/usb/gadget.h>
22#include <malloc.h>
23#include <usb.h>
24#include "core.h"
25#include "gadget.h"
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010026#include <reset.h>
27#include <clk.h>
Jean-Jacques Hiblotb575e902019-09-11 11:33:50 +020028#include <usb/xhci.h>
Michal Simek49d67452018-05-18 13:15:06 +020029
Frank Wang5d422ab2020-05-26 11:34:31 +080030struct dwc3_glue_data {
31 struct clk_bulk clks;
32 struct reset_ctl_bulk resets;
33 fdt_addr_t regs;
34};
35
Jean-Jacques Hiblot3a38a0a2019-09-11 11:33:48 +020036struct dwc3_generic_plat {
37 fdt_addr_t base;
38 u32 maximum_speed;
39 enum usb_dr_mode dr_mode;
40};
41
Jean-Jacques Hiblot3a38a0a2019-09-11 11:33:48 +020042struct dwc3_generic_priv {
Jean-Jacques Hiblot1af590d2019-09-11 11:33:49 +020043 void *base;
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010044 struct dwc3 dwc3;
Chunfeng Yun6dfb8a82020-05-02 11:35:13 +020045 struct phy_bulk phys;
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010046};
47
Jean-Jacques Hiblotb575e902019-09-11 11:33:50 +020048struct dwc3_generic_host_priv {
49 struct xhci_ctrl xhci_ctrl;
50 struct dwc3_generic_priv gen_priv;
51};
52
Jean-Jacques Hiblot1af590d2019-09-11 11:33:49 +020053static int dwc3_generic_probe(struct udevice *dev,
54 struct dwc3_generic_priv *priv)
Michal Simek49d67452018-05-18 13:15:06 +020055{
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010056 int rc;
Simon Glassc69cda22020-12-03 16:55:20 -070057 struct dwc3_generic_plat *plat = dev_get_plat(dev);
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010058 struct dwc3 *dwc3 = &priv->dwc3;
Simon Glassc69cda22020-12-03 16:55:20 -070059 struct dwc3_glue_data *glue = dev_get_plat(dev->parent);
Michal Simek49d67452018-05-18 13:15:06 +020060
Jean-Jacques Hiblotba6c5f72019-09-11 11:33:52 +020061 dwc3->dev = dev;
Jean-Jacques Hiblot3a38a0a2019-09-11 11:33:48 +020062 dwc3->maximum_speed = plat->maximum_speed;
63 dwc3->dr_mode = plat->dr_mode;
Jean-Jacques Hiblotba6c5f72019-09-11 11:33:52 +020064#if CONFIG_IS_ENABLED(OF_CONTROL)
65 dwc3_of_parse(dwc3);
66#endif
Jean-Jacques Hiblot3a38a0a2019-09-11 11:33:48 +020067
Frank Wang5d422ab2020-05-26 11:34:31 +080068 /*
69 * It must hold whole USB3.0 OTG controller in resetting to hold pipe
70 * power state in P2 before initializing TypeC PHY on RK3399 platform.
71 */
72 if (device_is_compatible(dev->parent, "rockchip,rk3399-dwc3")) {
73 reset_assert_bulk(&glue->resets);
74 udelay(1);
75 }
76
Chunfeng Yun6dfb8a82020-05-02 11:35:13 +020077 rc = dwc3_setup_phy(dev, &priv->phys);
Siva Durga Prasad Paladugue7f9e1f2020-10-21 14:17:31 +020078 if (rc && rc != -ENOTSUPP)
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010079 return rc;
80
Frank Wang5d422ab2020-05-26 11:34:31 +080081 if (device_is_compatible(dev->parent, "rockchip,rk3399-dwc3"))
82 reset_deassert_bulk(&glue->resets);
83
Jean-Jacques Hiblot1af590d2019-09-11 11:33:49 +020084 priv->base = map_physmem(plat->base, DWC3_OTG_REGS_END, MAP_NOCACHE);
85 dwc3->regs = priv->base + DWC3_GLOBALS_REGS_START;
Jean-Jacques Hiblotba6c5f72019-09-11 11:33:52 +020086
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010087
88 rc = dwc3_init(dwc3);
89 if (rc) {
Jean-Jacques Hiblot1af590d2019-09-11 11:33:49 +020090 unmap_physmem(priv->base, MAP_NOCACHE);
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010091 return rc;
92 }
93
94 return 0;
Michal Simek49d67452018-05-18 13:15:06 +020095}
96
Jean-Jacques Hiblot1af590d2019-09-11 11:33:49 +020097static int dwc3_generic_remove(struct udevice *dev,
98 struct dwc3_generic_priv *priv)
Michal Simek49d67452018-05-18 13:15:06 +020099{
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100100 struct dwc3 *dwc3 = &priv->dwc3;
Michal Simek49d67452018-05-18 13:15:06 +0200101
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100102 dwc3_remove(dwc3);
Chunfeng Yun6dfb8a82020-05-02 11:35:13 +0200103 dwc3_shutdown_phy(dev, &priv->phys);
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100104 unmap_physmem(dwc3->regs, MAP_NOCACHE);
Michal Simek49d67452018-05-18 13:15:06 +0200105
106 return 0;
107}
108
Simon Glassd1998a92020-12-03 16:55:21 -0700109static int dwc3_generic_of_to_plat(struct udevice *dev)
Michal Simek49d67452018-05-18 13:15:06 +0200110{
Simon Glassc69cda22020-12-03 16:55:20 -0700111 struct dwc3_generic_plat *plat = dev_get_plat(dev);
Simon Glassf10643c2020-12-19 10:40:14 -0700112 ofnode node = dev_ofnode(dev);
Michal Simek49d67452018-05-18 13:15:06 +0200113
Angus Ainsliec08db052022-02-02 15:08:54 -0800114 if (!strncmp(dev->name, "port", 4) || !strncmp(dev->name, "hub", 3)) {
115 /* This is a leaf so check the parent */
116 plat->base = dev_read_addr(dev->parent);
117 } else {
118 plat->base = dev_read_addr(dev);
119 }
Michal Simek49d67452018-05-18 13:15:06 +0200120
Jean-Jacques Hiblot3a38a0a2019-09-11 11:33:48 +0200121 plat->maximum_speed = usb_get_maximum_speed(node);
122 if (plat->maximum_speed == USB_SPEED_UNKNOWN) {
Jean-Jacques Hiblot1a63e5e2019-09-11 11:33:51 +0200123 pr_info("No USB maximum speed specified. Using super speed\n");
124 plat->maximum_speed = USB_SPEED_SUPER;
Michal Simek49d67452018-05-18 13:15:06 +0200125 }
126
Jean-Jacques Hiblot3a38a0a2019-09-11 11:33:48 +0200127 plat->dr_mode = usb_get_dr_mode(node);
128 if (plat->dr_mode == USB_DR_MODE_UNKNOWN) {
Angus Ainsliec08db052022-02-02 15:08:54 -0800129 /* might be a leaf so check the parent for mode */
130 node = dev_ofnode(dev->parent);
131 plat->dr_mode = usb_get_dr_mode(node);
132 if (plat->dr_mode == USB_DR_MODE_UNKNOWN) {
133 pr_err("Invalid usb mode setup\n");
134 return -ENODEV;
135 }
Michal Simek49d67452018-05-18 13:15:06 +0200136 }
137
138 return 0;
139}
140
Jean-Jacques Hiblot1af590d2019-09-11 11:33:49 +0200141#if CONFIG_IS_ENABLED(DM_USB_GADGET)
142int dm_usb_gadget_handle_interrupts(struct udevice *dev)
143{
144 struct dwc3_generic_priv *priv = dev_get_priv(dev);
145 struct dwc3 *dwc3 = &priv->dwc3;
146
147 dwc3_gadget_uboot_handle_interrupt(dwc3);
148
149 return 0;
150}
151
152static int dwc3_generic_peripheral_probe(struct udevice *dev)
153{
154 struct dwc3_generic_priv *priv = dev_get_priv(dev);
155
156 return dwc3_generic_probe(dev, priv);
157}
158
159static int dwc3_generic_peripheral_remove(struct udevice *dev)
160{
161 struct dwc3_generic_priv *priv = dev_get_priv(dev);
162
163 return dwc3_generic_remove(dev, priv);
164}
165
Michal Simek49d67452018-05-18 13:15:06 +0200166U_BOOT_DRIVER(dwc3_generic_peripheral) = {
167 .name = "dwc3-generic-peripheral",
Jean-Jacques Hiblot01311622018-11-29 10:52:46 +0100168 .id = UCLASS_USB_GADGET_GENERIC,
Simon Glassd1998a92020-12-03 16:55:21 -0700169 .of_to_plat = dwc3_generic_of_to_plat,
Michal Simek49d67452018-05-18 13:15:06 +0200170 .probe = dwc3_generic_peripheral_probe,
171 .remove = dwc3_generic_peripheral_remove,
Simon Glass41575d82020-12-03 16:55:17 -0700172 .priv_auto = sizeof(struct dwc3_generic_priv),
Simon Glasscaa4daa2020-12-03 16:55:18 -0700173 .plat_auto = sizeof(struct dwc3_generic_plat),
Michal Simek49d67452018-05-18 13:15:06 +0200174};
Jean-Jacques Hiblot687ab542018-11-29 10:52:42 +0100175#endif
Michal Simek49d67452018-05-18 13:15:06 +0200176
Simon Glass333e4a62021-07-10 21:14:29 -0600177#if defined(CONFIG_SPL_USB_HOST) || \
Kunihiko Hayashia5f9be12021-05-12 23:11:14 +0900178 !defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST)
Jean-Jacques Hiblotb575e902019-09-11 11:33:50 +0200179static int dwc3_generic_host_probe(struct udevice *dev)
180{
181 struct xhci_hcor *hcor;
182 struct xhci_hccr *hccr;
183 struct dwc3_generic_host_priv *priv = dev_get_priv(dev);
184 int rc;
185
186 rc = dwc3_generic_probe(dev, &priv->gen_priv);
187 if (rc)
188 return rc;
189
190 hccr = (struct xhci_hccr *)priv->gen_priv.base;
191 hcor = (struct xhci_hcor *)(priv->gen_priv.base +
192 HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
193
194 return xhci_register(dev, hccr, hcor);
195}
196
197static int dwc3_generic_host_remove(struct udevice *dev)
198{
199 struct dwc3_generic_host_priv *priv = dev_get_priv(dev);
200 int rc;
201
202 rc = xhci_deregister(dev);
203 if (rc)
204 return rc;
205
206 return dwc3_generic_remove(dev, &priv->gen_priv);
207}
208
209U_BOOT_DRIVER(dwc3_generic_host) = {
210 .name = "dwc3-generic-host",
211 .id = UCLASS_USB,
Simon Glassd1998a92020-12-03 16:55:21 -0700212 .of_to_plat = dwc3_generic_of_to_plat,
Jean-Jacques Hiblotb575e902019-09-11 11:33:50 +0200213 .probe = dwc3_generic_host_probe,
214 .remove = dwc3_generic_host_remove,
Simon Glass41575d82020-12-03 16:55:17 -0700215 .priv_auto = sizeof(struct dwc3_generic_host_priv),
Simon Glasscaa4daa2020-12-03 16:55:18 -0700216 .plat_auto = sizeof(struct dwc3_generic_plat),
Jean-Jacques Hiblotb575e902019-09-11 11:33:50 +0200217 .ops = &xhci_usb_ops,
218 .flags = DM_FLAG_ALLOC_PRIV_DMA,
219};
220#endif
221
Jean-Jacques Hiblot93991cf2018-11-29 10:52:49 +0100222struct dwc3_glue_ops {
223 void (*select_dr_mode)(struct udevice *dev, int index,
224 enum usb_dr_mode mode);
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100225};
226
Jean-Jacques Hiblotd66e54a2018-11-29 10:57:40 +0100227void dwc3_ti_select_dr_mode(struct udevice *dev, int index,
228 enum usb_dr_mode mode)
229{
230#define USBOTGSS_UTMI_OTG_STATUS 0x0084
231#define USBOTGSS_UTMI_OTG_OFFSET 0x0480
232
233/* UTMI_OTG_STATUS REGISTER */
234#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE BIT(31)
235#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT BIT(9)
236#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE BIT(8)
237#define USBOTGSS_UTMI_OTG_STATUS_IDDIG BIT(4)
238#define USBOTGSS_UTMI_OTG_STATUS_SESSEND BIT(3)
239#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID BIT(2)
240#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID BIT(1)
241enum dwc3_omap_utmi_mode {
242 DWC3_OMAP_UTMI_MODE_UNKNOWN = 0,
243 DWC3_OMAP_UTMI_MODE_HW,
244 DWC3_OMAP_UTMI_MODE_SW,
245};
246
247 u32 use_id_pin;
248 u32 host_mode;
249 u32 reg;
250 u32 utmi_mode;
251 u32 utmi_status_offset = USBOTGSS_UTMI_OTG_STATUS;
252
Simon Glassc69cda22020-12-03 16:55:20 -0700253 struct dwc3_glue_data *glue = dev_get_plat(dev);
Jean-Jacques Hiblotd66e54a2018-11-29 10:57:40 +0100254 void *base = map_physmem(glue->regs, 0x10000, MAP_NOCACHE);
255
256 if (device_is_compatible(dev, "ti,am437x-dwc3"))
257 utmi_status_offset += USBOTGSS_UTMI_OTG_OFFSET;
258
259 utmi_mode = dev_read_u32_default(dev, "utmi-mode",
260 DWC3_OMAP_UTMI_MODE_UNKNOWN);
261 if (utmi_mode != DWC3_OMAP_UTMI_MODE_HW) {
262 debug("%s: OTG is not supported. defaulting to PERIPHERAL\n",
263 dev->name);
264 mode = USB_DR_MODE_PERIPHERAL;
265 }
266
267 switch (mode) {
268 case USB_DR_MODE_PERIPHERAL:
269 use_id_pin = 0;
270 host_mode = 0;
271 break;
272 case USB_DR_MODE_HOST:
273 use_id_pin = 0;
274 host_mode = 1;
275 break;
276 case USB_DR_MODE_OTG:
277 default:
278 use_id_pin = 1;
279 host_mode = 0;
280 break;
281 }
282
283 reg = readl(base + utmi_status_offset);
284
285 reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SW_MODE);
286 if (!use_id_pin)
287 reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
288
289 writel(reg, base + utmi_status_offset);
290
291 reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSEND |
292 USBOTGSS_UTMI_OTG_STATUS_VBUSVALID |
293 USBOTGSS_UTMI_OTG_STATUS_IDDIG);
294
295 reg |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID |
296 USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
297
298 if (!host_mode)
299 reg |= USBOTGSS_UTMI_OTG_STATUS_IDDIG |
300 USBOTGSS_UTMI_OTG_STATUS_VBUSVALID;
301
302 writel(reg, base + utmi_status_offset);
303
304 unmap_physmem(base, MAP_NOCACHE);
305}
306
307struct dwc3_glue_ops ti_ops = {
308 .select_dr_mode = dwc3_ti_select_dr_mode,
309};
310
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100311static int dwc3_glue_bind(struct udevice *parent)
Michal Simek49d67452018-05-18 13:15:06 +0200312{
Kever Yangac28e592020-03-04 08:59:50 +0800313 ofnode node;
Michal Simek49d67452018-05-18 13:15:06 +0200314 int ret;
Angus Ainsliec08db052022-02-02 15:08:54 -0800315 enum usb_dr_mode dr_mode;
316
317 dr_mode = usb_get_dr_mode(dev_ofnode(parent));
Michal Simek49d67452018-05-18 13:15:06 +0200318
Simon Glassf10643c2020-12-19 10:40:14 -0700319 ofnode_for_each_subnode(node, dev_ofnode(parent)) {
Kever Yangac28e592020-03-04 08:59:50 +0800320 const char *name = ofnode_get_name(node);
Michal Simek49d67452018-05-18 13:15:06 +0200321 struct udevice *dev;
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100322 const char *driver = NULL;
Michal Simek49d67452018-05-18 13:15:06 +0200323
324 debug("%s: subnode name: %s\n", __func__, name);
Michal Simek49d67452018-05-18 13:15:06 +0200325
Angus Ainsliec08db052022-02-02 15:08:54 -0800326 /* if the parent node doesn't have a mode check the leaf */
327 if (!dr_mode)
328 dr_mode = usb_get_dr_mode(node);
Michal Simek49d67452018-05-18 13:15:06 +0200329
330 switch (dr_mode) {
331 case USB_DR_MODE_PERIPHERAL:
332 case USB_DR_MODE_OTG:
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100333#if CONFIG_IS_ENABLED(DM_USB_GADGET)
Michal Simek49d67452018-05-18 13:15:06 +0200334 debug("%s: dr_mode: OTG or Peripheral\n", __func__);
335 driver = "dwc3-generic-peripheral";
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100336#endif
Michal Simek49d67452018-05-18 13:15:06 +0200337 break;
Simon Glass333e4a62021-07-10 21:14:29 -0600338#if defined(CONFIG_SPL_USB_HOST) || !defined(CONFIG_SPL_BUILD)
Michal Simek49d67452018-05-18 13:15:06 +0200339 case USB_DR_MODE_HOST:
340 debug("%s: dr_mode: HOST\n", __func__);
Jean-Jacques Hiblotb575e902019-09-11 11:33:50 +0200341 driver = "dwc3-generic-host";
Michal Simek49d67452018-05-18 13:15:06 +0200342 break;
Jean-Jacques Hiblotb575e902019-09-11 11:33:50 +0200343#endif
Michal Simek49d67452018-05-18 13:15:06 +0200344 default:
345 debug("%s: unsupported dr_mode\n", __func__);
346 return -ENODEV;
347 };
348
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100349 if (!driver)
350 continue;
351
Michal Simek49d67452018-05-18 13:15:06 +0200352 ret = device_bind_driver_to_node(parent, driver, name,
Kever Yangac28e592020-03-04 08:59:50 +0800353 node, &dev);
Michal Simek49d67452018-05-18 13:15:06 +0200354 if (ret) {
355 debug("%s: not able to bind usb device mode\n",
356 __func__);
357 return ret;
358 }
359 }
360
361 return 0;
362}
363
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100364static int dwc3_glue_reset_init(struct udevice *dev,
365 struct dwc3_glue_data *glue)
366{
367 int ret;
368
369 ret = reset_get_bulk(dev, &glue->resets);
Vignesh Raghavendrad6244342019-10-25 13:48:05 +0530370 if (ret == -ENOTSUPP || ret == -ENOENT)
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100371 return 0;
372 else if (ret)
373 return ret;
374
375 ret = reset_deassert_bulk(&glue->resets);
376 if (ret) {
377 reset_release_bulk(&glue->resets);
378 return ret;
379 }
380
381 return 0;
382}
383
384static int dwc3_glue_clk_init(struct udevice *dev,
385 struct dwc3_glue_data *glue)
386{
387 int ret;
388
389 ret = clk_get_bulk(dev, &glue->clks);
Vignesh Raghavendrad6244342019-10-25 13:48:05 +0530390 if (ret == -ENOSYS || ret == -ENOENT)
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100391 return 0;
392 if (ret)
393 return ret;
394
395#if CONFIG_IS_ENABLED(CLK)
396 ret = clk_enable_bulk(&glue->clks);
397 if (ret) {
398 clk_release_bulk(&glue->clks);
399 return ret;
400 }
401#endif
402
403 return 0;
404}
405
406static int dwc3_glue_probe(struct udevice *dev)
407{
Jean-Jacques Hiblot93991cf2018-11-29 10:52:49 +0100408 struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev);
Simon Glassc69cda22020-12-03 16:55:20 -0700409 struct dwc3_glue_data *glue = dev_get_plat(dev);
Jean-Jacques Hiblot93991cf2018-11-29 10:52:49 +0100410 struct udevice *child = NULL;
411 int index = 0;
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100412 int ret;
Michal Simek142d50f2022-03-09 10:05:45 +0100413 struct phy phy;
414
415 ret = generic_phy_get_by_name(dev, "usb3-phy", &phy);
416 if (!ret) {
417 ret = generic_phy_init(&phy);
418 if (ret)
419 return ret;
420 } else if (ret != -ENOENT) {
421 debug("could not get phy (err %d)\n", ret);
422 return ret;
423 }
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100424
Jean-Jacques Hiblot93991cf2018-11-29 10:52:49 +0100425 glue->regs = dev_read_addr(dev);
426
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100427 ret = dwc3_glue_clk_init(dev, glue);
428 if (ret)
429 return ret;
430
431 ret = dwc3_glue_reset_init(dev, glue);
432 if (ret)
433 return ret;
434
Michal Simek142d50f2022-03-09 10:05:45 +0100435 if (phy.dev) {
436 ret = generic_phy_power_on(&phy);
437 if (ret)
438 return ret;
439 }
440
Jean-Jacques Hiblot93991cf2018-11-29 10:52:49 +0100441 ret = device_find_first_child(dev, &child);
442 if (ret)
443 return ret;
444
Frank Wang5d422ab2020-05-26 11:34:31 +0800445 if (glue->resets.count == 0) {
446 ret = dwc3_glue_reset_init(child, glue);
447 if (ret)
448 return ret;
449 }
450
Jean-Jacques Hiblot93991cf2018-11-29 10:52:49 +0100451 while (child) {
452 enum usb_dr_mode dr_mode;
453
Simon Glassf10643c2020-12-19 10:40:14 -0700454 dr_mode = usb_get_dr_mode(dev_ofnode(child));
Jean-Jacques Hiblot93991cf2018-11-29 10:52:49 +0100455 device_find_next_child(&child);
456 if (ops && ops->select_dr_mode)
457 ops->select_dr_mode(dev, index, dr_mode);
458 index++;
459 }
460
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100461 return 0;
462}
463
464static int dwc3_glue_remove(struct udevice *dev)
465{
Simon Glassc69cda22020-12-03 16:55:20 -0700466 struct dwc3_glue_data *glue = dev_get_plat(dev);
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100467
468 reset_release_bulk(&glue->resets);
469
470 clk_release_bulk(&glue->clks);
471
Jean-Jacques Hiblote445d462019-07-05 09:33:56 +0200472 return 0;
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100473}
474
475static const struct udevice_id dwc3_glue_ids[] = {
Michal Simek49d67452018-05-18 13:15:06 +0200476 { .compatible = "xlnx,zynqmp-dwc3" },
Siva Durga Prasad Paladugu648856a2020-05-12 08:36:01 +0200477 { .compatible = "xlnx,versal-dwc3" },
Jean-Jacques Hiblot1c03ade2018-12-04 11:12:56 +0100478 { .compatible = "ti,keystone-dwc3"},
Jean-Jacques Hiblotd66e54a2018-11-29 10:57:40 +0100479 { .compatible = "ti,dwc3", .data = (ulong)&ti_ops },
Jean-Jacques Hiblot1ce5f1f2018-12-04 11:30:50 +0100480 { .compatible = "ti,am437x-dwc3", .data = (ulong)&ti_ops },
Vignesh Raghavendracab4e272019-12-09 10:37:29 +0530481 { .compatible = "ti,am654-dwc3" },
Frank Wang5d422ab2020-05-26 11:34:31 +0800482 { .compatible = "rockchip,rk3328-dwc3" },
483 { .compatible = "rockchip,rk3399-dwc3" },
Robert Marko74a703a2020-09-10 16:00:05 +0200484 { .compatible = "qcom,dwc3" },
Angus Ainsliec08db052022-02-02 15:08:54 -0800485 { .compatible = "fsl,imx8mq-dwc3" },
Andy Shevchenko23cdbba2020-12-03 19:45:01 +0200486 { .compatible = "intel,tangier-dwc3" },
Michal Simek49d67452018-05-18 13:15:06 +0200487 { }
488};
489
490U_BOOT_DRIVER(dwc3_generic_wrapper) = {
491 .name = "dwc3-generic-wrapper",
Jean-Jacques Hiblot3b838292019-07-05 09:33:58 +0200492 .id = UCLASS_NOP,
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100493 .of_match = dwc3_glue_ids,
494 .bind = dwc3_glue_bind,
495 .probe = dwc3_glue_probe,
496 .remove = dwc3_glue_remove,
Simon Glasscaa4daa2020-12-03 16:55:18 -0700497 .plat_auto = sizeof(struct dwc3_glue_data),
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100498
Michal Simek49d67452018-05-18 13:15:06 +0200499};