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