xref: /freebsd/sys/dev/dpaa2/dpaa2_mc_fdt.c (revision 5d3e7166)
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", &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);
400