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.
11 #include <asm-generic/io.h>
13 #include <dm/device-internal.h>
15 #include <dwc3-uboot.h>
16 #include <linux/usb/ch9.h>
17 #include <linux/usb/gadget.h>
25 #if CONFIG_IS_ENABLED(DM_USB_GADGET)
26 struct dwc3_generic_peripheral
{
33 int dm_usb_gadget_handle_interrupts(struct udevice
*dev
)
35 struct dwc3_generic_peripheral
*priv
= dev_get_priv(dev
);
36 struct dwc3
*dwc3
= &priv
->dwc3
;
38 dwc3_gadget_uboot_handle_interrupt(dwc3
);
43 static int dwc3_generic_peripheral_probe(struct udevice
*dev
)
46 struct dwc3_generic_peripheral
*priv
= dev_get_priv(dev
);
47 struct dwc3
*dwc3
= &priv
->dwc3
;
49 rc
= dwc3_setup_phy(dev
, &priv
->phys
, &priv
->num_phys
);
53 dwc3
->regs
= map_physmem(priv
->base
, DWC3_OTG_REGS_END
, MAP_NOCACHE
);
54 dwc3
->regs
+= DWC3_GLOBALS_REGS_START
;
59 unmap_physmem(dwc3
->regs
, MAP_NOCACHE
);
66 static int dwc3_generic_peripheral_remove(struct udevice
*dev
)
68 struct dwc3_generic_peripheral
*priv
= dev_get_priv(dev
);
69 struct dwc3
*dwc3
= &priv
->dwc3
;
72 dwc3_shutdown_phy(dev
, priv
->phys
, priv
->num_phys
);
73 unmap_physmem(dwc3
->regs
, MAP_NOCACHE
);
78 static int dwc3_generic_peripheral_ofdata_to_platdata(struct udevice
*dev
)
80 struct dwc3_generic_peripheral
*priv
= dev_get_priv(dev
);
81 struct dwc3
*dwc3
= &priv
->dwc3
;
82 int node
= dev_of_offset(dev
);
84 priv
->base
= devfdt_get_addr(dev
);
86 dwc3
->maximum_speed
= usb_get_maximum_speed(node
);
87 if (dwc3
->maximum_speed
== USB_SPEED_UNKNOWN
) {
88 pr_err("Invalid usb maximum speed\n");
92 dwc3
->dr_mode
= usb_get_dr_mode(node
);
93 if (dwc3
->dr_mode
== USB_DR_MODE_UNKNOWN
) {
94 pr_err("Invalid usb mode setup\n");
101 U_BOOT_DRIVER(dwc3_generic_peripheral
) = {
102 .name
= "dwc3-generic-peripheral",
103 .id
= UCLASS_USB_GADGET_GENERIC
,
104 .ofdata_to_platdata
= dwc3_generic_peripheral_ofdata_to_platdata
,
105 .probe
= dwc3_generic_peripheral_probe
,
106 .remove
= dwc3_generic_peripheral_remove
,
107 .priv_auto_alloc_size
= sizeof(struct dwc3_generic_peripheral
),
111 struct dwc3_glue_data
{
112 struct clk_bulk clks
;
113 struct reset_ctl_bulk resets
;
117 struct dwc3_glue_ops
{
118 void (*select_dr_mode
)(struct udevice
*dev
, int index
,
119 enum usb_dr_mode mode
);
122 void dwc3_ti_select_dr_mode(struct udevice
*dev
, int index
,
123 enum usb_dr_mode mode
)
125 #define USBOTGSS_UTMI_OTG_STATUS 0x0084
126 #define USBOTGSS_UTMI_OTG_OFFSET 0x0480
128 /* UTMI_OTG_STATUS REGISTER */
129 #define USBOTGSS_UTMI_OTG_STATUS_SW_MODE BIT(31)
130 #define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT BIT(9)
131 #define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE BIT(8)
132 #define USBOTGSS_UTMI_OTG_STATUS_IDDIG BIT(4)
133 #define USBOTGSS_UTMI_OTG_STATUS_SESSEND BIT(3)
134 #define USBOTGSS_UTMI_OTG_STATUS_SESSVALID BIT(2)
135 #define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID BIT(1)
136 enum dwc3_omap_utmi_mode
{
137 DWC3_OMAP_UTMI_MODE_UNKNOWN
= 0,
138 DWC3_OMAP_UTMI_MODE_HW
,
139 DWC3_OMAP_UTMI_MODE_SW
,
146 u32 utmi_status_offset
= USBOTGSS_UTMI_OTG_STATUS
;
148 struct dwc3_glue_data
*glue
= dev_get_platdata(dev
);
149 void *base
= map_physmem(glue
->regs
, 0x10000, MAP_NOCACHE
);
151 if (device_is_compatible(dev
, "ti,am437x-dwc3"))
152 utmi_status_offset
+= USBOTGSS_UTMI_OTG_OFFSET
;
154 utmi_mode
= dev_read_u32_default(dev
, "utmi-mode",
155 DWC3_OMAP_UTMI_MODE_UNKNOWN
);
156 if (utmi_mode
!= DWC3_OMAP_UTMI_MODE_HW
) {
157 debug("%s: OTG is not supported. defaulting to PERIPHERAL\n",
159 mode
= USB_DR_MODE_PERIPHERAL
;
163 case USB_DR_MODE_PERIPHERAL
:
167 case USB_DR_MODE_HOST
:
171 case USB_DR_MODE_OTG
:
178 reg
= readl(base
+ utmi_status_offset
);
180 reg
&= ~(USBOTGSS_UTMI_OTG_STATUS_SW_MODE
);
182 reg
|= USBOTGSS_UTMI_OTG_STATUS_SW_MODE
;
184 writel(reg
, base
+ utmi_status_offset
);
186 reg
&= ~(USBOTGSS_UTMI_OTG_STATUS_SESSEND
|
187 USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
|
188 USBOTGSS_UTMI_OTG_STATUS_IDDIG
);
190 reg
|= USBOTGSS_UTMI_OTG_STATUS_SESSVALID
|
191 USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT
;
194 reg
|= USBOTGSS_UTMI_OTG_STATUS_IDDIG
|
195 USBOTGSS_UTMI_OTG_STATUS_VBUSVALID
;
197 writel(reg
, base
+ utmi_status_offset
);
199 unmap_physmem(base
, MAP_NOCACHE
);
202 struct dwc3_glue_ops ti_ops
= {
203 .select_dr_mode
= dwc3_ti_select_dr_mode
,
206 static int dwc3_glue_bind(struct udevice
*parent
)
208 const void *fdt
= gd
->fdt_blob
;
212 for (node
= fdt_first_subnode(fdt
, dev_of_offset(parent
)); node
> 0;
213 node
= fdt_next_subnode(fdt
, node
)) {
214 const char *name
= fdt_get_name(fdt
, node
, NULL
);
215 enum usb_dr_mode dr_mode
;
217 const char *driver
= NULL
;
219 debug("%s: subnode name: %s\n", __func__
, name
);
221 dr_mode
= usb_get_dr_mode(node
);
224 case USB_DR_MODE_PERIPHERAL
:
225 case USB_DR_MODE_OTG
:
226 #if CONFIG_IS_ENABLED(DM_USB_GADGET)
227 debug("%s: dr_mode: OTG or Peripheral\n", __func__
);
228 driver
= "dwc3-generic-peripheral";
231 case USB_DR_MODE_HOST
:
232 debug("%s: dr_mode: HOST\n", __func__
);
233 driver
= "xhci-dwc3";
236 debug("%s: unsupported dr_mode\n", __func__
);
243 ret
= device_bind_driver_to_node(parent
, driver
, name
,
244 offset_to_ofnode(node
), &dev
);
246 debug("%s: not able to bind usb device mode\n",
255 static int dwc3_glue_reset_init(struct udevice
*dev
,
256 struct dwc3_glue_data
*glue
)
260 ret
= reset_get_bulk(dev
, &glue
->resets
);
261 if (ret
== -ENOTSUPP
)
266 ret
= reset_deassert_bulk(&glue
->resets
);
268 reset_release_bulk(&glue
->resets
);
275 static int dwc3_glue_clk_init(struct udevice
*dev
,
276 struct dwc3_glue_data
*glue
)
280 ret
= clk_get_bulk(dev
, &glue
->clks
);
286 #if CONFIG_IS_ENABLED(CLK)
287 ret
= clk_enable_bulk(&glue
->clks
);
289 clk_release_bulk(&glue
->clks
);
297 static int dwc3_glue_probe(struct udevice
*dev
)
299 struct dwc3_glue_ops
*ops
= (struct dwc3_glue_ops
*)dev_get_driver_data(dev
);
300 struct dwc3_glue_data
*glue
= dev_get_platdata(dev
);
301 struct udevice
*child
= NULL
;
305 glue
->regs
= dev_read_addr(dev
);
307 ret
= dwc3_glue_clk_init(dev
, glue
);
311 ret
= dwc3_glue_reset_init(dev
, glue
);
315 ret
= device_find_first_child(dev
, &child
);
320 enum usb_dr_mode dr_mode
;
322 dr_mode
= usb_get_dr_mode(dev_of_offset(child
));
323 device_find_next_child(&child
);
324 if (ops
&& ops
->select_dr_mode
)
325 ops
->select_dr_mode(dev
, index
, dr_mode
);
332 static int dwc3_glue_remove(struct udevice
*dev
)
334 struct dwc3_glue_data
*glue
= dev_get_platdata(dev
);
336 reset_release_bulk(&glue
->resets
);
338 clk_release_bulk(&glue
->clks
);
343 static const struct udevice_id dwc3_glue_ids
[] = {
344 { .compatible
= "xlnx,zynqmp-dwc3" },
345 { .compatible
= "ti,keystone-dwc3"},
346 { .compatible
= "ti,dwc3", .data
= (ulong
)&ti_ops
},
347 { .compatible
= "ti,am437x-dwc3", .data
= (ulong
)&ti_ops
},
351 U_BOOT_DRIVER(dwc3_generic_wrapper
) = {
352 .name
= "dwc3-generic-wrapper",
354 .of_match
= dwc3_glue_ids
,
355 .bind
= dwc3_glue_bind
,
356 .probe
= dwc3_glue_probe
,
357 .remove
= dwc3_glue_remove
,
358 .platdata_auto_alloc_size
= sizeof(struct dwc3_glue_data
),