1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright © 2021-2022 Dmitry Salychev
5 * Copyright © 2022 Bjoern A. Zeeb
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 /*
33 * The DPAA2 Management Complex (MC) Bus Driver (FDT-based).
34 *
35 * MC is a hardware resource manager which can be found in several NXP
36 * SoCs (LX2160A, for example) and provides an access to the specialized
37 * hardware objects used in network-oriented packet processing applications.
38 */
39
40 #include <sys/param.h>
41 #include <sys/kernel.h>
42 #include <sys/bus.h>
43 #include <sys/rman.h>
44 #include <sys/module.h>
45 #include <sys/malloc.h>
46 #include <sys/mutex.h>
47
48 #include <machine/bus.h>
49 #include <machine/resource.h>
50
51 #include <dev/ofw/ofw_bus.h>
52 #include <dev/ofw/ofw_bus_subr.h>
53 #include <dev/fdt/simplebus.h>
54
55 #include "pcib_if.h"
56 #include "pci_if.h"
57 #include "ofw_bus_if.h"
58
59 #include "dpaa2_mcp.h"
60 #include "dpaa2_mc.h"
61 #include "dpaa2_mc_if.h"
62
63 struct dpaa2_mac_fdt_softc {
64 uint32_t reg;
65 phandle_t sfp;
66 phandle_t pcs_handle;
67 phandle_t phy_handle;
68 char managed[64];
69 char phy_conn_type[64];
70 };
71
72 #if 0
73 ethernet@1 {
74
75 compatible = "fsl,qoriq-mc-dpmac";
76 reg = <0x1>;
77 sfp = <0x14>;
78 pcs-handle = <0x15>;
79 phy-connection-type = "10gbase-r";
80 managed = "in-band-status";
81 };
82 ethernet@3 {
83
84 compatible = "fsl,qoriq-mc-dpmac";
85 reg = <0x3>;
86 phy-handle = <0x18>;
87 phy-connection-type = "qsgmii";
88 managed = "in-band-status";
89 pcs-handle = <0x19>;
90 };
91 #endif
92
93 static int
94 dpaa2_mac_dev_probe(device_t dev)
95 {
96 phandle_t node;
97 uint64_t reg;
98 ssize_t s;
99
100 node = ofw_bus_get_node(dev);
101 if (!ofw_bus_node_is_compatible(node, "fsl,qoriq-mc-dpmac")) {
102 device_printf(dev, "'%s' not fsl,qoriq-mc-dpmac compatible\n",
103 ofw_bus_get_name(dev));
104 return (ENXIO);
105 }
106
107 s = device_get_property(dev, "reg", ®, sizeof(reg),
108 DEVICE_PROP_UINT32);
109 if (s == -1) {
110 device_printf(dev, "%s: '%s' has no 'reg' property, s %zd\n",
111 __func__, ofw_bus_get_name(dev), s);
112 return (ENXIO);
113 }
114
115 device_set_desc(dev, "DPAA2 MAC DEV");
116 return (BUS_PROBE_DEFAULT);
117 }
118
119 static int
120 dpaa2_mac_fdt_attach(device_t dev)
121 {
122 struct dpaa2_mac_fdt_softc *sc;
123 phandle_t node;
124 ssize_t s;
125
126 sc = device_get_softc(dev);
127 node = ofw_bus_get_node(dev);
128
129 s = device_get_property(dev, "reg", &sc->reg, sizeof(sc->reg),
130 DEVICE_PROP_UINT32);
131 if (s == -1) {
132 device_printf(dev, "Cannot find 'reg' property: %zd\n", s);
133 return (ENXIO);
134 }
135
136 s = device_get_property(dev, "managed", sc->managed,
137 sizeof(sc->managed), DEVICE_PROP_ANY);
138 s = device_get_property(dev, "phy-connection-type", sc->phy_conn_type,
139 sizeof(sc->phy_conn_type), DEVICE_PROP_ANY);
140 s = device_get_property(dev, "pcs-handle", &sc->pcs_handle,
141 sizeof(sc->pcs_handle), DEVICE_PROP_HANDLE);
142
143 /* 'sfp' and 'phy-handle' are optional but we need one or the other. */
144 s = device_get_property(dev, "sfp", &sc->sfp, sizeof(sc->sfp),
145 DEVICE_PROP_HANDLE);
146 s = device_get_property(dev, "phy-handle", &sc->phy_handle,
147 sizeof(sc->phy_handle), DEVICE_PROP_HANDLE);
148
149 if (bootverbose)
150 device_printf(dev, "node %#x '%s': reg %#x sfp %#x pcs-handle "
151 "%#x phy-handle %#x managed '%s' phy-conn-type '%s'\n",
152 node, ofw_bus_get_name(dev),
153 sc->reg, sc->sfp, sc->pcs_handle, sc->phy_handle,
154 sc->managed, sc->phy_conn_type);
155
156 return (0);
157 }
158
159 static bool
160 dpaa2_mac_fdt_match_id(device_t dev, uint32_t id)
161 {
162 struct dpaa2_mac_fdt_softc *sc;
163
164 if (dev == NULL)
165 return (false);
166
167 sc = device_get_softc(dev);
168 if (sc->reg == id)
169 return (true);
170
171 return (false);
172 }
173
174 static device_t
175 dpaa2_mac_fdt_get_phy_dev(device_t dev)
176 {
177 struct dpaa2_mac_fdt_softc *sc;
178
179 if (dev == NULL)
180 return (NULL);
181
182 sc = device_get_softc(dev);
183 if (sc->phy_handle == 0 && sc->sfp == 0)
184 return (NULL);
185
186 #ifdef __not_yet__ /* No sff,sfp support yet. */
187 if (sc->sfp != 0) {
188 device_t xdev;
189
190 xdev = OF_device_from_xref(OF_xref_from_node(sc->sfp));
191 if (xdev != NULL)
192 return (xdev);
193 }
194 #endif
195 return (OF_device_from_xref(OF_xref_from_node(sc->phy_handle)));
196 }
197
198 static device_method_t dpaa2_mac_fdt_methods[] = {
199 /* Device interface */
200 DEVMETHOD(device_probe, dpaa2_mac_dev_probe),
201 DEVMETHOD(device_attach, dpaa2_mac_fdt_attach),
202 DEVMETHOD(device_detach, bus_generic_detach),
203
204 DEVMETHOD_END
205 };
206
207 DEFINE_CLASS_0(dpaa2_mac_fdt, dpaa2_mac_fdt_driver, dpaa2_mac_fdt_methods,
208 sizeof(struct dpaa2_mac_fdt_softc));
209 DRIVER_MODULE(dpaa2_mac_fdt, dpaa2_mc, dpaa2_mac_fdt_driver, 0, 0);
210 MODULE_DEPEND(dpaa2_mac_fdt, memac_mdio_fdt, 1, 1, 1);
211
212 /*
213 * Device interface.
214 */
215
216 static int
217 dpaa2_mc_fdt_probe(device_t dev)
218 {
219 if (!ofw_bus_status_okay(dev))
220 return (ENXIO);
221
222 if (!ofw_bus_is_compatible(dev, "fsl,qoriq-mc"))
223 return (ENXIO);
224
225 device_set_desc(dev, "DPAA2 Management Complex");
226 return (BUS_PROBE_DEFAULT);
227 }
228
229 static int
230 dpaa2_mc_fdt_probe_child(device_t bus, phandle_t child)
231 {
232 device_t childdev;
233
234 /* make sure we do not aliready have a device. */
235 childdev = ofw_bus_find_child_device_by_phandle(bus, child);
236 if (childdev != NULL)
237 return (0);
238
239 childdev = simplebus_add_device(bus, child, 0, "dpaa2_mac_fdt", -1,
240 NULL);
241 if (childdev == NULL)
242 return (ENXIO);
243
244 return (device_probe_and_attach(childdev));
245 }
246
247 static int
248 dpaa2_mc_fdt_attach(device_t dev)
249 {
250 struct dpaa2_mc_softc *sc;
251 phandle_t node;
252 phandle_t child;
253
254 sc = device_get_softc(dev);
255 sc->acpi_based = false;
256 sc->ofw_node = ofw_bus_get_node(dev);
257
258 bus_generic_probe(dev);
259 bus_enumerate_hinted_children(dev);
260
261 bus_generic_probe(dev);
262 bus_enumerate_hinted_children(dev);
263 /*
264 * Attach the children represented in the device tree.
265 */
266 /* fsl-mc -> dpamcs */
267 node = OF_child(sc->ofw_node);
268 simplebus_init(dev, node);
269
270 /* Attach the dpmac children represented in the device tree. */
271 child = ofw_bus_find_compatible(node, "fsl,qoriq-mc-dpmac");
272 for (; child > 0; child = OF_peer(child)) {
273 if (!ofw_bus_node_is_compatible(child, "fsl,qoriq-mc-dpmac"))
274 continue;
275 if (!OF_hasprop(child, "reg"))
276 continue;
277 if (!OF_hasprop(child, "pcs-handle"))
278 continue;
279 if (dpaa2_mc_fdt_probe_child(dev, child) != 0)
280 continue;
281 }
282
283 return (dpaa2_mc_attach(dev));
284 }
285
286 /*
287 * FDT compat layer.
288 */
289 static device_t
290 dpaa2_mc_fdt_find_dpaa2_mac_dev(device_t dev, uint32_t id)
291 {
292 int devcount, error, i, len;
293 device_t *devlist, mdev;
294 const char *mdevname;
295
296 error = device_get_children(dev, &devlist, &devcount);
297 if (error != 0)
298 return (NULL);
299
300 for (i = 0; i < devcount; i++) {
301 mdev = devlist[i];
302 mdevname = device_get_name(mdev);
303 if (mdevname == NULL)
304 continue;
305 len = strlen(mdevname);
306 if (strncmp("dpaa2_mac_fdt", mdevname, len) != 0)
307 continue;
308 if (!device_is_attached(mdev))
309 continue;
310
311 if (dpaa2_mac_fdt_match_id(mdev, id))
312 return (mdev);
313 }
314
315 return (NULL);
316 }
317
318 static int
319 dpaa2_mc_fdt_get_phy_dev(device_t dev, device_t *phy_dev, uint32_t id)
320 {
321 device_t mdev, pdev;
322
323 mdev = dpaa2_mc_fdt_find_dpaa2_mac_dev(dev, id);
324 if (mdev == NULL) {
325 device_printf(dev, "%s: error finding dpmac device with id=%u\n",
326 __func__, id);
327 return (ENXIO);
328 }
329
330 pdev = dpaa2_mac_fdt_get_phy_dev(mdev);
331 if (pdev == NULL) {
332 device_printf(dev, "%s: error getting MDIO device for dpamc %s "
333 "(id=%u)\n", __func__, device_get_nameunit(mdev), id);
334 return (ENXIO);
335 }
336
337 if (phy_dev != NULL)
338 *phy_dev = pdev;
339
340 if (bootverbose)
341 device_printf(dev, "dpmac_id %u mdev %p (%s) pdev %p (%s)\n",
342 id, mdev, device_get_nameunit(mdev),
343 pdev, device_get_nameunit(pdev));
344
345 return (0);
346 }
347
348 static const struct ofw_bus_devinfo *
349 dpaa2_mc_simplebus_get_devinfo(device_t bus, device_t child)
350 {
351
352 return (OFW_BUS_GET_DEVINFO(device_get_parent(bus), child));
353 }
354
355 static device_method_t dpaa2_mc_fdt_methods[] = {
356 /* Device interface */
357 DEVMETHOD(device_probe, dpaa2_mc_fdt_probe),
358 DEVMETHOD(device_attach, dpaa2_mc_fdt_attach),
359 DEVMETHOD(device_detach, dpaa2_mc_detach),
360
361 /* Bus interface */
362 DEVMETHOD(bus_alloc_resource, dpaa2_mc_alloc_resource),
363 DEVMETHOD(bus_adjust_resource, dpaa2_mc_adjust_resource),
364 DEVMETHOD(bus_release_resource, dpaa2_mc_release_resource),
365 DEVMETHOD(bus_activate_resource, dpaa2_mc_activate_resource),
366 DEVMETHOD(bus_deactivate_resource, dpaa2_mc_deactivate_resource),
367 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
368 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
369
370 /* Pseudo-PCIB interface */
371 DEVMETHOD(pcib_alloc_msi, dpaa2_mc_alloc_msi),
372 DEVMETHOD(pcib_release_msi, dpaa2_mc_release_msi),
373 DEVMETHOD(pcib_map_msi, dpaa2_mc_map_msi),
374 DEVMETHOD(pcib_get_id, dpaa2_mc_get_id),
375
376 /* DPAA2 MC bus interface */
377 DEVMETHOD(dpaa2_mc_manage_dev, dpaa2_mc_manage_dev),
378 DEVMETHOD(dpaa2_mc_get_free_dev,dpaa2_mc_get_free_dev),
379 DEVMETHOD(dpaa2_mc_get_dev, dpaa2_mc_get_dev),
380 DEVMETHOD(dpaa2_mc_get_shared_dev, dpaa2_mc_get_shared_dev),
381 DEVMETHOD(dpaa2_mc_reserve_dev, dpaa2_mc_reserve_dev),
382 DEVMETHOD(dpaa2_mc_release_dev, dpaa2_mc_release_dev),
383 DEVMETHOD(dpaa2_mc_get_phy_dev, dpaa2_mc_fdt_get_phy_dev),
384
385 /* OFW/simplebus */
386 DEVMETHOD(ofw_bus_get_devinfo, dpaa2_mc_simplebus_get_devinfo),
387 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat),
388 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model),
389 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name),
390 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node),
391 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type),
392
393 DEVMETHOD_END
394 };
395
396 DEFINE_CLASS_1(dpaa2_mc, dpaa2_mc_fdt_driver, dpaa2_mc_fdt_methods,
397 sizeof(struct dpaa2_mc_softc), dpaa2_mc_driver);
398
399 DRIVER_MODULE(dpaa2_mc, simplebus, dpaa2_mc_fdt_driver, 0, 0);
Cache object: 6acf0746012897118ae7cb3bbc9bb5c3
|