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:
Martin Blumenstingl 2021-01-06 14:42:51 +01:00 committed by Jakub Kicinski
parent 7985244d10
commit de94fc104d
1 changed files with 48 additions and 13 deletions

View File

@ -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,
},
{ }
};