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