Commit 095c3ea6 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'ksz886x-forced-link-modes'



Oleksij Rempel says:

====================
fix forced link mode for KSZ886X switches

changes v3:
- squash patch 1 and 2
- use genphy_config_aneg() instead of genphy_setup_forced()

changes v2:
- address kernel test robot warning
- change comment explaining clearing of KSZ886X_CTRL_FORCE_LINK bit
- s/PHY we create/PHY will create/
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c0518571 510f02fe
Loading
Loading
Loading
Loading
+83 −3
Original line number Diff line number Diff line
@@ -632,6 +632,50 @@ static void ksz8_w_vlan_table(struct ksz_device *dev, u16 vid, u16 vlan)
	ksz8_w_table(dev, TABLE_VLAN, addr, buf);
}

/**
 * ksz8_r_phy_ctrl - Translates and reads from the SMI interface to a MIIM PHY
 *		     Control register (Reg. 31).
 * @dev: The KSZ device instance.
 * @port: The port number to be read.
 * @val: The value read from the SMI interface.
 *
 * This function reads the SMI interface and translates the hardware register
 * bit values into their corresponding control settings for a MIIM PHY Control
 * register.
 *
 * Return: 0 on success, error code on failure.
 */
static int ksz8_r_phy_ctrl(struct ksz_device *dev, int port, u16 *val)
{
	const u16 *regs = dev->info->regs;
	u8 reg_val;
	int ret;

	*val = 0;

	ret = ksz_pread8(dev, port, regs[P_LINK_STATUS], &reg_val);
	if (ret < 0)
		return ret;

	if (reg_val & PORT_MDIX_STATUS)
		*val |= KSZ886X_CTRL_MDIX_STAT;

	ret = ksz_pread8(dev, port, REG_PORT_LINK_MD_CTRL, &reg_val);
	if (ret < 0)
		return ret;

	if (reg_val & PORT_FORCE_LINK)
		*val |= KSZ886X_CTRL_FORCE_LINK;

	if (reg_val & PORT_POWER_SAVING)
		*val |= KSZ886X_CTRL_PWRSAVE;

	if (reg_val & PORT_PHY_REMOTE_LOOPBACK)
		*val |= KSZ886X_CTRL_REMOTE_LOOPBACK;

	return 0;
}

int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
{
	u8 restart, speed, ctrl, link;
@@ -769,12 +813,10 @@ int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
				FIELD_GET(PORT_CABLE_FAULT_COUNTER_L, val2));
		break;
	case PHY_REG_PHY_CTRL:
		ret = ksz_pread8(dev, p, regs[P_LINK_STATUS], &link);
		ret = ksz8_r_phy_ctrl(dev, p, &data);
		if (ret)
			return ret;

		if (link & PORT_MDIX_STATUS)
			data |= KSZ886X_CTRL_MDIX_STAT;
		break;
	default:
		processed = false;
@@ -786,6 +828,38 @@ int ksz8_r_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 *val)
	return 0;
}

/**
 * ksz8_w_phy_ctrl - Translates and writes to the SMI interface from a MIIM PHY
 *		     Control register (Reg. 31).
 * @dev: The KSZ device instance.
 * @port: The port number to be configured.
 * @val: The register value to be written.
 *
 * This function translates control settings from a MIIM PHY Control register
 * into their corresponding hardware register bit values for the SMI
 * interface.
 *
 * Return: 0 on success, error code on failure.
 */
static int ksz8_w_phy_ctrl(struct ksz_device *dev, int port, u16 val)
{
	u8 reg_val = 0;
	int ret;

	if (val & KSZ886X_CTRL_FORCE_LINK)
		reg_val |= PORT_FORCE_LINK;

	if (val & KSZ886X_CTRL_PWRSAVE)
		reg_val |= PORT_POWER_SAVING;

	if (val & KSZ886X_CTRL_REMOTE_LOOPBACK)
		reg_val |= PORT_PHY_REMOTE_LOOPBACK;

	ret = ksz_prmw8(dev, port, REG_PORT_LINK_MD_CTRL, PORT_FORCE_LINK |
			PORT_POWER_SAVING | PORT_PHY_REMOTE_LOOPBACK, reg_val);
	return ret;
}

int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
{
	u8 restart, speed, ctrl, data;
@@ -926,6 +1000,12 @@ int ksz8_w_phy(struct ksz_device *dev, u16 phy, u16 reg, u16 val)
		if (val & PHY_START_CABLE_DIAG)
			ksz_port_cfg(dev, p, REG_PORT_LINK_MD_CTRL, PORT_START_CABLE_DIAG, true);
		break;

	case PHY_REG_PHY_CTRL:
		ret = ksz8_w_phy_ctrl(dev, p, val);
		if (ret)
			return ret;
		break;
	default:
		break;
	}
+22 −0
Original line number Diff line number Diff line
@@ -1733,6 +1733,28 @@ static int ksz886x_config_aneg(struct phy_device *phydev)
	if (ret)
		return ret;

	if (phydev->autoneg != AUTONEG_ENABLE) {
		/* When autonegotation is disabled, we need to manually force
		 * the link state. If we don't do this, the PHY will keep
		 * sending Fast Link Pulses (FLPs) which are part of the
		 * autonegotiation process. This is not desired when
		 * autonegotiation is off.
		 */
		ret = phy_set_bits(phydev, MII_KSZPHY_CTRL,
				   KSZ886X_CTRL_FORCE_LINK);
		if (ret)
			return ret;
	} else {
		/* If we had previously forced the link state, we need to
		 * clear KSZ886X_CTRL_FORCE_LINK bit now. Otherwise, the PHY
		 * will not perform autonegotiation.
		 */
		ret = phy_clear_bits(phydev, MII_KSZPHY_CTRL,
				     KSZ886X_CTRL_FORCE_LINK);
		if (ret)
			return ret;
	}

	/* The MDI-X configuration is automatically changed by the PHY after
	 * switching from autoneg off to on. So, take MDI-X configuration under
	 * own control and set it after autoneg configuration was done.
+4 −0
Original line number Diff line number Diff line
@@ -64,6 +64,10 @@
#define KSZ886X_BMCR_DISABLE_TRANSMIT		BIT(1)
#define KSZ886X_BMCR_DISABLE_LED		BIT(0)

/* PHY Special Control/Status Register (Reg 31) */
#define KSZ886X_CTRL_MDIX_STAT			BIT(4)
#define KSZ886X_CTRL_FORCE_LINK			BIT(3)
#define KSZ886X_CTRL_PWRSAVE			BIT(2)
#define KSZ886X_CTRL_REMOTE_LOOPBACK		BIT(1)

#endif /* _MICREL_PHY_H */