diff mbox series

[U-Boot,v2,1/3] net: phy: Add support for accessing MMD PHY registers

Message ID 20190123131314.4514-2-ccaione@baylibre.com
State Changes Requested
Delegated to: Joe Hershberger
Headers show
Series Add MMD PHY helpers | expand

Commit Message

Carlo Caione Jan. 23, 2019, 1:13 p.m. UTC
Two new helper functions (phy_read_mmd() and phy_write_mmd()) are added
to allow access to the MMD PHY registers.

The MMD PHY registers can be accessed by two means:

1. Using two new MMD access function hooks in the PHY driver. These
functions can be implemented when the PHY driver does not support the
standard IEEE Compatible clause 45 access mechanism described in clause
22 or if the PHY uses its own non-standard access mechanism.

2. The standard clause 45 access extensions to the MMD registers through
the indirection registers (clause 22) in all the other cases.

Signed-off-by: Carlo Caione <ccaione@baylibre.com>
---
 drivers/net/phy/phy.c |  4 +++
 include/phy.h         | 62 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+)

Comments

Joe Hershberger Jan. 23, 2019, 2:12 p.m. UTC | #1
On Wed, Jan 23, 2019 at 7:14 AM Carlo Caione <ccaione@baylibre.com> wrote:
>
> Two new helper functions (phy_read_mmd() and phy_write_mmd()) are added
> to allow access to the MMD PHY registers.
>
> The MMD PHY registers can be accessed by two means:
>
> 1. Using two new MMD access function hooks in the PHY driver. These
> functions can be implemented when the PHY driver does not support the
> standard IEEE Compatible clause 45 access mechanism described in clause
> 22 or if the PHY uses its own non-standard access mechanism.
>
> 2. The standard clause 45 access extensions to the MMD registers through
> the indirection registers (clause 22) in all the other cases.
>
> Signed-off-by: Carlo Caione <ccaione@baylibre.com>
> ---
>  drivers/net/phy/phy.c |  4 +++
>  include/phy.h         | 62 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 66 insertions(+)
>
> diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
> index cda4caa803..6769047407 100644
> --- a/drivers/net/phy/phy.c
> +++ b/drivers/net/phy/phy.c
> @@ -549,6 +549,10 @@ int phy_register(struct phy_driver *drv)
>                 drv->readext += gd->reloc_off;
>         if (drv->writeext)
>                 drv->writeext += gd->reloc_off;
> +       if (drv->read_mmd)
> +               drv->read_mmd += gd->reloc_off;
> +       if (drv->write_mmd)
> +               drv->write_mmd += gd->reloc_off;
>  #endif
>         return 0;
>  }
> diff --git a/include/phy.h b/include/phy.h
> index b86fdfb2ce..0ce41661fa 100644
> --- a/include/phy.h
> +++ b/include/phy.h
> @@ -101,6 +101,13 @@ struct phy_driver {
>         int (*readext)(struct phy_device *phydev, int addr, int devad, int reg);
>         int (*writeext)(struct phy_device *phydev, int addr, int devad, int reg,
>                         u16 val);
> +
> +       /* Phy specific driver override for reading a MMD register */
> +       int (*read_mmd)(struct phy_device *phydev, int devad, int reg);
> +
> +       /* Phy specific driver override for writing a MMD register */
> +       int (*write_mmd)(struct phy_device *phydev, int devad, int reg, u16 val);
> +
>         struct list_head list;
>  };
>
> @@ -164,6 +171,61 @@ static inline int phy_write(struct phy_device *phydev, int devad, int regnum,
>         return bus->write(bus, phydev->addr, devad, regnum, val);
>  }
>
> +static inline void phy_mmd_indirect(struct phy_device *phydev, int devad,
> +                                   int regnum)
> +{
> +       /* Write the desired MMD Devad */
> +       phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_CTRL, devad);
> +
> +       /* Write the desired MMD register address */
> +       phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA, regnum);
> +
> +       /* Select the Function : DATA with no post increment */
> +       phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
> +}
> +
> +static inline int phy_read_mmd(struct phy_device *phydev, int devad,
> +                              int regnum)
> +{
> +       int ret;
> +
> +       if (regnum > (u16)~0 || devad > 32)
> +               return -EINVAL;
> +
> +       if (phydev->drv->read_mmd) {
> +               ret = phydev->drv->read_mmd(phydev, devad, regnum);
> +       } else {
> +               phy_mmd_indirect(phydev, devad, regnum);

I think this function should have a name that more clearly conveys
that it doesn't actually complete an indirect access.

Maybe phy_mmd_start_indirect() ?

> +
> +               /* Read the content of the MMD's selected register */
> +               ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA);
> +       }
> +
> +       return ret;

You shouldn't need this variable... just return from the 2 sites that
return errors.

> +}
> +
> +static inline int phy_write_mmd(struct phy_device *phydev, int devad,
> +                               int regnum, u16 val)
> +{
> +       int ret;
> +
> +       if (regnum > (u16)~0 || devad > 32)
> +               return -EINVAL;
> +
> +       if (phydev->drv->write_mmd) {
> +               ret = phydev->drv->write_mmd(phydev, devad, regnum, val);

You could simply return from here.

> +       } else {
> +               phy_mmd_indirect(phydev, devad, regnum);
> +
> +               /* Write the data into MMD's selected register */
> +               phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA, val);
> +
> +               ret = 0;

You should return any error from phy_write above and get rid of the
ret variable.

> +       }
> +
> +       return ret;
> +}
> +
>  #ifdef CONFIG_PHYLIB_10G
>  extern struct phy_driver gen10g_driver;
>
> --
> 2.19.1
>
> _______________________________________________
> U-Boot mailing list
> U-Boot@lists.denx.de
> https://lists.denx.de/listinfo/u-boot
diff mbox series

Patch

diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index cda4caa803..6769047407 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -549,6 +549,10 @@  int phy_register(struct phy_driver *drv)
 		drv->readext += gd->reloc_off;
 	if (drv->writeext)
 		drv->writeext += gd->reloc_off;
+	if (drv->read_mmd)
+		drv->read_mmd += gd->reloc_off;
+	if (drv->write_mmd)
+		drv->write_mmd += gd->reloc_off;
 #endif
 	return 0;
 }
diff --git a/include/phy.h b/include/phy.h
index b86fdfb2ce..0ce41661fa 100644
--- a/include/phy.h
+++ b/include/phy.h
@@ -101,6 +101,13 @@  struct phy_driver {
 	int (*readext)(struct phy_device *phydev, int addr, int devad, int reg);
 	int (*writeext)(struct phy_device *phydev, int addr, int devad, int reg,
 			u16 val);
+
+	/* Phy specific driver override for reading a MMD register */
+	int (*read_mmd)(struct phy_device *phydev, int devad, int reg);
+
+	/* Phy specific driver override for writing a MMD register */
+	int (*write_mmd)(struct phy_device *phydev, int devad, int reg, u16 val);
+
 	struct list_head list;
 };
 
@@ -164,6 +171,61 @@  static inline int phy_write(struct phy_device *phydev, int devad, int regnum,
 	return bus->write(bus, phydev->addr, devad, regnum, val);
 }
 
+static inline void phy_mmd_indirect(struct phy_device *phydev, int devad,
+				    int regnum)
+{
+	/* Write the desired MMD Devad */
+	phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_CTRL, devad);
+
+	/* Write the desired MMD register address */
+	phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA, regnum);
+
+	/* Select the Function : DATA with no post increment */
+	phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_CTRL, (devad | MII_MMD_CTRL_NOINCR));
+}
+
+static inline int phy_read_mmd(struct phy_device *phydev, int devad,
+			       int regnum)
+{
+	int ret;
+
+	if (regnum > (u16)~0 || devad > 32)
+		return -EINVAL;
+
+	if (phydev->drv->read_mmd) {
+		ret = phydev->drv->read_mmd(phydev, devad, regnum);
+	} else {
+		phy_mmd_indirect(phydev, devad, regnum);
+
+		/* Read the content of the MMD's selected register */
+		ret = phy_read(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA);
+	}
+
+	return ret;
+}
+
+static inline int phy_write_mmd(struct phy_device *phydev, int devad,
+				int regnum, u16 val)
+{
+	int ret;
+
+	if (regnum > (u16)~0 || devad > 32)
+		return -EINVAL;
+
+	if (phydev->drv->write_mmd) {
+		ret = phydev->drv->write_mmd(phydev, devad, regnum, val);
+	} else {
+		phy_mmd_indirect(phydev, devad, regnum);
+
+		/* Write the data into MMD's selected register */
+		phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA, val);
+
+		ret = 0;
+	}
+
+	return ret;
+}
+
 #ifdef CONFIG_PHYLIB_10G
 extern struct phy_driver gen10g_driver;