xref: /rk3399_rockchip-uboot/drivers/usb/dwc3/dwc3-generic.c (revision 20828bbaa724e2dae360b8e48839a7d1366ea21b)
1e2f919a1SMichal Simek // SPDX-License-Identifier:     GPL-2.0
2e2f919a1SMichal Simek /*
3e2f919a1SMichal Simek  * Generic DWC3 Glue layer
4e2f919a1SMichal Simek  *
5e2f919a1SMichal Simek  * Copyright (C) 2016 - 2018 Xilinx, Inc.
6e2f919a1SMichal Simek  *
7e2f919a1SMichal Simek  * Based on dwc3-omap.c.
8e2f919a1SMichal Simek  */
9e2f919a1SMichal Simek 
10e2f919a1SMichal Simek #include <common.h>
11e2f919a1SMichal Simek #include <dm.h>
12e2f919a1SMichal Simek #include <dm/device-internal.h>
13e2f919a1SMichal Simek #include <dm/lists.h>
14e2f919a1SMichal Simek #include <linux/usb/otg.h>
15e2f919a1SMichal Simek #include <linux/compat.h>
16e2f919a1SMichal Simek #include <linux/usb/ch9.h>
17e2f919a1SMichal Simek #include <linux/usb/gadget.h>
18e2f919a1SMichal Simek #include <malloc.h>
19e2f919a1SMichal Simek #include <usb.h>
20e2f919a1SMichal Simek #include "core.h"
21e2f919a1SMichal Simek #include "gadget.h"
22e2f919a1SMichal Simek #include "linux-compat.h"
23e2f919a1SMichal Simek 
24717f5765SJean-Jacques Hiblot #if CONFIG_IS_ENABLED(DM_USB_GADGET)
25256dc48fSJean-Jacques Hiblot int dm_usb_gadget_handle_interrupts(struct udevice *dev)
26e2f919a1SMichal Simek {
27256dc48fSJean-Jacques Hiblot 	struct dwc3 *priv = dev_get_priv(dev);
28e2f919a1SMichal Simek 
29e2f919a1SMichal Simek 	dwc3_gadget_uboot_handle_interrupt(priv);
30e2f919a1SMichal Simek 
31e2f919a1SMichal Simek 	return 0;
32e2f919a1SMichal Simek }
33e2f919a1SMichal Simek 
34e2f919a1SMichal Simek static int dwc3_generic_peripheral_probe(struct udevice *dev)
35e2f919a1SMichal Simek {
36e2f919a1SMichal Simek 	struct dwc3 *priv = dev_get_priv(dev);
37e2f919a1SMichal Simek 
38e2f919a1SMichal Simek 	return dwc3_init(priv);
39e2f919a1SMichal Simek }
40e2f919a1SMichal Simek 
41e2f919a1SMichal Simek static int dwc3_generic_peripheral_remove(struct udevice *dev)
42e2f919a1SMichal Simek {
43e2f919a1SMichal Simek 	struct dwc3 *priv = dev_get_priv(dev);
44e2f919a1SMichal Simek 
45e2f919a1SMichal Simek 	dwc3_remove(priv);
46e2f919a1SMichal Simek 
47e2f919a1SMichal Simek 	return 0;
48e2f919a1SMichal Simek }
49e2f919a1SMichal Simek 
50e2f919a1SMichal Simek static int dwc3_generic_peripheral_ofdata_to_platdata(struct udevice *dev)
51e2f919a1SMichal Simek {
52e2f919a1SMichal Simek 	struct dwc3 *priv = dev_get_priv(dev);
53e2f919a1SMichal Simek 	int node = dev_of_offset(dev);
54e2f919a1SMichal Simek 
55e2f919a1SMichal Simek 	priv->regs = (void *)devfdt_get_addr(dev);
56e2f919a1SMichal Simek 	priv->regs += DWC3_GLOBALS_REGS_START;
57e2f919a1SMichal Simek 
58e2f919a1SMichal Simek 	priv->maximum_speed = usb_get_maximum_speed(node);
59e2f919a1SMichal Simek 	if (priv->maximum_speed == USB_SPEED_UNKNOWN) {
60e2f919a1SMichal Simek 		pr_err("Invalid usb maximum speed\n");
61e2f919a1SMichal Simek 		return -ENODEV;
62e2f919a1SMichal Simek 	}
63e2f919a1SMichal Simek 
64e2f919a1SMichal Simek 	priv->dr_mode = usb_get_dr_mode(node);
65e2f919a1SMichal Simek 	if (priv->dr_mode == USB_DR_MODE_UNKNOWN) {
66e2f919a1SMichal Simek 		pr_err("Invalid usb mode setup\n");
67e2f919a1SMichal Simek 		return -ENODEV;
68e2f919a1SMichal Simek 	}
69e2f919a1SMichal Simek 
70e2f919a1SMichal Simek 	return 0;
71e2f919a1SMichal Simek }
72e2f919a1SMichal Simek 
73e2f919a1SMichal Simek U_BOOT_DRIVER(dwc3_generic_peripheral) = {
74e2f919a1SMichal Simek 	.name	= "dwc3-generic-peripheral",
75*20828bbaSJean-Jacques Hiblot 	.id	= UCLASS_USB_GADGET_GENERIC,
76e2f919a1SMichal Simek 	.ofdata_to_platdata = dwc3_generic_peripheral_ofdata_to_platdata,
77e2f919a1SMichal Simek 	.probe = dwc3_generic_peripheral_probe,
78e2f919a1SMichal Simek 	.remove = dwc3_generic_peripheral_remove,
79e2f919a1SMichal Simek 	.platdata_auto_alloc_size = sizeof(struct usb_platdata),
80e2f919a1SMichal Simek 	.priv_auto_alloc_size = sizeof(struct dwc3),
81e2f919a1SMichal Simek };
82717f5765SJean-Jacques Hiblot #endif
83e2f919a1SMichal Simek 
84e2f919a1SMichal Simek static int dwc3_generic_bind(struct udevice *parent)
85e2f919a1SMichal Simek {
86e2f919a1SMichal Simek 	const void *fdt = gd->fdt_blob;
87e2f919a1SMichal Simek 	int node;
88e2f919a1SMichal Simek 	int ret;
89e2f919a1SMichal Simek 
90e2f919a1SMichal Simek 	for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0;
91e2f919a1SMichal Simek 	     node = fdt_next_subnode(fdt, node)) {
92e2f919a1SMichal Simek 		const char *name = fdt_get_name(fdt, node, NULL);
93e2f919a1SMichal Simek 		enum usb_dr_mode dr_mode;
94e2f919a1SMichal Simek 		struct udevice *dev;
95e2f919a1SMichal Simek 		const char *driver;
96e2f919a1SMichal Simek 
97e2f919a1SMichal Simek 		debug("%s: subnode name: %s\n", __func__, name);
98e2f919a1SMichal Simek 		if (strncmp(name, "dwc3@", 4))
99e2f919a1SMichal Simek 			continue;
100e2f919a1SMichal Simek 
101e2f919a1SMichal Simek 		dr_mode = usb_get_dr_mode(node);
102e2f919a1SMichal Simek 
103e2f919a1SMichal Simek 		switch (dr_mode) {
104e2f919a1SMichal Simek 		case USB_DR_MODE_PERIPHERAL:
105e2f919a1SMichal Simek 		case USB_DR_MODE_OTG:
106e2f919a1SMichal Simek 			debug("%s: dr_mode: OTG or Peripheral\n", __func__);
107e2f919a1SMichal Simek 			driver = "dwc3-generic-peripheral";
108e2f919a1SMichal Simek 			break;
109e2f919a1SMichal Simek 		case USB_DR_MODE_HOST:
110e2f919a1SMichal Simek 			debug("%s: dr_mode: HOST\n", __func__);
111e2f919a1SMichal Simek 			driver = "dwc3-generic-host";
112e2f919a1SMichal Simek 			break;
113e2f919a1SMichal Simek 		default:
114e2f919a1SMichal Simek 			debug("%s: unsupported dr_mode\n", __func__);
115e2f919a1SMichal Simek 			return -ENODEV;
116e2f919a1SMichal Simek 		};
117e2f919a1SMichal Simek 
118e2f919a1SMichal Simek 		ret = device_bind_driver_to_node(parent, driver, name,
119e2f919a1SMichal Simek 						 offset_to_ofnode(node), &dev);
120e2f919a1SMichal Simek 		if (ret) {
121e2f919a1SMichal Simek 			debug("%s: not able to bind usb device mode\n",
122e2f919a1SMichal Simek 			      __func__);
123e2f919a1SMichal Simek 			return ret;
124e2f919a1SMichal Simek 		}
125e2f919a1SMichal Simek 	}
126e2f919a1SMichal Simek 
127e2f919a1SMichal Simek 	return 0;
128e2f919a1SMichal Simek }
129e2f919a1SMichal Simek 
130e2f919a1SMichal Simek static const struct udevice_id dwc3_generic_ids[] = {
131e2f919a1SMichal Simek 	{ .compatible = "xlnx,zynqmp-dwc3" },
132e2f919a1SMichal Simek 	{ }
133e2f919a1SMichal Simek };
134e2f919a1SMichal Simek 
135e2f919a1SMichal Simek U_BOOT_DRIVER(dwc3_generic_wrapper) = {
136e2f919a1SMichal Simek 	.name	= "dwc3-generic-wrapper",
137e2f919a1SMichal Simek 	.id	= UCLASS_MISC,
138e2f919a1SMichal Simek 	.of_match = dwc3_generic_ids,
139e2f919a1SMichal Simek 	.bind = dwc3_generic_bind,
140e2f919a1SMichal Simek };
141