]> Git Repo - J-u-boot.git/blame - drivers/usb/dwc3/dwc3-generic.c
test: dm: phy: add a test item for the phy_bulk API
[J-u-boot.git] / drivers / usb / dwc3 / dwc3-generic.c
CommitLineData
22929e12 1// SPDX-License-Identifier: GPL-2.0
49d67454
MS
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>
1eb69ae4 11#include <cpu_func.h>
93991cf1 12#include <asm-generic/io.h>
49d67454
MS
13#include <dm.h>
14#include <dm/device-internal.h>
15#include <dm/lists.h>
446e3a20 16#include <dwc3-uboot.h>
49d67454
MS
17#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"
446e3a20
JJH
23#include <reset.h>
24#include <clk.h>
b575e909 25#include <usb/xhci.h>
49d67454 26
3a38a0ad
JJH
27struct dwc3_generic_plat {
28 fdt_addr_t base;
29 u32 maximum_speed;
30 enum usb_dr_mode dr_mode;
31};
32
3a38a0ad 33struct dwc3_generic_priv {
1af590df 34 void *base;
446e3a20
JJH
35 struct dwc3 dwc3;
36 struct phy *phys;
37 int num_phys;
446e3a20
JJH
38};
39
b575e909
JJH
40struct dwc3_generic_host_priv {
41 struct xhci_ctrl xhci_ctrl;
42 struct dwc3_generic_priv gen_priv;
43};
44
1af590df
JJH
45static int dwc3_generic_probe(struct udevice *dev,
46 struct dwc3_generic_priv *priv)
49d67454 47{
446e3a20 48 int rc;
3a38a0ad 49 struct dwc3_generic_plat *plat = dev_get_platdata(dev);
446e3a20
JJH
50 struct dwc3 *dwc3 = &priv->dwc3;
51
ba6c5f7a 52 dwc3->dev = dev;
3a38a0ad
JJH
53 dwc3->maximum_speed = plat->maximum_speed;
54 dwc3->dr_mode = plat->dr_mode;
ba6c5f7a
JJH
55#if CONFIG_IS_ENABLED(OF_CONTROL)
56 dwc3_of_parse(dwc3);
57#endif
3a38a0ad 58
446e3a20
JJH
59 rc = dwc3_setup_phy(dev, &priv->phys, &priv->num_phys);
60 if (rc)
61 return rc;
62
1af590df
JJH
63 priv->base = map_physmem(plat->base, DWC3_OTG_REGS_END, MAP_NOCACHE);
64 dwc3->regs = priv->base + DWC3_GLOBALS_REGS_START;
ba6c5f7a 65
446e3a20
JJH
66
67 rc = dwc3_init(dwc3);
68 if (rc) {
1af590df 69 unmap_physmem(priv->base, MAP_NOCACHE);
446e3a20
JJH
70 return rc;
71 }
49d67454 72
446e3a20 73 return 0;
49d67454
MS
74}
75
1af590df
JJH
76static int dwc3_generic_remove(struct udevice *dev,
77 struct dwc3_generic_priv *priv)
49d67454 78{
446e3a20 79 struct dwc3 *dwc3 = &priv->dwc3;
49d67454 80
446e3a20
JJH
81 dwc3_remove(dwc3);
82 dwc3_shutdown_phy(dev, priv->phys, priv->num_phys);
83 unmap_physmem(dwc3->regs, MAP_NOCACHE);
49d67454
MS
84
85 return 0;
86}
87
1af590df 88static int dwc3_generic_ofdata_to_platdata(struct udevice *dev)
49d67454 89{
3a38a0ad 90 struct dwc3_generic_plat *plat = dev_get_platdata(dev);
ac28e59a 91 ofnode node = dev->node;
49d67454 92
ac28e59a 93 plat->base = dev_read_addr(dev);
49d67454 94
3a38a0ad
JJH
95 plat->maximum_speed = usb_get_maximum_speed(node);
96 if (plat->maximum_speed == USB_SPEED_UNKNOWN) {
1a63e5e5
JJH
97 pr_info("No USB maximum speed specified. Using super speed\n");
98 plat->maximum_speed = USB_SPEED_SUPER;
49d67454
MS
99 }
100
3a38a0ad
JJH
101 plat->dr_mode = usb_get_dr_mode(node);
102 if (plat->dr_mode == USB_DR_MODE_UNKNOWN) {
49d67454
MS
103 pr_err("Invalid usb mode setup\n");
104 return -ENODEV;
105 }
106
107 return 0;
108}
109
1af590df
JJH
110#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
49d67454
MS
135U_BOOT_DRIVER(dwc3_generic_peripheral) = {
136 .name = "dwc3-generic-peripheral",
01311624 137 .id = UCLASS_USB_GADGET_GENERIC,
1af590df 138 .ofdata_to_platdata = dwc3_generic_ofdata_to_platdata,
49d67454
MS
139 .probe = dwc3_generic_peripheral_probe,
140 .remove = dwc3_generic_peripheral_remove,
3a38a0ad
JJH
141 .priv_auto_alloc_size = sizeof(struct dwc3_generic_priv),
142 .platdata_auto_alloc_size = sizeof(struct dwc3_generic_plat),
49d67454 143};
687ab545 144#endif
49d67454 145
b575e909
JJH
146#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
446e3a20
JJH
190struct dwc3_glue_data {
191 struct clk_bulk clks;
192 struct reset_ctl_bulk resets;
93991cf1
JJH
193 fdt_addr_t regs;
194};
195
196struct dwc3_glue_ops {
197 void (*select_dr_mode)(struct udevice *dev, int index,
198 enum usb_dr_mode mode);
446e3a20
JJH
199};
200
d66e54ac
JJH
201void 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
446e3a20 285static int dwc3_glue_bind(struct udevice *parent)
49d67454 286{
ac28e59a 287 ofnode node;
49d67454
MS
288 int ret;
289
ac28e59a
KY
290 ofnode_for_each_subnode(node, parent->node) {
291 const char *name = ofnode_get_name(node);
49d67454
MS
292 enum usb_dr_mode dr_mode;
293 struct udevice *dev;
446e3a20 294 const char *driver = NULL;
49d67454
MS
295
296 debug("%s: subnode name: %s\n", __func__, name);
49d67454
MS
297
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:
446e3a20 303#if CONFIG_IS_ENABLED(DM_USB_GADGET)
49d67454
MS
304 debug("%s: dr_mode: OTG or Peripheral\n", __func__);
305 driver = "dwc3-generic-peripheral";
446e3a20 306#endif
49d67454 307 break;
b575e909 308#if defined(CONFIG_SPL_USB_HOST_SUPPORT) || !defined(CONFIG_SPL_BUILD)
49d67454
MS
309 case USB_DR_MODE_HOST:
310 debug("%s: dr_mode: HOST\n", __func__);
b575e909 311 driver = "dwc3-generic-host";
49d67454 312 break;
b575e909 313#endif
49d67454
MS
314 default:
315 debug("%s: unsupported dr_mode\n", __func__);
316 return -ENODEV;
317 };
318
446e3a20
JJH
319 if (!driver)
320 continue;
321
49d67454 322 ret = device_bind_driver_to_node(parent, driver, name,
ac28e59a 323 node, &dev);
49d67454
MS
324 if (ret) {
325 debug("%s: not able to bind usb device mode\n",
326 __func__);
327 return ret;
328 }
329 }
330
331 return 0;
332}
333
446e3a20
JJH
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);
d624434f 340 if (ret == -ENOTSUPP || ret == -ENOENT)
446e3a20
JJH
341 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);
d624434f 360 if (ret == -ENOSYS || ret == -ENOENT)
446e3a20
JJH
361 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{
93991cf1 378 struct dwc3_glue_ops *ops = (struct dwc3_glue_ops *)dev_get_driver_data(dev);
446e3a20 379 struct dwc3_glue_data *glue = dev_get_platdata(dev);
93991cf1
JJH
380 struct udevice *child = NULL;
381 int index = 0;
446e3a20
JJH
382 int ret;
383
93991cf1
JJH
384 glue->regs = dev_read_addr(dev);
385
446e3a20
JJH
386 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;
393
93991cf1
JJH
394 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
ac28e59a 401 dr_mode = usb_get_dr_mode(child->node);
93991cf1
JJH
402 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
446e3a20
JJH
408 return 0;
409}
410
411static 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
e445d466 419 return 0;
446e3a20
JJH
420}
421
422static const struct udevice_id dwc3_glue_ids[] = {
49d67454 423 { .compatible = "xlnx,zynqmp-dwc3" },
1c03ade3 424 { .compatible = "ti,keystone-dwc3"},
d66e54ac 425 { .compatible = "ti,dwc3", .data = (ulong)&ti_ops },
1ce5f1f9 426 { .compatible = "ti,am437x-dwc3", .data = (ulong)&ti_ops },
cab4e275 427 { .compatible = "ti,am654-dwc3" },
49d67454
MS
428 { }
429};
430
431U_BOOT_DRIVER(dwc3_generic_wrapper) = {
432 .name = "dwc3-generic-wrapper",
3b83829e 433 .id = UCLASS_NOP,
446e3a20
JJH
434 .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
49d67454 440};
This page took 0.175625 seconds and 4 git commands to generate.