Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 09cb7dfd authored by Vivien Didelot's avatar Vivien Didelot Committed by David S. Miller
Browse files

net: dsa: mv88e6xxx: describe PHY page and SerDes



Add mv88e6xxx_phy_page_{read,write} routines and use them to access the
SerDes PHY device registers.

Signed-off-by: default avatarVivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e57e5e77
Loading
Loading
Loading
Loading
+81 −14
Original line number Diff line number Diff line
@@ -238,6 +238,74 @@ static int mv88e6xxx_phy_write(struct mv88e6xxx_chip *chip, int phy,
	return chip->phy_ops->write(chip, addr, reg, val);
}

static int mv88e6xxx_phy_page_get(struct mv88e6xxx_chip *chip, int phy, u8 page)
{
	if (!mv88e6xxx_has(chip, MV88E6XXX_FLAG_PHY_PAGE))
		return -EOPNOTSUPP;

	return mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page);
}

static void mv88e6xxx_phy_page_put(struct mv88e6xxx_chip *chip, int phy)
{
	int err;

	/* Restore PHY page Copper 0x0 for access via the registered MDIO bus */
	err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, PHY_PAGE_COPPER);
	if (unlikely(err)) {
		dev_err(chip->dev, "failed to restore PHY %d page Copper (%d)\n",
			phy, err);
	}
}

static int mv88e6xxx_phy_page_read(struct mv88e6xxx_chip *chip, int phy,
				   u8 page, int reg, u16 *val)
{
	int err;

	/* There is no paging for registers 22 */
	if (reg == PHY_PAGE)
		return -EINVAL;

	err = mv88e6xxx_phy_page_get(chip, phy, page);
	if (!err) {
		err = mv88e6xxx_phy_read(chip, phy, reg, val);
		mv88e6xxx_phy_page_put(chip, phy);
	}

	return err;
}

static int mv88e6xxx_phy_page_write(struct mv88e6xxx_chip *chip, int phy,
				    u8 page, int reg, u16 val)
{
	int err;

	/* There is no paging for registers 22 */
	if (reg == PHY_PAGE)
		return -EINVAL;

	err = mv88e6xxx_phy_page_get(chip, phy, page);
	if (!err) {
		err = mv88e6xxx_phy_write(chip, phy, PHY_PAGE, page);
		mv88e6xxx_phy_page_put(chip, phy);
	}

	return err;
}

static int mv88e6xxx_serdes_read(struct mv88e6xxx_chip *chip, int reg, u16 *val)
{
	return mv88e6xxx_phy_page_read(chip, ADDR_SERDES, SERDES_PAGE_FIBER,
				       reg, val);
}

static int mv88e6xxx_serdes_write(struct mv88e6xxx_chip *chip, int reg, u16 val)
{
	return mv88e6xxx_phy_page_write(chip, ADDR_SERDES, SERDES_PAGE_FIBER,
					reg, val);
}

static int mv88e6xxx_wait(struct mv88e6xxx_chip *chip, int addr, int reg,
			  u16 mask)
{
@@ -2408,23 +2476,22 @@ static int mv88e6xxx_switch_reset(struct mv88e6xxx_chip *chip)
	return ret;
}

static int mv88e6xxx_power_on_serdes(struct mv88e6xxx_chip *chip)
static int mv88e6xxx_serdes_power_on(struct mv88e6xxx_chip *chip)
{
	int ret;
	u16 val;
	int err;

	ret = _mv88e6xxx_mdio_page_read(chip, REG_FIBER_SERDES,
					PAGE_FIBER_SERDES, MII_BMCR);
	if (ret < 0)
		return ret;
	/* Clear Power Down bit */
	err = mv88e6xxx_serdes_read(chip, MII_BMCR, &val);
	if (err)
		return err;

	if (ret & BMCR_PDOWN) {
		ret &= ~BMCR_PDOWN;
		ret = _mv88e6xxx_mdio_page_write(chip, REG_FIBER_SERDES,
						 PAGE_FIBER_SERDES, MII_BMCR,
						 ret);
	if (val & BMCR_PDOWN) {
		val &= ~BMCR_PDOWN;
		err = mv88e6xxx_serdes_write(chip, MII_BMCR, val);
	}

	return ret;
	return err;
}

static int mv88e6xxx_port_read(struct mv88e6xxx_chip *chip, int port,
@@ -2547,7 +2614,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
	/* If this port is connected to a SerDes, make sure the SerDes is not
	 * powered down.
	 */
	if (mv88e6xxx_6352_family(chip)) {
	if (mv88e6xxx_has(chip, MV88E6XXX_FLAGS_SERDES)) {
		ret = _mv88e6xxx_reg_read(chip, REG_PORT(port), PORT_STATUS);
		if (ret < 0)
			return ret;
@@ -2555,7 +2622,7 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
		if ((ret == PORT_STATUS_CMODE_100BASE_X) ||
		    (ret == PORT_STATUS_CMODE_1000BASE_X) ||
		    (ret == PORT_STATUS_CMODE_SGMII)) {
			ret = mv88e6xxx_power_on_serdes(chip);
			ret = mv88e6xxx_serdes_power_on(chip);
			if (ret < 0)
				return ret;
		}
+24 −3
Original line number Diff line number Diff line
@@ -30,9 +30,12 @@
#define SMI_CMD_OP_45_READ_DATA_INC	((3 << 10) | SMI_CMD_BUSY)
#define SMI_DATA		0x01

/* Fiber/SERDES Registers are located at SMI address F, page 1 */
#define REG_FIBER_SERDES	0x0f
#define PAGE_FIBER_SERDES	0x01
/* PHY Registers */
#define PHY_PAGE		0x16
#define PHY_PAGE_COPPER		0x00

#define ADDR_SERDES		0x0f
#define SERDES_PAGE_FIBER	0x01

#define REG_PORT(p)		(0x10 + (p))
#define PORT_STATUS		0x00
@@ -394,6 +397,14 @@ enum mv88e6xxx_cap {
	MV88E6XXX_CAP_SMI_CMD,		/* (0x00) SMI Command */
	MV88E6XXX_CAP_SMI_DATA,		/* (0x01) SMI Data */

	/* PHY Registers.
	 */
	MV88E6XXX_CAP_PHY_PAGE,		/* (0x16) Page Register */

	/* Fiber/SERDES Registers (SMI address F).
	 */
	MV88E6XXX_CAP_SERDES,

	/* Switch Global 2 Registers.
	 * The device contains a second set of global 16-bit registers.
	 */
@@ -441,6 +452,10 @@ enum mv88e6xxx_cap {
#define MV88E6XXX_FLAG_SMI_CMD		BIT(MV88E6XXX_CAP_SMI_CMD)
#define MV88E6XXX_FLAG_SMI_DATA		BIT(MV88E6XXX_CAP_SMI_DATA)

#define MV88E6XXX_FLAG_PHY_PAGE		BIT(MV88E6XXX_CAP_PHY_PAGE)

#define MV88E6XXX_FLAG_SERDES		BIT(MV88E6XXX_CAP_SERDES)

#define MV88E6XXX_FLAG_GLOBAL2		BIT(MV88E6XXX_CAP_GLOBAL2)
#define MV88E6XXX_FLAG_G2_MGMT_EN_2X	BIT(MV88E6XXX_CAP_G2_MGMT_EN_2X)
#define MV88E6XXX_FLAG_G2_MGMT_EN_0X	BIT(MV88E6XXX_CAP_G2_MGMT_EN_0X)
@@ -482,6 +497,11 @@ enum mv88e6xxx_cap {
	(MV88E6XXX_FLAG_G2_PVT_ADDR |	\
	 MV88E6XXX_FLAG_G2_PVT_DATA)

/* Fiber/SERDES Registers at SMI address F, page 1 */
#define MV88E6XXX_FLAGS_SERDES		\
	(MV88E6XXX_FLAG_PHY_PAGE |	\
	 MV88E6XXX_FLAG_SERDES)

/* Indirect PHY access via Global2 SMI PHY registers */
#define MV88E6XXX_FLAGS_SMI_PHY		\
	(MV88E6XXX_FLAG_G2_SMI_PHY_CMD |\
@@ -574,6 +594,7 @@ enum mv88e6xxx_cap {
	 MV88E6XXX_FLAGS_IRL |		\
	 MV88E6XXX_FLAGS_MULTI_CHIP |	\
	 MV88E6XXX_FLAGS_PVT |		\
	 MV88E6XXX_FLAGS_SERDES |	\
	 MV88E6XXX_FLAGS_SMI_PHY)

struct mv88e6xxx_info {