1 // SPDX-License-Identifier: GPL-2.0
3 * Generic DWC3 Glue layer
5 * Copyright (C) 2016 - 2018 Xilinx, Inc.
7 * Based on dwc3-omap.c.
14 #include <dm/device-internal.h>
16 #include <dwc3-uboot.h>
17 #include <generic-phy.h>
18 #include <linux/bitops.h>
19 #include <linux/delay.h>
20 #include <linux/usb/ch9.h>
21 #include <linux/usb/gadget.h>
31 struct dwc3_glue_data
{
33 struct reset_ctl_bulk resets
;
37 struct dwc3_generic_plat
{
40 enum usb_dr_mode dr_mode
;
43 struct dwc3_generic_priv
{
47 struct gpio_desc
*ulpi_reset
;
50 struct dwc3_generic_host_priv
{
51 struct xhci_ctrl xhci_ctrl
;
52 struct dwc3_generic_priv gen_priv
;
55 static int dwc3_generic_probe(struct udevice
*dev
,
56 struct dwc3_generic_priv
*priv
)
59 struct dwc3_generic_plat
*plat
= dev_get_plat(dev
);
60 struct dwc3
*dwc3
= &priv
->dwc3
;
61 struct dwc3_glue_data
*glue
= dev_get_plat(dev
->parent
);
62 int __maybe_unused index
;
63 ofnode __maybe_unused node
;
66 dwc3
->maximum_speed
= plat
->maximum_speed
;
67 dwc3
->dr_mode
= plat
->dr_mode
;
68 #if CONFIG_IS_ENABLED(OF_CONTROL)
71 node
= dev_ofnode(dev
->parent
);
72 index
= ofnode_stringlist_search(node
, "clock-names", "ref");
74 index
= ofnode_stringlist_search(node
, "clock-names", "ref_clk");
76 dwc3
->ref_clk
= &glue
->clks
.clks
[index
];
80 * It must hold whole USB3.0 OTG controller in resetting to hold pipe
81 * power state in P2 before initializing TypeC PHY on RK3399 platform.
83 if (device_is_compatible(dev
->parent
, "rockchip,rk3399-dwc3")) {
84 reset_assert_bulk(&glue
->resets
);
88 rc
= dwc3_setup_phy(dev
, &priv
->phys
);
89 if (rc
&& rc
!= -ENOTSUPP
)
92 if (CONFIG_IS_ENABLED(DM_GPIO
) &&
93 device_is_compatible(dev
->parent
, "xlnx,zynqmp-dwc3")) {
94 priv
->ulpi_reset
= devm_gpiod_get_optional(dev
->parent
, "reset",
96 /* property is optional, don't return error! */
97 if (priv
->ulpi_reset
) {
98 /* Toggle ulpi to reset the phy. */
99 rc
= dm_gpio_set_value(priv
->ulpi_reset
, 1);
105 rc
= dm_gpio_set_value(priv
->ulpi_reset
, 0);
113 if (device_is_compatible(dev
->parent
, "rockchip,rk3399-dwc3"))
114 reset_deassert_bulk(&glue
->resets
);
116 priv
->base
= map_physmem(plat
->base
, DWC3_OTG_REGS_END
, MAP_NOCACHE
);
117 dwc3
->regs
= priv
->base
+ DWC3_GLOBALS_REGS_START
;
120 rc
= dwc3_init(dwc3
);
122 unmap_physmem(priv
->base
, MAP_NOCACHE
);
129 static int dwc3_generic_remove(struct udevice
*dev
,
130 struct dwc3_generic_priv
*priv
)
132 struct dwc3
*dwc3
= &priv
->dwc3
;
134 if (CONFIG_IS_ENABLED(DM_GPIO
) &&
135 device_is_compatible(dev
->parent
, "xlnx,zynqmp-dwc3")) {
136 struct gpio_desc
*ulpi_reset
= priv
->ulpi_reset
;
138 dm_gpio_free(ulpi_reset
->dev
, ulpi_reset
);
142 dwc3_shutdown_phy(dev
, &priv
->phys
);
143 unmap_physmem(dwc3
->regs
, MAP_NOCACHE
);
148 static int dwc3_generic_of_to_plat(struct udevice
*dev
)
150 struct dwc3_generic_plat
*plat
= dev_get_plat(dev
);
151 ofnode node
= dev_ofnode(dev
);
153 if (!strncmp(dev
->name
, "port", 4) || !strncmp(dev
->name
, "hub", 3)) {
154 /* This is a leaf so check the parent */
155 plat
->base
= dev_read_addr(dev
->parent
);
157 plat
->base
= dev_read_addr(dev
);
160 plat
->maximum_speed
= usb_get_maximum_speed(node
);
161 if (plat
->maximum_speed
== USB_SPEED_UNKNOWN
) {
162 pr_info("No USB maximum speed specified. Using super speed\n");
163 plat
->maximum_speed
= USB_SPEED_SUPER
;
166 plat
->dr_mode
= usb_get_dr_mode(node
);
167 if (plat
->dr_mode
== USB_DR_MODE_UNKNOWN
) {
168 /* might be a leaf so check the parent for mode */
169 node
= dev_ofnode(dev
->parent
);
170 plat
->dr_mode
= usb_get_dr_mode(node
);
171 if (plat
->dr_mode
== USB_DR_MODE_UNKNOWN
) {
172 pr_err("Invalid usb mode setup\n");
180 #if CONFIG_IS_ENABLED(DM_USB_GADGET)
181 int dm_usb_gadget_handle_interrupts(struct udevice
*dev
)
183 struct dwc3_generic_priv
*priv
= dev_get_priv(dev
);
184 struct dwc3
*dwc3
= &priv
->dwc3
;
186 dwc3_gadget_uboot_handle_interrupt(dwc3
);
191 static int dwc3_generic_peripheral_probe(struct udevice
*dev
)
193 struct dwc3_generic_priv
*priv
= dev_get_priv(dev
);
195 return dwc3_generic_probe(dev
, priv
);
198 static int dwc3_generic_peripheral_remove(struct udevice
*dev
)
200 struct dwc3_generic_priv
*priv
= dev_get_priv(dev
);
202 return dwc3_generic_remove(dev
, priv
);
205 U_BOOT_DRIVER(dwc3_generic_peripheral
) = {
206 .name
= "dwc3-generic-peripheral",
207 .id
= UCLASS_USB_GADGET_GENERIC
,
208 .of_to_plat
= dwc3_generic_of_to_plat
,
209 .probe
= dwc3_generic_peripheral_probe
,
210 .remove
= dwc3_generic_peripheral_remove
,
211 .priv_auto
= sizeof(struct dwc3_generic_priv
),
212 .plat_auto
= sizeof(struct dwc3_generic_plat
),
216 #if defined(CONFIG_SPL_USB_HOST) || \
217 !defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST)
218 static int dwc3_generic_host_probe(struct udevice
*dev
)
220 struct xhci_hcor
*hcor
;
221 struct xhci_hccr
*hccr
;
222 struct dwc3_generic_host_priv
*priv
= dev_get_priv(dev
);
225 rc
= dwc3_generic_probe(dev
, &priv
->gen_priv
);
229 hccr
= (struct xhci_hccr
*)priv
->gen_priv
.base
;
230 hcor
= (struct xhci_hcor
*)(priv
->gen_priv
.base
+
231 HC_LENGTH(xhci_readl(&(hccr
)->cr_capbase
)));
233 return xhci_register(dev
, hccr
, hcor
);
236 static int dwc3_generic_host_remove(struct udevice
*dev
)
238 struct dwc3_generic_host_priv
*priv
= dev_get_priv(dev
);
241 rc
= xhci_deregister(dev
);
245 return dwc3_generic_remove(dev
, &priv
->gen_priv
);
248 U_BOOT_DRIVER(dwc3_generic_host
) = {
249 .name
= "dwc3-generic-host",
251 .of_to_plat
= dwc3_generic_of_to_plat
,
252 .probe
= dwc3_generic_host_probe
,
253 .remove
= dwc3_generic_host_remove
,
254 .priv_auto
= sizeof(struct dwc3_generic_host_priv
),
255 .plat_auto
= sizeof(struct dwc3_generic_plat
),
256 .ops
= &xhci_usb_ops
,
257 .flags
= DM_FLAG_ALLOC_PRIV_DMA
,
261 struct dwc3_glue_ops
{
262 void (*glue_configure
)(struct udevice
*dev
, int index
,
263 enum usb_dr_mode mode
);
266 void dwc3_imx8mp_glue_configure(struct udevice
*dev
, int index
,
267 enum usb_dr_mode mode
)
269 /* USB glue registers */
270 #define USB_CTRL0 0x00
271 #define USB_CTRL1 0x04
273 #define USB_CTRL0_PORTPWR_EN BIT(12) /* 1 - PPC enabled (default) */
274 #define USB_CTRL0_USB3_FIXED BIT(22) /* 1 - USB3 permanent attached */
275 #define USB_CTRL0_USB2_FIXED BIT(23) /* 1 - USB2 permanent attached */
277 #define USB_CTRL1_OC_POLARITY BIT(16) /* 0 - HIGH / 1 - LOW */
278 #define USB_CTRL1_PWR_POLARITY BIT(17) /* 0 - HIGH / 1 - LOW */
279 fdt_addr_t regs
= dev_read_addr_index(dev
, 1);
280 void *base
= map_physmem(regs
, 0x8, MAP_NOCACHE
);
283 value
= readl(base
+ USB_CTRL0
);
285 if (dev_read_bool(dev
, "fsl,permanently-attached"))
286 value
|= (USB_CTRL0_USB2_FIXED
| USB_CTRL0_USB3_FIXED
);
288 value
&= ~(USB_CTRL0_USB2_FIXED
| USB_CTRL0_USB3_FIXED
);
290 if (dev_read_bool(dev
, "fsl,disable-port-power-control"))
291 value
&= ~(USB_CTRL0_PORTPWR_EN
);
293 value
|= USB_CTRL0_PORTPWR_EN
;
295 writel(value
, base
+ USB_CTRL0
);
297 value
= readl(base
+ USB_CTRL1
);
298 if (dev_read_bool(dev
, "fsl,over-current-active-low"))
299 value
|= USB_CTRL1_OC_POLARITY
;
301 value
&= ~USB_CTRL1_OC_POLARITY
;
303 if (dev_read_bool(dev
, "fsl,power-active-low"))
304 value
|= USB_CTRL1_PWR_POLARITY
;
306 value
&= ~USB_CTRL1_PWR_POLARITY
;
308 writel(value
, base
+ USB_CTRL1
);
310 unmap_physmem(base
, MAP_NOCACHE
);
313 struct dwc3_glue_ops imx8mp_ops
= {
314 .glue_configure
= dwc3_imx8mp_glue_configure
,
317 void dwc3_ti_glue_configure(struct udevice
*dev
, int index
,
318 enum usb_dr_mode mode
)
320 #define USBOTGSS_UTMI_OTG_STATUS 0x0084
321 #define USBOTGSS_UTMI_OTG_OFFSET 0x0480
323 /* UTMI_OTG_STATUS REGISTER */
324 #define USBOTGSS_UTMI_OTG_STATUS_SW_MODE BIT(31)
325 #define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT BIT(9)
326 #define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE BIT(8)
327 #define USBOTGSS_UTMI_OTG_STATUS_IDDIG BIT(4)
328 #define USBOTGSS_UTMI_OTG_STATUS_SESSEND BIT(3)
329 #define USBOTGSS_UTMI_OTG_STATUS_SESSVALID BIT(2)
330 #define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID BIT(1)
331 enum dwc3_omap_utmi_mode
{
332 DWC3_OMAP_UTMI_MODE_UNKNOWN
= 0,
333 DWC3_OMAP_UTMI_MODE_HW
,
334 DWC3_OMAP_UTMI_MODE_SW
,
341 u32 utmi_status_offset
= USBOTGSS_UTMI_OTG_STATUS
;
343 struct dwc3_glue_data
*glue
= dev_get_plat(dev
);
344 void *base
= map_physmem(glue
->regs
, 0x10000, MAP_NOCACHE
);
346 if (device_is_compatible(dev
, "ti,am437x-dwc3"))
347 utmi_status_offset
+= USBOTGSS_UTMI_OTG_OFFSET
;
349 utmi_mode
= dev_read_u32_default(dev
, "utmi-mode",
350 DWC3_OMAP_UTMI_MODE_UNKNOWN
);
351 if (utmi_mode
!= DWC3_OMAP_UTMI_MODE_HW
) {
352 debug("%s: OTG is not supported. defaulting to PERIPHERAL\n",
354 mode
= USB_DR_MODE_PERIPHERAL
;
358 case USB_DR_MODE_PERIPHERAL
:
362 case USB_DR_MODE_HOST
:
366 case USB_DR_MODE_OTG
:
373 reg
= readl(base
+ utmi_status_offset
);
375 reg
&= ~(USBOTGSS_UTMI_OTG_STATUS_SW_MODE
);
377 reg
|= USBOTGSS_UTMI_OTG_STATUS_SW_MODE
;
379 writel(reg
, base
+ utmi_status_offset
);
381 reg
&= ~(USBOTGSS_UTMI_OTG_STATUS_SESSEND
|
382 USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
|
383 USBOTGSS_UTMI_OTG_STATUS_IDDIG
);
385 reg
|= USBOTGSS_UTMI_OTG_STATUS_SESSVALID
|
386 USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT
;
389 reg
|= USBOTGSS_UTMI_OTG_STATUS_IDDIG
|
390 USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
;
392 writel(reg
, base
+ utmi_status_offset
);
394 unmap_physmem(base
, MAP_NOCACHE
);
397 struct dwc3_glue_ops ti_ops
= {
398 .glue_configure
= dwc3_ti_glue_configure
,
401 static int dwc3_glue_bind(struct udevice
*parent
)
405 enum usb_dr_mode dr_mode
;
407 dr_mode
= usb_get_dr_mode(dev_ofnode(parent
));
409 ofnode_for_each_subnode(node
, dev_ofnode(parent
)) {
410 const char *name
= ofnode_get_name(node
);
412 const char *driver
= NULL
;
414 debug("%s: subnode name: %s\n", __func__
, name
);
416 /* if the parent node doesn't have a mode check the leaf */
418 dr_mode
= usb_get_dr_mode(node
);
421 case USB_DR_MODE_PERIPHERAL
:
422 case USB_DR_MODE_OTG
:
423 #if CONFIG_IS_ENABLED(DM_USB_GADGET)
424 debug("%s: dr_mode: OTG or Peripheral\n", __func__
);
425 driver
= "dwc3-generic-peripheral";
428 #if defined(CONFIG_SPL_USB_HOST) || !defined(CONFIG_SPL_BUILD)
429 case USB_DR_MODE_HOST
:
430 debug("%s: dr_mode: HOST\n", __func__
);
431 driver
= "dwc3-generic-host";
435 debug("%s: unsupported dr_mode\n", __func__
);
442 ret
= device_bind_driver_to_node(parent
, driver
, name
,
445 debug("%s: not able to bind usb device mode\n",
454 static int dwc3_glue_reset_init(struct udevice
*dev
,
455 struct dwc3_glue_data
*glue
)
459 ret
= reset_get_bulk(dev
, &glue
->resets
);
460 if (ret
== -ENOTSUPP
|| ret
== -ENOENT
)
465 ret
= reset_deassert_bulk(&glue
->resets
);
467 reset_release_bulk(&glue
->resets
);
474 static int dwc3_glue_clk_init(struct udevice
*dev
,
475 struct dwc3_glue_data
*glue
)
479 ret
= clk_get_bulk(dev
, &glue
->clks
);
480 if (ret
== -ENOSYS
|| ret
== -ENOENT
)
485 #if CONFIG_IS_ENABLED(CLK)
486 ret
= clk_enable_bulk(&glue
->clks
);
488 clk_release_bulk(&glue
->clks
);
496 static int dwc3_glue_probe(struct udevice
*dev
)
498 struct dwc3_glue_ops
*ops
= (struct dwc3_glue_ops
*)dev_get_driver_data(dev
);
499 struct dwc3_glue_data
*glue
= dev_get_plat(dev
);
500 struct udevice
*child
= NULL
;
505 ret
= generic_phy_get_by_name(dev
, "usb3-phy", &phy
);
507 ret
= generic_phy_init(&phy
);
510 } else if (ret
!= -ENOENT
&& ret
!= -ENODATA
) {
511 debug("could not get phy (err %d)\n", ret
);
517 glue
->regs
= dev_read_addr(dev
);
519 ret
= dwc3_glue_clk_init(dev
, glue
);
523 ret
= dwc3_glue_reset_init(dev
, glue
);
528 ret
= generic_phy_power_on(&phy
);
533 ret
= device_find_first_child(dev
, &child
);
537 if (glue
->resets
.count
== 0) {
538 ret
= dwc3_glue_reset_init(child
, glue
);
544 enum usb_dr_mode dr_mode
;
546 dr_mode
= usb_get_dr_mode(dev_ofnode(child
));
547 device_find_next_child(&child
);
548 if (ops
&& ops
->glue_configure
)
549 ops
->glue_configure(dev
, index
, dr_mode
);
556 static int dwc3_glue_remove(struct udevice
*dev
)
558 struct dwc3_glue_data
*glue
= dev_get_plat(dev
);
560 reset_release_bulk(&glue
->resets
);
562 clk_release_bulk(&glue
->clks
);
567 static const struct udevice_id dwc3_glue_ids
[] = {
568 { .compatible
= "xlnx,zynqmp-dwc3" },
569 { .compatible
= "xlnx,versal-dwc3" },
570 { .compatible
= "ti,keystone-dwc3"},
571 { .compatible
= "ti,dwc3", .data
= (ulong
)&ti_ops
},
572 { .compatible
= "ti,am437x-dwc3", .data
= (ulong
)&ti_ops
},
573 { .compatible
= "ti,am654-dwc3" },
574 { .compatible
= "rockchip,rk3328-dwc3" },
575 { .compatible
= "rockchip,rk3399-dwc3" },
576 { .compatible
= "qcom,dwc3" },
577 { .compatible
= "fsl,imx8mp-dwc3", .data
= (ulong
)&imx8mp_ops
},
578 { .compatible
= "fsl,imx8mq-dwc3" },
579 { .compatible
= "intel,tangier-dwc3" },
583 U_BOOT_DRIVER(dwc3_generic_wrapper
) = {
584 .name
= "dwc3-generic-wrapper",
586 .of_match
= dwc3_glue_ids
,
587 .bind
= dwc3_glue_bind
,
588 .probe
= dwc3_glue_probe
,
589 .remove
= dwc3_glue_remove
,
590 .plat_auto
= sizeof(struct dwc3_glue_data
),