157 lines
5.0 KiB
Diff
157 lines
5.0 KiB
Diff
From af5a137b69d3f9f88b89601abf8a2be3aec2c180 Mon Sep 17 00:00:00 2001
|
|
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
|
Date: Sat, 14 Nov 2020 19:41:11 +0100
|
|
Subject: [PATCH 27/88] FROMGIT: 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>
|
|
---
|
|
.../ethernet/stmicro/stmmac/dwmac-meson8b.c | 61 +++++++++++++++----
|
|
1 file changed, 48 insertions(+), 13 deletions(-)
|
|
|
|
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
|
|
index 4937432ac70d..55152d7ba99a 100644
|
|
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
|
|
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson8b.c
|
|
@@ -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 @@ static int meson8b_dwmac_probe(struct platform_device *pdev)
|
|
|
|
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,
|
|
},
|
|
{ }
|
|
};
|
|
--
|
|
2.17.1
|
|
|