net: phy: dp83867: fix hfs boot in rgmii mode
The commitef87f7da6b
("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:ef87f7da6b
("net: phy: dp83867: move dt parsing to probe") Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
51302f77be
commit
fafc5db28a
@ -101,8 +101,11 @@
|
|||||||
/* RGMIIDCTL bits */
|
/* RGMIIDCTL bits */
|
||||||
#define DP83867_RGMII_TX_CLK_DELAY_MAX 0xf
|
#define DP83867_RGMII_TX_CLK_DELAY_MAX 0xf
|
||||||
#define DP83867_RGMII_TX_CLK_DELAY_SHIFT 4
|
#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_MAX 0xf
|
||||||
#define DP83867_RGMII_RX_CLK_DELAY_SHIFT 0
|
#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 */
|
/* IO_MUX_CFG bits */
|
||||||
#define DP83867_IO_MUX_CFG_IO_IMPEDANCE_MASK 0x1f
|
#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;
|
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
|
#ifdef CONFIG_OF_MDIO
|
||||||
static int dp83867_of_init(struct phy_device *phydev)
|
static int dp83867_of_init(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
@ -335,55 +380,25 @@ static int dp83867_of_init(struct phy_device *phydev)
|
|||||||
dp83867->sgmii_ref_clk_en = of_property_read_bool(of_node,
|
dp83867->sgmii_ref_clk_en = of_property_read_bool(of_node,
|
||||||
"ti,sgmii-ref-clock-output-enable");
|
"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 ||
|
dp83867->rx_id_delay = DP83867_RGMII_RX_CLK_DELAY_INV;
|
||||||
rxskew != DP83867_STRAP_STS2_CLK_SKEW_NONE)
|
ret = of_property_read_u32(of_node, "ti,rx-internal-delay",
|
||||||
phydev_warn(phydev,
|
&dp83867->rx_id_delay);
|
||||||
"PHY has delays via pin strapping, but phy-mode = 'rgmii'\n"
|
if (!ret && dp83867->rx_id_delay > DP83867_RGMII_RX_CLK_DELAY_MAX) {
|
||||||
"Should be 'rgmii-id' to use internal delays\n");
|
phydev_err(phydev,
|
||||||
|
"ti,rx-internal-delay value of %u out of range\n",
|
||||||
|
dp83867->rx_id_delay);
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RX delay *must* be specified if internal delay of RX is used. */
|
dp83867->tx_id_delay = DP83867_RGMII_TX_CLK_DELAY_INV;
|
||||||
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID ||
|
ret = of_property_read_u32(of_node, "ti,tx-internal-delay",
|
||||||
phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
|
&dp83867->tx_id_delay);
|
||||||
ret = of_property_read_u32(of_node, "ti,rx-internal-delay",
|
if (!ret && dp83867->tx_id_delay > DP83867_RGMII_TX_CLK_DELAY_MAX) {
|
||||||
&dp83867->rx_id_delay);
|
phydev_err(phydev,
|
||||||
if (ret) {
|
"ti,tx-internal-delay value of %u out of range\n",
|
||||||
phydev_err(phydev, "ti,rx-internal-delay must be specified\n");
|
dp83867->tx_id_delay);
|
||||||
return ret;
|
return -EINVAL;
|
||||||
}
|
|
||||||
if (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) {
|
|
||||||
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) {
|
|
||||||
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"))
|
if (of_property_read_bool(of_node, "enet-phy-lane-swap"))
|
||||||
@ -434,6 +449,10 @@ static int dp83867_config_init(struct phy_device *phydev)
|
|||||||
int ret, val, bs;
|
int ret, val, bs;
|
||||||
u16 delay;
|
u16 delay;
|
||||||
|
|
||||||
|
ret = dp83867_verify_rgmii_cfg(phydev);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* RX_DV/RX_CTRL strapped in mode 1 or mode 2 workaround */
|
/* RX_DV/RX_CTRL strapped in mode 1 or mode 2 workaround */
|
||||||
if (dp83867->rxctrl_strap_quirk)
|
if (dp83867->rxctrl_strap_quirk)
|
||||||
phy_clear_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4,
|
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);
|
phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIICTL, val);
|
||||||
|
|
||||||
delay = (dp83867->rx_id_delay |
|
delay = 0;
|
||||||
(dp83867->tx_id_delay << DP83867_RGMII_TX_CLK_DELAY_SHIFT));
|
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,
|
phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIIDCTL,
|
||||||
delay);
|
delay);
|
||||||
|
Loading…
Reference in New Issue
Block a user