Message ID | 20200312160620.29593-2-ioana.ciornei@nxp.com |
---|---|
State | New |
Headers | show |
Series | net: ldpaa_eth: transition to CONFIG_DM_ETH | expand |
On Thu, Mar 12, 2020 at 11:24 AM Ioana Ciornei <ioana.ciornei at nxp.com> wrote: > > Add a driver for the MDIO interface integrated in the mEMAC (Multi-rate > Ethernet Media Access Controller) and the Fman 10G Ethernet MACs. > > Signed-off-by: Ioana Ciornei <ioana.ciornei at nxp.com> > --- > drivers/net/Kconfig | 7 ++ > drivers/net/Makefile | 1 + > drivers/net/fsl_ls_mdio.c | 158 ++++++++++++++++++++++++++++++++++++++ > 3 files changed, 166 insertions(+) > create mode 100644 drivers/net/fsl_ls_mdio.c > > diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig > index 4d1013c98466..bc518f218da6 100644 > --- a/drivers/net/Kconfig > +++ b/drivers/net/Kconfig > @@ -640,4 +640,11 @@ config MVMDIO > > This driver is used by the MVPP2 and MVNETA drivers. > > +config FSL_LS_MDIO > + bool "NXP Layerscape MDIO interface support" > + depends on DM_MDIO > + help > + This driver supports the MDIO bus found on the Fman 10G Ethernet MACs and > + on the mEMAC (which supports both Clauses 22 and 45). > + > endif # NETDEVICES > diff --git a/drivers/net/Makefile b/drivers/net/Makefile > index 6e0a68834d97..6d9b8772b1a5 100644 > --- a/drivers/net/Makefile > +++ b/drivers/net/Makefile > @@ -83,3 +83,4 @@ obj-y += mscc_eswitch/ > obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o > obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o > obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o > +obj-$(CONFIG_FSL_LS_MDIO) += fsl_ls_mdio.o > diff --git a/drivers/net/fsl_ls_mdio.c b/drivers/net/fsl_ls_mdio.c > new file mode 100644 > index 000000000000..845c0ac1ffd8 > --- /dev/null > +++ b/drivers/net/fsl_ls_mdio.c > @@ -0,0 +1,158 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Copyright 2020 NXP > + */ > + > +#include <common.h> > +#include <dm.h> > +#include <errno.h> > +#include <miiphy.h> > +#include <asm/io.h> > +#include <fsl_memac.h> > + > +#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN Is there a reason we have a special separate endian flag for this NIC instead of using a platform config? > +#define memac_out_32(a, v) out_le32(a, v) > +#define memac_clrbits_32(a, v) clrbits_le32(a, v) > +#define memac_setbits_32(a, v) setbits_le32(a, v) > +#else > +#define memac_out_32(a, v) out_be32(a, v) > +#define memac_clrbits_32(a, v) clrbits_be32(a, v) > +#define memac_setbits_32(a, v) setbits_be32(a, v) > +#endif > + > +static u32 memac_in_32(u32 *reg) > +{ > +#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN > + return in_le32(reg); > +#else > + return in_be32(reg); > +#endif > +} > + > +struct fsl_ls_mdio_priv { > + void *regs_base; > +}; > + > +static int dm_fsl_ls_mdio_read(struct udevice *dev, int addr, > + int devad, int reg) > +{ > + struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); > + struct memac_mdio_controller *regs; > + u32 mdio_ctl; > + u32 c45 = 1; > + > + regs = (struct memac_mdio_controller *)(priv->regs_base); > + if (devad == MDIO_DEVAD_NONE) { > + c45 = 0; /* clause 22 */ > + devad = reg & 0x1f; > + memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); > + } else { > + memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); > + } > + > + /* Wait till the bus is free */ > + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) > + ; > + > + /* Set the Port and Device Addrs */ > + mdio_ctl = MDIO_CTL_PORT_ADDR(addr) | MDIO_CTL_DEV_ADDR(devad); > + memac_out_32(®s->mdio_ctl, mdio_ctl); > + > + /* Set the register address */ > + if (c45) > + memac_out_32(®s->mdio_addr, reg & 0xffff); > + > + /* Wait till the bus is free */ > + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) > + ; > + > + /* Initiate the read */ > + mdio_ctl |= MDIO_CTL_READ; > + memac_out_32(®s->mdio_ctl, mdio_ctl); > + > + /* Wait till the MDIO write is complete */ > + while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) > + ; > + > + /* Return all Fs if nothing was there */ > + if (memac_in_32(®s->mdio_stat) & MDIO_STAT_RD_ER) > + return 0xffff; > + > + return memac_in_32(®s->mdio_data) & 0xffff; > + return 0; > +} > + > +static int dm_fsl_ls_mdio_write(struct udevice *dev, int addr, int devad, > + int reg, u16 val) > +{ > + struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); > + struct memac_mdio_controller *regs; > + u32 mdio_ctl; > + u32 c45 = 1; > + > + regs = (struct memac_mdio_controller *)(priv->regs_base); > + if (devad == MDIO_DEVAD_NONE) { > + c45 = 0; /* clause 22 */ > + devad = reg & 0x1f; > + memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); > + } else { > + memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); > + } > + > + /* Wait till the bus is free */ > + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) > + ; > + > + /* Set the port and dev addr */ > + mdio_ctl = MDIO_CTL_PORT_ADDR(addr) | MDIO_CTL_DEV_ADDR(devad); > + memac_out_32(®s->mdio_ctl, mdio_ctl); > + > + /* Set the register address */ > + if (c45) > + memac_out_32(®s->mdio_addr, reg & 0xffff); > + > + /* Wait till the bus is free */ > + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) > + ; > + > + /* Write the value to the register */ > + memac_out_32(®s->mdio_data, MDIO_DATA(val)); > + > + /* Wait till the MDIO write is complete */ > + while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) > + ; > + > + return 0; > +} These two functions are almost identical... It seems you could make a common function to reuse most of the access setup. > + > +static const struct mdio_ops fsl_ls_mdio_ops = { > + .read = dm_fsl_ls_mdio_read, > + .write = dm_fsl_ls_mdio_write, > +}; > + > +static int fsl_ls_mdio_probe(struct udevice *dev) > +{ > + struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); > + struct memac_mdio_controller *regs; > + > + priv->regs_base = dev_read_addr_ptr(dev); > + regs = (struct memac_mdio_controller *)(priv->regs_base); > + > + memac_setbits_32(®s->mdio_stat, > + MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG); > + > + return 0; > +} > + > +static const struct udevice_id fsl_ls_mdio_of_ids[] = { > + { .compatible = "fsl,ls-mdio" }, > +}; > + > +U_BOOT_DRIVER(fsl_ls_mdio) = { > + .name = "fsl_ls_mdio", > + .id = UCLASS_MDIO, > + .of_match = fsl_ls_mdio_of_ids, > + .probe = fsl_ls_mdio_probe, > + .ops = &fsl_ls_mdio_ops, > + .priv_auto_alloc_size = sizeof(struct fsl_ls_mdio_priv), > +}; > -- > 2.17.1 >
>-----Original Message----- >From: U-Boot <u-boot-bounces at lists.denx.de> On Behalf Of Ioana Ciornei >Sent: Thursday, March 12, 2020 9:36 PM >To: Priyanka Jain <priyanka.jain at nxp.com>; joe.hershberger at ni.com; u- >boot at lists.denx.de >Cc: Florin Laurentiu Chiculita <florinlaurentiu.chiculita at nxp.com>; Madalin >Bucur (OSS) <madalin.bucur at oss.nxp.com>; Ioana Ciornei ><ioana.ciornei at nxp.com> >Subject: [PATCH 01/14] drivers: net: add Layerscape mEMAC MDIO driver > >Add a driver for the MDIO interface integrated in the mEMAC (Multi-rate >Ethernet Media Access Controller) and the Fman 10G Ethernet MACs. > >Signed-off-by: Ioana Ciornei <ioana.ciornei at nxp.com> >--- > drivers/net/Kconfig | 7 ++ > drivers/net/Makefile | 1 + > drivers/net/fsl_ls_mdio.c | 158 ++++++++++++++++++++++++++++++++++++++ > 3 files changed, 166 insertions(+) > create mode 100644 drivers/net/fsl_ls_mdio.c > >diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index >4d1013c98466..bc518f218da6 100644 >--- a/drivers/net/Kconfig >+++ b/drivers/net/Kconfig >@@ -640,4 +640,11 @@ config MVMDIO > > This driver is used by the MVPP2 and MVNETA drivers. > >+config FSL_LS_MDIO Please use prefix NXP for new configs >+ bool "NXP Layerscape MDIO interface support" >+ depends on DM_MDIO >+ help >+ This driver supports the MDIO bus found on the Fman 10G Ethernet >MACs and >+ on the mEMAC (which supports both Clauses 22 and 45). >+ > endif # NETDEVICES >diff --git a/drivers/net/Makefile b/drivers/net/Makefile index >6e0a68834d97..6d9b8772b1a5 100644 >--- a/drivers/net/Makefile >+++ b/drivers/net/Makefile >@@ -83,3 +83,4 @@ obj-y += mscc_eswitch/ > obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o > obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o > obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o >+obj-$(CONFIG_FSL_LS_MDIO) += fsl_ls_mdio.o >diff --git a/drivers/net/fsl_ls_mdio.c b/drivers/net/fsl_ls_mdio.c new file mode >100644 index 000000000000..845c0ac1ffd8 >--- /dev/null >+++ b/drivers/net/fsl_ls_mdio.c >@@ -0,0 +1,158 @@ >+// SPDX-License-Identifier: GPL-2.0+ >+/* >+ * Copyright 2020 NXP >+ */ >+ >+#include <common.h> >+#include <dm.h> >+#include <errno.h> >+#include <miiphy.h> >+#include <asm/io.h> >+#include <fsl_memac.h> >+ >+#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN >+#define memac_out_32(a, v) out_le32(a, v) >+#define memac_clrbits_32(a, v) clrbits_le32(a, v) >+#define memac_setbits_32(a, v) setbits_le32(a, v) >+#else >+#define memac_out_32(a, v) out_be32(a, v) >+#define memac_clrbits_32(a, v) clrbits_be32(a, v) >+#define memac_setbits_32(a, v) setbits_be32(a, v) >+#endif >+ >+static u32 memac_in_32(u32 *reg) >+{ >+#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN >+ return in_le32(reg); >+#else >+ return in_be32(reg); >+#endif >+} >+ >+struct fsl_ls_mdio_priv { >+ void *regs_base; >+}; >+ >+static int dm_fsl_ls_mdio_read(struct udevice *dev, int addr, >+ int devad, int reg) >+{ >+ struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); >+ struct memac_mdio_controller *regs; >+ u32 mdio_ctl; >+ u32 c45 = 1; >+ >+ regs = (struct memac_mdio_controller *)(priv->regs_base); >+ if (devad == MDIO_DEVAD_NONE) { >+ c45 = 0; /* clause 22 */ >+ devad = reg & 0x1f; I don't see devad getting used in below code. >+ memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); >+ } else { >+ memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); >+ } >+ >+ /* Wait till the bus is free */ >+ while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) >+ ; >+ >+ /* Set the Port and Device Addrs */ >+ mdio_ctl = MDIO_CTL_PORT_ADDR(addr) | >MDIO_CTL_DEV_ADDR(devad); >+ memac_out_32(®s->mdio_ctl, mdio_ctl); >+ >+ /* Set the register address */ >+ if (c45) >+ memac_out_32(®s->mdio_addr, reg & 0xffff); >+ >+ /* Wait till the bus is free */ >+ while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) >+ ; >+ >+ /* Initiate the read */ >+ mdio_ctl |= MDIO_CTL_READ; >+ memac_out_32(®s->mdio_ctl, mdio_ctl); >+ >+ /* Wait till the MDIO write is complete */ >+ while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) >+ ; >+ >+ /* Return all Fs if nothing was there */ >+ if (memac_in_32(®s->mdio_stat) & MDIO_STAT_RD_ER) >+ return 0xffff; >+ >+ return memac_in_32(®s->mdio_data) & 0xffff; >+ return 0; >+} >+ >+static int dm_fsl_ls_mdio_write(struct udevice *dev, int addr, int devad, >+ int reg, u16 val) >+{ >+ struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); >+ struct memac_mdio_controller *regs; >+ u32 mdio_ctl; >+ u32 c45 = 1; >+ >+ regs = (struct memac_mdio_controller *)(priv->regs_base); >+ if (devad == MDIO_DEVAD_NONE) { >+ c45 = 0; /* clause 22 */ >+ devad = reg & 0x1f; Sane commen as above >+ memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); >+ } else { >+ memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); >+ } >+ >+ /* Wait till the bus is free */ >+ while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) >+ ; >+ >+ /* Set the port and dev addr */ >+ mdio_ctl = MDIO_CTL_PORT_ADDR(addr) | >MDIO_CTL_DEV_ADDR(devad); >+ memac_out_32(®s->mdio_ctl, mdio_ctl); >+ >+ /* Set the register address */ >+ if (c45) >+ memac_out_32(®s->mdio_addr, reg & 0xffff); >+ >+ /* Wait till the bus is free */ >+ while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) >+ ; >+ >+ /* Write the value to the register */ >+ memac_out_32(®s->mdio_data, MDIO_DATA(val)); >+ >+ /* Wait till the MDIO write is complete */ >+ while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) >+ ; >+ >+ return 0; >+} >+ >+static const struct mdio_ops fsl_ls_mdio_ops = { >+ .read = dm_fsl_ls_mdio_read, >+ .write = dm_fsl_ls_mdio_write, >+}; >+ >+static int fsl_ls_mdio_probe(struct udevice *dev) { >+ struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); >+ struct memac_mdio_controller *regs; >+ >+ priv->regs_base = dev_read_addr_ptr(dev); >+ regs = (struct memac_mdio_controller *)(priv->regs_base); >+ >+ memac_setbits_32(®s->mdio_stat, >+ MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG); >+ >+ return 0; >+} >+ >+static const struct udevice_id fsl_ls_mdio_of_ids[] = { >+ { .compatible = "fsl,ls-mdio" }, >+}; >+ >+U_BOOT_DRIVER(fsl_ls_mdio) = { >+ .name = "fsl_ls_mdio", >+ .id = UCLASS_MDIO, >+ .of_match = fsl_ls_mdio_of_ids, >+ .probe = fsl_ls_mdio_probe, >+ .ops = &fsl_ls_mdio_ops, >+ .priv_auto_alloc_size = sizeof(struct fsl_ls_mdio_priv), }; >-- >2.17.1 Regards Priyanka
> Subject: RE: [PATCH 01/14] drivers: net: add Layerscape mEMAC MDIO driver > > >-----Original Message----- > >From: U-Boot <u-boot-bounces at lists.denx.de> On Behalf Of Ioana Ciornei > >Sent: Thursday, March 12, 2020 9:36 PM > >To: Priyanka Jain <priyanka.jain at nxp.com>; joe.hershberger at ni.com; u- > >boot at lists.denx.de > >Cc: Florin Laurentiu Chiculita <florinlaurentiu.chiculita at nxp.com>; > >Madalin Bucur (OSS) <madalin.bucur at oss.nxp.com>; Ioana Ciornei > ><ioana.ciornei at nxp.com> > >Subject: [PATCH 01/14] drivers: net: add Layerscape mEMAC MDIO driver > > > >Add a driver for the MDIO interface integrated in the mEMAC (Multi-rate > >Ethernet Media Access Controller) and the Fman 10G Ethernet MACs. > > > >Signed-off-by: Ioana Ciornei <ioana.ciornei at nxp.com> > >--- > > drivers/net/Kconfig | 7 ++ > > drivers/net/Makefile | 1 + > > drivers/net/fsl_ls_mdio.c | 158 ++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 166 insertions(+) > > create mode 100644 drivers/net/fsl_ls_mdio.c > > > >diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index > >4d1013c98466..bc518f218da6 100644 > >--- a/drivers/net/Kconfig > >+++ b/drivers/net/Kconfig > >@@ -640,4 +640,11 @@ config MVMDIO > > > > This driver is used by the MVPP2 and MVNETA drivers. > > > >+config FSL_LS_MDIO > Please use prefix NXP for new configs > >+ bool "NXP Layerscape MDIO interface support" > >+ depends on DM_MDIO > >+ help > >+ This driver supports the MDIO bus found on the Fman 10G Ethernet > >MACs and > >+ on the mEMAC (which supports both Clauses 22 and 45). > >+ > > endif # NETDEVICES > >diff --git a/drivers/net/Makefile b/drivers/net/Makefile index > >6e0a68834d97..6d9b8772b1a5 100644 > >--- a/drivers/net/Makefile > >+++ b/drivers/net/Makefile > >@@ -83,3 +83,4 @@ obj-y += mscc_eswitch/ > > obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o > > obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o > > obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o > >+obj-$(CONFIG_FSL_LS_MDIO) += fsl_ls_mdio.o > >diff --git a/drivers/net/fsl_ls_mdio.c b/drivers/net/fsl_ls_mdio.c new > >file mode > >100644 index 000000000000..845c0ac1ffd8 > >--- /dev/null > >+++ b/drivers/net/fsl_ls_mdio.c > >@@ -0,0 +1,158 @@ > >+// SPDX-License-Identifier: GPL-2.0+ > >+/* > >+ * Copyright 2020 NXP > >+ */ > >+ > >+#include <common.h> > >+#include <dm.h> > >+#include <errno.h> > >+#include <miiphy.h> > >+#include <asm/io.h> > >+#include <fsl_memac.h> > >+ > >+#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN > >+#define memac_out_32(a, v) out_le32(a, v) > >+#define memac_clrbits_32(a, v) clrbits_le32(a, v) > >+#define memac_setbits_32(a, v) setbits_le32(a, v) > >+#else > >+#define memac_out_32(a, v) out_be32(a, v) > >+#define memac_clrbits_32(a, v) clrbits_be32(a, v) > >+#define memac_setbits_32(a, v) setbits_be32(a, v) > >+#endif > >+ > >+static u32 memac_in_32(u32 *reg) > >+{ > >+#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN > >+ return in_le32(reg); > >+#else > >+ return in_be32(reg); > >+#endif > >+} > >+ > >+struct fsl_ls_mdio_priv { > >+ void *regs_base; > >+}; > >+ > >+static int dm_fsl_ls_mdio_read(struct udevice *dev, int addr, > >+ int devad, int reg) > >+{ > >+ struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); > >+ struct memac_mdio_controller *regs; > >+ u32 mdio_ctl; > >+ u32 c45 = 1; > >+ > >+ regs = (struct memac_mdio_controller *)(priv->regs_base); > >+ if (devad == MDIO_DEVAD_NONE) { > >+ c45 = 0; /* clause 22 */ > >+ devad = reg & 0x1f; > > I don't see devad getting used in below code. > It it used below in setting up the port and device address. Below is the exact snippet: + mdio_ctl = MDIO_CTL_PORT_ADDR(addr) | MDIO_CTL_DEV_ADDR(devad); + memac_out_32(®s->mdio_ctl, mdio_ctl); > >+ memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); > >+ } else { > >+ memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); > >+ } > >+ > >+ /* Wait till the bus is free */ > >+ while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) > >+ ; > >+ > >+ /* Set the Port and Device Addrs */ > >+ mdio_ctl = MDIO_CTL_PORT_ADDR(addr) | > >MDIO_CTL_DEV_ADDR(devad); > >+ memac_out_32(®s->mdio_ctl, mdio_ctl); > >+ > >+ /* Set the register address */ > >+ if (c45) > >+ memac_out_32(®s->mdio_addr, reg & 0xffff); > >+ > >+ /* Wait till the bus is free */ > >+ while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) > >+ ; > >+ > >+ /* Initiate the read */ > >+ mdio_ctl |= MDIO_CTL_READ; > >+ memac_out_32(®s->mdio_ctl, mdio_ctl); > >+ > >+ /* Wait till the MDIO write is complete */ > >+ while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) > >+ ; > >+ > >+ /* Return all Fs if nothing was there */ > >+ if (memac_in_32(®s->mdio_stat) & MDIO_STAT_RD_ER) > >+ return 0xffff; > >+ > >+ return memac_in_32(®s->mdio_data) & 0xffff; > >+ return 0; > >+} > >+ > >+static int dm_fsl_ls_mdio_write(struct udevice *dev, int addr, int devad, > >+ int reg, u16 val) > >+{ > >+ struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); > >+ struct memac_mdio_controller *regs; > >+ u32 mdio_ctl; > >+ u32 c45 = 1; > >+ > >+ regs = (struct memac_mdio_controller *)(priv->regs_base); > >+ if (devad == MDIO_DEVAD_NONE) { > >+ c45 = 0; /* clause 22 */ > >+ devad = reg & 0x1f; > Sane commen as above > >+ memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); > >+ } else { > >+ memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); > >+ } > >+ > >+ /* Wait till the bus is free */ > >+ while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) > >+ ; > >+ > >+ /* Set the port and dev addr */ > >+ mdio_ctl = MDIO_CTL_PORT_ADDR(addr) | > >MDIO_CTL_DEV_ADDR(devad); > >+ memac_out_32(®s->mdio_ctl, mdio_ctl); > >+ > >+ /* Set the register address */ > >+ if (c45) > >+ memac_out_32(®s->mdio_addr, reg & 0xffff); > >+ > >+ /* Wait till the bus is free */ > >+ while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) > >+ ; > >+ > >+ /* Write the value to the register */ > >+ memac_out_32(®s->mdio_data, MDIO_DATA(val)); > >+ > >+ /* Wait till the MDIO write is complete */ > >+ while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) > >+ ; > >+ > >+ return 0; > >+} > >+ > >+static const struct mdio_ops fsl_ls_mdio_ops = { > >+ .read = dm_fsl_ls_mdio_read, > >+ .write = dm_fsl_ls_mdio_write, > >+}; > >+ > >+static int fsl_ls_mdio_probe(struct udevice *dev) { > >+ struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); > >+ struct memac_mdio_controller *regs; > >+ > >+ priv->regs_base = dev_read_addr_ptr(dev); > >+ regs = (struct memac_mdio_controller *)(priv->regs_base); > >+ > >+ memac_setbits_32(®s->mdio_stat, > >+ MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG); > >+ > >+ return 0; > >+} > >+ > >+static const struct udevice_id fsl_ls_mdio_of_ids[] = { > >+ { .compatible = "fsl,ls-mdio" }, > >+}; > >+ > >+U_BOOT_DRIVER(fsl_ls_mdio) = { > >+ .name = "fsl_ls_mdio", > >+ .id = UCLASS_MDIO, > >+ .of_match = fsl_ls_mdio_of_ids, > >+ .probe = fsl_ls_mdio_probe, > >+ .ops = &fsl_ls_mdio_ops, > >+ .priv_auto_alloc_size = sizeof(struct fsl_ls_mdio_priv), }; > >-- > >2.17.1 > > Regards > Priyanka
> Subject: Re: [PATCH 01/14] drivers: net: add Layerscape mEMAC MDIO driver > > On Thu, Mar 12, 2020 at 11:24 AM Ioana Ciornei <ioana.ciornei at nxp.com> > wrote: > > > > Add a driver for the MDIO interface integrated in the mEMAC > > (Multi-rate Ethernet Media Access Controller) and the Fman 10G Ethernet > MACs. > > > > Signed-off-by: Ioana Ciornei <ioana.ciornei at nxp.com> > > --- > > drivers/net/Kconfig | 7 ++ > > drivers/net/Makefile | 1 + > > drivers/net/fsl_ls_mdio.c | 158 > > ++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 166 insertions(+) > > create mode 100644 drivers/net/fsl_ls_mdio.c > > > > diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index > > 4d1013c98466..bc518f218da6 100644 > > --- a/drivers/net/Kconfig > > +++ b/drivers/net/Kconfig > > @@ -640,4 +640,11 @@ config MVMDIO > > > > This driver is used by the MVPP2 and MVNETA drivers. > > > > +config FSL_LS_MDIO > > + bool "NXP Layerscape MDIO interface support" > > + depends on DM_MDIO > > + help > > + This driver supports the MDIO bus found on the Fman 10G Ethernet > MACs and > > + on the mEMAC (which supports both Clauses 22 and 45). > > + > > endif # NETDEVICES > > diff --git a/drivers/net/Makefile b/drivers/net/Makefile index > > 6e0a68834d97..6d9b8772b1a5 100644 > > --- a/drivers/net/Makefile > > +++ b/drivers/net/Makefile > > @@ -83,3 +83,4 @@ obj-y += mscc_eswitch/ > > obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o > > obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o > > obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o > > +obj-$(CONFIG_FSL_LS_MDIO) += fsl_ls_mdio.o > > diff --git a/drivers/net/fsl_ls_mdio.c b/drivers/net/fsl_ls_mdio.c new > > file mode 100644 index 000000000000..845c0ac1ffd8 > > --- /dev/null > > +++ b/drivers/net/fsl_ls_mdio.c > > @@ -0,0 +1,158 @@ > > +// SPDX-License-Identifier: GPL-2.0+ > > +/* > > + * Copyright 2020 NXP > > + */ > > + > > +#include <common.h> > > +#include <dm.h> > > +#include <errno.h> > > +#include <miiphy.h> > > +#include <asm/io.h> > > +#include <fsl_memac.h> > > + > > +#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN > > Is there a reason we have a special separate endian flag for this NIC instead of > using a platform config? > The same MAC IP (mEMAC) is integrated in both gen 1 DPAA (FMan) and gen 2 DPAA (WRIOP - Wire Rate IO Processor) based SoCs but with different endianness settings. For example, in DPAA2 it's integrated as little-endian while in DPAA1 based SoCs (even those that are ARM based) it?s integrated as big-endian. This is why a different config is used and not directly the platform config. > > +#define memac_out_32(a, v) out_le32(a, v) > > +#define memac_clrbits_32(a, v) clrbits_le32(a, v) #define > > +memac_setbits_32(a, v) setbits_le32(a, v) #else > > +#define memac_out_32(a, v) out_be32(a, v) > > +#define memac_clrbits_32(a, v) clrbits_be32(a, v) #define > > +memac_setbits_32(a, v) setbits_be32(a, v) #endif > > + > > +static u32 memac_in_32(u32 *reg) > > +{ > > +#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN > > + return in_le32(reg); > > +#else > > + return in_be32(reg); > > +#endif > > +} > > + > > +struct fsl_ls_mdio_priv { > > + void *regs_base; > > +}; > > + > > +static int dm_fsl_ls_mdio_read(struct udevice *dev, int addr, > > + int devad, int reg) { > > + struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); > > + struct memac_mdio_controller *regs; > > + u32 mdio_ctl; > > + u32 c45 = 1; > > + > > + regs = (struct memac_mdio_controller *)(priv->regs_base); > > + if (devad == MDIO_DEVAD_NONE) { > > + c45 = 0; /* clause 22 */ > > + devad = reg & 0x1f; > > + memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); > > + } else { > > + memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); > > + } > > + > > + /* Wait till the bus is free */ > > + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) > > + ; > > + > > + /* Set the Port and Device Addrs */ > > + mdio_ctl = MDIO_CTL_PORT_ADDR(addr) | > MDIO_CTL_DEV_ADDR(devad); > > + memac_out_32(®s->mdio_ctl, mdio_ctl); > > + > > + /* Set the register address */ > > + if (c45) > > + memac_out_32(®s->mdio_addr, reg & 0xffff); > > + > > + /* Wait till the bus is free */ > > + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) > > + ; > > + > > + /* Initiate the read */ > > + mdio_ctl |= MDIO_CTL_READ; > > + memac_out_32(®s->mdio_ctl, mdio_ctl); > > + > > + /* Wait till the MDIO write is complete */ > > + while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) > > + ; > > + > > + /* Return all Fs if nothing was there */ > > + if (memac_in_32(®s->mdio_stat) & MDIO_STAT_RD_ER) > > + return 0xffff; > > + > > + return memac_in_32(®s->mdio_data) & 0xffff; > > + return 0; > > +} > > + > > +static int dm_fsl_ls_mdio_write(struct udevice *dev, int addr, int devad, > > + int reg, u16 val) { > > + struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); > > + struct memac_mdio_controller *regs; > > + u32 mdio_ctl; > > + u32 c45 = 1; > > + > > + regs = (struct memac_mdio_controller *)(priv->regs_base); > > + if (devad == MDIO_DEVAD_NONE) { > > + c45 = 0; /* clause 22 */ > > + devad = reg & 0x1f; > > + memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); > > + } else { > > + memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); > > + } > > + > > + /* Wait till the bus is free */ > > + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) > > + ; > > + > > + /* Set the port and dev addr */ > > + mdio_ctl = MDIO_CTL_PORT_ADDR(addr) | > MDIO_CTL_DEV_ADDR(devad); > > + memac_out_32(®s->mdio_ctl, mdio_ctl); > > + > > + /* Set the register address */ > > + if (c45) > > + memac_out_32(®s->mdio_addr, reg & 0xffff); > > + > > + /* Wait till the bus is free */ > > + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) > > + ; > > + > > + /* Write the value to the register */ > > + memac_out_32(®s->mdio_data, MDIO_DATA(val)); > > + > > + /* Wait till the MDIO write is complete */ > > + while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) > > + ; > > + > > + return 0; > > +} > > These two functions are almost identical... It seems you could make a common > function to reuse most of the access setup. > That's a good idea. I'll refactor this part in v2. Thanks, Ioana > > + > > +static const struct mdio_ops fsl_ls_mdio_ops = { > > + .read = dm_fsl_ls_mdio_read, > > + .write = dm_fsl_ls_mdio_write, }; > > + > > +static int fsl_ls_mdio_probe(struct udevice *dev) { > > + struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); > > + struct memac_mdio_controller *regs; > > + > > + priv->regs_base = dev_read_addr_ptr(dev); > > + regs = (struct memac_mdio_controller *)(priv->regs_base); > > + > > + memac_setbits_32(®s->mdio_stat, > > + MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG); > > + > > + return 0; > > +} > > + > > +static const struct udevice_id fsl_ls_mdio_of_ids[] = { > > + { .compatible = "fsl,ls-mdio" }, }; > > + > > +U_BOOT_DRIVER(fsl_ls_mdio) = { > > + .name = "fsl_ls_mdio", > > + .id = UCLASS_MDIO, > > + .of_match = fsl_ls_mdio_of_ids, > > + .probe = fsl_ls_mdio_probe, > > + .ops = &fsl_ls_mdio_ops, > > + .priv_auto_alloc_size = sizeof(struct fsl_ls_mdio_priv), }; > > -- > > 2.17.1 > >
>-----Original Message----- >From: Ioana Ciornei <ioana.ciornei at nxp.com> >Sent: Wednesday, March 18, 2020 5:33 PM >To: Priyanka Jain (OSS) <priyanka.jain at oss.nxp.com>; >joe.hershberger at ni.com; u-boot at lists.denx.de >Cc: Florin Laurentiu Chiculita <florinlaurentiu.chiculita at nxp.com>; Madalin >Bucur (OSS) <madalin.bucur at oss.nxp.com> >Subject: RE: [PATCH 01/14] drivers: net: add Layerscape mEMAC MDIO driver > >> Subject: RE: [PATCH 01/14] drivers: net: add Layerscape mEMAC MDIO >> driver >> >> >-----Original Message----- >> >From: U-Boot <u-boot-bounces at lists.denx.de> On Behalf Of Ioana >> >Ciornei >> >Sent: Thursday, March 12, 2020 9:36 PM >> >To: Priyanka Jain <priyanka.jain at nxp.com>; joe.hershberger at ni.com; u- >> >boot at lists.denx.de >> >Cc: Florin Laurentiu Chiculita <florinlaurentiu.chiculita at nxp.com>; >> >Madalin Bucur (OSS) <madalin.bucur at oss.nxp.com>; Ioana Ciornei >> ><ioana.ciornei at nxp.com> >> >Subject: [PATCH 01/14] drivers: net: add Layerscape mEMAC MDIO driver >> > >> >Add a driver for the MDIO interface integrated in the mEMAC >> >(Multi-rate Ethernet Media Access Controller) and the Fman 10G Ethernet >MACs. >> > >> >Signed-off-by: Ioana Ciornei <ioana.ciornei at nxp.com> >> >--- >> > drivers/net/Kconfig | 7 ++ >> > drivers/net/Makefile | 1 + >> > drivers/net/fsl_ls_mdio.c | 158 >> >++++++++++++++++++++++++++++++++++++++ >> > 3 files changed, 166 insertions(+) >> > create mode 100644 drivers/net/fsl_ls_mdio.c >> > >> >diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index >> >4d1013c98466..bc518f218da6 100644 >> >--- a/drivers/net/Kconfig >> >+++ b/drivers/net/Kconfig >> >@@ -640,4 +640,11 @@ config MVMDIO >> > >> > This driver is used by the MVPP2 and MVNETA drivers. >> > >> >+config FSL_LS_MDIO >> Please use prefix NXP for new configs >> >+ bool "NXP Layerscape MDIO interface support" >> >+ depends on DM_MDIO >> >+ help >> >+ This driver supports the MDIO bus found on the Fman 10G Ethernet >> >MACs and >> >+ on the mEMAC (which supports both Clauses 22 and 45). >> >+ >> > endif # NETDEVICES >> >diff --git a/drivers/net/Makefile b/drivers/net/Makefile index >> >6e0a68834d97..6d9b8772b1a5 100644 >> >--- a/drivers/net/Makefile >> >+++ b/drivers/net/Makefile >> >@@ -83,3 +83,4 @@ obj-y += mscc_eswitch/ >> > obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o >> > obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o >> > obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o >> >+obj-$(CONFIG_FSL_LS_MDIO) += fsl_ls_mdio.o >> >diff --git a/drivers/net/fsl_ls_mdio.c b/drivers/net/fsl_ls_mdio.c >> >new file mode >> >100644 index 000000000000..845c0ac1ffd8 >> >--- /dev/null >> >+++ b/drivers/net/fsl_ls_mdio.c >> >@@ -0,0 +1,158 @@ >> >+// SPDX-License-Identifier: GPL-2.0+ >> >+/* >> >+ * Copyright 2020 NXP >> >+ */ >> >+ >> >+#include <common.h> >> >+#include <dm.h> >> >+#include <errno.h> >> >+#include <miiphy.h> >> >+#include <asm/io.h> >> >+#include <fsl_memac.h> >> >+ >> >+#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN >> >+#define memac_out_32(a, v) out_le32(a, v) >> >+#define memac_clrbits_32(a, v) clrbits_le32(a, v) >> >+#define memac_setbits_32(a, v) setbits_le32(a, v) >> >+#else >> >+#define memac_out_32(a, v) out_be32(a, v) >> >+#define memac_clrbits_32(a, v) clrbits_be32(a, v) >> >+#define memac_setbits_32(a, v) setbits_be32(a, v) >> >+#endif >> >+ >> >+static u32 memac_in_32(u32 *reg) >> >+{ >> >+#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN >> >+ return in_le32(reg); >> >+#else >> >+ return in_be32(reg); >> >+#endif >> >+} >> >+ >> >+struct fsl_ls_mdio_priv { >> >+ void *regs_base; >> >+}; >> >+ >> >+static int dm_fsl_ls_mdio_read(struct udevice *dev, int addr, >> >+ int devad, int reg) >> >+{ >> >+ struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); >> >+ struct memac_mdio_controller *regs; >> >+ u32 mdio_ctl; >> >+ u32 c45 = 1; >> >+ >> >+ regs = (struct memac_mdio_controller *)(priv->regs_base); >> >+ if (devad == MDIO_DEVAD_NONE) { >> >+ c45 = 0; /* clause 22 */ >> >+ devad = reg & 0x1f; >> >> I don't see devad getting used in below code. >> > >It it used below in setting up the port and device address. >Below is the exact snippet: > >+ mdio_ctl = MDIO_CTL_PORT_ADDR(addr) | >MDIO_CTL_DEV_ADDR(devad); Thanks for pointing. Priyanka <snip>
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 4d1013c98466..bc518f218da6 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -640,4 +640,11 @@ config MVMDIO This driver is used by the MVPP2 and MVNETA drivers. +config FSL_LS_MDIO + bool "NXP Layerscape MDIO interface support" + depends on DM_MDIO + help + This driver supports the MDIO bus found on the Fman 10G Ethernet MACs and + on the mEMAC (which supports both Clauses 22 and 45). + endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 6e0a68834d97..6d9b8772b1a5 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -83,3 +83,4 @@ obj-y += mscc_eswitch/ obj-$(CONFIG_HIGMACV300_ETH) += higmacv300.o obj-$(CONFIG_MDIO_SANDBOX) += mdio_sandbox.o obj-$(CONFIG_FSL_ENETC) += fsl_enetc.o fsl_enetc_mdio.o +obj-$(CONFIG_FSL_LS_MDIO) += fsl_ls_mdio.o diff --git a/drivers/net/fsl_ls_mdio.c b/drivers/net/fsl_ls_mdio.c new file mode 100644 index 000000000000..845c0ac1ffd8 --- /dev/null +++ b/drivers/net/fsl_ls_mdio.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2020 NXP + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <miiphy.h> +#include <asm/io.h> +#include <fsl_memac.h> + +#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN +#define memac_out_32(a, v) out_le32(a, v) +#define memac_clrbits_32(a, v) clrbits_le32(a, v) +#define memac_setbits_32(a, v) setbits_le32(a, v) +#else +#define memac_out_32(a, v) out_be32(a, v) +#define memac_clrbits_32(a, v) clrbits_be32(a, v) +#define memac_setbits_32(a, v) setbits_be32(a, v) +#endif + +static u32 memac_in_32(u32 *reg) +{ +#ifdef CONFIG_SYS_MEMAC_LITTLE_ENDIAN + return in_le32(reg); +#else + return in_be32(reg); +#endif +} + +struct fsl_ls_mdio_priv { + void *regs_base; +}; + +static int dm_fsl_ls_mdio_read(struct udevice *dev, int addr, + int devad, int reg) +{ + struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); + struct memac_mdio_controller *regs; + u32 mdio_ctl; + u32 c45 = 1; + + regs = (struct memac_mdio_controller *)(priv->regs_base); + if (devad == MDIO_DEVAD_NONE) { + c45 = 0; /* clause 22 */ + devad = reg & 0x1f; + memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); + } else { + memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); + } + + /* Wait till the bus is free */ + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) + ; + + /* Set the Port and Device Addrs */ + mdio_ctl = MDIO_CTL_PORT_ADDR(addr) | MDIO_CTL_DEV_ADDR(devad); + memac_out_32(®s->mdio_ctl, mdio_ctl); + + /* Set the register address */ + if (c45) + memac_out_32(®s->mdio_addr, reg & 0xffff); + + /* Wait till the bus is free */ + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) + ; + + /* Initiate the read */ + mdio_ctl |= MDIO_CTL_READ; + memac_out_32(®s->mdio_ctl, mdio_ctl); + + /* Wait till the MDIO write is complete */ + while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) + ; + + /* Return all Fs if nothing was there */ + if (memac_in_32(®s->mdio_stat) & MDIO_STAT_RD_ER) + return 0xffff; + + return memac_in_32(®s->mdio_data) & 0xffff; + return 0; +} + +static int dm_fsl_ls_mdio_write(struct udevice *dev, int addr, int devad, + int reg, u16 val) +{ + struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); + struct memac_mdio_controller *regs; + u32 mdio_ctl; + u32 c45 = 1; + + regs = (struct memac_mdio_controller *)(priv->regs_base); + if (devad == MDIO_DEVAD_NONE) { + c45 = 0; /* clause 22 */ + devad = reg & 0x1f; + memac_clrbits_32(®s->mdio_stat, MDIO_STAT_ENC); + } else { + memac_setbits_32(®s->mdio_stat, MDIO_STAT_ENC); + } + + /* Wait till the bus is free */ + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) + ; + + /* Set the port and dev addr */ + mdio_ctl = MDIO_CTL_PORT_ADDR(addr) | MDIO_CTL_DEV_ADDR(devad); + memac_out_32(®s->mdio_ctl, mdio_ctl); + + /* Set the register address */ + if (c45) + memac_out_32(®s->mdio_addr, reg & 0xffff); + + /* Wait till the bus is free */ + while ((memac_in_32(®s->mdio_stat)) & MDIO_STAT_BSY) + ; + + /* Write the value to the register */ + memac_out_32(®s->mdio_data, MDIO_DATA(val)); + + /* Wait till the MDIO write is complete */ + while ((memac_in_32(®s->mdio_data)) & MDIO_DATA_BSY) + ; + + return 0; +} + +static const struct mdio_ops fsl_ls_mdio_ops = { + .read = dm_fsl_ls_mdio_read, + .write = dm_fsl_ls_mdio_write, +}; + +static int fsl_ls_mdio_probe(struct udevice *dev) +{ + struct fsl_ls_mdio_priv *priv = dev_get_priv(dev); + struct memac_mdio_controller *regs; + + priv->regs_base = dev_read_addr_ptr(dev); + regs = (struct memac_mdio_controller *)(priv->regs_base); + + memac_setbits_32(®s->mdio_stat, + MDIO_STAT_CLKDIV(258) | MDIO_STAT_NEG); + + return 0; +} + +static const struct udevice_id fsl_ls_mdio_of_ids[] = { + { .compatible = "fsl,ls-mdio" }, +}; + +U_BOOT_DRIVER(fsl_ls_mdio) = { + .name = "fsl_ls_mdio", + .id = UCLASS_MDIO, + .of_match = fsl_ls_mdio_of_ids, + .probe = fsl_ls_mdio_probe, + .ops = &fsl_ls_mdio_ops, + .priv_auto_alloc_size = sizeof(struct fsl_ls_mdio_priv), +};
Add a driver for the MDIO interface integrated in the mEMAC (Multi-rate Ethernet Media Access Controller) and the Fman 10G Ethernet MACs. Signed-off-by: Ioana Ciornei <ioana.ciornei at nxp.com> --- drivers/net/Kconfig | 7 ++ drivers/net/Makefile | 1 + drivers/net/fsl_ls_mdio.c | 158 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+) create mode 100644 drivers/net/fsl_ls_mdio.c