/* Bypass (= 0, the signal from the GPIO input directly connects to the * internal sampling) or enable (= 1) the internal logic for RXEN and RXD[3:0] * timing tuning.
*/ #define PRG_ETH0_ADJ_ENABLE BIT(13) /* Controls whether the RXEN and RXD[3:0] signals should be aligned with the * input RX rising/falling edge and sent to the Ethernet internals. This sets * the automatically delay and skew automatically (internally).
*/ #define PRG_ETH0_ADJ_SETUP BIT(14) /* An internal counter based on the "timing-adjustment" clock. The counter is * cleared on both, the falling and rising edge of the RX_CLK. This selects the * delay (= the counter value) when to start sampling RXEN and RXD[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 * large input delay, the bit for that signal (RXEN = bit 0, RXD[3] = bit 1, * ...) can be configured to be 1 to compensate for a delay of about 1ns.
*/ #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. * Each step is 200ps. These bits are used with external RGMII PHYs * because RGMII RX only has the small window. cfg_rxclk_dly can * adjust the window between RX_CLK and RX_DATA and improve the stability * of "rx data valid".
*/ #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 * the output automatically (= without us having to configure * a register) based on the line-speed (125MHz for Gbit speeds, * 25MHz for 100Mbit/s and 2.5MHz for 10Mbit/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.