net: stmmac: dwmac-meson8b: add support for the RGMII RX delay on G12A
Amlogic Meson G12A (and newer: G12B, SM1) SoCs have a more advanced RX delay logic. Instead of fine-tuning the delay in the nanoseconds range it now allows tuning in 200 picosecond steps. This support comes with new bits in the PRG_ETH1[19:16] register. Add support for validating the RGMII RX delay as well as configuring the register accordingly on these platforms. Reviewed-by: Andrew Lunn <andrew@lunn.ch> Reviewed-by: Florian Fainelli <f.fainelli@gmail.com> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
7985244d10
commit
de94fc104d
@ -68,10 +68,21 @@
|
||||
*/
|
||||
#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;
|
||||
};
|
||||
|
||||
struct meson8b_dwmac {
|
||||
@ -270,30 +281,35 @@ static int meson8b_devm_clk_prepare_enable(struct meson8b_dwmac *dwmac,
|
||||
|
||||
static int meson8b_init_rgmii_delays(struct meson8b_dwmac *dwmac)
|
||||
{
|
||||
u32 tx_dly_config, rx_dly_config, delay_config;
|
||||
u32 tx_dly_config, rx_adj_config, cfg_rxclk_dly, delay_config;
|
||||
int ret;
|
||||
|
||||
rx_adj_config = 0;
|
||||
cfg_rxclk_dly = 0;
|
||||
tx_dly_config = FIELD_PREP(PRG_ETH0_TXDLY_MASK,
|
||||
dwmac->tx_delay_ns >> 1);
|
||||
|
||||
if (dwmac->rx_delay_ps == 2000)
|
||||
rx_dly_config = PRG_ETH0_ADJ_ENABLE | PRG_ETH0_ADJ_SETUP;
|
||||
else
|
||||
rx_dly_config = 0;
|
||||
if (dwmac->data->has_prg_eth1_rgmii_rx_delay)
|
||||
cfg_rxclk_dly = FIELD_PREP(PRG_ETH1_CFG_RXCLK_DLY,
|
||||
dwmac->rx_delay_ps / 200);
|
||||
else if (dwmac->rx_delay_ps == 2000)
|
||||
rx_adj_config = PRG_ETH0_ADJ_ENABLE | PRG_ETH0_ADJ_SETUP;
|
||||
|
||||
switch (dwmac->phy_mode) {
|
||||
case PHY_INTERFACE_MODE_RGMII:
|
||||
delay_config = tx_dly_config | rx_dly_config;
|
||||
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_dly_config;
|
||||
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",
|
||||
@ -323,6 +339,9 @@ static int meson8b_init_rgmii_delays(struct meson8b_dwmac *dwmac)
|
||||
PRG_ETH0_ADJ_DELAY | PRG_ETH0_ADJ_SKEW,
|
||||
delay_config);
|
||||
|
||||
meson8b_dwmac_mask_bits(dwmac, PRG_ETH1, PRG_ETH1_CFG_RXCLK_DLY,
|
||||
cfg_rxclk_dly);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -423,11 +442,20 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
|
||||
dwmac->rx_delay_ps *= 1000;
|
||||
}
|
||||
|
||||
if (dwmac->rx_delay_ps != 0 && dwmac->rx_delay_ps != 2000) {
|
||||
dev_err(&pdev->dev,
|
||||
"The only allowed RX delays values are: 0ps, 2000ps");
|
||||
ret = -EINVAL;
|
||||
goto err_remove_config_dt;
|
||||
if (dwmac->data->has_prg_eth1_rgmii_rx_delay) {
|
||||
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");
|
||||
ret = -EINVAL;
|
||||
goto err_remove_config_dt;
|
||||
}
|
||||
} else {
|
||||
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");
|
||||
ret = -EINVAL;
|
||||
goto err_remove_config_dt;
|
||||
}
|
||||
}
|
||||
|
||||
dwmac->timing_adj_clk = devm_clk_get_optional(dwmac->dev,
|
||||
@ -469,10 +497,17 @@ err_remove_config_dt:
|
||||
|
||||
static const struct meson8b_dwmac_data meson8b_dwmac_data = {
|
||||
.set_phy_mode = meson8b_set_phy_mode,
|
||||
.has_prg_eth1_rgmii_rx_delay = false,
|
||||
};
|
||||
|
||||
static const struct meson8b_dwmac_data meson_axg_dwmac_data = {
|
||||
.set_phy_mode = meson_axg_set_phy_mode,
|
||||
.has_prg_eth1_rgmii_rx_delay = false,
|
||||
};
|
||||
|
||||
static const struct meson8b_dwmac_data meson_g12a_dwmac_data = {
|
||||
.set_phy_mode = meson_axg_set_phy_mode,
|
||||
.has_prg_eth1_rgmii_rx_delay = true,
|
||||
};
|
||||
|
||||
static const struct of_device_id meson8b_dwmac_match[] = {
|
||||
@ -494,7 +529,7 @@ static const struct of_device_id meson8b_dwmac_match[] = {
|
||||
},
|
||||
{
|
||||
.compatible = "amlogic,meson-g12a-dwmac",
|
||||
.data = &meson_axg_dwmac_data,
|
||||
.data = &meson_g12a_dwmac_data,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user