lkml.org 
[lkml]   [2021]   [Jan]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v4 5/5] net: stmmac: dwmac-meson8b: add support for the RGMII RX delay on G12A
    Date
    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.30.0
    \
     
     \ /
      Last update: 2021-01-06 14:47    [W:5.366 / U:0.124 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site