blob: 108b44c67eb0e5d81f2c37d2340c4f370365e6a5 [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)
Marek Vasuteab470b2024-06-14 02:51:19 +0200102static int dwc3_layerscape_peripheral_probe(struct udevice *dev)
Michael Walle16d97852021-10-15 15:15:23 +0200103{
104 struct dwc3_layerscape_priv *priv = dev_get_priv(dev);
105
Marek Vasuteab470b2024-06-14 02:51:19 +0200106 return dwc3_layerscape_probe(dev, priv);
Michael Walle16d97852021-10-15 15:15:23 +0200107}
108
Marek Vasuteab470b2024-06-14 02:51:19 +0200109static int dwc3_layerscape_peripheral_remove(struct udevice *dev)
Michael Walle16d97852021-10-15 15:15:23 +0200110{
111 struct dwc3_layerscape_priv *priv = dev_get_priv(dev);
112
Marek Vasuteab470b2024-06-14 02:51:19 +0200113 return dwc3_layerscape_remove(dev, priv);
Michael Walle16d97852021-10-15 15:15:23 +0200114}
115
Marek Vasuteab470b2024-06-14 02:51:19 +0200116static int dwc3_layerscape_gadget_handle_interrupts(struct udevice *dev)
Michael Walle16d97852021-10-15 15:15:23 +0200117{
118 struct dwc3_layerscape_priv *priv = dev_get_priv(dev);
119
Marek Vasuteab470b2024-06-14 02:51:19 +0200120 dwc3_gadget_uboot_handle_interrupt(&priv->dwc3);
121
122 return 0;
Michael Walle16d97852021-10-15 15:15:23 +0200123}
124
Marek Vasuteab470b2024-06-14 02:51:19 +0200125static const struct usb_gadget_generic_ops dwc3_layerscape_gadget_ops = {
126 .handle_interrupts = dwc3_layerscape_gadget_handle_interrupts,
127};
128
Michael Walle16d97852021-10-15 15:15:23 +0200129U_BOOT_DRIVER(dwc3_layerscape_peripheral) = {
130 .name = "dwc3-layerscape-peripheral",
131 .id = UCLASS_USB_GADGET_GENERIC,
132 .of_to_plat = dwc3_layerscape_of_to_plat,
Marek Vasuteab470b2024-06-14 02:51:19 +0200133 .ops = &dwc3_layerscape_gadget_ops,
Michael Walle16d97852021-10-15 15:15:23 +0200134 .probe = dwc3_layerscape_peripheral_probe,
135 .remove = dwc3_layerscape_peripheral_remove,
136 .priv_auto = sizeof(struct dwc3_layerscape_priv),
137 .plat_auto = sizeof(struct dwc3_layerscape_plat),
138};
139#endif
140
Oleksandr Suvorovce56a122023-08-25 13:42:39 +0300141#if CONFIG_IS_ENABLED(USB_HOST)
Michael Walle16d97852021-10-15 15:15:23 +0200142static int dwc3_layerscape_host_probe(struct udevice *dev)
143{
144 struct xhci_hcor *hcor;
145 struct xhci_hccr *hccr;
146 struct dwc3_layerscape_host_priv *priv = dev_get_priv(dev);
147 int rc;
148
149 rc = dwc3_layerscape_probe(dev, &priv->gen_priv);
150 if (rc)
151 return rc;
152
153 hccr = priv->gen_priv.base;
154 hcor = priv->gen_priv.base + HC_LENGTH(xhci_readl(&hccr->cr_capbase));
155
156 return xhci_register(dev, hccr, hcor);
157}
158
159static int dwc3_layerscape_host_remove(struct udevice *dev)
160{
161 struct dwc3_layerscape_host_priv *priv = dev_get_priv(dev);
162 int rc;
163
164 rc = xhci_deregister(dev);
165 if (rc)
166 return rc;
167
168 return dwc3_layerscape_remove(dev, &priv->gen_priv);
169}
170
171U_BOOT_DRIVER(dwc3_layerscape_host) = {
172 .name = "dwc3-layerscape-host",
173 .id = UCLASS_USB,
174 .of_to_plat = dwc3_layerscape_of_to_plat,
175 .probe = dwc3_layerscape_host_probe,
176 .remove = dwc3_layerscape_host_remove,
177 .priv_auto = sizeof(struct dwc3_layerscape_host_priv),
178 .plat_auto = sizeof(struct dwc3_layerscape_plat),
179 .ops = &xhci_usb_ops,
180 .flags = DM_FLAG_ALLOC_PRIV_DMA,
181};
182#endif
183
184static int dwc3_layerscape_bind(struct udevice *dev)
185{
186 ofnode node = dev_ofnode(dev);
187 const char *name = ofnode_get_name(node);
188 enum usb_dr_mode dr_mode;
189 char *driver;
190
191 dr_mode = usb_get_dr_mode(node);
192
193 switch (dr_mode) {
194#if CONFIG_IS_ENABLED(DM_USB_GADGET)
195 case USB_DR_MODE_PERIPHERAL:
196 dev_dbg(dev, "Using peripheral mode\n");
197 driver = "dwc3-layerscape-peripheral";
198 break;
199#endif
Oleksandr Suvorov2d69af62023-08-25 13:42:40 +0300200#if CONFIG_IS_ENABLED(USB_HOST)
Michael Walle16d97852021-10-15 15:15:23 +0200201 case USB_DR_MODE_HOST:
202 dev_dbg(dev, "Using host mode\n");
203 driver = "dwc3-layerscape-host";
204 break;
205#endif
206 default:
207 dev_dbg(dev, "Unsupported dr_mode\n");
208 return -ENODEV;
209 };
210
211 return device_bind_driver_to_node(dev, driver, name, node, NULL);
212}
213
214static const struct udevice_id dwc3_layerscape_ids[] = {
215 { .compatible = "fsl,layerscape-dwc3" },
216 { .compatible = "fsl,ls1028a-dwc3" },
217 { }
218};
219
220U_BOOT_DRIVER(dwc3_layerscape_wrapper) = {
221 .name = "dwc3-layerscape-wrapper",
222 .id = UCLASS_NOP,
223 .of_match = dwc3_layerscape_ids,
224 .bind = dwc3_layerscape_bind,
225};