[PATCH rtems-libbsd 2/2] if_ffec: Allow PHY that is connected to other FFEC
Gedare Bloom
gedare at rtems.org
Wed Jun 1 12:50:22 UTC 2022
Should this be upstreamed?
On Mon, May 23, 2022 at 6:22 AM Christian Mauderer
<christian.mauderer at embedded-brains.de> wrote:
>
> 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);
> --
> 2.35.3
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
More information about the devel
mailing list