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
1 changed files with 48 additions and 13 deletions
|
@ -68,10 +68,21 @@
|
||||||
*/
|
*/
|
||||||
#define PRG_ETH0_ADJ_SKEW GENMASK(24, 20)
|
#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;
|
||||||
|
|
||||||
struct meson8b_dwmac_data {
|
struct meson8b_dwmac_data {
|
||||||
int (*set_phy_mode)(struct meson8b_dwmac *dwmac);
|
int (*set_phy_mode)(struct meson8b_dwmac *dwmac);
|
||||||
|
bool has_prg_eth1_rgmii_rx_delay;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct meson8b_dwmac {
|
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)
|
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;
|
int ret;
|
||||||
|
|
||||||
|
rx_adj_config = 0;
|
||||||
|
cfg_rxclk_dly = 0;
|
||||||
tx_dly_config = FIELD_PREP(PRG_ETH0_TXDLY_MASK,
|
tx_dly_config = FIELD_PREP(PRG_ETH0_TXDLY_MASK,
|
||||||
dwmac->tx_delay_ns >> 1);
|
dwmac->tx_delay_ns >> 1);
|
||||||
|
|
||||||
if (dwmac->rx_delay_ps == 2000)
|
if (dwmac->data->has_prg_eth1_rgmii_rx_delay)
|
||||||
rx_dly_config = PRG_ETH0_ADJ_ENABLE | PRG_ETH0_ADJ_SETUP;
|
cfg_rxclk_dly = FIELD_PREP(PRG_ETH1_CFG_RXCLK_DLY,
|
||||||
else
|
dwmac->rx_delay_ps / 200);
|
||||||
rx_dly_config = 0;
|
else if (dwmac->rx_delay_ps == 2000)
|
||||||
|
rx_adj_config = PRG_ETH0_ADJ_ENABLE | PRG_ETH0_ADJ_SETUP;
|
||||||
|
|
||||||
switch (dwmac->phy_mode) {
|
switch (dwmac->phy_mode) {
|
||||||
case PHY_INTERFACE_MODE_RGMII:
|
case PHY_INTERFACE_MODE_RGMII:
|
||||||
delay_config = tx_dly_config | rx_dly_config;
|
delay_config = tx_dly_config | rx_adj_config;
|
||||||
break;
|
break;
|
||||||
case PHY_INTERFACE_MODE_RGMII_RXID:
|
case PHY_INTERFACE_MODE_RGMII_RXID:
|
||||||
delay_config = tx_dly_config;
|
delay_config = tx_dly_config;
|
||||||
|
cfg_rxclk_dly = 0;
|
||||||
break;
|
break;
|
||||||
case PHY_INTERFACE_MODE_RGMII_TXID:
|
case PHY_INTERFACE_MODE_RGMII_TXID:
|
||||||
delay_config = rx_dly_config;
|
delay_config = rx_adj_config;
|
||||||
break;
|
break;
|
||||||
case PHY_INTERFACE_MODE_RGMII_ID:
|
case PHY_INTERFACE_MODE_RGMII_ID:
|
||||||
case PHY_INTERFACE_MODE_RMII:
|
case PHY_INTERFACE_MODE_RMII:
|
||||||
delay_config = 0;
|
delay_config = 0;
|
||||||
|
cfg_rxclk_dly = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
dev_err(dwmac->dev, "unsupported phy-mode %s\n",
|
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,
|
PRG_ETH0_ADJ_DELAY | PRG_ETH0_ADJ_SKEW,
|
||||||
delay_config);
|
delay_config);
|
||||||
|
|
||||||
|
meson8b_dwmac_mask_bits(dwmac, PRG_ETH1, PRG_ETH1_CFG_RXCLK_DLY,
|
||||||
|
cfg_rxclk_dly);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,12 +442,21 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
|
||||||
dwmac->rx_delay_ps *= 1000;
|
dwmac->rx_delay_ps *= 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dwmac->data->has_prg_eth1_rgmii_rx_delay) {
|
||||||
if (dwmac->rx_delay_ps != 0 && dwmac->rx_delay_ps != 2000) {
|
if (dwmac->rx_delay_ps != 0 && dwmac->rx_delay_ps != 2000) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(dwmac->dev,
|
||||||
"The only allowed RX delays values are: 0ps, 2000ps");
|
"The only allowed RGMII RX delays values are: 0ps, 2000ps");
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto err_remove_config_dt;
|
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,
|
dwmac->timing_adj_clk = devm_clk_get_optional(dwmac->dev,
|
||||||
"timing-adjustment");
|
"timing-adjustment");
|
||||||
|
@ -469,10 +497,17 @@ err_remove_config_dt:
|
||||||
|
|
||||||
static const struct meson8b_dwmac_data meson8b_dwmac_data = {
|
static const struct meson8b_dwmac_data meson8b_dwmac_data = {
|
||||||
.set_phy_mode = meson8b_set_phy_mode,
|
.set_phy_mode = meson8b_set_phy_mode,
|
||||||
|
.has_prg_eth1_rgmii_rx_delay = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct meson8b_dwmac_data meson_axg_dwmac_data = {
|
static const struct meson8b_dwmac_data meson_axg_dwmac_data = {
|
||||||
.set_phy_mode = meson_axg_set_phy_mode,
|
.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[] = {
|
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",
|
.compatible = "amlogic,meson-g12a-dwmac",
|
||||||
.data = &meson_axg_dwmac_data,
|
.data = &meson_g12a_dwmac_data,
|
||||||
},
|
},
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue