Commit 54f4c257 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'phy-ackage-addr-mmd-apis'



Christian Marangi says:

====================
net: phy: add PHY package base addr + mmd APIs

This small series is required for the upcoming qca807x PHY that
will make use of PHY package mmd API and the new implementation
with read/write based on base addr.

The MMD PHY package patch currently has no use but it will be
used in the upcoming patch and it does complete what a PHY package
may require in addition to basic read/write to setup global PHY address.

(Changelog for all the revision is present in the single patch)
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents dd784287 d63710fc
Loading
Loading
Loading
Loading
+12 −4
Original line number Diff line number Diff line
@@ -128,6 +128,10 @@
#define BCM54140_DEFAULT_DOWNSHIFT 5
#define BCM54140_MAX_DOWNSHIFT 9

enum bcm54140_global_phy {
	BCM54140_BASE_ADDR = 0,
};

struct bcm54140_priv {
	int port;
	int base_addr;
@@ -429,11 +433,13 @@ static int bcm54140_base_read_rdb(struct phy_device *phydev, u16 rdb)
	int ret;

	phy_lock_mdio_bus(phydev);
	ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
	ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
				  MII_BCM54XX_RDB_ADDR, rdb);
	if (ret < 0)
		goto out;

	ret = __phy_package_read(phydev, MII_BCM54XX_RDB_DATA);
	ret = __phy_package_read(phydev, BCM54140_BASE_ADDR,
				 MII_BCM54XX_RDB_DATA);

out:
	phy_unlock_mdio_bus(phydev);
@@ -446,11 +452,13 @@ static int bcm54140_base_write_rdb(struct phy_device *phydev,
	int ret;

	phy_lock_mdio_bus(phydev);
	ret = __phy_package_write(phydev, MII_BCM54XX_RDB_ADDR, rdb);
	ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
				  MII_BCM54XX_RDB_ADDR, rdb);
	if (ret < 0)
		goto out;

	ret = __phy_package_write(phydev, MII_BCM54XX_RDB_DATA, val);
	ret = __phy_package_write(phydev, BCM54140_BASE_ADDR,
				  MII_BCM54XX_RDB_DATA, val);

out:
	phy_unlock_mdio_bus(phydev);
+5 −0
Original line number Diff line number Diff line
@@ -416,6 +416,11 @@ struct vsc8531_private {
 * gpio_lock: used for PHC operations. Common for all PHYs as the load/save GPIO
 * is shared.
 */

enum vsc85xx_global_phy {
	VSC88XX_BASE_ADDR = 0,
};

struct vsc85xx_shared_private {
	struct mutex gpio_lock;
};
+2 −2
Original line number Diff line number Diff line
@@ -711,7 +711,7 @@ int phy_base_write(struct phy_device *phydev, u32 regnum, u16 val)
		dump_stack();
	}

	return __phy_package_write(phydev, regnum, val);
	return __phy_package_write(phydev, VSC88XX_BASE_ADDR, regnum, val);
}

/* phydev->bus->mdio_lock should be locked when using this function */
@@ -722,7 +722,7 @@ int phy_base_read(struct phy_device *phydev, u32 regnum)
		dump_stack();
	}

	return __phy_package_read(phydev, regnum);
	return __phy_package_read(phydev, VSC88XX_BASE_ADDR, regnum);
}

u32 vsc85xx_csr_read(struct phy_device *phydev,
+170 −34
Original line number Diff line number Diff line
@@ -540,6 +540,28 @@ static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
			devad | MII_MMD_CTRL_NOINCR);
}

static int mmd_phy_read(struct mii_bus *bus, int phy_addr, bool is_c45,
			int devad, u32 regnum)
{
	if (is_c45)
		return __mdiobus_c45_read(bus, phy_addr, devad, regnum);

	mmd_phy_indirect(bus, phy_addr, devad, regnum);
	/* Read the content of the MMD's selected register */
	return __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
}

static int mmd_phy_write(struct mii_bus *bus, int phy_addr, bool is_c45,
			 int devad, u32 regnum, u16 val)
{
	if (is_c45)
		return __mdiobus_c45_write(bus, phy_addr, devad, regnum, val);

	mmd_phy_indirect(bus, phy_addr, devad, regnum);
	/* Write the data into MMD's selected register */
	return __mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
}

/**
 * __phy_read_mmd - Convenience function for reading a register
 * from an MMD on a given PHY.
@@ -551,26 +573,14 @@ static void mmd_phy_indirect(struct mii_bus *bus, int phy_addr, int devad,
 */
int __phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
{
	int val;

	if (regnum > (u16)~0 || devad > 32)
		return -EINVAL;

	if (phydev->drv && phydev->drv->read_mmd) {
		val = phydev->drv->read_mmd(phydev, devad, regnum);
	} else if (phydev->is_c45) {
		val = __mdiobus_c45_read(phydev->mdio.bus, phydev->mdio.addr,
					 devad, regnum);
	} else {
		struct mii_bus *bus = phydev->mdio.bus;
		int phy_addr = phydev->mdio.addr;

		mmd_phy_indirect(bus, phy_addr, devad, regnum);
	if (phydev->drv && phydev->drv->read_mmd)
		return phydev->drv->read_mmd(phydev, devad, regnum);

		/* Read the content of the MMD's selected register */
		val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
	}
	return val;
	return mmd_phy_read(phydev->mdio.bus, phydev->mdio.addr,
			    phydev->is_c45, devad, regnum);
}
EXPORT_SYMBOL(__phy_read_mmd);

@@ -607,28 +617,14 @@ EXPORT_SYMBOL(phy_read_mmd);
 */
int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
{
	int ret;

	if (regnum > (u16)~0 || devad > 32)
		return -EINVAL;

	if (phydev->drv && phydev->drv->write_mmd) {
		ret = phydev->drv->write_mmd(phydev, devad, regnum, val);
	} else if (phydev->is_c45) {
		ret = __mdiobus_c45_write(phydev->mdio.bus, phydev->mdio.addr,
					  devad, regnum, val);
	} else {
		struct mii_bus *bus = phydev->mdio.bus;
		int phy_addr = phydev->mdio.addr;

		mmd_phy_indirect(bus, phy_addr, devad, regnum);
	if (phydev->drv && phydev->drv->write_mmd)
		return phydev->drv->write_mmd(phydev, devad, regnum, val);

		/* Write the data into MMD's selected register */
		__mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);

		ret = 0;
	}
	return ret;
	return mmd_phy_write(phydev->mdio.bus, phydev->mdio.addr,
			     phydev->is_c45, devad, regnum, val);
}
EXPORT_SYMBOL(__phy_write_mmd);

@@ -654,6 +650,146 @@ int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
}
EXPORT_SYMBOL(phy_write_mmd);

/**
 * __phy_package_read_mmd - read MMD reg relative to PHY package base addr
 * @phydev: The phy_device struct
 * @addr_offset: The offset to be added to PHY package base_addr
 * @devad: The MMD to read from
 * @regnum: The register on the MMD to read
 *
 * Convenience helper for reading a register of an MMD on a given PHY
 * using the PHY package base address. The base address is added to
 * the addr_offset value.
 *
 * Same calling rules as for __phy_read();
 *
 * NOTE: It's assumed that the entire PHY package is either C22 or C45.
 */
int __phy_package_read_mmd(struct phy_device *phydev,
			   unsigned int addr_offset, int devad,
			   u32 regnum)
{
	int addr = phy_package_address(phydev, addr_offset);

	if (addr < 0)
		return addr;

	if (regnum > (u16)~0 || devad > 32)
		return -EINVAL;

	return mmd_phy_read(phydev->mdio.bus, addr, phydev->is_c45, devad,
			    regnum);
}
EXPORT_SYMBOL(__phy_package_read_mmd);

/**
 * phy_package_read_mmd - read MMD reg relative to PHY package base addr
 * @phydev: The phy_device struct
 * @addr_offset: The offset to be added to PHY package base_addr
 * @devad: The MMD to read from
 * @regnum: The register on the MMD to read
 *
 * Convenience helper for reading a register of an MMD on a given PHY
 * using the PHY package base address. The base address is added to
 * the addr_offset value.
 *
 * Same calling rules as for phy_read();
 *
 * NOTE: It's assumed that the entire PHY package is either C22 or C45.
 */
int phy_package_read_mmd(struct phy_device *phydev,
			 unsigned int addr_offset, int devad,
			 u32 regnum)
{
	int addr = phy_package_address(phydev, addr_offset);
	int val;

	if (addr < 0)
		return addr;

	if (regnum > (u16)~0 || devad > 32)
		return -EINVAL;

	phy_lock_mdio_bus(phydev);
	val = mmd_phy_read(phydev->mdio.bus, addr, phydev->is_c45, devad,
			   regnum);
	phy_unlock_mdio_bus(phydev);

	return val;
}
EXPORT_SYMBOL(phy_package_read_mmd);

/**
 * __phy_package_write_mmd - write MMD reg relative to PHY package base addr
 * @phydev: The phy_device struct
 * @addr_offset: The offset to be added to PHY package base_addr
 * @devad: The MMD to write to
 * @regnum: The register on the MMD to write
 * @val: value to write to @regnum
 *
 * Convenience helper for writing a register of an MMD on a given PHY
 * using the PHY package base address. The base address is added to
 * the addr_offset value.
 *
 * Same calling rules as for __phy_write();
 *
 * NOTE: It's assumed that the entire PHY package is either C22 or C45.
 */
int __phy_package_write_mmd(struct phy_device *phydev,
			    unsigned int addr_offset, int devad,
			    u32 regnum, u16 val)
{
	int addr = phy_package_address(phydev, addr_offset);

	if (addr < 0)
		return addr;

	if (regnum > (u16)~0 || devad > 32)
		return -EINVAL;

	return mmd_phy_write(phydev->mdio.bus, addr, phydev->is_c45, devad,
			     regnum, val);
}
EXPORT_SYMBOL(__phy_package_write_mmd);

/**
 * phy_package_write_mmd - write MMD reg relative to PHY package base addr
 * @phydev: The phy_device struct
 * @addr_offset: The offset to be added to PHY package base_addr
 * @devad: The MMD to write to
 * @regnum: The register on the MMD to write
 * @val: value to write to @regnum
 *
 * Convenience helper for writing a register of an MMD on a given PHY
 * using the PHY package base address. The base address is added to
 * the addr_offset value.
 *
 * Same calling rules as for phy_write();
 *
 * NOTE: It's assumed that the entire PHY package is either C22 or C45.
 */
int phy_package_write_mmd(struct phy_device *phydev,
			  unsigned int addr_offset, int devad,
			  u32 regnum, u16 val)
{
	int addr = phy_package_address(phydev, addr_offset);
	int ret;

	if (addr < 0)
		return addr;

	if (regnum > (u16)~0 || devad > 32)
		return -EINVAL;

	phy_lock_mdio_bus(phydev);
	ret = mmd_phy_write(phydev->mdio.bus, addr, phydev->is_c45, devad,
			    regnum, val);
	phy_unlock_mdio_bus(phydev);

	return ret;
}
EXPORT_SYMBOL(phy_package_write_mmd);

/**
 * phy_modify_changed - Function for modifying a PHY register
 * @phydev: the phy_device struct
+19 −16
Original line number Diff line number Diff line
@@ -1651,20 +1651,22 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_10g);
/**
 * phy_package_join - join a common PHY group
 * @phydev: target phy_device struct
 * @addr: cookie and PHY address for global register access
 * @base_addr: cookie and base PHY address of PHY package for offset
 *   calculation of global register access
 * @priv_size: if non-zero allocate this amount of bytes for private data
 *
 * This joins a PHY group and provides a shared storage for all phydevs in
 * this group. This is intended to be used for packages which contain
 * more than one PHY, for example a quad PHY transceiver.
 *
 * The addr parameter serves as a cookie which has to have the same value
 * for all members of one group and as a PHY address to access generic
 * registers of a PHY package. Usually, one of the PHY addresses of the
 * different PHYs in the package provides access to these global registers.
 * The base_addr parameter serves as cookie which has to have the same values
 * for all members of one group and as the base PHY address of the PHY package
 * for offset calculation to access generic registers of a PHY package.
 * Usually, one of the PHY addresses of the different PHYs in the package
 * provides access to these global registers.
 * The address which is given here, will be used in the phy_package_read()
 * and phy_package_write() convenience functions. If your PHY doesn't have
 * global registers you can just pick any of the PHY addresses.
 * and phy_package_write() convenience functions as base and added to the
 * passed offset in those functions.
 *
 * This will set the shared pointer of the phydev to the shared storage.
 * If this is the first call for a this cookie the shared storage will be
@@ -1674,17 +1676,17 @@ EXPORT_SYMBOL_GPL(phy_driver_is_genphy_10g);
 * Returns < 1 on error, 0 on success. Esp. calling phy_package_join()
 * with the same cookie but a different priv_size is an error.
 */
int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size)
int phy_package_join(struct phy_device *phydev, int base_addr, size_t priv_size)
{
	struct mii_bus *bus = phydev->mdio.bus;
	struct phy_package_shared *shared;
	int ret;

	if (addr < 0 || addr >= PHY_MAX_ADDR)
	if (base_addr < 0 || base_addr >= PHY_MAX_ADDR)
		return -EINVAL;

	mutex_lock(&bus->shared_lock);
	shared = bus->shared[addr];
	shared = bus->shared[base_addr];
	if (!shared) {
		ret = -ENOMEM;
		shared = kzalloc(sizeof(*shared), GFP_KERNEL);
@@ -1696,9 +1698,9 @@ int phy_package_join(struct phy_device *phydev, int addr, size_t priv_size)
				goto err_free;
			shared->priv_size = priv_size;
		}
		shared->addr = addr;
		shared->base_addr = base_addr;
		refcount_set(&shared->refcnt, 1);
		bus->shared[addr] = shared;
		bus->shared[base_addr] = shared;
	} else {
		ret = -EINVAL;
		if (priv_size && priv_size != shared->priv_size)
@@ -1736,7 +1738,7 @@ void phy_package_leave(struct phy_device *phydev)
		return;

	if (refcount_dec_and_mutex_lock(&shared->refcnt, &bus->shared_lock)) {
		bus->shared[shared->addr] = NULL;
		bus->shared[shared->base_addr] = NULL;
		mutex_unlock(&bus->shared_lock);
		kfree(shared->priv);
		kfree(shared);
@@ -1755,7 +1757,8 @@ static void devm_phy_package_leave(struct device *dev, void *res)
 * devm_phy_package_join - resource managed phy_package_join()
 * @dev: device that is registering this PHY package
 * @phydev: target phy_device struct
 * @addr: cookie and PHY address for global register access
 * @base_addr: cookie and base PHY address of PHY package for offset
 *   calculation of global register access
 * @priv_size: if non-zero allocate this amount of bytes for private data
 *
 * Managed phy_package_join(). Shared storage fetched by this function,
@@ -1763,7 +1766,7 @@ static void devm_phy_package_leave(struct device *dev, void *res)
 * phy_package_join() for more information.
 */
int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
			  int addr, size_t priv_size)
			  int base_addr, size_t priv_size)
{
	struct phy_device **ptr;
	int ret;
@@ -1773,7 +1776,7 @@ int devm_phy_package_join(struct device *dev, struct phy_device *phydev,
	if (!ptr)
		return -ENOMEM;

	ret = phy_package_join(phydev, addr, priv_size);
	ret = phy_package_join(phydev, base_addr, priv_size);

	if (!ret) {
		*ptr = phydev;
Loading