Commit fafc5db2 authored by Grygorii Strashko's avatar Grygorii Strashko Committed by David S. Miller
Browse files

net: phy: dp83867: fix hfs boot in rgmii mode



The commit ef87f7da ("net: phy: dp83867: move dt parsing to probe")
causes regression on TI dra71x-evm and dra72x-evm, where DP83867 PHY is
used in "rgmii-id" mode - the networking stops working.
Unfortunately, it's not enough to just move DT parsing code to .probe() as
it depends on phydev->interface value, which is set to correct value abter
the .probe() is completed and before calling .config_init(). So, RGMII
configuration can't be loaded from DT.

To fix and issue
- move RGMII validation code to .config_init()
- parse RGMII parameters in dp83867_of_init(), but consider them as
optional.

Fixes: ef87f7da ("net: phy: dp83867: move dt parsing to probe")
Signed-off-by: default avatarGrygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 51302f77
Loading
Loading
Loading
Loading
+71 −48
Original line number Diff line number Diff line
@@ -101,8 +101,11 @@
/* RGMIIDCTL bits */
#define DP83867_RGMII_TX_CLK_DELAY_MAX		0xf
#define DP83867_RGMII_TX_CLK_DELAY_SHIFT	4
#define DP83867_RGMII_TX_CLK_DELAY_INV	(DP83867_RGMII_TX_CLK_DELAY_MAX + 1)
#define DP83867_RGMII_RX_CLK_DELAY_MAX		0xf
#define DP83867_RGMII_RX_CLK_DELAY_SHIFT	0
#define DP83867_RGMII_RX_CLK_DELAY_INV	(DP83867_RGMII_RX_CLK_DELAY_MAX + 1)


/* IO_MUX_CFG bits */
#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MASK	0x1f
@@ -294,6 +297,48 @@ static int dp83867_config_port_mirroring(struct phy_device *phydev)
	return 0;
}

static int dp83867_verify_rgmii_cfg(struct phy_device *phydev)
{
	struct dp83867_private *dp83867 = phydev->priv;

	/* Existing behavior was to use default pin strapping delay in rgmii
	 * mode, but rgmii should have meant no delay.  Warn existing users.
	 */
	if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
		const u16 val = phy_read_mmd(phydev, DP83867_DEVADDR,
					     DP83867_STRAP_STS2);
		const u16 txskew = (val & DP83867_STRAP_STS2_CLK_SKEW_TX_MASK) >>
				   DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT;
		const u16 rxskew = (val & DP83867_STRAP_STS2_CLK_SKEW_RX_MASK) >>
				   DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT;

		if (txskew != DP83867_STRAP_STS2_CLK_SKEW_NONE ||
		    rxskew != DP83867_STRAP_STS2_CLK_SKEW_NONE)
			phydev_warn(phydev,
				    "PHY has delays via pin strapping, but phy-mode = 'rgmii'\n"
				    "Should be 'rgmii-id' to use internal delays txskew:%x rxskew:%x\n",
				    txskew, rxskew);
	}

	/* RX delay *must* be specified if internal delay of RX is used. */
	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
	     phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) &&
	     dp83867->rx_id_delay == DP83867_RGMII_RX_CLK_DELAY_INV) {
		phydev_err(phydev, "ti,rx-internal-delay must be specified\n");
		return -EINVAL;
	}

	/* TX delay *must* be specified if internal delay of TX is used. */
	if ((phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
	     phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) &&
	     dp83867->tx_id_delay == DP83867_RGMII_TX_CLK_DELAY_INV) {
		phydev_err(phydev, "ti,tx-internal-delay must be specified\n");
		return -EINVAL;
	}

	return 0;
}

#ifdef CONFIG_OF_MDIO
static int dp83867_of_init(struct phy_device *phydev)
{
@@ -335,56 +380,26 @@ static int dp83867_of_init(struct phy_device *phydev)
	dp83867->sgmii_ref_clk_en = of_property_read_bool(of_node,
					"ti,sgmii-ref-clock-output-enable");

	/* Existing behavior was to use default pin strapping delay in rgmii
	 * mode, but rgmii should have meant no delay.  Warn existing users.
	 */
	if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
		const u16 val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_STRAP_STS2);
		const u16 txskew = (val & DP83867_STRAP_STS2_CLK_SKEW_TX_MASK) >>
				   DP83867_STRAP_STS2_CLK_SKEW_TX_SHIFT;
		const u16 rxskew = (val & DP83867_STRAP_STS2_CLK_SKEW_RX_MASK) >>
				   DP83867_STRAP_STS2_CLK_SKEW_RX_SHIFT;

		if (txskew != DP83867_STRAP_STS2_CLK_SKEW_NONE ||
		    rxskew != DP83867_STRAP_STS2_CLK_SKEW_NONE)
			phydev_warn(phydev,
				    "PHY has delays via pin strapping, but phy-mode = 'rgmii'\n"
				    "Should be 'rgmii-id' to use internal delays\n");
	}

	/* RX delay *must* be specified if internal delay of RX is used. */
	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
	    phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
	dp83867->rx_id_delay = DP83867_RGMII_RX_CLK_DELAY_INV;
	ret = of_property_read_u32(of_node, "ti,rx-internal-delay",
				   &dp83867->rx_id_delay);
		if (ret) {
			phydev_err(phydev, "ti,rx-internal-delay must be specified\n");
			return ret;
		}
		if (dp83867->rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX) {
	if (!ret && dp83867->rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX) {
		phydev_err(phydev,
			   "ti,rx-internal-delay value of %u out of range\n",
			   dp83867->rx_id_delay);
		return -EINVAL;
	}
	}

	/* TX delay *must* be specified if internal delay of RX is used. */
	if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
	    phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
	dp83867->tx_id_delay = DP83867_RGMII_TX_CLK_DELAY_INV;
	ret = of_property_read_u32(of_node, "ti,tx-internal-delay",
				   &dp83867->tx_id_delay);
		if (ret) {
			phydev_err(phydev, "ti,tx-internal-delay must be specified\n");
			return ret;
		}
		if (dp83867->tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX) {
	if (!ret && dp83867->tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX) {
		phydev_err(phydev,
			   "ti,tx-internal-delay value of %u out of range\n",
			   dp83867->tx_id_delay);
		return -EINVAL;
	}
	}

	if (of_property_read_bool(of_node, "enet-phy-lane-swap"))
		dp83867->port_mirroring = DP83867_PORT_MIRROING_EN;
@@ -434,6 +449,10 @@ static int dp83867_config_init(struct phy_device *phydev)
	int ret, val, bs;
	u16 delay;

	ret = dp83867_verify_rgmii_cfg(phydev);
	if (ret)
		return ret;

	/* RX_DV/RX_CTRL strapped in mode 1 or mode 2 workaround */
	if (dp83867->rxctrl_strap_quirk)
		phy_clear_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4,
@@ -485,8 +504,12 @@ static int dp83867_config_init(struct phy_device *phydev)

		phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIICTL, val);

		delay = (dp83867->rx_id_delay |
			(dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT));
		delay = 0;
		if (dp83867->rx_id_delay != DP83867_RGMII_RX_CLK_DELAY_INV)
			delay |= dp83867->rx_id_delay;
		if (dp83867->tx_id_delay != DP83867_RGMII_TX_CLK_DELAY_INV)
			delay |= dp83867->tx_id_delay <<
				 DP83867_RGMII_TX_CLK_DELAY_SHIFT;

		phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIIDCTL,
			      delay);