blob: 8d45748b3b894fecae8879da2568590a34557765 [file] [log] [blame]
Patrick Delaunayd6e53c72018-10-26 09:02:52 +02001// SPDX-License-Identifier: GPL-2.0
Michal Simek9d8cbbf2018-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>
Simon Glass63334482019-11-14 12:57:39 -070011#include <cpu_func.h>
Jean-Jacques Hiblotae004d32018-11-29 10:52:49 +010012#include <asm-generic/io.h>
Michal Simek9d8cbbf2018-05-18 13:15:06 +020013#include <dm.h>
14#include <dm/device-internal.h>
15#include <dm/lists.h>
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +010016#include <dwc3-uboot.h>
Michal Simek9d8cbbf2018-05-18 13:15:06 +020017#include <linux/usb/ch9.h>
18#include <linux/usb/gadget.h>
19#include <malloc.h>
20#include <usb.h>
21#include "core.h"
22#include "gadget.h"
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +010023#include <reset.h>
24#include <clk.h>
Jean-Jacques Hiblot175cd7c2019-09-11 11:33:50 +020025#include <usb/xhci.h>
Michal Simek9d8cbbf2018-05-18 13:15:06 +020026
Jean-Jacques Hiblota33aa762019-09-11 11:33:48 +020027struct dwc3_generic_plat {
28 fdt_addr_t base;
29 u32 maximum_speed;
30 enum usb_dr_mode dr_mode;
31};
32
Jean-Jacques Hiblota33aa762019-09-11 11:33:48 +020033struct dwc3_generic_priv {
Jean-Jacques Hiblot2bf2c352019-09-11 11:33:49 +020034 void *base;
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +010035 struct dwc3 dwc3;
36 struct phy *phys;
37 int num_phys;
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +010038};
39
Jean-Jacques Hiblot175cd7c2019-09-11 11:33:50 +020040struct dwc3_generic_host_priv {
41 struct xhci_ctrl xhci_ctrl;
42 struct dwc3_generic_priv gen_priv;
43};
44
Jean-Jacques Hiblot2bf2c352019-09-11 11:33:49 +020045static int dwc3_generic_probe(struct udevice *dev,
46 struct dwc3_generic_priv *priv)
Michal Simek9d8cbbf2018-05-18 13:15:06 +020047{
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +010048 int rc;
Jean-Jacques Hiblota33aa762019-09-11 11:33:48 +020049 struct dwc3_generic_plat *plat = dev_get_platdata(dev);
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +010050 struct dwc3 *dwc3 = &priv->dwc3;
51
Jean-Jacques Hiblotce868d02019-09-11 11:33:52 +020052 dwc3->dev = dev;
Jean-Jacques Hiblota33aa762019-09-11 11:33:48 +020053 dwc3->maximum_speed = plat->maximum_speed;
54 dwc3->dr_mode = plat->dr_mode;
Jean-Jacques Hiblotce868d02019-09-11 11:33:52 +020055#if CONFIG_IS_ENABLED(OF_CONTROL)
56 dwc3_of_parse(dwc3);
57#endif
Jean-Jacques Hiblota33aa762019-09-11 11:33:48 +020058
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +010059 rc = dwc3_setup_phy(dev, &priv->phys, &priv->num_phys);
60 if (rc)
61 return rc;
62
Jean-Jacques Hiblot2bf2c352019-09-11 11:33:49 +020063 priv->base = map_physmem(plat->base, DWC3_OTG_REGS_END, MAP_NOCACHE);
64 dwc3->regs = priv->base + DWC3_GLOBALS_REGS_START;
Jean-Jacques Hiblotce868d02019-09-11 11:33:52 +020065
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +010066
67 rc = dwc3_init(dwc3);
68 if (rc) {
Jean-Jacques Hiblot2bf2c352019-09-11 11:33:49 +020069 unmap_physmem(priv->base, MAP_NOCACHE);
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +010070 return rc;
71 }
Michal Simek9d8cbbf2018-05-18 13:15:06 +020072
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +010073 return 0;
Michal Simek9d8cbbf2018-05-18 13:15:06 +020074}
75
Jean-Jacques Hiblot2bf2c352019-09-11 11:33:49 +020076static int dwc3_generic_remove(struct udevice *dev,
77 struct dwc3_generic_priv *priv)
Michal Simek9d8cbbf2018-05-18 13:15:06 +020078{
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +010079 struct dwc3 *dwc3 = &priv->dwc3;
Michal Simek9d8cbbf2018-05-18 13:15:06 +020080
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +010081 dwc3_remove(dwc3);
82 dwc3_shutdown_phy(dev, priv->phys, priv->num_phys);
83 unmap_physmem(dwc3->regs, MAP_NOCACHE);
Michal Simek9d8cbbf2018-05-18 13:15:06 +020084
85 return 0;
86}
87
Jean-Jacques Hiblot2bf2c352019-09-11 11:33:49 +020088static int dwc3_generic_ofdata_to_platdata(struct udevice *dev)
Michal Simek9d8cbbf2018-05-18 13:15:06 +020089{
Jean-Jacques Hiblota33aa762019-09-11 11:33:48 +020090 struct dwc3_generic_plat *plat = dev_get_platdata(dev);
Michal Simek9d8cbbf2018-05-18 13:15:06 +020091 int node = dev_of_offset(dev);
92
Jean-Jacques Hiblota33aa762019-09-11 11:33:48 +020093 plat->base = devfdt_get_addr(dev);
Michal Simek9d8cbbf2018-05-18 13:15:06 +020094
Jean-Jacques Hiblota33aa762019-09-11 11:33:48 +020095 plat->maximum_speed = usb_get_maximum_speed(node);
96 if (plat->maximum_speed == USB_SPEED_UNKNOWN) {
Jean-Jacques Hiblot547df0d2019-09-11 11:33:51 +020097 pr_info("No USB maximum speed specified. Using super speed\n");
98 plat->maximum_speed = USB_SPEED_SUPER;
Michal Simek9d8cbbf2018-05-18 13:15:06 +020099 }
100
Jean-Jacques Hiblota33aa762019-09-11 11:33:48 +0200101 plat->dr_mode = usb_get_dr_mode(node);
102 if (plat->dr_mode == USB_DR_MODE_UNKNOWN) {
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200103 pr_err("Invalid usb mode setup\n");
104 return -ENODEV;
105 }
106
107 return 0;
108}
109
Jean-Jacques Hiblot2bf2c352019-09-11 11:33:49 +0200110#if CONFIG_IS_ENABLED(DM_USB_GADGET)
111int dm_usb_gadget_handle_interrupts(struct udevice *dev)
112{
113 struct dwc3_generic_priv *priv = dev_get_priv(dev);
114 struct dwc3 *dwc3 = &priv->dwc3;
115
116 dwc3_gadget_uboot_handle_interrupt(dwc3);
117
118 return 0;
119}
120
121static int dwc3_generic_peripheral_probe(struct udevice *dev)
122{
123 struct dwc3_generic_priv *priv = dev_get_priv(dev);
124
125 return dwc3_generic_probe(dev, priv);
126}
127
128static int dwc3_generic_peripheral_remove(struct udevice *dev)
129{
130 struct dwc3_generic_priv *priv = dev_get_priv(dev);
131
132 return dwc3_generic_remove(dev, priv);
133}
134
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200135U_BOOT_DRIVER(dwc3_generic_peripheral) = {
136 .name = "dwc3-generic-peripheral",
Jean-Jacques Hiblot9dc0d5c2018-11-29 10:52:46 +0100137 .id = UCLASS_USB_GADGET_GENERIC,
Jean-Jacques Hiblot2bf2c352019-09-11 11:33:49 +0200138 .ofdata_to_platdata = dwc3_generic_ofdata_to_platdata,
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200139 .probe = dwc3_generic_peripheral_probe,
140 .remove = dwc3_generic_peripheral_remove,
Jean-Jacques Hiblota33aa762019-09-11 11:33:48 +0200141 .priv_auto_alloc_size = sizeof(struct dwc3_generic_priv),
142 .platdata_auto_alloc_size = sizeof(struct dwc3_generic_plat),
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200143};
Jean-Jacques Hiblot44aaec72018-11-29 10:52:42 +0100144#endif
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200145
Jean-Jacques Hiblot175cd7c2019-09-11 11:33:50 +0200146#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD)
147static int dwc3_generic_host_probe(struct udevice *dev)
148{
149 struct xhci_hcor *hcor;
150 struct xhci_hccr *hccr;
151 struct dwc3_generic_host_priv *priv = dev_get_priv(dev);
152 int rc;
153
154 rc = dwc3_generic_probe(dev, &priv->gen_priv);
155 if (rc)
156 return rc;
157
158 hccr = (struct xhci_hccr *)priv->gen_priv.base;
159 hcor = (struct xhci_hcor *)(priv->gen_priv.base +
160 HC_LENGTH(xhci_readl(&(hccr)->cr_capbase)));
161
162 return xhci_register(dev, hccr, hcor);
163}
164
165static int dwc3_generic_host_remove(struct udevice *dev)
166{
167 struct dwc3_generic_host_priv *priv = dev_get_priv(dev);
168 int rc;
169
170 rc = xhci_deregister(dev);
171 if (rc)
172 return rc;
173
174 return dwc3_generic_remove(dev, &priv->gen_priv);
175}
176
177U_BOOT_DRIVER(dwc3_generic_host) = {
178 .name = "dwc3-generic-host",
179 .id = UCLASS_USB,
180 .ofdata_to_platdata = dwc3_generic_ofdata_to_platdata,
181 .probe = dwc3_generic_host_probe,
182 .remove = dwc3_generic_host_remove,
183 .priv_auto_alloc_size = sizeof(struct dwc3_generic_host_priv),
184 .platdata_auto_alloc_size = sizeof(struct dwc3_generic_plat),
185 .ops = &xhci_usb_ops,
186 .flags = DM_FLAG_ALLOC_PRIV_DMA,
187};
188#endif
189
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100190struct dwc3_glue_data {
191 struct clk_bulk clks;
192 struct reset_ctl_bulk resets;
Jean-Jacques Hiblotae004d32018-11-29 10:52:49 +0100193 fdt_addr_t regs;
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100194};
195
Jean-Jacques Hiblotae004d32018-11-29 10:52:49 +0100196struct dwc3_glue_ops {
197 void (*select_dr_mode)(struct udevice *dev, int index,
198 enum usb_dr_mode mode);
199};
200
Jean-Jacques Hiblot65596f12018-11-29 10:57:40 +0100201void dwc3_ti_select_dr_mode(struct udevice *dev, int index,
202 enum usb_dr_mode mode)
203{
204#define USBOTGSS_UTMI_OTG_STATUS 0x0084
205#define USBOTGSS_UTMI_OTG_OFFSET 0x0480
206
207/* UTMI_OTG_STATUS REGISTER */
208#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE BIT(31)
209#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT BIT(9)
210#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE BIT(8)
211#define USBOTGSS_UTMI_OTG_STATUS_IDDIG BIT(4)
212#define USBOTGSS_UTMI_OTG_STATUS_SESSEND BIT(3)
213#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID BIT(2)
214#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID BIT(1)
215enum dwc3_omap_utmi_mode {
216 DWC3_OMAP_UTMI_MODE_UNKNOWN = 0,
217 DWC3_OMAP_UTMI_MODE_HW,
218 DWC3_OMAP_UTMI_MODE_SW,
219};
220
221 u32 use_id_pin;
222 u32 host_mode;
223 u32 reg;
224 u32 utmi_mode;
225 u32 utmi_status_offset = USBOTGSS_UTMI_OTG_STATUS;
226
227 struct dwc3_glue_data *glue = dev_get_platdata(dev);
228 void *base = map_physmem(glue->regs, 0x10000, MAP_NOCACHE);
229
230 if (device_is_compatible(dev, "ti,am437x-dwc3"))
231 utmi_status_offset += USBOTGSS_UTMI_OTG_OFFSET;
232
233 utmi_mode = dev_read_u32_default(dev, "utmi-mode",
234 DWC3_OMAP_UTMI_MODE_UNKNOWN);
235 if (utmi_mode != DWC3_OMAP_UTMI_MODE_HW) {
236 debug("%s: OTG is not supported. defaulting to PERIPHERAL\n",
237 dev->name);
238 mode = USB_DR_MODE_PERIPHERAL;
239 }
240
241 switch (mode) {
242 case USB_DR_MODE_PERIPHERAL:
243 use_id_pin = 0;
244 host_mode = 0;
245 break;
246 case USB_DR_MODE_HOST:
247 use_id_pin = 0;
248 host_mode = 1;
249 break;
250 case USB_DR_MODE_OTG:
251 default:
252 use_id_pin = 1;
253 host_mode = 0;
254 break;
255 }
256
257 reg = readl(base + utmi_status_offset);
258
259 reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SW_MODE);
260 if (!use_id_pin)
261 reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
262
263 writel(reg, base + utmi_status_offset);
264
265 reg &= ~(USBOTGSS_UTMI_OTG_STATUS_SESSEND |
266 USBOTGSS_UTMI_OTG_STATUS_VBUSVALID |
267 USBOTGSS_UTMI_OTG_STATUS_IDDIG);
268
269 reg |= USBOTGSS_UTMI_OTG_STATUS_SESSVALID |
270 USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT;
271
272 if (!host_mode)
273 reg |= USBOTGSS_UTMI_OTG_STATUS_IDDIG |
274 USBOTGSS_UTMI_OTG_STATUS_VBUSVALID;
275
276 writel(reg, base + utmi_status_offset);
277
278 unmap_physmem(base, MAP_NOCACHE);
279}
280
281struct dwc3_glue_ops ti_ops = {
282 .select_dr_mode = dwc3_ti_select_dr_mode,
283};
284
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100285static int dwc3_glue_bind(struct udevice *parent)
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200286{
287 const void *fdt = gd->fdt_blob;
288 int node;
289 int ret;
290
291 for (node = fdt_first_subnode(fdt, dev_of_offset(parent)); node > 0;
292 node = fdt_next_subnode(fdt, node)) {
293 const char *name = fdt_get_name(fdt, node, NULL);
294 enum usb_dr_mode dr_mode;
295 struct udevice *dev;
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100296 const char *driver = NULL;
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200297
298 debug("%s: subnode name: %s\n", __func__, name);
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200299
300 dr_mode = usb_get_dr_mode(node);
301
302 switch (dr_mode) {
303 case USB_DR_MODE_PERIPHERAL:
304 case USB_DR_MODE_OTG:
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100305#if CONFIG_IS_ENABLED(DM_USB_GADGET)
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200306 debug("%s: dr_mode: OTG or Peripheral\n", __func__);
307 driver = "dwc3-generic-peripheral";
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100308#endif
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200309 break;
Jean-Jacques Hiblot175cd7c2019-09-11 11:33:50 +0200310#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD)
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200311 case USB_DR_MODE_HOST:
312 debug("%s: dr_mode: HOST\n", __func__);
Jean-Jacques Hiblot175cd7c2019-09-11 11:33:50 +0200313 driver = "dwc3-generic-host";
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200314 break;
Jean-Jacques Hiblot175cd7c2019-09-11 11:33:50 +0200315#endif
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200316 default:
317 debug("%s: unsupported dr_mode\n", __func__);
318 return -ENODEV;
319 };
320
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100321 if (!driver)
322 continue;
323
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200324 ret = device_bind_driver_to_node(parent, driver, name,
325 offset_to_ofnode(node), &dev);
326 if (ret) {
327 debug("%s: not able to bind usb device mode\n",
328 __func__);
329 return ret;
330 }
331 }
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100332
333 return 0;
334}
335
336static int dwc3_glue_reset_init(struct udevice *dev,
337 struct dwc3_glue_data *glue)
338{
339 int ret;
340
341 ret = reset_get_bulk(dev, &glue->resets);
Vignesh Raghavendrae9310fc2019-10-25 13:48:05 +0530342 if (ret == -ENOTSUPP || ret == -ENOENT)
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100343 return 0;
344 else if (ret)
345 return ret;
346
347 ret = reset_deassert_bulk(&glue->resets);
348 if (ret) {
349 reset_release_bulk(&glue->resets);
350 return ret;
351 }
352
353 return 0;
354}
355
356static int dwc3_glue_clk_init(struct udevice *dev,
357 struct dwc3_glue_data *glue)
358{
359 int ret;
360
361 ret = clk_get_bulk(dev, &glue->clks);
Vignesh Raghavendrae9310fc2019-10-25 13:48:05 +0530362 if (ret == -ENOSYS || ret == -ENOENT)
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100363 return 0;
364 if (ret)
365 return ret;
366
367#if CONFIG_IS_ENABLED(CLK)
368 ret = clk_enable_bulk(&glue->clks);
369 if (ret) {
370 clk_release_bulk(&glue->clks);
371 return ret;
372 }
373#endif
374
375 return 0;
376}
377
378static int dwc3_glue_probe(struct udevice *dev)
379{
Jean-Jacques Hiblotae004d32018-11-29 10:52:49 +0100380 struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev);
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100381 struct dwc3_glue_data *glue = dev_get_platdata(dev);
Jean-Jacques Hiblotae004d32018-11-29 10:52:49 +0100382 struct udevice *child = NULL;
383 int index = 0;
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100384 int ret;
385
Jean-Jacques Hiblotae004d32018-11-29 10:52:49 +0100386 glue->regs = dev_read_addr(dev);
387
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100388 ret = dwc3_glue_clk_init(dev, glue);
389 if (ret)
390 return ret;
391
392 ret = dwc3_glue_reset_init(dev, glue);
393 if (ret)
394 return ret;
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200395
Jean-Jacques Hiblotae004d32018-11-29 10:52:49 +0100396 ret = device_find_first_child(dev, &child);
397 if (ret)
398 return ret;
399
400 while (child) {
401 enum usb_dr_mode dr_mode;
402
403 dr_mode = usb_get_dr_mode(dev_of_offset(child));
404 device_find_next_child(&child);
405 if (ops && ops->select_dr_mode)
406 ops->select_dr_mode(dev, index, dr_mode);
407 index++;
408 }
409
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200410 return 0;
411}
412
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100413static int dwc3_glue_remove(struct udevice *dev)
414{
415 struct dwc3_glue_data *glue = dev_get_platdata(dev);
416
417 reset_release_bulk(&glue->resets);
418
419 clk_release_bulk(&glue->clks);
420
Jean-Jacques Hiblot5a945572019-07-05 09:33:56 +0200421 return 0;
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100422}
423
424static const struct udevice_id dwc3_glue_ids[] = {
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200425 { .compatible = "xlnx,zynqmp-dwc3" },
Jean-Jacques Hiblot3e0684b2018-12-04 11:12:56 +0100426 { .compatible = "ti,keystone-dwc3"},
Jean-Jacques Hiblot65596f12018-11-29 10:57:40 +0100427 { .compatible = "ti,dwc3", .data = (ulong)&ti_ops },
Jean-Jacques Hiblotca848df2018-12-04 11:30:50 +0100428 { .compatible = "ti,am437x-dwc3", .data = (ulong)&ti_ops },
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200429 { }
430};
431
432U_BOOT_DRIVER(dwc3_generic_wrapper) = {
433 .name = "dwc3-generic-wrapper",
Jean-Jacques Hiblotb49b5c22019-07-05 09:33:58 +0200434 .id = UCLASS_NOP,
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100435 .of_match = dwc3_glue_ids,
436 .bind = dwc3_glue_bind,
437 .probe = dwc3_glue_probe,
438 .remove = dwc3_glue_remove,
439 .platdata_auto_alloc_size = sizeof(struct dwc3_glue_data),
440
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200441};