blob: febcfc0f54c48e80ba932c351de1565ab3d7b60f [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);
Kever Yang1b807052020-03-04 08:59:50 +080091 ofnode node = dev->node;
Michal Simek9d8cbbf2018-05-18 13:15:06 +020092
Kever Yang1b807052020-03-04 08:59:50 +080093 plat->base = dev_read_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{
Kever Yang1b807052020-03-04 08:59:50 +0800287 ofnode node;
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200288 int ret;
289
Kever Yang1b807052020-03-04 08:59:50 +0800290 ofnode_for_each_subnode(node, parent->node) {
291 const char *name = ofnode_get_name(node);
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200292 enum usb_dr_mode dr_mode;
293 struct udevice *dev;
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100294 const char *driver = NULL;
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200295
296 debug("%s: subnode name: %s\n", __func__, name);
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200297
298 dr_mode = usb_get_dr_mode(node);
299
300 switch (dr_mode) {
301 case USB_DR_MODE_PERIPHERAL:
302 case USB_DR_MODE_OTG:
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100303#if CONFIG_IS_ENABLED(DM_USB_GADGET)
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200304 debug("%s: dr_mode: OTG or Peripheral\n", __func__);
305 driver = "dwc3-generic-peripheral";
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100306#endif
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200307 break;
Jean-Jacques Hiblot175cd7c2019-09-11 11:33:50 +0200308#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD)
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200309 case USB_DR_MODE_HOST:
310 debug("%s: dr_mode: HOST\n", __func__);
Jean-Jacques Hiblot175cd7c2019-09-11 11:33:50 +0200311 driver = "dwc3-generic-host";
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200312 break;
Jean-Jacques Hiblot175cd7c2019-09-11 11:33:50 +0200313#endif
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200314 default:
315 debug("%s: unsupported dr_mode\n", __func__);
316 return -ENODEV;
317 };
318
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100319 if (!driver)
320 continue;
321
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200322 ret = device_bind_driver_to_node(parent, driver, name,
Kever Yang1b807052020-03-04 08:59:50 +0800323 node, &dev);
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200324 if (ret) {
325 debug("%s: not able to bind usb device mode\n",
326 __func__);
327 return ret;
328 }
329 }
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100330
331 return 0;
332}
333
334static int dwc3_glue_reset_init(struct udevice *dev,
335 struct dwc3_glue_data *glue)
336{
337 int ret;
338
339 ret = reset_get_bulk(dev, &glue->resets);
Vignesh Raghavendrae9310fc2019-10-25 13:48:05 +0530340 if (ret == -ENOTSUPP || ret == -ENOENT)
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100341 return 0;
342 else if (ret)
343 return ret;
344
345 ret = reset_deassert_bulk(&glue->resets);
346 if (ret) {
347 reset_release_bulk(&glue->resets);
348 return ret;
349 }
350
351 return 0;
352}
353
354static int dwc3_glue_clk_init(struct udevice *dev,
355 struct dwc3_glue_data *glue)
356{
357 int ret;
358
359 ret = clk_get_bulk(dev, &glue->clks);
Vignesh Raghavendrae9310fc2019-10-25 13:48:05 +0530360 if (ret == -ENOSYS || ret == -ENOENT)
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100361 return 0;
362 if (ret)
363 return ret;
364
365#if CONFIG_IS_ENABLED(CLK)
366 ret = clk_enable_bulk(&glue->clks);
367 if (ret) {
368 clk_release_bulk(&glue->clks);
369 return ret;
370 }
371#endif
372
373 return 0;
374}
375
376static int dwc3_glue_probe(struct udevice *dev)
377{
Jean-Jacques Hiblotae004d32018-11-29 10:52:49 +0100378 struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev);
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100379 struct dwc3_glue_data *glue = dev_get_platdata(dev);
Jean-Jacques Hiblotae004d32018-11-29 10:52:49 +0100380 struct udevice *child = NULL;
381 int index = 0;
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100382 int ret;
383
Jean-Jacques Hiblotae004d32018-11-29 10:52:49 +0100384 glue->regs = dev_read_addr(dev);
385
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100386 ret = dwc3_glue_clk_init(dev, glue);
387 if (ret)
388 return ret;
389
390 ret = dwc3_glue_reset_init(dev, glue);
391 if (ret)
392 return ret;
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200393
Jean-Jacques Hiblotae004d32018-11-29 10:52:49 +0100394 ret = device_find_first_child(dev, &child);
395 if (ret)
396 return ret;
397
398 while (child) {
399 enum usb_dr_mode dr_mode;
400
Kever Yang1b807052020-03-04 08:59:50 +0800401 dr_mode = usb_get_dr_mode(child->node);
Jean-Jacques Hiblotae004d32018-11-29 10:52:49 +0100402 device_find_next_child(&child);
403 if (ops && ops->select_dr_mode)
404 ops->select_dr_mode(dev, index, dr_mode);
405 index++;
406 }
407
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200408 return 0;
409}
410
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100411static int dwc3_glue_remove(struct udevice *dev)
412{
413 struct dwc3_glue_data *glue = dev_get_platdata(dev);
414
415 reset_release_bulk(&glue->resets);
416
417 clk_release_bulk(&glue->clks);
418
Jean-Jacques Hiblot5a945572019-07-05 09:33:56 +0200419 return 0;
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100420}
421
422static const struct udevice_id dwc3_glue_ids[] = {
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200423 { .compatible = "xlnx,zynqmp-dwc3" },
Jean-Jacques Hiblot3e0684b2018-12-04 11:12:56 +0100424 { .compatible = "ti,keystone-dwc3"},
Jean-Jacques Hiblot65596f12018-11-29 10:57:40 +0100425 { .compatible = "ti,dwc3", .data = (ulong)&ti_ops },
Jean-Jacques Hiblotca848df2018-12-04 11:30:50 +0100426 { .compatible = "ti,am437x-dwc3", .data = (ulong)&ti_ops },
Vignesh Raghavendrac6282952019-12-09 10:37:29 +0530427 { .compatible = "ti,am654-dwc3" },
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200428 { }
429};
430
431U_BOOT_DRIVER(dwc3_generic_wrapper) = {
432 .name = "dwc3-generic-wrapper",
Jean-Jacques Hiblotb49b5c22019-07-05 09:33:58 +0200433 .id = UCLASS_NOP,
Jean-Jacques Hiblotaa866a02018-11-29 10:52:48 +0100434 .of_match = dwc3_glue_ids,
435 .bind = dwc3_glue_bind,
436 .probe = dwc3_glue_probe,
437 .remove = dwc3_glue_remove,
438 .platdata_auto_alloc_size = sizeof(struct dwc3_glue_data),
439
Michal Simek9d8cbbf2018-05-18 13:15:06 +0200440};