blob: a3b65088f17196650996320c01b4ae32be93bc3e [file] [log] [blame]
Patrick Delaunay22929e12018-10-26 09:02:52 +02001// SPDX-License-Identifier: GPL-2.0
Michal Simek49d67452018-05-18 13:15:06 +02002/*
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>
Jean-Jacques Hiblot93991cf2018-11-29 10:52:49 +010011#include <asm-generic/io.h>
Michal Simek49d67452018-05-18 13:15:06 +020012#include <dm.h>
13#include <dm/device-internal.h>
14#include <dm/lists.h>
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010015#include <dwc3-uboot.h>
Michal Simek49d67452018-05-18 13:15:06 +020016#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"
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010022#include <reset.h>
23#include <clk.h>
Jean-Jacques Hiblotb575e902019-09-11 11:33:50 +020024#include <usb/xhci.h>
Michal Simek49d67452018-05-18 13:15:06 +020025
Jean-Jacques Hiblot3a38a0a2019-09-11 11:33:48 +020026struct dwc3_generic_plat {
27 fdt_addr_t base;
28 u32 maximum_speed;
29 enum usb_dr_mode dr_mode;
30};
31
Jean-Jacques Hiblot3a38a0a2019-09-11 11:33:48 +020032struct dwc3_generic_priv {
Jean-Jacques Hiblot1af590d2019-09-11 11:33:49 +020033 void *base;
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010034 struct dwc3 dwc3;
35 struct phy *phys;
36 int num_phys;
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010037};
38
Jean-Jacques Hiblotb575e902019-09-11 11:33:50 +020039struct dwc3_generic_host_priv {
40 struct xhci_ctrl xhci_ctrl;
41 struct dwc3_generic_priv gen_priv;
42};
43
Jean-Jacques Hiblot1af590d2019-09-11 11:33:49 +020044static int dwc3_generic_probe(struct udevice *dev,
45 struct dwc3_generic_priv *priv)
Michal Simek49d67452018-05-18 13:15:06 +020046{
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010047 int rc;
Jean-Jacques Hiblot3a38a0a2019-09-11 11:33:48 +020048 struct dwc3_generic_plat *plat = dev_get_platdata(dev);
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010049 struct dwc3 *dwc3 = &priv->dwc3;
Michal Simek49d67452018-05-18 13:15:06 +020050
Jean-Jacques Hiblot3a38a0a2019-09-11 11:33:48 +020051 dwc3->maximum_speed = plat->maximum_speed;
52 dwc3->dr_mode = plat->dr_mode;
53
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010054 rc = dwc3_setup_phy(dev, &priv->phys, &priv->num_phys);
55 if (rc)
56 return rc;
57
Jean-Jacques Hiblot1af590d2019-09-11 11:33:49 +020058 priv->base = map_physmem(plat->base, DWC3_OTG_REGS_END, MAP_NOCACHE);
59 dwc3->regs = priv->base + DWC3_GLOBALS_REGS_START;
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010060 dwc3->dev = dev;
61
62 rc = dwc3_init(dwc3);
63 if (rc) {
Jean-Jacques Hiblot1af590d2019-09-11 11:33:49 +020064 unmap_physmem(priv->base, MAP_NOCACHE);
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010065 return rc;
66 }
67
68 return 0;
Michal Simek49d67452018-05-18 13:15:06 +020069}
70
Jean-Jacques Hiblot1af590d2019-09-11 11:33:49 +020071static int dwc3_generic_remove(struct udevice *dev,
72 struct dwc3_generic_priv *priv)
Michal Simek49d67452018-05-18 13:15:06 +020073{
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010074 struct dwc3 *dwc3 = &priv->dwc3;
Michal Simek49d67452018-05-18 13:15:06 +020075
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +010076 dwc3_remove(dwc3);
77 dwc3_shutdown_phy(dev, priv->phys, priv->num_phys);
78 unmap_physmem(dwc3->regs, MAP_NOCACHE);
Michal Simek49d67452018-05-18 13:15:06 +020079
80 return 0;
81}
82
Jean-Jacques Hiblot1af590d2019-09-11 11:33:49 +020083static int dwc3_generic_ofdata_to_platdata(struct udevice *dev)
Michal Simek49d67452018-05-18 13:15:06 +020084{
Jean-Jacques Hiblot3a38a0a2019-09-11 11:33:48 +020085 struct dwc3_generic_plat *plat = dev_get_platdata(dev);
Michal Simek49d67452018-05-18 13:15:06 +020086 int node = dev_of_offset(dev);
87
Jean-Jacques Hiblot3a38a0a2019-09-11 11:33:48 +020088 plat->base = devfdt_get_addr(dev);
Michal Simek49d67452018-05-18 13:15:06 +020089
Jean-Jacques Hiblot3a38a0a2019-09-11 11:33:48 +020090 plat->maximum_speed = usb_get_maximum_speed(node);
91 if (plat->maximum_speed == USB_SPEED_UNKNOWN) {
Jean-Jacques Hiblot1a63e5e2019-09-11 11:33:51 +020092 pr_info("No USB maximum speed specified. Using super speed\n");
93 plat->maximum_speed = USB_SPEED_SUPER;
Michal Simek49d67452018-05-18 13:15:06 +020094 }
95
Jean-Jacques Hiblot3a38a0a2019-09-11 11:33:48 +020096 plat->dr_mode = usb_get_dr_mode(node);
97 if (plat->dr_mode == USB_DR_MODE_UNKNOWN) {
Michal Simek49d67452018-05-18 13:15:06 +020098 pr_err("Invalid usb mode setup\n");
99 return -ENODEV;
100 }
101
102 return 0;
103}
104
Jean-Jacques Hiblot1af590d2019-09-11 11:33:49 +0200105#if CONFIG_IS_ENABLED(DM_USB_GADGET)
106int dm_usb_gadget_handle_interrupts(struct udevice *dev)
107{
108 struct dwc3_generic_priv *priv = dev_get_priv(dev);
109 struct dwc3 *dwc3 = &priv->dwc3;
110
111 dwc3_gadget_uboot_handle_interrupt(dwc3);
112
113 return 0;
114}
115
116static int dwc3_generic_peripheral_probe(struct udevice *dev)
117{
118 struct dwc3_generic_priv *priv = dev_get_priv(dev);
119
120 return dwc3_generic_probe(dev, priv);
121}
122
123static int dwc3_generic_peripheral_remove(struct udevice *dev)
124{
125 struct dwc3_generic_priv *priv = dev_get_priv(dev);
126
127 return dwc3_generic_remove(dev, priv);
128}
129
Michal Simek49d67452018-05-18 13:15:06 +0200130U_BOOT_DRIVER(dwc3_generic_peripheral) = {
131 .name = "dwc3-generic-peripheral",
Jean-Jacques Hiblot01311622018-11-29 10:52:46 +0100132 .id = UCLASS_USB_GADGET_GENERIC,
Jean-Jacques Hiblot1af590d2019-09-11 11:33:49 +0200133 .ofdata_to_platdata = dwc3_generic_ofdata_to_platdata,
Michal Simek49d67452018-05-18 13:15:06 +0200134 .probe = dwc3_generic_peripheral_probe,
135 .remove = dwc3_generic_peripheral_remove,
Jean-Jacques Hiblot3a38a0a2019-09-11 11:33:48 +0200136 .priv_auto_alloc_size = sizeof(struct dwc3_generic_priv),
137 .platdata_auto_alloc_size = sizeof(struct dwc3_generic_plat),
Michal Simek49d67452018-05-18 13:15:06 +0200138};
Jean-Jacques Hiblot687ab542018-11-29 10:52:42 +0100139#endif
Michal Simek49d67452018-05-18 13:15:06 +0200140
Jean-Jacques Hiblotb575e902019-09-11 11:33:50 +0200141#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD)
142static int dwc3_generic_host_probe(struct udevice *dev)
143{
144 struct xhci_hcor *hcor;
145 struct xhci_hccr *hccr;
146 struct dwc3_generic_host_priv *priv = dev_get_priv(dev);
147 int rc;
148
149 rc = dwc3_generic_probe(dev, &priv->gen_priv);
150 if (rc)
151 return rc;
152
153 hccr = (struct xhci_hccr *)priv->gen_priv.base;
154 hcor = (struct xhci_hcor *)(priv->gen_priv.base +
155 HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
156
157 return xhci_register(dev, hccr, hcor);
158}
159
160static int dwc3_generic_host_remove(struct udevice *dev)
161{
162 struct dwc3_generic_host_priv *priv = dev_get_priv(dev);
163 int rc;
164
165 rc = xhci_deregister(dev);
166 if (rc)
167 return rc;
168
169 return dwc3_generic_remove(dev, &priv->gen_priv);
170}
171
172U_BOOT_DRIVER(dwc3_generic_host) = {
173 .name = "dwc3-generic-host",
174 .id = UCLASS_USB,
175 .ofdata_to_platdata = dwc3_generic_ofdata_to_platdata,
176 .probe = dwc3_generic_host_probe,
177 .remove = dwc3_generic_host_remove,
178 .priv_auto_alloc_size = sizeof(struct dwc3_generic_host_priv),
179 .platdata_auto_alloc_size = sizeof(struct dwc3_generic_plat),
180 .ops = &xhci_usb_ops,
181 .flags = DM_FLAG_ALLOC_PRIV_DMA,
182};
183#endif
184
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100185struct dwc3_glue_data {
186 struct clk_bulk clks;
187 struct reset_ctl_bulk resets;
Jean-Jacques Hiblot93991cf2018-11-29 10:52:49 +0100188 fdt_addr_t regs;
189};
190
191struct dwc3_glue_ops {
192 void (*select_dr_mode)(struct udevice *dev, int index,
193 enum usb_dr_mode mode);
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100194};
195
Jean-Jacques Hiblotd66e54a2018-11-29 10:57:40 +0100196void dwc3_ti_select_dr_mode(struct udevice *dev, int index,
197 enum usb_dr_mode mode)
198{
199#define USBOTGSS_UTMI_OTG_STATUS 0x0084
200#define USBOTGSS_UTMI_OTG_OFFSET 0x0480
201
202/* UTMI_OTG_STATUS REGISTER */
203#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE BIT(31)
204#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT BIT(9)
205#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE BIT(8)
206#define USBOTGSS_UTMI_OTG_STATUS_IDDIG BIT(4)
207#define USBOTGSS_UTMI_OTG_STATUS_SESSEND BIT(3)
208#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID BIT(2)
209#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID BIT(1)
210enum dwc3_omap_utmi_mode {
211 DWC3_OMAP_UTMI_MODE_UNKNOWN = 0,
212 DWC3_OMAP_UTMI_MODE_HW,
213 DWC3_OMAP_UTMI_MODE_SW,
214};
215
216 u32 use_id_pin;
217 u32 host_mode;
218 u32 reg;
219 u32 utmi_mode;
220 u32 utmi_status_offset = USBOTGSS_UTMI_OTG_STATUS;
221
222 struct dwc3_glue_data *glue = dev_get_platdata(dev);
223 void *base = map_physmem(glue->regs, 0x10000, MAP_NOCACHE);
224
225 if (device_is_compatible(dev, "ti,am437x-dwc3"))
226 utmi_status_offset += USBOTGSS_UTMI_OTG_OFFSET;
227
228 utmi_mode = dev_read_u32_default(dev, "utmi-mode",
229 DWC3_OMAP_UTMI_MODE_UNKNOWN);
230 if (utmi_mode != DWC3_OMAP_UTMI_MODE_HW) {
231 debug("%s: OTG is not supported. defaulting to PERIPHERAL\n",
232 dev->name);
233 mode = USB_DR_MODE_PERIPHERAL;
234 }
235
236 switch (mode) {
237 case USB_DR_MODE_PERIPHERAL:
238 use_id_pin = 0;
239 host_mode = 0;
240 break;
241 case USB_DR_MODE_HOST:
242 use_id_pin = 0;
243 host_mode = 1;
244 break;
245 case USB_DR_MODE_OTG:
246 default:
247 use_id_pin = 1;
248 host_mode = 0;
249 break;
250 }
251
252 reg = readl(base + utmi_status_offset);
253
254 reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SW_MODE);
255 if (!use_id_pin)
256 reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
257
258 writel(reg, base + utmi_status_offset);
259
260 reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSEND |
261 USBOTGSS_UTMI_OTG_STATUS_VBUSVALID |
262 USBOTGSS_UTMI_OTG_STATUS_IDDIG);
263
264 reg |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID |
265 USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
266
267 if (!host_mode)
268 reg |= USBOTGSS_UTMI_OTG_STATUS_IDDIG |
269 USBOTGSS_UTMI_OTG_STATUS_VBUSVALID;
270
271 writel(reg, base + utmi_status_offset);
272
273 unmap_physmem(base, MAP_NOCACHE);
274}
275
276struct dwc3_glue_ops ti_ops = {
277 .select_dr_mode = dwc3_ti_select_dr_mode,
278};
279
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100280static int dwc3_glue_bind(struct udevice *parent)
Michal Simek49d67452018-05-18 13:15:06 +0200281{
282 const void *fdt = gd->fdt_blob;
283 int node;
284 int ret;
285
286 for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0;
287 node = fdt_next_subnode(fdt, node)) {
288 const char *name = fdt_get_name(fdt, node, NULL);
289 enum usb_dr_mode dr_mode;
290 struct udevice *dev;
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100291 const char *driver = NULL;
Michal Simek49d67452018-05-18 13:15:06 +0200292
293 debug("%s: subnode name: %s\n", __func__, name);
Michal Simek49d67452018-05-18 13:15:06 +0200294
295 dr_mode = usb_get_dr_mode(node);
296
297 switch (dr_mode) {
298 case USB_DR_MODE_PERIPHERAL:
299 case USB_DR_MODE_OTG:
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100300#if CONFIG_IS_ENABLED(DM_USB_GADGET)
Michal Simek49d67452018-05-18 13:15:06 +0200301 debug("%s: dr_mode: OTG or Peripheral\n", __func__);
302 driver = "dwc3-generic-peripheral";
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100303#endif
Michal Simek49d67452018-05-18 13:15:06 +0200304 break;
Jean-Jacques Hiblotb575e902019-09-11 11:33:50 +0200305#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD)
Michal Simek49d67452018-05-18 13:15:06 +0200306 case USB_DR_MODE_HOST:
307 debug("%s: dr_mode: HOST\n", __func__);
Jean-Jacques Hiblotb575e902019-09-11 11:33:50 +0200308 driver = "dwc3-generic-host";
Michal Simek49d67452018-05-18 13:15:06 +0200309 break;
Jean-Jacques Hiblotb575e902019-09-11 11:33:50 +0200310#endif
Michal Simek49d67452018-05-18 13:15:06 +0200311 default:
312 debug("%s: unsupported dr_mode\n", __func__);
313 return -ENODEV;
314 };
315
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100316 if (!driver)
317 continue;
318
Michal Simek49d67452018-05-18 13:15:06 +0200319 ret = device_bind_driver_to_node(parent, driver, name,
320 offset_to_ofnode(node), &dev);
321 if (ret) {
322 debug("%s: not able to bind usb device mode\n",
323 __func__);
324 return ret;
325 }
326 }
327
328 return 0;
329}
330
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100331static int dwc3_glue_reset_init(struct udevice *dev,
332 struct dwc3_glue_data *glue)
333{
334 int ret;
335
336 ret = reset_get_bulk(dev, &glue->resets);
337 if (ret == -ENOTSUPP)
338 return 0;
339 else if (ret)
340 return ret;
341
342 ret = reset_deassert_bulk(&glue->resets);
343 if (ret) {
344 reset_release_bulk(&glue->resets);
345 return ret;
346 }
347
348 return 0;
349}
350
351static int dwc3_glue_clk_init(struct udevice *dev,
352 struct dwc3_glue_data *glue)
353{
354 int ret;
355
356 ret = clk_get_bulk(dev, &glue->clks);
357 if (ret == -ENOSYS)
358 return 0;
359 if (ret)
360 return ret;
361
362#if CONFIG_IS_ENABLED(CLK)
363 ret = clk_enable_bulk(&glue->clks);
364 if (ret) {
365 clk_release_bulk(&glue->clks);
366 return ret;
367 }
368#endif
369
370 return 0;
371}
372
373static int dwc3_glue_probe(struct udevice *dev)
374{
Jean-Jacques Hiblot93991cf2018-11-29 10:52:49 +0100375 struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev);
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100376 struct dwc3_glue_data *glue = dev_get_platdata(dev);
Jean-Jacques Hiblot93991cf2018-11-29 10:52:49 +0100377 struct udevice *child = NULL;
378 int index = 0;
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100379 int ret;
380
Jean-Jacques Hiblot93991cf2018-11-29 10:52:49 +0100381 glue->regs = dev_read_addr(dev);
382
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100383 ret = dwc3_glue_clk_init(dev, glue);
384 if (ret)
385 return ret;
386
387 ret = dwc3_glue_reset_init(dev, glue);
388 if (ret)
389 return ret;
390
Jean-Jacques Hiblot93991cf2018-11-29 10:52:49 +0100391 ret = device_find_first_child(dev, &child);
392 if (ret)
393 return ret;
394
395 while (child) {
396 enum usb_dr_mode dr_mode;
397
398 dr_mode = usb_get_dr_mode(dev_of_offset(child));
399 device_find_next_child(&child);
400 if (ops && ops->select_dr_mode)
401 ops->select_dr_mode(dev, index, dr_mode);
402 index++;
403 }
404
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100405 return 0;
406}
407
408static int dwc3_glue_remove(struct udevice *dev)
409{
410 struct dwc3_glue_data *glue = dev_get_platdata(dev);
411
412 reset_release_bulk(&glue->resets);
413
414 clk_release_bulk(&glue->clks);
415
Jean-Jacques Hiblote445d462019-07-05 09:33:56 +0200416 return 0;
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100417}
418
419static const struct udevice_id dwc3_glue_ids[] = {
Michal Simek49d67452018-05-18 13:15:06 +0200420 { .compatible = "xlnx,zynqmp-dwc3" },
Jean-Jacques Hiblot1c03ade2018-12-04 11:12:56 +0100421 { .compatible = "ti,keystone-dwc3"},
Jean-Jacques Hiblotd66e54a2018-11-29 10:57:40 +0100422 { .compatible = "ti,dwc3", .data = (ulong)&ti_ops },
Jean-Jacques Hiblot1ce5f1f2018-12-04 11:30:50 +0100423 { .compatible = "ti,am437x-dwc3", .data = (ulong)&ti_ops },
Michal Simek49d67452018-05-18 13:15:06 +0200424 { }
425};
426
427U_BOOT_DRIVER(dwc3_generic_wrapper) = {
428 .name = "dwc3-generic-wrapper",
Jean-Jacques Hiblot3b838292019-07-05 09:33:58 +0200429 .id = UCLASS_NOP,
Jean-Jacques Hiblot446e3a22018-11-29 10:52:48 +0100430 .of_match = dwc3_glue_ids,
431 .bind = dwc3_glue_bind,
432 .probe = dwc3_glue_probe,
433 .remove = dwc3_glue_remove,
434 .platdata_auto_alloc_size = sizeof(struct dwc3_glue_data),
435
Michal Simek49d67452018-05-18 13:15:06 +0200436};