blob: ff83bf71e89857dec27eee2847277eb0ce2a2f7d [file] [log] [blame]
Michael Walle16d97852021-10-15 15:15:23 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Layerscape DWC3 Glue layer
4 *
5 * Copyright (C) 2021 Michael Walle <michael@walle.cc>
6 *
7 * Based on dwc3-generic.c.
8 */
9
Michael Walle16d97852021-10-15 15:15:23 +020010#include <dm.h>
11#include <dm/device_compat.h>
12#include <dm/device-internal.h>
13#include <dm/lists.h>
14#include <dwc3-uboot.h>
15#include <linux/usb/gadget.h>
16#include <usb.h>
17#include "core.h"
18#include "gadget.h"
19#include <usb/xhci.h>
20
21struct dwc3_layerscape_plat {
22 fdt_addr_t base;
23 u32 maximum_speed;
24 enum usb_dr_mode dr_mode;
25};
26
27struct dwc3_layerscape_priv {
28 void *base;
29 struct dwc3 dwc3;
30 struct phy_bulk phys;
31};
32
33struct dwc3_layerscape_host_priv {
34 struct xhci_ctrl xhci_ctrl;
35 struct dwc3_layerscape_priv gen_priv;
36};
37
38static int dwc3_layerscape_probe(struct udevice *dev,
39 struct dwc3_layerscape_priv *priv)
40{
41 int rc;
42 struct dwc3_layerscape_plat *plat = dev_get_plat(dev);
43 struct dwc3 *dwc3 = &priv->dwc3;
44
45 dwc3->dev = dev;
46 dwc3->maximum_speed = plat->maximum_speed;
47 dwc3->dr_mode = plat->dr_mode;
48 if (CONFIG_IS_ENABLED(OF_CONTROL))
49 dwc3_of_parse(dwc3);
50
51 rc = dwc3_setup_phy(dev, &priv->phys);
52 if (rc && rc != -ENOTSUPP)
53 return rc;
54
55 priv->base = map_physmem(plat->base, DWC3_OTG_REGS_END, MAP_NOCACHE);
56 dwc3->regs = priv->base + DWC3_GLOBALS_REGS_START;
57
58 rc = dwc3_init(dwc3);
59 if (rc) {
60 unmap_physmem(priv->base, MAP_NOCACHE);
61 return rc;
62 }
63
64 return 0;
65}
66
67static int dwc3_layerscape_remove(struct udevice *dev,
68 struct dwc3_layerscape_priv *priv)
69{
70 struct dwc3 *dwc3 = &priv->dwc3;
71
72 dwc3_remove(dwc3);
73 dwc3_shutdown_phy(dev, &priv->phys);
74 unmap_physmem(dwc3->regs, MAP_NOCACHE);
75
76 return 0;
77}
78
79static int dwc3_layerscape_of_to_plat(struct udevice *dev)
80{
81 struct dwc3_layerscape_plat *plat = dev_get_plat(dev);
82 ofnode node = dev_ofnode(dev);
83
84 plat->base = dev_read_addr(dev);
85
86 plat->maximum_speed = usb_get_maximum_speed(node);
87 if (plat->maximum_speed == USB_SPEED_UNKNOWN) {
88 dev_dbg(dev, "No USB maximum speed specified. Using super speed\n");
89 plat->maximum_speed = USB_SPEED_SUPER;
90 }
91
92 plat->dr_mode = usb_get_dr_mode(node);
93 if (plat->dr_mode == USB_DR_MODE_UNKNOWN) {
94 dev_err(dev, "Invalid usb mode setup\n");
95 return -ENODEV;
96 }
97
98 return 0;
99}
100
101#if CONFIG_IS_ENABLED(DM_USB_GADGET)
102int dm_usb_gadget_handle_interrupts(struct udevice *dev)
103{
104 struct dwc3_layerscape_priv *priv = dev_get_priv(dev);
105
106 dwc3_gadget_uboot_handle_interrupt(&priv->dwc3);
107
108 return 0;
109}
110
111static int dwc3_layerscape_peripheral_probe(struct udevice *dev)
112{
113 struct dwc3_layerscape_priv *priv = dev_get_priv(dev);
114
115 return dwc3_layerscape_probe(dev, priv);
116}
117
118static int dwc3_layerscape_peripheral_remove(struct udevice *dev)
119{
120 struct dwc3_layerscape_priv *priv = dev_get_priv(dev);
121
122 return dwc3_layerscape_remove(dev, priv);
123}
124
125U_BOOT_DRIVER(dwc3_layerscape_peripheral) = {
126 .name = "dwc3-layerscape-peripheral",
127 .id = UCLASS_USB_GADGET_GENERIC,
128 .of_to_plat = dwc3_layerscape_of_to_plat,
129 .probe = dwc3_layerscape_peripheral_probe,
130 .remove = dwc3_layerscape_peripheral_remove,
131 .priv_auto = sizeof(struct dwc3_layerscape_priv),
132 .plat_auto = sizeof(struct dwc3_layerscape_plat),
133};
134#endif
135
Oleksandr Suvorovce56a122023-08-25 13:42:39 +0300136#if CONFIG_IS_ENABLED(USB_HOST)
Michael Walle16d97852021-10-15 15:15:23 +0200137static int dwc3_layerscape_host_probe(struct udevice *dev)
138{
139 struct xhci_hcor *hcor;
140 struct xhci_hccr *hccr;
141 struct dwc3_layerscape_host_priv *priv = dev_get_priv(dev);
142 int rc;
143
144 rc = dwc3_layerscape_probe(dev, &priv->gen_priv);
145 if (rc)
146 return rc;
147
148 hccr = priv->gen_priv.base;
149 hcor = priv->gen_priv.base + HC_LENGTH(xhci_readl(&hccr->cr_capbase));
150
151 return xhci_register(dev, hccr, hcor);
152}
153
154static int dwc3_layerscape_host_remove(struct udevice *dev)
155{
156 struct dwc3_layerscape_host_priv *priv = dev_get_priv(dev);
157 int rc;
158
159 rc = xhci_deregister(dev);
160 if (rc)
161 return rc;
162
163 return dwc3_layerscape_remove(dev, &priv->gen_priv);
164}
165
166U_BOOT_DRIVER(dwc3_layerscape_host) = {
167 .name = "dwc3-layerscape-host",
168 .id = UCLASS_USB,
169 .of_to_plat = dwc3_layerscape_of_to_plat,
170 .probe = dwc3_layerscape_host_probe,
171 .remove = dwc3_layerscape_host_remove,
172 .priv_auto = sizeof(struct dwc3_layerscape_host_priv),
173 .plat_auto = sizeof(struct dwc3_layerscape_plat),
174 .ops = &xhci_usb_ops,
175 .flags = DM_FLAG_ALLOC_PRIV_DMA,
176};
177#endif
178
179static int dwc3_layerscape_bind(struct udevice *dev)
180{
181 ofnode node = dev_ofnode(dev);
182 const char *name = ofnode_get_name(node);
183 enum usb_dr_mode dr_mode;
184 char *driver;
185
186 dr_mode = usb_get_dr_mode(node);
187
188 switch (dr_mode) {
189#if CONFIG_IS_ENABLED(DM_USB_GADGET)
190 case USB_DR_MODE_PERIPHERAL:
191 dev_dbg(dev, "Using peripheral mode\n");
192 driver = "dwc3-layerscape-peripheral";
193 break;
194#endif
Oleksandr Suvorov2d69af62023-08-25 13:42:40 +0300195#if CONFIG_IS_ENABLED(USB_HOST)
Michael Walle16d97852021-10-15 15:15:23 +0200196 case USB_DR_MODE_HOST:
197 dev_dbg(dev, "Using host mode\n");
198 driver = "dwc3-layerscape-host";
199 break;
200#endif
201 default:
202 dev_dbg(dev, "Unsupported dr_mode\n");
203 return -ENODEV;
204 };
205
206 return device_bind_driver_to_node(dev, driver, name, node, NULL);
207}
208
209static const struct udevice_id dwc3_layerscape_ids[] = {
210 { .compatible = "fsl,layerscape-dwc3" },
211 { .compatible = "fsl,ls1028a-dwc3" },
212 { }
213};
214
215U_BOOT_DRIVER(dwc3_layerscape_wrapper) = {
216 .name = "dwc3-layerscape-wrapper",
217 .id = UCLASS_NOP,
218 .of_match = dwc3_layerscape_ids,
219 .bind = dwc3_layerscape_bind,
220};