1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright © 2021-2022 Bjoern A. Zeeb 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/kernel.h> 30 #include <sys/bus.h> 31 #include <sys/rman.h> 32 #include <sys/malloc.h> 33 #include <sys/module.h> 34 #include <sys/endian.h> 35 #include <sys/socket.h> 36 37 #include <machine/bus.h> 38 #include <machine/resource.h> 39 40 #include <dev/ofw/ofw_bus.h> 41 #include <dev/ofw/ofw_bus_subr.h> 42 #include <dev/fdt/simplebus.h> 43 44 #include <net/if.h> 45 #include <net/if_var.h> 46 #include <net/if_media.h> 47 48 #include <dev/mii/mii.h> 49 #include <dev/mii/miivar.h> 50 51 #include "memac_mdio.h" 52 #include "memac_mdio_if.h" 53 #include "ofw_bus_if.h" 54 #include "miibus_if.h" 55 56 /* -------------------------------------------------------------------------- */ 57 58 struct memacphy_softc_fdt { 59 struct memacphy_softc_common scc; 60 uint32_t reg; 61 phandle_t xref; 62 }; 63 64 static void 65 memacphy_fdt_miibus_statchg(device_t dev) 66 { 67 struct memacphy_softc_fdt *sc; 68 69 sc = device_get_softc(dev); 70 memacphy_miibus_statchg(&sc->scc); 71 } 72 73 static int 74 memacphy_fdt_set_ni_dev(device_t dev, device_t nidev) 75 { 76 struct memacphy_softc_fdt *sc; 77 78 sc = device_get_softc(dev); 79 return (memacphy_set_ni_dev(&sc->scc, nidev)); 80 } 81 82 static int 83 memacphy_fdt_get_phy_loc(device_t dev, int *phy_loc) 84 { 85 struct memacphy_softc_fdt *sc; 86 87 sc = device_get_softc(dev); 88 return (memacphy_get_phy_loc(&sc->scc, phy_loc)); 89 } 90 91 static int 92 memacphy_fdt_probe(device_t dev) 93 { 94 95 if (!ofw_bus_status_okay(dev)) 96 return (ENXIO); 97 98 device_set_desc(dev, "MEMAC PHY (fdt)"); 99 return (BUS_PROBE_DEFAULT); 100 } 101 102 static int 103 memacphy_fdt_attach(device_t dev) 104 { 105 struct memacphy_softc_fdt *sc; 106 phandle_t node; 107 ssize_t s; 108 int error; 109 110 sc = device_get_softc(dev); 111 sc->scc.dev = dev; 112 node = ofw_bus_get_node(dev); 113 114 s = device_get_property(dev, "reg", &sc->reg, sizeof(sc->reg), 115 DEVICE_PROP_UINT32); 116 if (s != -1) 117 sc->scc.phy = sc->reg; 118 else 119 sc->scc.phy = -1; 120 sc->xref = OF_xref_from_node(node); 121 122 error = OF_device_register_xref(sc->xref, dev); 123 if (error != 0) 124 device_printf(dev, "Failed to register xref %#x\n", sc->xref); 125 126 if (bootverbose) 127 device_printf(dev, "node %#x '%s': reg %#x xref %#x phy %u\n", 128 node, ofw_bus_get_name(dev), sc->reg, sc->xref, sc->scc.phy); 129 130 if (sc->scc.phy == -1) 131 error = ENXIO; 132 return (error); 133 } 134 135 static device_method_t memacphy_fdt_methods[] = { 136 /* Device interface */ 137 DEVMETHOD(device_probe, memacphy_fdt_probe), 138 DEVMETHOD(device_attach, memacphy_fdt_attach), 139 DEVMETHOD(device_detach, bus_generic_detach), 140 141 /* MII interface */ 142 DEVMETHOD(miibus_readreg, memacphy_miibus_readreg), 143 DEVMETHOD(miibus_writereg, memacphy_miibus_writereg), 144 DEVMETHOD(miibus_statchg, memacphy_fdt_miibus_statchg), 145 146 /* memac */ 147 DEVMETHOD(memac_mdio_set_ni_dev, memacphy_fdt_set_ni_dev), 148 DEVMETHOD(memac_mdio_get_phy_loc, memacphy_fdt_get_phy_loc), 149 150 DEVMETHOD_END 151 }; 152 153 DEFINE_CLASS_0(memacphy_fdt, memacphy_fdt_driver, memacphy_fdt_methods, 154 sizeof(struct memacphy_softc_fdt)); 155 156 EARLY_DRIVER_MODULE(memacphy_fdt, memac_mdio_fdt, memacphy_fdt_driver, 0, 0, 157 BUS_PASS_SUPPORTDEV); 158 DRIVER_MODULE(miibus, memacphy_fdt, miibus_driver, 0, 0); 159 MODULE_DEPEND(memacphy_fdt, miibus, 1, 1, 1); 160 161 /* -------------------------------------------------------------------------- */ 162 163 struct memac_mdio_softc_fdt { 164 struct memac_mdio_softc_common scc; 165 }; 166 167 static int 168 memac_fdt_miibus_readreg(device_t dev, int phy, int reg) 169 { 170 struct memac_mdio_softc_fdt *sc; 171 172 sc = device_get_softc(dev); 173 return (memac_miibus_readreg(&sc->scc, phy, reg)); 174 } 175 176 static int 177 memac_fdt_miibus_writereg(device_t dev, int phy, int reg, int data) 178 { 179 struct memac_mdio_softc_fdt *sc; 180 181 sc = device_get_softc(dev); 182 return (memac_miibus_writereg(&sc->scc, phy, reg, data)); 183 } 184 185 static struct ofw_compat_data compat_data[] = { 186 { "fsl,fman-memac-mdio", 1 }, 187 { NULL, 0 } 188 }; 189 190 static int 191 memac_mdio_fdt_probe(device_t dev) 192 { 193 194 if (!ofw_bus_status_okay(dev)) 195 return (ENXIO); 196 197 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 198 return (ENXIO); 199 200 device_set_desc(dev, "Freescale XGMAC MDIO Bus (FDT)"); 201 return (BUS_PROBE_DEFAULT); 202 } 203 204 static int 205 memac_mdio_fdt_probe_child(device_t bus, phandle_t child) 206 { 207 device_t childdev; 208 209 /* Make sure we do not aliready have a device. */ 210 childdev = ofw_bus_find_child_device_by_phandle(bus, child); 211 if (childdev != NULL) 212 return (0); 213 214 childdev = simplebus_add_device(bus, child, 0, NULL, -1, NULL); 215 if (childdev == NULL) 216 return (ENXIO); 217 218 return (device_probe_and_attach(childdev)); 219 } 220 221 static int 222 memac_mdio_fdt_attach(device_t dev) 223 { 224 struct memac_mdio_softc_fdt *sc; 225 phandle_t node, child; 226 int error; 227 228 sc = device_get_softc(dev); 229 sc->scc.dev = dev; 230 231 error = memac_mdio_generic_attach(&sc->scc); 232 if (error != 0) 233 return (error); 234 235 /* Attach the *phy* children represented in the device tree. */ 236 bus_identify_children(dev); 237 bus_enumerate_hinted_children(dev); 238 node = ofw_bus_get_node(dev); 239 simplebus_init(dev, node); 240 for (child = OF_child(node); child > 0; child = OF_peer(child)) { 241 if (!OF_hasprop(child, "reg")) 242 continue; 243 if (memac_mdio_fdt_probe_child(dev, child) != 0) 244 continue; 245 } 246 247 return (0); 248 } 249 250 static int 251 memac_mdio_fdt_detach(device_t dev) 252 { 253 struct memac_mdio_softc_fdt *sc; 254 255 sc = device_get_softc(dev); 256 return (memac_mdio_generic_detach(&sc->scc)); 257 } 258 259 static const struct ofw_bus_devinfo * 260 memac_simplebus_get_devinfo(device_t bus, device_t child) 261 { 262 263 return (OFW_BUS_GET_DEVINFO(device_get_parent(bus), child)); 264 } 265 266 static device_method_t memac_mdio_fdt_methods[] = { 267 /* Device interface */ 268 DEVMETHOD(device_probe, memac_mdio_fdt_probe), 269 DEVMETHOD(device_attach, memac_mdio_fdt_attach), 270 DEVMETHOD(device_detach, memac_mdio_fdt_detach), 271 272 /* MII interface */ 273 DEVMETHOD(miibus_readreg, memac_fdt_miibus_readreg), 274 DEVMETHOD(miibus_writereg, memac_fdt_miibus_writereg), 275 276 /* OFW/simplebus */ 277 DEVMETHOD(ofw_bus_get_devinfo, memac_simplebus_get_devinfo), 278 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 279 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 280 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 281 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 282 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 283 284 /* Bus interface */ 285 DEVMETHOD(bus_add_child, bus_generic_add_child), 286 DEVMETHOD(bus_read_ivar, memac_mdio_read_ivar), 287 DEVMETHOD(bus_get_property, memac_mdio_get_property), 288 289 DEVMETHOD_END 290 }; 291 292 DEFINE_CLASS_1(memac_mdio_fdt, memac_mdio_fdt_driver, memac_mdio_fdt_methods, 293 sizeof(struct memac_mdio_softc_fdt), simplebus_driver); 294 295 EARLY_DRIVER_MODULE(memac_mdio_fdt, simplebus, memac_mdio_fdt_driver, 0, 0, 296 BUS_PASS_SUPPORTDEV); 297 298 DRIVER_MODULE(miibus, memac_mdio_fdt, miibus_driver, 0, 0); 299 MODULE_DEPEND(memac_mdio_fdt, miibus, 1, 1, 1); 300 MODULE_VERSION(memac_mdio_fdt, 1); 301