xref: /rk3399_rockchip-uboot/drivers/usb/dwc3/dwc3-generic.c (revision 4a2b8db466479ddec6ee85f9fe9d7f934016be9a)
1 // SPDX-License-Identifier:     GPL-2.0
2 /*
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>
11 #include <asm-generic/io.h>
12 #include <dm.h>
13 #include <dm/device-internal.h>
14 #include <dm/lists.h>
15 #include <dwc3-uboot.h>
16 #include <linux/usb/ch9.h>
17 #include <linux/usb/gadget.h>
18 #include <malloc.h>
19 #include <usb.h>
20 #include "core.h"
21 #include "gadget.h"
22 #include <reset.h>
23 #include <clk.h>
24 #include <usb/xhci.h>
25 
26 struct dwc3_glue_data {
27 	struct clk_bulk		clks;
28 	struct reset_ctl_bulk	resets;
29 	fdt_addr_t regs;
30 };
31 
32 struct dwc3_generic_plat {
33 	fdt_addr_t base;
34 	u32 maximum_speed;
35 	enum usb_dr_mode dr_mode;
36 };
37 
38 struct dwc3_generic_priv {
39 	void *base;
40 	struct dwc3 dwc3;
41 	struct phy *phys;
42 	int num_phys;
43 };
44 
45 struct dwc3_generic_host_priv {
46 	struct xhci_ctrl xhci_ctrl;
47 	struct dwc3_generic_priv gen_priv;
48 };
49 
50 static int dwc3_generic_probe(struct udevice *dev,
51 			      struct dwc3_generic_priv *priv)
52 {
53 	int rc;
54 	struct dwc3_generic_plat *plat = dev_get_platdata(dev);
55 	struct dwc3 *dwc3 = &priv->dwc3;
56 	struct dwc3_glue_data *glue = dev_get_platdata(dev->parent);
57 
58 	dwc3->dev = dev;
59 	dwc3->maximum_speed = plat->maximum_speed;
60 	dwc3->dr_mode = plat->dr_mode;
61 #if CONFIG_IS_ENABLED(OF_CONTROL)
62 	dwc3_of_parse(dwc3);
63 #endif
64 
65 	/*
66 	 * It must hold whole USB3.0 OTG controller in resetting to hold pipe
67 	 * power state in P2 before initializing TypeC PHY on RK3399 platform.
68 	 */
69 	if (device_is_compatible(dev->parent, "rockchip,rk3399-dwc3")) {
70 		reset_assert_bulk(&glue->resets);
71 		udelay(1);
72 	}
73 
74 	rc = dwc3_setup_phy(dev, &priv->phys, &priv->num_phys);
75 	if (rc)
76 		return rc;
77 
78 	if (device_is_compatible(dev->parent, "rockchip,rk3399-dwc3"))
79 		reset_deassert_bulk(&glue->resets);
80 
81 	priv->base = map_physmem(plat->base, DWC3_OTG_REGS_END, MAP_NOCACHE);
82 	dwc3->regs = priv->base + DWC3_GLOBALS_REGS_START;
83 
84 
85 	rc =  dwc3_init(dwc3);
86 	if (rc) {
87 		unmap_physmem(priv->base, MAP_NOCACHE);
88 		return rc;
89 	}
90 
91 	return 0;
92 }
93 
94 static int dwc3_generic_remove(struct udevice *dev,
95 			       struct dwc3_generic_priv *priv)
96 {
97 	struct dwc3 *dwc3 = &priv->dwc3;
98 
99 	dwc3_remove(dwc3);
100 	dwc3_shutdown_phy(dev, priv->phys, priv->num_phys);
101 	unmap_physmem(dwc3->regs, MAP_NOCACHE);
102 
103 	return 0;
104 }
105 
106 static int dwc3_generic_ofdata_to_platdata(struct udevice *dev)
107 {
108 	struct dwc3_generic_plat *plat = dev_get_platdata(dev);
109 	ofnode node = dev->node;
110 
111 	plat->base = dev_read_addr(dev);
112 
113 	plat->maximum_speed = usb_get_maximum_speed(node);
114 	if (plat->maximum_speed == USB_SPEED_UNKNOWN) {
115 		pr_info("No USB maximum speed specified. Using super speed\n");
116 		plat->maximum_speed = USB_SPEED_SUPER;
117 	}
118 
119 	plat->dr_mode = usb_get_dr_mode(node);
120 	if (plat->dr_mode == USB_DR_MODE_UNKNOWN) {
121 		pr_err("Invalid usb mode setup\n");
122 		return -ENODEV;
123 	}
124 
125 	return 0;
126 }
127 
128 #if CONFIG_IS_ENABLED(DM_USB_GADGET)
129 int dm_usb_gadget_handle_interrupts(struct udevice *dev)
130 {
131 	struct dwc3_generic_priv *priv = dev_get_priv(dev);
132 	struct dwc3 *dwc3 = &priv->dwc3;
133 
134 	dwc3_gadget_uboot_handle_interrupt(dwc3);
135 
136 	return 0;
137 }
138 
139 static int dwc3_generic_peripheral_probe(struct udevice *dev)
140 {
141 	struct dwc3_generic_priv *priv = dev_get_priv(dev);
142 
143 	return dwc3_generic_probe(dev, priv);
144 }
145 
146 static int dwc3_generic_peripheral_remove(struct udevice *dev)
147 {
148 	struct dwc3_generic_priv *priv = dev_get_priv(dev);
149 
150 	return dwc3_generic_remove(dev, priv);
151 }
152 
153 U_BOOT_DRIVER(dwc3_generic_peripheral) = {
154 	.name	= "dwc3-generic-peripheral",
155 	.id	= UCLASS_USB_GADGET_GENERIC,
156 	.ofdata_to_platdata = dwc3_generic_ofdata_to_platdata,
157 	.probe = dwc3_generic_peripheral_probe,
158 	.remove = dwc3_generic_peripheral_remove,
159 	.priv_auto_alloc_size = sizeof(struct dwc3_generic_priv),
160 	.platdata_auto_alloc_size = sizeof(struct dwc3_generic_plat),
161 };
162 #endif
163 
164 #if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD)
165 static int dwc3_generic_host_probe(struct udevice *dev)
166 {
167 	struct xhci_hcor *hcor;
168 	struct xhci_hccr *hccr;
169 	struct dwc3_generic_host_priv *priv = dev_get_priv(dev);
170 	int rc;
171 
172 	rc = dwc3_generic_probe(dev, &priv->gen_priv);
173 	if (rc)
174 		return rc;
175 
176 	hccr = (struct xhci_hccr *)priv->gen_priv.base;
177 	hcor = (struct xhci_hcor *)(priv->gen_priv.base +
178 			HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
179 
180 	return xhci_register(dev, hccr, hcor);
181 }
182 
183 static int dwc3_generic_host_remove(struct udevice *dev)
184 {
185 	struct dwc3_generic_host_priv *priv = dev_get_priv(dev);
186 	int rc;
187 
188 	rc = xhci_deregister(dev);
189 	if (rc)
190 		return rc;
191 
192 	return dwc3_generic_remove(dev, &priv->gen_priv);
193 }
194 
195 U_BOOT_DRIVER(dwc3_generic_host) = {
196 	.name	= "dwc3-generic-host",
197 	.id	= UCLASS_USB,
198 	.ofdata_to_platdata = dwc3_generic_ofdata_to_platdata,
199 	.probe = dwc3_generic_host_probe,
200 	.remove = dwc3_generic_host_remove,
201 	.priv_auto_alloc_size = sizeof(struct dwc3_generic_host_priv),
202 	.platdata_auto_alloc_size = sizeof(struct dwc3_generic_plat),
203 	.ops = &xhci_usb_ops,
204 	.flags = DM_FLAG_ALLOC_PRIV_DMA,
205 };
206 #endif
207 
208 struct dwc3_glue_ops {
209 	void (*select_dr_mode)(struct udevice *dev, int index,
210 			       enum usb_dr_mode mode);
211 };
212 
213 void dwc3_ti_select_dr_mode(struct udevice *dev, int index,
214 			    enum usb_dr_mode mode)
215 {
216 #define USBOTGSS_UTMI_OTG_STATUS		0x0084
217 #define USBOTGSS_UTMI_OTG_OFFSET		0x0480
218 
219 /* UTMI_OTG_STATUS REGISTER */
220 #define USBOTGSS_UTMI_OTG_STATUS_SW_MODE	BIT(31)
221 #define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT	BIT(9)
222 #define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE BIT(8)
223 #define USBOTGSS_UTMI_OTG_STATUS_IDDIG		BIT(4)
224 #define USBOTGSS_UTMI_OTG_STATUS_SESSEND	BIT(3)
225 #define USBOTGSS_UTMI_OTG_STATUS_SESSVALID	BIT(2)
226 #define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID	BIT(1)
227 enum dwc3_omap_utmi_mode {
228 	DWC3_OMAP_UTMI_MODE_UNKNOWN = 0,
229 	DWC3_OMAP_UTMI_MODE_HW,
230 	DWC3_OMAP_UTMI_MODE_SW,
231 };
232 
233 	u32 use_id_pin;
234 	u32 host_mode;
235 	u32 reg;
236 	u32 utmi_mode;
237 	u32 utmi_status_offset = USBOTGSS_UTMI_OTG_STATUS;
238 
239 	struct dwc3_glue_data *glue = dev_get_platdata(dev);
240 	void *base = map_physmem(glue->regs, 0x10000, MAP_NOCACHE);
241 
242 	if (device_is_compatible(dev, "ti,am437x-dwc3"))
243 		utmi_status_offset += USBOTGSS_UTMI_OTG_OFFSET;
244 
245 	utmi_mode = dev_read_u32_default(dev, "utmi-mode",
246 					 DWC3_OMAP_UTMI_MODE_UNKNOWN);
247 	if (utmi_mode != DWC3_OMAP_UTMI_MODE_HW) {
248 		debug("%s: OTG is not supported. defaulting to PERIPHERAL\n",
249 		      dev->name);
250 		mode = USB_DR_MODE_PERIPHERAL;
251 	}
252 
253 	switch (mode)  {
254 	case USB_DR_MODE_PERIPHERAL:
255 		use_id_pin = 0;
256 		host_mode = 0;
257 		break;
258 	case USB_DR_MODE_HOST:
259 		use_id_pin = 0;
260 		host_mode = 1;
261 		break;
262 	case USB_DR_MODE_OTG:
263 	default:
264 		use_id_pin = 1;
265 		host_mode = 0;
266 		break;
267 	}
268 
269 	reg = readl(base + utmi_status_offset);
270 
271 	reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SW_MODE);
272 	if (!use_id_pin)
273 		reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
274 
275 	writel(reg, base + utmi_status_offset);
276 
277 	reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSEND |
278 		USBOTGSS_UTMI_OTG_STATUS_VBUSVALID |
279 		USBOTGSS_UTMI_OTG_STATUS_IDDIG);
280 
281 	reg |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID |
282 		USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
283 
284 	if (!host_mode)
285 		reg |= USBOTGSS_UTMI_OTG_STATUS_IDDIG |
286 			USBOTGSS_UTMI_OTG_STATUS_VBUSVALID;
287 
288 	writel(reg, base + utmi_status_offset);
289 
290 	unmap_physmem(base, MAP_NOCACHE);
291 }
292 
293 struct dwc3_glue_ops ti_ops = {
294 	.select_dr_mode = dwc3_ti_select_dr_mode,
295 };
296 
297 static int dwc3_glue_bind(struct udevice *parent)
298 {
299 	ofnode node;
300 	int ret;
301 
302 	ofnode_for_each_subnode(node, parent->node) {
303 		const char *name = ofnode_get_name(node);
304 		enum usb_dr_mode dr_mode;
305 		struct udevice *dev;
306 		const char *driver = NULL;
307 
308 		debug("%s: subnode name: %s\n", __func__, name);
309 
310 		dr_mode = usb_get_dr_mode(node);
311 
312 		switch (dr_mode) {
313 		case USB_DR_MODE_PERIPHERAL:
314 		case USB_DR_MODE_OTG:
315 #if CONFIG_IS_ENABLED(DM_USB_GADGET)
316 			debug("%s: dr_mode: OTG or Peripheral\n", __func__);
317 			driver = "dwc3-generic-peripheral";
318 #endif
319 			break;
320 #if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD)
321 		case USB_DR_MODE_HOST:
322 			debug("%s: dr_mode: HOST\n", __func__);
323 			driver = "dwc3-generic-host";
324 			break;
325 #endif
326 		default:
327 			debug("%s: unsupported dr_mode\n", __func__);
328 			return -ENODEV;
329 		};
330 
331 		if (!driver)
332 			continue;
333 
334 		ret = device_bind_driver_to_node(parent, driver, name,
335 						 node, &dev);
336 		if (ret) {
337 			debug("%s: not able to bind usb device mode\n",
338 			      __func__);
339 			return ret;
340 		}
341 	}
342 
343 	return 0;
344 }
345 
346 static int dwc3_glue_reset_init(struct udevice *dev,
347 				struct dwc3_glue_data *glue)
348 {
349 	int ret;
350 
351 	ret = reset_get_bulk(dev, &glue->resets);
352 	if (ret == -ENOTSUPP || ret == -ENOENT)
353 		return 0;
354 	else if (ret)
355 		return ret;
356 
357 	ret = reset_deassert_bulk(&glue->resets);
358 	if (ret) {
359 		reset_release_bulk(&glue->resets);
360 		return ret;
361 	}
362 
363 	return 0;
364 }
365 
366 static int dwc3_glue_clk_init(struct udevice *dev,
367 			      struct dwc3_glue_data *glue)
368 {
369 	int ret;
370 
371 	ret = clk_get_bulk(dev, &glue->clks);
372 	if (ret == -ENOSYS || ret == -ENOENT)
373 		return 0;
374 	if (ret)
375 		return ret;
376 
377 #if CONFIG_IS_ENABLED(CLK)
378 	ret = clk_enable_bulk(&glue->clks);
379 	if (ret) {
380 		clk_release_bulk(&glue->clks);
381 		return ret;
382 	}
383 #endif
384 
385 	return 0;
386 }
387 
388 static int dwc3_glue_probe(struct udevice *dev)
389 {
390 	struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev);
391 	struct dwc3_glue_data *glue = dev_get_platdata(dev);
392 	struct udevice *child = NULL;
393 	int index = 0;
394 	int ret;
395 
396 	glue->regs = dev_read_addr(dev);
397 
398 	ret = dwc3_glue_clk_init(dev, glue);
399 	if (ret)
400 		return ret;
401 
402 	ret = dwc3_glue_reset_init(dev, glue);
403 	if (ret)
404 		return ret;
405 
406 	ret = device_find_first_child(dev, &child);
407 	if (ret)
408 		return ret;
409 
410 	if (glue->resets.count < 1) {
411 		ret = dwc3_glue_reset_init(child, glue);
412 		if (ret)
413 			return ret;
414 	}
415 
416 	while (child) {
417 		enum usb_dr_mode dr_mode;
418 
419 		dr_mode = usb_get_dr_mode(child->node);
420 		device_find_next_child(&child);
421 		if (ops && ops->select_dr_mode)
422 			ops->select_dr_mode(dev, index, dr_mode);
423 		index++;
424 	}
425 
426 	return 0;
427 }
428 
429 static int dwc3_glue_remove(struct udevice *dev)
430 {
431 	struct dwc3_glue_data *glue = dev_get_platdata(dev);
432 
433 	reset_release_bulk(&glue->resets);
434 
435 	clk_release_bulk(&glue->clks);
436 
437 	return 0;
438 }
439 
440 static const struct udevice_id dwc3_glue_ids[] = {
441 	{ .compatible = "xlnx,zynqmp-dwc3" },
442 	{ .compatible = "ti,keystone-dwc3"},
443 	{ .compatible = "ti,dwc3", .data = (ulong)&ti_ops },
444 	{ .compatible = "ti,am437x-dwc3", .data = (ulong)&ti_ops },
445 	{ .compatible = "rockchip,rk3328-dwc3" },
446 	{ .compatible = "rockchip,rk3399-dwc3" },
447 	{ }
448 };
449 
450 U_BOOT_DRIVER(dwc3_generic_wrapper) = {
451 	.name	= "dwc3-generic-wrapper",
452 	.id	= UCLASS_NOP,
453 	.of_match = dwc3_glue_ids,
454 	.bind = dwc3_glue_bind,
455 	.probe = dwc3_glue_probe,
456 	.remove = dwc3_glue_remove,
457 	.platdata_auto_alloc_size = sizeof(struct dwc3_glue_data),
458 
459 };
460