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 /* 164 * Order in this softc is important; memac_mdio_fdt_attach() calls 165 * simplebus_init() which expects sb_sc at the beginning. 166 */ 167 struct memac_mdio_softc_fdt { 168 struct simplebus_softc sb_sc; /* Must stay first. */ 169 struct memac_mdio_softc_common scc; 170 }; 171 172 static int 173 memac_fdt_miibus_readreg(device_t dev, int phy, int reg) 174 { 175 struct memac_mdio_softc_fdt *sc; 176 177 sc = device_get_softc(dev); 178 return (memac_miibus_readreg(&sc->scc, phy, reg)); 179 } 180 181 static int 182 memac_fdt_miibus_writereg(device_t dev, int phy, int reg, int data) 183 { 184 struct memac_mdio_softc_fdt *sc; 185 186 sc = device_get_softc(dev); 187 return (memac_miibus_writereg(&sc->scc, phy, reg, data)); 188 } 189 190 static struct ofw_compat_data compat_data[] = { 191 { "fsl,fman-memac-mdio", 1 }, 192 { NULL, 0 } 193 }; 194 195 static int 196 memac_mdio_fdt_probe(device_t dev) 197 { 198 199 if (!ofw_bus_status_okay(dev)) 200 return (ENXIO); 201 202 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 203 return (ENXIO); 204 205 device_set_desc(dev, "Freescale XGMAC MDIO Bus (FDT)"); 206 return (BUS_PROBE_DEFAULT); 207 } 208 209 static int 210 memac_mdio_fdt_probe_child(device_t bus, phandle_t child) 211 { 212 device_t childdev; 213 214 /* Make sure we do not aliready have a device. */ 215 childdev = ofw_bus_find_child_device_by_phandle(bus, child); 216 if (childdev != NULL) 217 return (0); 218 219 childdev = simplebus_add_device(bus, child, 0, NULL, -1, NULL); 220 if (childdev == NULL) 221 return (ENXIO); 222 223 return (device_probe_and_attach(childdev)); 224 } 225 226 static int 227 memac_mdio_fdt_attach(device_t dev) 228 { 229 struct memac_mdio_softc_fdt *sc; 230 phandle_t node, child; 231 int error; 232 233 sc = device_get_softc(dev); 234 sc->scc.dev = dev; 235 236 error = memac_mdio_generic_attach(&sc->scc); 237 if (error != 0) 238 return (error); 239 240 /* Attach the *phy* children represented in the device tree. */ 241 bus_generic_probe(dev); 242 bus_enumerate_hinted_children(dev); 243 node = ofw_bus_get_node(dev); 244 simplebus_init(dev, node); 245 for (child = OF_child(node); child > 0; child = OF_peer(child)) { 246 if (!OF_hasprop(child, "reg")) 247 continue; 248 if (memac_mdio_fdt_probe_child(dev, child) != 0) 249 continue; 250 } 251 252 return (0); 253 } 254 255 static int 256 memac_mdio_fdt_detach(device_t dev) 257 { 258 struct memac_mdio_softc_fdt *sc; 259 260 sc = device_get_softc(dev); 261 return (memac_mdio_generic_detach(&sc->scc)); 262 } 263 264 static const struct ofw_bus_devinfo * 265 memac_simplebus_get_devinfo(device_t bus, device_t child) 266 { 267 268 return (OFW_BUS_GET_DEVINFO(device_get_parent(bus), child)); 269 } 270 271 static device_method_t memac_mdio_fdt_methods[] = { 272 /* Device interface */ 273 DEVMETHOD(device_probe, memac_mdio_fdt_probe), 274 DEVMETHOD(device_attach, memac_mdio_fdt_attach), 275 DEVMETHOD(device_detach, memac_mdio_fdt_detach), 276 277 /* MII interface */ 278 DEVMETHOD(miibus_readreg, memac_fdt_miibus_readreg), 279 DEVMETHOD(miibus_writereg, memac_fdt_miibus_writereg), 280 281 /* OFW/simplebus */ 282 DEVMETHOD(ofw_bus_get_devinfo, memac_simplebus_get_devinfo), 283 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 284 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 285 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 286 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 287 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 288 289 /* Bus interface */ 290 DEVMETHOD(bus_add_child, bus_generic_add_child), 291 DEVMETHOD(bus_read_ivar, memac_mdio_read_ivar), 292 DEVMETHOD(bus_get_property, memac_mdio_get_property), 293 294 DEVMETHOD_END 295 }; 296 297 DEFINE_CLASS_0(memac_mdio_fdt, memac_mdio_fdt_driver, memac_mdio_fdt_methods, 298 sizeof(struct memac_mdio_softc_fdt)); 299 300 EARLY_DRIVER_MODULE(memac_mdio_fdt, simplebus, memac_mdio_fdt_driver, 0, 0, 301 BUS_PASS_SUPPORTDEV); 302 303 DRIVER_MODULE(miibus, memac_mdio_fdt, miibus_driver, 0, 0); 304 MODULE_DEPEND(memac_mdio_fdt, miibus, 1, 1, 1); 305 MODULE_VERSION(memac_mdio_fdt, 1); 306