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); 400