From c9b4bed650a8ce585e53821eb563efd50a8b2f65 Mon Sep 17 00:00:00 2001 From: Christian Mauderer Date: Thu, 19 May 2022 16:55:11 +0200 Subject: if_ffec: Allow PHY that is connected to other FFEC The i.MX6UL (and some others from the i.MX family) have shared MDIO lines for multiple FFECs. This patch allows to use the MDIO interface from another Ethernet controller. Note that you have to make sure that the FFECs are initialized in the right order. Normally that can be done via FDT. --- freebsd/sys/dev/ffec/if_ffec.c | 120 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/freebsd/sys/dev/ffec/if_ffec.c b/freebsd/sys/dev/ffec/if_ffec.c index 4c1e147b..316e077c 100644 --- a/freebsd/sys/dev/ffec/if_ffec.c +++ b/freebsd/sys/dev/ffec/if_ffec.c @@ -209,6 +209,11 @@ struct ffec_softc { int rx_ic_count; /* RW, valid values 0..255 */ int tx_ic_time; int tx_ic_count; +#ifdef __rtems__ + + device_t mdio_device; + struct mtx mdio_mtx; +#endif /* __rtems__ */ }; static struct resource_spec irq_res_spec[MAX_IRQ_COUNT + 1] = { @@ -376,6 +381,13 @@ ffec_miibus_readreg(device_t dev, int phy, int reg) int val; sc = device_get_softc(dev); +#ifdef __rtems__ + if (sc->mdio_device) { + return (MIIBUS_READREG(sc->mdio_device, phy, reg)); + } + + mtx_lock(&sc->mdio_mtx); +#endif /* __rtems__ */ WR4(sc, FEC_IER_REG, FEC_IER_MII); @@ -386,11 +398,17 @@ ffec_miibus_readreg(device_t dev, int phy, int reg) if (!ffec_miibus_iowait(sc)) { device_printf(dev, "timeout waiting for mii read\n"); +#ifdef __rtems__ + mtx_unlock(&sc->mdio_mtx); +#endif /* __rtems__ */ return (-1); /* All-ones is a symptom of bad mdio. */ } val = RD4(sc, FEC_MMFR_REG) & FEC_MMFR_DATA_MASK; +#ifdef __rtems__ + mtx_unlock(&sc->mdio_mtx); +#endif /* __rtems__ */ return (val); } @@ -400,6 +418,13 @@ ffec_miibus_writereg(device_t dev, int phy, int reg, int val) struct ffec_softc *sc; sc = device_get_softc(dev); +#ifdef __rtems__ + if (sc->mdio_device) { + return (MIIBUS_WRITEREG(sc->mdio_device, phy, reg, val)); + } + + mtx_lock(&sc->mdio_mtx); +#endif /* __rtems__ */ WR4(sc, FEC_IER_REG, FEC_IER_MII); @@ -411,9 +436,15 @@ ffec_miibus_writereg(device_t dev, int phy, int reg, int val) if (!ffec_miibus_iowait(sc)) { device_printf(dev, "timeout waiting for mii write\n"); +#ifdef __rtems__ + mtx_unlock(&sc->mdio_mtx); +#endif /* __rtems__ */ return (-1); } +#ifdef __rtems__ + mtx_unlock(&sc->mdio_mtx); +#endif /* __rtems__ */ return (0); } @@ -1577,6 +1608,9 @@ ffec_detach(device_t dev) if (sc->mem_res != NULL) bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->mem_res); +#ifdef __rtems__ + mtx_destroy(&sc->mtx); +#endif /* __rtems__ */ FFEC_LOCK_DESTROY(sc); return (0); } @@ -1726,6 +1760,80 @@ ffec_set_txic(struct ffec_softc *sc) ffec_set_ic(sc, FEC_TXIC0_REG, sc->tx_ic_count, sc->tx_ic_time); } +#ifdef __rtems__ +int +ffec_get_phy_information( + struct ffec_softc *sc, + phandle_t node, + device_t dev, + int *phy_addr +) +{ + phandle_t phy_node; + phandle_t parent_node; + pcell_t phy_handle, phy_reg; + device_t other; + phandle_t xref; + + /* Search for the phy-handle and get the address */ + + if (OF_getencprop(node, "phy-handle", (void *)&phy_handle, + sizeof(phy_handle)) <= 0) + return (ENXIO); + + phy_node = OF_node_from_xref(phy_handle); + + if (OF_getencprop(phy_node, "reg", (void *)&phy_reg, + sizeof(phy_reg)) <= 0) + return (ENXIO); + + *phy_addr = phy_reg; + + /* Detect whether PHY handle is connected to this or another FFEC. */ + parent_node = phy_node; + + while (parent_node != 0) { + if (parent_node == node) { + /* PHY is directly connected. That's easy. */ + sc->mdio_device = NULL; + return 0; + } + + /* + * Check whether the node is also an Ethernet controller. Do + * that by just assuming that every Ethernet controller has a + * PHY attached to it. + */ + if (OF_getencprop(parent_node, "phy-handle", + (void *)&phy_handle, sizeof(phy_handle)) > 0) { + /* + * Try to find the device of the other Ethernet + * controller and use that for MDIO communication. + * Note: This is not really a nice workaround but it + * works. + */ + xref = OF_xref_from_node(parent_node); + if (xref == 0) { + device_printf(dev, + "Couldn't get device that handles PHY\n"); + return (ENXIO); + } + other = OF_device_from_xref(xref); + if (other == 0) { + device_printf(dev, + "Couldn't get device that handles PHY\n"); + return (ENXIO); + } + sc->mdio_device = other; + return 0; + } + + parent_node = OF_parent(parent_node); + } + return (ENXIO); +} + +#endif /* __rtems__ */ static int ffec_attach(device_t dev) { @@ -1743,6 +1851,10 @@ ffec_attach(device_t dev) sc->dev = dev; FFEC_LOCK_INIT(sc); +#ifdef __rtems__ + mtx_init(&sc->mtx, device_get_nameunit(sc->dev), + MTX_NETWORK_LOCK, MTX_DEF); +#endif /* __rtems__ */ /* * There are differences in the implementation and features of the FEC @@ -2047,9 +2159,17 @@ ffec_attach(device_t dev) ffec_miigasket_setup(sc); /* Attach the mii driver. */ +#ifdef __rtems__ + OF_device_register_xref(OF_xref_from_node(ofw_node), dev); + if (ffec_get_phy_information(sc, ofw_node, dev, &phynum) != 0) { + phynum = MII_PHY_ANY; + } + (void) dummy; +#else /* __rtems__ */ if (fdt_get_phyaddr(ofw_node, dev, &phynum, &dummy) != 0) { phynum = MII_PHY_ANY; } +#endif /* __rtems__ */ error = mii_attach(dev, &sc->miibus, ifp, ffec_media_change, ffec_media_status, BMSR_DEFCAPMASK, phynum, MII_OFFSET_ANY, (sc->fecflags & FECTYPE_MVF) ? MIIF_FORCEANEG : 0); -- cgit v1.2.3