@@ -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;
}
@@ -101,6 +101,14 @@ 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 +172,50 @@ 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_start_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)
+{
+ if (regnum > (u16)~0 || devad > 32)
+ return -EINVAL;
+
+ if (phydev->drv->read_mmd)
+ return phydev->drv->read_mmd(phydev, devad, regnum);
+
+ phy_mmd_start_indirect(phydev, devad, regnum);
+
+ /* Read the content of the MMD's selected register */
+ return phy_read(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA);
+}
+
+static inline int phy_write_mmd(struct phy_device *phydev, int devad,
+ int regnum, u16 val)
+{
+ if (regnum > (u16)~0 || devad > 32)
+ return -EINVAL;
+
+ if (phydev->drv->write_mmd)
+ return phydev->drv->write_mmd(phydev, devad, regnum, val);
+
+ phy_mmd_start_indirect(phydev, devad, regnum);
+
+ /* Write the data into MMD's selected register */
+ return phy_write(phydev, MDIO_DEVAD_NONE, MII_MMD_DATA, val);
+}
+
#ifdef CONFIG_PHYLIB_10G
extern struct phy_driver gen10g_driver;