/* Bypass (= 0, the signal from the GPIO input directly connects to the *internalsampling)orenable(=1)theinternallogicforRXENandRXD[3:0] *timingtuning.
*/ #define PRG_ETH0_ADJ_ENABLE BIT(13) /* Controls whether the RXEN and RXD[3:0] signals should be aligned with the *inputRXrising/fallingedgeandsenttotheEthernetinternals.Thissets *theautomaticallydelayandskewautomatically(internally).
*/ #define PRG_ETH0_ADJ_SETUP BIT(14) /* An internal counter based on the "timing-adjustment" clock. The counter is *clearedonboth,thefallingandrisingedgeoftheRX_CLK.Thisselectsthe *delay(=thecountervalue)whentostartsamplingRXENandRXD[3:0].
*/ #define PRG_ETH0_ADJ_DELAY GENMASK(19, 15) /* Adjusts the skew between each bit of RXEN and RXD[3:0]. If a signal has a *largeinputdelay,thebitforthatsignal(RXEN=bit0,RXD[3]=bit1, *...)canbeconfiguredtobe1tocompensateforadelayofabout1ns.
*/ #define PRG_ETH0_ADJ_SKEW GENMASK(24, 20)
#define PRG_ETH1 0x4
/* Defined for adding a delay to the input RX_CLK for better timing. *Eachstepis200ps.ThesebitsareusedwithexternalRGMIIPHYs *becauseRGMIIRXonlyhasthesmallwindow.cfg_rxclk_dlycan *adjustthewindowbetweenRX_CLKandRX_DATAandimprovethestability *of"rxdatavalid".
*/ #define PRG_ETH1_CFG_RXCLK_DLY GENMASK(19, 16)
struct meson8b_dwmac;
struct meson8b_dwmac_data { int (*set_phy_mode)(struct meson8b_dwmac *dwmac); bool has_prg_eth1_rgmii_rx_delay;
};
switch (dwmac->phy_mode) { case PHY_INTERFACE_MODE_RGMII:
delay_config = tx_dly_config | rx_adj_config; break; case PHY_INTERFACE_MODE_RGMII_RXID:
delay_config = tx_dly_config;
cfg_rxclk_dly = 0; break; case PHY_INTERFACE_MODE_RGMII_TXID:
delay_config = rx_adj_config; break; case PHY_INTERFACE_MODE_RGMII_ID: case PHY_INTERFACE_MODE_RMII:
delay_config = 0;
cfg_rxclk_dly = 0; break; default:
dev_err(dwmac->dev, "unsupported phy-mode %s\n",
phy_modes(dwmac->phy_mode)); return -EINVAL;
}
if (delay_config & PRG_ETH0_ADJ_ENABLE) { if (!dwmac->timing_adj_clk) {
dev_err(dwmac->dev, "The timing-adjustment clock is mandatory for the RX delay re-timing\n"); return -EINVAL;
}
/* The timing adjustment logic is driven by a separate clock */
ret = meson8b_devm_clk_prepare_enable(dwmac,
dwmac->timing_adj_clk); if (ret) {
dev_err(dwmac->dev, "Failed to enable the timing-adjustment clock\n"); return ret;
}
}
staticint meson8b_init_prg_eth(struct meson8b_dwmac *dwmac)
{ int ret;
if (phy_interface_mode_is_rgmii(dwmac->phy_mode)) { /* only relevant for RMII mode -> disable in RGMII mode */
meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
PRG_ETH0_INVERTED_RMII_CLK, 0);
/* Configure the 125MHz RGMII TX clock, the IP block changes *theoutputautomatically(=withoutushavingtoconfigure *aregister)basedontheline-speed(125MHzforGbitspeeds, *25MHzfor100Mbit/sand2.5MHzfor10Mbit/s).
*/
ret = clk_set_rate(dwmac->rgmii_tx_clk, 125 * 1000 * 1000); if (ret) {
dev_err(dwmac->dev, "failed to set RGMII TX clock\n"); return ret;
}
ret = meson8b_devm_clk_prepare_enable(dwmac,
dwmac->rgmii_tx_clk); if (ret) {
dev_err(dwmac->dev, "failed to enable the RGMII TX clock\n"); return ret;
}
} else { /* invert internal clk_rmii_i to generate 25/2.5 tx_rx_clk */
meson8b_dwmac_mask_bits(dwmac, PRG_ETH0,
PRG_ETH0_INVERTED_RMII_CLK,
PRG_ETH0_INVERTED_RMII_CLK);
}
/* use 2ns as fallback since this value was previously hardcoded */ if (of_property_read_u32(pdev->dev.of_node, "amlogic,tx-delay-ns",
&dwmac->tx_delay_ns))
dwmac->tx_delay_ns = 2;
/* RX delay defaults to 0ps since this is what many boards use */ if (of_property_read_u32(pdev->dev.of_node, "rx-internal-delay-ps",
&dwmac->rx_delay_ps)) { if (!of_property_read_u32(pdev->dev.of_node, "amlogic,rx-delay-ns",
&dwmac->rx_delay_ps)) /* convert ns to ps */
dwmac->rx_delay_ps *= 1000;
}
if (dwmac->data->has_prg_eth1_rgmii_rx_delay) { if (dwmac->rx_delay_ps > 3000 || dwmac->rx_delay_ps % 200) {
dev_err(dwmac->dev, "The RGMII RX delay range is 0..3000ps in 200ps steps"); return -EINVAL;
}
} else { if (dwmac->rx_delay_ps != 0 && dwmac->rx_delay_ps != 2000) {
dev_err(dwmac->dev, "The only allowed RGMII RX delays values are: 0ps, 2000ps"); return -EINVAL;
}
}
dwmac->timing_adj_clk = devm_clk_get_optional(dwmac->dev, "timing-adjustment"); if (IS_ERR(dwmac->timing_adj_clk)) return PTR_ERR(dwmac->timing_adj_clk);
ret = meson8b_init_rgmii_delays(dwmac); if (ret) return ret;
ret = meson8b_init_rgmii_tx_clk(dwmac); if (ret) return ret;
ret = dwmac->data->set_phy_mode(dwmac); if (ret) return ret;
ret = meson8b_init_prg_eth(dwmac); 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.