struct dp83869_private { int tx_fifo_depth; int rx_fifo_depth;
s32 rx_int_delay;
s32 tx_int_delay; int io_impedance; int port_mirroring; bool rxctrl_strap_quirk; int clk_output_sel; int mode;
};
if (of_property_read_bool(of_node, "enet-phy-lane-swap")) {
dp83869->port_mirroring = DP83869_PORT_MIRRORING_EN;
} else { /* If the lane swap is not in the DT then check the straps */
ret = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_STRAP_STS1); if (ret < 0) return ret;
staticint dp83869_configure_rgmii(struct phy_device *phydev, struct dp83869_private *dp83869)
{ int ret = 0, val;
if (phy_interface_is_rgmii(phydev)) {
val = phy_read(phydev, MII_DP83869_PHYCTRL); if (val < 0) return val;
val &= ~DP83869_PHYCR_FIFO_DEPTH_MASK;
val |= (dp83869->tx_fifo_depth << DP83869_TX_FIFO_SHIFT);
val |= (dp83869->rx_fifo_depth << DP83869_RX_FIFO_SHIFT);
ret = phy_write(phydev, MII_DP83869_PHYCTRL, val); if (ret) return ret;
}
if (dp83869->io_impedance >= 0)
ret = phy_modify_mmd(phydev, DP83869_DEVADDR,
DP83869_IO_MUX_CFG,
DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL,
dp83869->io_impedance &
DP83869_IO_MUX_CFG_IO_IMPEDANCE_CTRL);
return ret;
}
staticint dp83869_configure_fiber(struct phy_device *phydev, struct dp83869_private *dp83869)
{ int bmcr; int ret;
/* Only allow advertising what this PHY supports */
linkmode_and(phydev->advertising, phydev->advertising,
phydev->supported);
if (bmcr & BMCR_ANENABLE) {
ret = phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0); if (ret < 0) return ret;
}
}
/* Update advertising from supported */
linkmode_or(phydev->advertising, phydev->advertising,
phydev->supported);
return 0;
}
staticint dp83869_configure_mode(struct phy_device *phydev, struct dp83869_private *dp83869)
{ int phy_ctrl_val; int ret;
if (dp83869->mode < DP83869_RGMII_COPPER_ETHERNET ||
dp83869->mode > DP83869_SGMII_COPPER_ETHERNET) return -EINVAL;
/* Below init sequence for each operational mode is defined in * section 9.4.8 of the datasheet.
*/
phy_ctrl_val = dp83869->mode; if (phydev->interface == PHY_INTERFACE_MODE_MII) { if (dp83869->mode == DP83869_100M_MEDIA_CONVERT ||
dp83869->mode == DP83869_RGMII_100_BASE ||
dp83869->mode == DP83869_RGMII_COPPER_ETHERNET) {
phy_ctrl_val |= DP83869_OP_MODE_MII;
} else {
phydev_err(phydev, "selected op-mode is not valid with MII mode\n"); return -EINVAL;
}
}
ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_OP_MODE,
phy_ctrl_val); if (ret) return ret;
ret = phy_write(phydev, MII_BMCR, MII_DP83869_BMCR_DEFAULT); if (ret) return ret;
switch (dp83869->mode) { case DP83869_RGMII_COPPER_ETHERNET:
ret = phy_write(phydev, MII_DP83869_PHYCTRL,
phy_ctrl_val); if (ret) return ret;
ret = phy_write(phydev, MII_CTRL1000, DP83869_CFG1_DEFAULT); if (ret) return ret;
ret = dp83869_configure_rgmii(phydev, dp83869); if (ret) return ret; break; case DP83869_RGMII_SGMII_BRIDGE:
ret = phy_modify_mmd(phydev, DP83869_DEVADDR, DP83869_OP_MODE,
DP83869_SGMII_RGMII_BRIDGE,
DP83869_SGMII_RGMII_BRIDGE); if (ret) return ret;
ret = phy_write_mmd(phydev, DP83869_DEVADDR,
DP83869_FX_CTRL, DP83869_FX_CTRL_DEFAULT); if (ret) return ret;
break; case DP83869_1000M_MEDIA_CONVERT:
ret = phy_write(phydev, MII_DP83869_PHYCTRL,
phy_ctrl_val); if (ret) return ret;
ret = phy_write_mmd(phydev, DP83869_DEVADDR,
DP83869_FX_CTRL, DP83869_FX_CTRL_DEFAULT); if (ret) return ret; break; case DP83869_100M_MEDIA_CONVERT:
ret = phy_write(phydev, MII_DP83869_PHYCTRL,
phy_ctrl_val); if (ret) return ret; break; case DP83869_SGMII_COPPER_ETHERNET:
ret = phy_write(phydev, MII_DP83869_PHYCTRL,
phy_ctrl_val); if (ret) return ret;
ret = phy_write(phydev, MII_CTRL1000, DP83869_CFG1_DEFAULT); if (ret) return ret;
ret = phy_write_mmd(phydev, DP83869_DEVADDR,
DP83869_FX_CTRL, DP83869_FX_CTRL_DEFAULT); if (ret) return ret;
break; case DP83869_RGMII_1000_BASE: case DP83869_RGMII_100_BASE:
ret = dp83869_configure_fiber(phydev, dp83869); break; default: return -EINVAL;
}
/* Force speed optimization for the PHY even if it strapped */
ret = phy_modify(phydev, DP83869_CFG2, DP83869_DOWNSHIFT_EN,
DP83869_DOWNSHIFT_EN); if (ret) return ret;
ret = dp83869_configure_mode(phydev, dp83869); if (ret) return ret;
/* Enable Interrupt output INT_OE in CFG4 register */ if (phy_interrupt_is_valid(phydev)) {
val = phy_read(phydev, DP83869_CFG4);
val |= DP83869_INT_OE;
phy_write(phydev, DP83869_CFG4, val);
}
if (dp83869->port_mirroring != DP83869_PORT_MIRRORING_KEEP)
dp83869_config_port_mirroring(phydev);
/* Clock output selection if muxing property is set */ if (dp83869->clk_output_sel != DP83869_CLK_O_SEL_REF_CLK)
ret = phy_modify_mmd(phydev,
DP83869_DEVADDR, DP83869_IO_MUX_CFG,
DP83869_IO_MUX_CFG_CLK_O_SEL_MASK,
dp83869->clk_output_sel <<
DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT);
if (phy_interface_is_rgmii(phydev)) {
ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL,
dp83869->rx_int_delay |
dp83869->tx_int_delay << DP83869_RGMII_CLK_DELAY_SHIFT); if (ret) return ret;
val = phy_read_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIICTL);
val |= (DP83869_RGMII_TX_CLK_DELAY_EN |
DP83869_RGMII_RX_CLK_DELAY_EN);
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
val &= ~(DP83869_RGMII_TX_CLK_DELAY_EN |
DP83869_RGMII_RX_CLK_DELAY_EN);
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
val &= ~DP83869_RGMII_TX_CLK_DELAY_EN;
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
val &= ~DP83869_RGMII_RX_CLK_DELAY_EN;
ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIICTL,
val);
}
return ret;
}
staticint dp83869_probe(struct phy_device *phydev)
{ struct dp83869_private *dp83869; int ret;
dp83869 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83869),
GFP_KERNEL); if (!dp83869) return -ENOMEM;
phydev->priv = dp83869;
ret = dp83869_of_init(phydev); if (ret) return ret;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.