cell = of_nvmem_cell_get(of_node, "io_impedance_ctrl"); if (IS_ERR(cell)) {
ret = PTR_ERR(cell); if (ret != -ENOENT && ret != -EOPNOTSUPP) return phydev_err_probe(phydev, ret, "failed to get nvmem cell io_impedance_ctrl\n");
/* If no nvmem cell, check for the boolean properties. */ if (of_property_read_bool(of_node, "ti,max-output-impedance"))
dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MAX; elseif (of_property_read_bool(of_node, "ti,min-output-impedance"))
dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN; else
dp83867->io_impedance = -1; /* leave at default */
/* Optional configuration */
ret = of_property_read_u32(of_node, "ti,clk-output-sel",
&dp83867->clk_output_sel); /* If not set, keep default */ if (!ret) {
dp83867->set_clk_output = true; /* Valid values are 0 to DP83867_CLK_O_SEL_REF_CLK or * DP83867_CLK_O_SEL_OFF.
*/ if (dp83867->clk_output_sel > DP83867_CLK_O_SEL_REF_CLK &&
dp83867->clk_output_sel != DP83867_CLK_O_SEL_OFF) {
phydev_err(phydev, "ti,clk-output-sel value %u out of range\n",
dp83867->clk_output_sel); return -EINVAL;
}
}
ret = dp83867_of_init_io_impedance(phydev); if (ret) return ret;
dp83867->rx_id_delay = DP83867_RGMIIDCTL_2_00_NS;
ret = of_property_read_u32(of_node, "ti,rx-internal-delay",
&dp83867->rx_id_delay); 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;
}
dp83867->tx_id_delay = DP83867_RGMIIDCTL_2_00_NS;
ret = of_property_read_u32(of_node, "ti,tx-internal-delay",
&dp83867->tx_id_delay); 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;
if (of_property_read_bool(of_node, "enet-phy-lane-no-swap"))
dp83867->port_mirroring = DP83867_PORT_MIRROING_DIS;
ret = of_property_read_u32(of_node, "ti,fifo-depth",
&dp83867->tx_fifo_depth); if (ret) {
ret = of_property_read_u32(of_node, "tx-fifo-depth",
&dp83867->tx_fifo_depth); if (ret)
dp83867->tx_fifo_depth =
DP83867_PHYCR_FIFO_DEPTH_4_B_NIB;
}
if (dp83867->tx_fifo_depth > DP83867_PHYCR_FIFO_DEPTH_MAX) {
phydev_err(phydev, "tx-fifo-depth value %u out of range\n",
dp83867->tx_fifo_depth); return -EINVAL;
}
ret = of_property_read_u32(of_node, "rx-fifo-depth",
&dp83867->rx_fifo_depth); if (ret)
dp83867->rx_fifo_depth = DP83867_PHYCR_FIFO_DEPTH_4_B_NIB;
if (dp83867->rx_fifo_depth > DP83867_PHYCR_FIFO_DEPTH_MAX) {
phydev_err(phydev, "rx-fifo-depth value %u out of range\n",
dp83867->rx_fifo_depth); return -EINVAL;
}
/* For non-OF device, the RX and TX ID values are either strapped * or take from default value. So, we init RX & TX ID values here * so that the RGMIIDCTL is configured correctly later in * dp83867_config_init();
*/
delay = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIIDCTL);
dp83867->rx_id_delay = delay & DP83867_RGMII_RX_CLK_DELAY_MAX;
dp83867->tx_id_delay = (delay >> DP83867_RGMII_TX_CLK_DELAY_SHIFT) &
DP83867_RGMII_TX_CLK_DELAY_MAX;
/* Per datasheet, IO impedance is default to 50-ohm, so we set the * same here or else the default '0' means highest IO impedance * which is wrong.
*/
dp83867->io_impedance = DP83867_IO_MUX_CFG_IO_IMPEDANCE_MIN / 2;
/* For non-OF device, the RX and TX FIFO depths are taken from * default value. So, we init RX & TX FIFO depths here * so that it is configured correctly later in dp83867_config_init();
*/
dp83867->tx_fifo_depth = DP83867_PHYCR_FIFO_DEPTH_4_B_NIB;
dp83867->rx_fifo_depth = DP83867_PHYCR_FIFO_DEPTH_4_B_NIB;
/* Force speed optimization for the PHY even if it strapped */
ret = phy_modify(phydev, DP83867_CFG2, DP83867_DOWNSHIFT_EN,
DP83867_DOWNSHIFT_EN); 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,
BIT(7));
bs = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_STRAP_STS2); if (bs & DP83867_STRAP_STS2_STRAP_FLD) { /* When using strap to enable FLD, the ENERGY_LOST_FLD_THR will * be set to 0x2. This may causes the PHY link to be unstable - * the default value 0x1 need to be restored.
*/
ret = phy_modify_mmd(phydev, DP83867_DEVADDR,
DP83867_FLD_THR_CFG,
DP83867_FLD_THR_CFG_ENERGY_LOST_THR_MASK,
0x1); if (ret) return ret;
}
/* Although the DP83867 reports EEE capability through the * MDIO_PCS_EEE_ABLE and MDIO_AN_EEE_ADV registers, the feature * is not actually implemented in hardware.
*/
phy_disable_eee(phydev);
if (phy_interface_is_rgmii(phydev) ||
phydev->interface == PHY_INTERFACE_MODE_SGMII) {
val = phy_read(phydev, MII_DP83867_PHYCTRL); if (val < 0) return val;
val &= ~DP83867_PHYCR_TX_FIFO_DEPTH_MASK;
val |= (dp83867->tx_fifo_depth <<
DP83867_PHYCR_TX_FIFO_DEPTH_SHIFT);
if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
val &= ~DP83867_PHYCR_RX_FIFO_DEPTH_MASK;
val |= (dp83867->rx_fifo_depth <<
DP83867_PHYCR_RX_FIFO_DEPTH_SHIFT);
}
ret = phy_write(phydev, MII_DP83867_PHYCTRL, val); if (ret) return ret;
}
if (phy_interface_is_rgmii(phydev)) {
val = phy_read(phydev, MII_DP83867_PHYCTRL); if (val < 0) return val;
/* The code below checks if "port mirroring" N/A MODE4 has been * enabled during power on bootstrap. * * Such N/A mode enabled by mistake can put PHY IC in some * internal testing mode and disable RGMII transmission. * * In this particular case one needs to check STRAP_STS1 * register's bit 11 (marked as RESERVED).
*/
bs = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_STRAP_STS1); if (bs & DP83867_STRAP_STS1_RESERVED)
val &= ~DP83867_PHYCR_RESERVED_MASK;
ret = phy_write(phydev, MII_DP83867_PHYCTRL, val); if (ret) return ret;
/* Set up RGMII delays */
val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_RGMIICTL);
val &= ~(DP83867_RGMII_TX_CLK_DELAY_EN | DP83867_RGMII_RX_CLK_DELAY_EN); if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
val |= (DP83867_RGMII_TX_CLK_DELAY_EN | DP83867_RGMII_RX_CLK_DELAY_EN);
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
val |= DP83867_RGMII_TX_CLK_DELAY_EN;
if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
val |= DP83867_RGMII_RX_CLK_DELAY_EN;
/* If specified, set io impedance */ if (dp83867->io_impedance >= 0)
phy_modify_mmd(phydev, DP83867_DEVADDR, DP83867_IO_MUX_CFG,
DP83867_IO_MUX_CFG_IO_IMPEDANCE_MASK,
dp83867->io_impedance);
if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { /* For support SPEED_10 in SGMII mode * DP83867_10M_SGMII_RATE_ADAPT bit * has to be cleared by software. That * does not affect SPEED_100 and * SPEED_1000.
*/
ret = phy_modify_mmd(phydev, DP83867_DEVADDR,
DP83867_10M_SGMII_CFG,
DP83867_10M_SGMII_RATE_ADAPT_MASK,
0); if (ret) return ret;
/* After reset SGMII Autoneg timer is set to 2us (bits 6 and 5 * are 01). That is not enough to finalize autoneg on some * devices. Increase this timer duration to maximum 16ms.
*/
ret = phy_modify_mmd(phydev, DP83867_DEVADDR,
DP83867_CFG4,
DP83867_CFG4_SGMII_ANEG_MASK,
DP83867_CFG4_SGMII_ANEG_TIMER_16MS);
if (ret) return ret;
val = phy_read_mmd(phydev, DP83867_DEVADDR, DP83867_SGMIICTL); /* SGMII type is set to 4-wire mode by default. * If we place appropriate property in dts (see above) * switch on 6-wire mode.
*/ if (dp83867->sgmii_ref_clk_en)
val |= DP83867_SGMII_TYPE; else
val &= ~DP83867_SGMII_TYPE;
phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_SGMIICTL, val);
/* This is a SW workaround for link instability if RX_CTRL is * not strapped to mode 3 or 4 in HW. This is required for SGMII * in addition to clearing bit 7, handled above.
*/ if (dp83867->rxctrl_strap_quirk)
phy_set_bits_mmd(phydev, DP83867_DEVADDR, DP83867_CFG4,
BIT(8));
}
val = phy_read(phydev, DP83867_CFG3); /* Enable Interrupt output INT_OE in CFG3 register */ if (phy_interrupt_is_valid(phydev))
val |= DP83867_CFG3_INT_OE;
val |= DP83867_CFG3_ROBUST_AUTO_MDIX;
phy_write(phydev, DP83867_CFG3, val);
if (dp83867->port_mirroring != DP83867_PORT_MIRROING_KEEP)
dp83867_config_port_mirroring(phydev);
/* Clock output selection if muxing property is set */ if (dp83867->set_clk_output) {
u16 mask = DP83867_IO_MUX_CFG_CLK_O_DISABLE;
if (dp83867->clk_output_sel == DP83867_CLK_O_SEL_OFF) {
val = DP83867_IO_MUX_CFG_CLK_O_DISABLE;
} else {
mask |= DP83867_IO_MUX_CFG_CLK_O_SEL_MASK;
val = dp83867->clk_output_sel <<
DP83867_IO_MUX_CFG_CLK_O_SEL_SHIFT;
}
/* Configure the DSP Feedforward Equalizer Configuration register to * improve short cable (< 1 meter) performance. This will not affect * long cable performance.
*/
err = phy_write_mmd(phydev, DP83867_DEVADDR, DP83867_DSP_FFE_CFG,
0x0e81); if (err < 0) return err;
staticvoid dp83867_link_change_notify(struct phy_device *phydev)
{ /* There is a limitation in DP83867 PHY device where SGMII AN is * only triggered once after the device is booted up. Even after the * PHY TPI is down and up again, SGMII AN is not triggered and * hence no new in-band message from PHY to MAC side SGMII. * This could cause an issue during power up, when PHY is up prior * to MAC. At this condition, once MAC side SGMII is up, MAC side * SGMII wouldn`t receive new in-band message from TI PHY with * correct link status, speed and duplex info. * Thus, implemented a SW solution here to retrigger SGMII Auto-Neg * whenever there is a link change.
*/ if (phydev->interface == PHY_INTERFACE_MODE_SGMII) { int val = 0;
val = phy_clear_bits(phydev, DP83867_CFG2,
DP83867_SGMII_AUTONEG_EN); if (val < 0) return;
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.