1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Layerscape DWC3 Glue layer
4  *
5  * Copyright (C) 2021 Michael Walle <michael@walle.cc>
6  *
7  * Based on dwc3-generic.c.
8  */
9 
10 #include <common.h>
11 #include <dm.h>
12 #include <dm/device_compat.h>
13 #include <dm/device-internal.h>
14 #include <dm/lists.h>
15 #include <dwc3-uboot.h>
16 #include <linux/usb/gadget.h>
17 #include <usb.h>
18 #include "core.h"
19 #include "gadget.h"
20 #include <usb/xhci.h>
21 
22 struct dwc3_layerscape_plat {
23 	fdt_addr_t base;
24 	u32 maximum_speed;
25 	enum usb_dr_mode dr_mode;
26 };
27 
28 struct dwc3_layerscape_priv {
29 	void *base;
30 	struct dwc3 dwc3;
31 	struct phy_bulk phys;
32 };
33 
34 struct dwc3_layerscape_host_priv {
35 	struct xhci_ctrl xhci_ctrl;
36 	struct dwc3_layerscape_priv gen_priv;
37 };
38 
dwc3_layerscape_probe(struct udevice * dev,struct dwc3_layerscape_priv * priv)39 static int dwc3_layerscape_probe(struct udevice *dev,
40 				 struct dwc3_layerscape_priv *priv)
41 {
42 	int rc;
43 	struct dwc3_layerscape_plat *plat = dev_get_plat(dev);
44 	struct dwc3 *dwc3 = &priv->dwc3;
45 
46 	dwc3->dev = dev;
47 	dwc3->maximum_speed = plat->maximum_speed;
48 	dwc3->dr_mode = plat->dr_mode;
49 	if (CONFIG_IS_ENABLED(OF_CONTROL))
50 		dwc3_of_parse(dwc3);
51 
52 	rc = dwc3_setup_phy(dev, &priv->phys);
53 	if (rc && rc != -ENOTSUPP)
54 		return rc;
55 
56 	priv->base = map_physmem(plat->base, DWC3_OTG_REGS_END, MAP_NOCACHE);
57 	dwc3->regs = priv->base + DWC3_GLOBALS_REGS_START;
58 
59 	rc =  dwc3_init(dwc3);
60 	if (rc) {
61 		unmap_physmem(priv->base, MAP_NOCACHE);
62 		return rc;
63 	}
64 
65 	return 0;
66 }
67 
dwc3_layerscape_remove(struct udevice * dev,struct dwc3_layerscape_priv * priv)68 static int dwc3_layerscape_remove(struct udevice *dev,
69 				  struct dwc3_layerscape_priv *priv)
70 {
71 	struct dwc3 *dwc3 = &priv->dwc3;
72 
73 	dwc3_remove(dwc3);
74 	dwc3_shutdown_phy(dev, &priv->phys);
75 	unmap_physmem(dwc3->regs, MAP_NOCACHE);
76 
77 	return 0;
78 }
79 
dwc3_layerscape_of_to_plat(struct udevice * dev)80 static int dwc3_layerscape_of_to_plat(struct udevice *dev)
81 {
82 	struct dwc3_layerscape_plat *plat = dev_get_plat(dev);
83 	ofnode node = dev_ofnode(dev);
84 
85 	plat->base = dev_read_addr(dev);
86 
87 	plat->maximum_speed = usb_get_maximum_speed(node);
88 	if (plat->maximum_speed == USB_SPEED_UNKNOWN) {
89 		dev_dbg(dev, "No USB maximum speed specified. Using super speed\n");
90 		plat->maximum_speed = USB_SPEED_SUPER;
91 	}
92 
93 	plat->dr_mode = usb_get_dr_mode(node);
94 	if (plat->dr_mode == USB_DR_MODE_UNKNOWN) {
95 		dev_err(dev, "Invalid usb mode setup\n");
96 		return -ENODEV;
97 	}
98 
99 	return 0;
100 }
101 
102 #if CONFIG_IS_ENABLED(DM_USB_GADGET)
dm_usb_gadget_handle_interrupts(struct udevice * dev)103 int dm_usb_gadget_handle_interrupts(struct udevice *dev)
104 {
105 	struct dwc3_layerscape_priv *priv = dev_get_priv(dev);
106 
107 	dwc3_gadget_uboot_handle_interrupt(&priv->dwc3);
108 
109 	return 0;
110 }
111 
dwc3_layerscape_peripheral_probe(struct udevice * dev)112 static int dwc3_layerscape_peripheral_probe(struct udevice *dev)
113 {
114 	struct dwc3_layerscape_priv *priv = dev_get_priv(dev);
115 
116 	return dwc3_layerscape_probe(dev, priv);
117 }
118 
dwc3_layerscape_peripheral_remove(struct udevice * dev)119 static int dwc3_layerscape_peripheral_remove(struct udevice *dev)
120 {
121 	struct dwc3_layerscape_priv *priv = dev_get_priv(dev);
122 
123 	return dwc3_layerscape_remove(dev, priv);
124 }
125 
126 U_BOOT_DRIVER(dwc3_layerscape_peripheral) = {
127 	.name	= "dwc3-layerscape-peripheral",
128 	.id	= UCLASS_USB_GADGET_GENERIC,
129 	.of_to_plat = dwc3_layerscape_of_to_plat,
130 	.probe = dwc3_layerscape_peripheral_probe,
131 	.remove = dwc3_layerscape_peripheral_remove,
132 	.priv_auto	= sizeof(struct dwc3_layerscape_priv),
133 	.plat_auto	= sizeof(struct dwc3_layerscape_plat),
134 };
135 #endif
136 
137 #if defined(CONFIG_SPL_USB_HOST_SUPPORT) || \
138 	!defined(CONFIG_SPL_BUILD) && defined(CONFIG_USB_HOST)
dwc3_layerscape_host_probe(struct udevice * dev)139 static int dwc3_layerscape_host_probe(struct udevice *dev)
140 {
141 	struct xhci_hcor *hcor;
142 	struct xhci_hccr *hccr;
143 	struct dwc3_layerscape_host_priv *priv = dev_get_priv(dev);
144 	int rc;
145 
146 	rc = dwc3_layerscape_probe(dev, &priv->gen_priv);
147 	if (rc)
148 		return rc;
149 
150 	hccr = priv->gen_priv.base;
151 	hcor = priv->gen_priv.base + HC_LENGTH(xhci_readl(&hccr->cr_capbase));
152 
153 	return xhci_register(dev, hccr, hcor);
154 }
155 
dwc3_layerscape_host_remove(struct udevice * dev)156 static int dwc3_layerscape_host_remove(struct udevice *dev)
157 {
158 	struct dwc3_layerscape_host_priv *priv = dev_get_priv(dev);
159 	int rc;
160 
161 	rc = xhci_deregister(dev);
162 	if (rc)
163 		return rc;
164 
165 	return dwc3_layerscape_remove(dev, &priv->gen_priv);
166 }
167 
168 U_BOOT_DRIVER(dwc3_layerscape_host) = {
169 	.name	= "dwc3-layerscape-host",
170 	.id	= UCLASS_USB,
171 	.of_to_plat = dwc3_layerscape_of_to_plat,
172 	.probe = dwc3_layerscape_host_probe,
173 	.remove = dwc3_layerscape_host_remove,
174 	.priv_auto	= sizeof(struct dwc3_layerscape_host_priv),
175 	.plat_auto	= sizeof(struct dwc3_layerscape_plat),
176 	.ops = &xhci_usb_ops,
177 	.flags = DM_FLAG_ALLOC_PRIV_DMA,
178 };
179 #endif
180 
dwc3_layerscape_bind(struct udevice * dev)181 static int dwc3_layerscape_bind(struct udevice *dev)
182 {
183 	ofnode node = dev_ofnode(dev);
184 	const char *name = ofnode_get_name(node);
185 	enum usb_dr_mode dr_mode;
186 	char *driver;
187 
188 	dr_mode = usb_get_dr_mode(node);
189 
190 	switch (dr_mode) {
191 #if CONFIG_IS_ENABLED(DM_USB_GADGET)
192 	case USB_DR_MODE_PERIPHERAL:
193 		dev_dbg(dev, "Using peripheral mode\n");
194 		driver = "dwc3-layerscape-peripheral";
195 		break;
196 #endif
197 #if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD)
198 	case USB_DR_MODE_HOST:
199 		dev_dbg(dev, "Using host mode\n");
200 		driver = "dwc3-layerscape-host";
201 		break;
202 #endif
203 	default:
204 		dev_dbg(dev, "Unsupported dr_mode\n");
205 		return -ENODEV;
206 	};
207 
208 	return device_bind_driver_to_node(dev, driver, name, node, NULL);
209 }
210 
211 static const struct udevice_id dwc3_layerscape_ids[] = {
212 	{ .compatible = "fsl,layerscape-dwc3" },
213 	{ .compatible = "fsl,ls1028a-dwc3" },
214 	{ }
215 };
216 
217 U_BOOT_DRIVER(dwc3_layerscape_wrapper) = {
218 	.name	= "dwc3-layerscape-wrapper",
219 	.id	= UCLASS_NOP,
220 	.of_match = dwc3_layerscape_ids,
221 	.bind = dwc3_layerscape_bind,
222 };
223