[PATCH v2 5/7] net: dwc_eth_qos_rockchip: Add support for RK3588

Stefan Agner stefan at agner.ch
Mon Jan 29 15:45:30 CET 2024


Hi Jonas,

On 2023-10-01 21:17, Jonas Karlman wrote:
> Add rk_gmac_ops and other special handling that is needed for GMAC to
> work on RK3588.
> 
> rk_gmac_ops was ported from linux commits:
> 2f2b60a0ec28 ("net: ethernet: stmmac: dwmac-rk: Add gmac support for rk3588")
> 88619e77b33d ("net: stmmac: rk3588: Allow multiple gmac controller")

I've updated from U-Boot 2023.07.2 to 2024.01, and noticed Ethernet
issue on Linux. On a ODROID-M1 with 8GB of RAM I had a packet drop rate
of ~20%:

107 packets transmitted, 87 received, 18.6916% packet loss, time
107390ms
rtt min/avg/max/mdev = 0.337/0.405/0.889/0.076 ms

SSH connections feel very sluggy, presumably due to packet losses.

Strangely, the same build works just fine on another ODROID-M1 with 4GB
of RAM. I swapped Ethernet cable and switches to rule this out. It
really seems to bee that particular unit which is problematic.

Disabling this driver fixes the Etherent issue on Linux.

Do you have an idea what this could be? I am happy to run commands or
test patches to debug this.

--
Stefan


> 
> Signed-off-by: Jonas Karlman <jonas at kwiboo.se>
> Reviewed-by: Kever Yang <kever.yang at rock-chips.com>
> ---
> Cc: David Wu <david.wu at rock-chips.com>
> Cc: Sebastian Reichel <sebastian.reichel at collabora.com>
> Cc: Benjamin Gaignard <benjamin.gaignard at collabora.com>
> ---
> v2:
> - Collect r-b tag
> 
>  drivers/net/dwc_eth_qos.c          |   4 +
>  drivers/net/dwc_eth_qos_rockchip.c | 182 ++++++++++++++++++++++++++++-
>  2 files changed, 182 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c
> index 9fb98a2c3c74..dc04416865dd 100644
> --- a/drivers/net/dwc_eth_qos.c
> +++ b/drivers/net/dwc_eth_qos.c
> @@ -1712,6 +1712,10 @@ static const struct udevice_id eqos_ids[] = {
>  		.compatible = "rockchip,rk3568-gmac",
>  		.data = (ulong)&eqos_rockchip_config
>  	},
> +	{
> +		.compatible = "rockchip,rk3588-gmac",
> +		.data = (ulong)&eqos_rockchip_config
> +	},
>  #endif
>  #if IS_ENABLED(CONFIG_DWC_ETH_QOS_QCOM)
>  	{
> diff --git a/drivers/net/dwc_eth_qos_rockchip.c
> b/drivers/net/dwc_eth_qos_rockchip.c
> index 05edc098f50d..20fd3a25c3dd 100644
> --- a/drivers/net/dwc_eth_qos_rockchip.c
> +++ b/drivers/net/dwc_eth_qos_rockchip.c
> @@ -28,6 +28,7 @@ struct rk_gmac_ops {
>  			    int tx_delay, int rx_delay);
>  	int (*set_to_rmii)(struct udevice *dev);
>  	int (*set_gmac_speed)(struct udevice *dev);
> +	void (*set_clock_selection)(struct udevice *dev, bool enable);
>  	u32 regs[3];
>  };
>  
> @@ -35,7 +36,9 @@ struct rockchip_platform_data {
>  	struct reset_ctl_bulk resets;
>  	const struct rk_gmac_ops *ops;
>  	int id;
> +	bool clock_input;
>  	struct regmap *grf;
> +	struct regmap *php_grf;
>  };
>  
>  #define HIWORD_UPDATE(val, mask, shift) \
> @@ -129,6 +132,137 @@ static int rk3568_set_gmac_speed(struct udevice *dev)
>  	return 0;
>  }
>  
> +/* sys_grf */
> +#define RK3588_GRF_GMAC_CON7			0x031c
> +#define RK3588_GRF_GMAC_CON8			0x0320
> +#define RK3588_GRF_GMAC_CON9			0x0324
> +
> +#define RK3588_GMAC_RXCLK_DLY_ENABLE(id)	GRF_BIT(2 * (id) + 3)
> +#define RK3588_GMAC_RXCLK_DLY_DISABLE(id)	GRF_CLR_BIT(2 * (id) + 3)
> +#define RK3588_GMAC_TXCLK_DLY_ENABLE(id)	GRF_BIT(2 * (id) + 2)
> +#define RK3588_GMAC_TXCLK_DLY_DISABLE(id)	GRF_CLR_BIT(2 * (id) + 2)
> +
> +#define RK3588_GMAC_CLK_RX_DL_CFG(val)		HIWORD_UPDATE(val, 0xFF, 8)
> +#define RK3588_GMAC_CLK_TX_DL_CFG(val)		HIWORD_UPDATE(val, 0xFF, 0)
> +
> +/* php_grf */
> +#define RK3588_GRF_GMAC_CON0			0x0008
> +#define RK3588_GRF_CLK_CON1			0x0070
> +
> +#define RK3588_GMAC_PHY_INTF_SEL_RGMII(id)	\
> +	(GRF_BIT(3 + (id) * 6) | GRF_CLR_BIT(4 + (id) * 6) | GRF_CLR_BIT(5 +
> (id) * 6))
> +#define RK3588_GMAC_PHY_INTF_SEL_RMII(id)	\
> +	(GRF_CLR_BIT(3 + (id) * 6) | GRF_CLR_BIT(4 + (id) * 6) | GRF_BIT(5 +
> (id) * 6))
> +
> +#define RK3588_GMAC_CLK_RMII_MODE(id)		GRF_BIT(5 * (id))
> +#define RK3588_GMAC_CLK_RGMII_MODE(id)		GRF_CLR_BIT(5 * (id))
> +
> +#define RK3588_GMAC_CLK_SELET_CRU(id)		GRF_BIT(5 * (id) + 4)
> +#define RK3588_GMAC_CLK_SELET_IO(id)		GRF_CLR_BIT(5 * (id) + 4)
> +
> +#define RK3588_GMAC_CLK_RMII_DIV2(id)		GRF_BIT(5 * (id) + 2)
> +#define RK3588_GMAC_CLK_RMII_DIV20(id)		GRF_CLR_BIT(5 * (id) + 2)
> +
> +#define RK3588_GMAC_CLK_RGMII_DIV1(id)		\
> +			(GRF_CLR_BIT(5 * (id) + 2) | GRF_CLR_BIT(5 * (id) + 3))
> +#define RK3588_GMAC_CLK_RGMII_DIV5(id)		\
> +			(GRF_BIT(5 * (id) + 2) | GRF_BIT(5 * (id) + 3))
> +#define RK3588_GMAC_CLK_RGMII_DIV50(id)		\
> +			(GRF_CLR_BIT(5 * (id) + 2) | GRF_BIT(5 * (id) + 3))
> +
> +#define RK3588_GMAC_CLK_RMII_GATE(id)		GRF_BIT(5 * (id) + 1)
> +#define RK3588_GMAC_CLK_RMII_NOGATE(id)		GRF_CLR_BIT(5 * (id) + 1)
> +
> +static int rk3588_set_to_rgmii(struct udevice *dev,
> +			       int tx_delay, int rx_delay)
> +{
> +	struct eth_pdata *pdata = dev_get_plat(dev);
> +	struct rockchip_platform_data *data = pdata->priv_pdata;
> +	u32 offset_con, id = data->id;
> +
> +	offset_con = data->id == 1 ? RK3588_GRF_GMAC_CON9 :
> +				     RK3588_GRF_GMAC_CON8;
> +
> +	regmap_write(data->php_grf, RK3588_GRF_GMAC_CON0,
> +		     RK3588_GMAC_PHY_INTF_SEL_RGMII(id));
> +
> +	regmap_write(data->php_grf, RK3588_GRF_CLK_CON1,
> +		     RK3588_GMAC_CLK_RGMII_MODE(id));
> +
> +	regmap_write(data->grf, RK3588_GRF_GMAC_CON7,
> +		     RK3588_GMAC_RXCLK_DLY_ENABLE(id) |
> +		     RK3588_GMAC_TXCLK_DLY_ENABLE(id));
> +
> +	regmap_write(data->grf, offset_con,
> +		     RK3588_GMAC_CLK_RX_DL_CFG(rx_delay) |
> +		     RK3588_GMAC_CLK_TX_DL_CFG(tx_delay));
> +
> +	return 0;
> +}
> +
> +static int rk3588_set_to_rmii(struct udevice *dev)
> +{
> +	struct eth_pdata *pdata = dev_get_plat(dev);
> +	struct rockchip_platform_data *data = pdata->priv_pdata;
> +
> +	regmap_write(data->php_grf, RK3588_GRF_GMAC_CON0,
> +		     RK3588_GMAC_PHY_INTF_SEL_RMII(data->id));
> +
> +	regmap_write(data->php_grf, RK3588_GRF_CLK_CON1,
> +		     RK3588_GMAC_CLK_RMII_MODE(data->id));
> +
> +	return 0;
> +}
> +
> +static int rk3588_set_gmac_speed(struct udevice *dev)
> +{
> +	struct eqos_priv *eqos = dev_get_priv(dev);
> +	struct eth_pdata *pdata = dev_get_plat(dev);
> +	struct rockchip_platform_data *data = pdata->priv_pdata;
> +	u32 val = 0, id = data->id;
> +
> +	switch (eqos->phy->speed) {
> +	case SPEED_10:
> +		if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII)
> +			val = RK3588_GMAC_CLK_RMII_DIV20(id);
> +		else
> +			val = RK3588_GMAC_CLK_RGMII_DIV50(id);
> +		break;
> +	case SPEED_100:
> +		if (pdata->phy_interface == PHY_INTERFACE_MODE_RMII)
> +			val = RK3588_GMAC_CLK_RMII_DIV2(id);
> +		else
> +			val = RK3588_GMAC_CLK_RGMII_DIV5(id);
> +		break;
> +	case SPEED_1000:
> +		if (pdata->phy_interface != PHY_INTERFACE_MODE_RMII)
> +			val = RK3588_GMAC_CLK_RGMII_DIV1(id);
> +		else
> +			return -EINVAL;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	regmap_write(data->php_grf, RK3588_GRF_CLK_CON1, val);
> +
> +	return 0;
> +}
> +
> +static void rk3588_set_clock_selection(struct udevice *dev, bool enable)
> +{
> +	struct eth_pdata *pdata = dev_get_plat(dev);
> +	struct rockchip_platform_data *data = pdata->priv_pdata;
> +
> +	u32 val = data->clock_input ? RK3588_GMAC_CLK_SELET_IO(data->id) :
> +				      RK3588_GMAC_CLK_SELET_CRU(data->id);
> +
> +	val |= enable ? RK3588_GMAC_CLK_RMII_NOGATE(data->id) :
> +			RK3588_GMAC_CLK_RMII_GATE(data->id);
> +
> +	regmap_write(data->php_grf, RK3588_GRF_CLK_CON1, val);
> +}
> +
>  static const struct rk_gmac_ops rk_gmac_ops[] = {
>  	{
>  		.compatible = "rockchip,rk3568-gmac",
> @@ -141,6 +275,18 @@ static const struct rk_gmac_ops rk_gmac_ops[] = {
>  			0x0, /* sentinel */
>  		},
>  	},
> +	{
> +		.compatible = "rockchip,rk3588-gmac",
> +		.set_to_rgmii = rk3588_set_to_rgmii,
> +		.set_to_rmii = rk3588_set_to_rmii,
> +		.set_gmac_speed = rk3588_set_gmac_speed,
> +		.set_clock_selection = rk3588_set_clock_selection,
> +		.regs = {
> +			0xfe1b0000, /* gmac0 */
> +			0xfe1c0000, /* gmac1 */
> +			0x0, /* sentinel */
> +		},
> +	},
>  	{ }
>  };
>  
> @@ -162,6 +308,7 @@ static int eqos_probe_resources_rk(struct udevice *dev)
>  	struct eqos_priv *eqos = dev_get_priv(dev);
>  	struct eth_pdata *pdata = dev_get_plat(dev);
>  	struct rockchip_platform_data *data;
> +	const char *clock_in_out;
>  	int reset_flags = GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE;
>  	int ret;
>  
> @@ -199,6 +346,16 @@ static int eqos_probe_resources_rk(struct udevice *dev)
>  		goto err_free;
>  	}
>  
> +	if (device_is_compatible(dev, "rockchip,rk3588-gmac")) {
> +		data->php_grf =
> +			syscon_regmap_lookup_by_phandle(dev, "rockchip,php-grf");
> +		if (IS_ERR(data->php_grf)) {
> +			dev_err(dev, "Missing rockchip,php-grf property\n");
> +			ret = -EINVAL;
> +			goto err_free;
> +		}
> +	}
> +
>  	ret = reset_get_bulk(dev, &data->resets);
>  	if (ret < 0)
>  		goto err_free;
> @@ -211,12 +368,20 @@ static int eqos_probe_resources_rk(struct udevice *dev)
>  		goto err_release_resets;
>  	}
>  
> -	ret = clk_get_by_name(dev, "clk_mac_speed", &eqos->clk_tx);
> -	if (ret) {
> -		dev_dbg(dev, "clk_get_by_name(clk_mac_speed) failed: %d", ret);
> -		goto err_free_clk_master_bus;
> +	if (device_is_compatible(dev, "rockchip,rk3568-gmac")) {
> +		ret = clk_get_by_name(dev, "clk_mac_speed", &eqos->clk_tx);
> +		if (ret) {
> +			dev_dbg(dev, "clk_get_by_name(clk_mac_speed) failed: %d", ret);
> +			goto err_free_clk_master_bus;
> +		}
>  	}
>  
> +	clock_in_out = dev_read_string(dev, "clock_in_out");
> +	if (clock_in_out && !strcmp(clock_in_out, "input"))
> +		data->clock_input = true;
> +	else
> +		data->clock_input = false;
> +
>  	/* snps,reset props are deprecated, do bare minimum to support them */
>  	if (dev_read_bool(dev, "snps,reset-active-low"))
>  		reset_flags |= GPIOD_ACTIVE_LOW;
> @@ -273,6 +438,12 @@ static int eqos_start_resets_rk(struct udevice *dev)
>  
>  static int eqos_stop_clks_rk(struct udevice *dev)
>  {
> +	struct eth_pdata *pdata = dev_get_plat(dev);
> +	struct rockchip_platform_data *data = pdata->priv_pdata;
> +
> +	if (data->ops->set_clock_selection)
> +		data->ops->set_clock_selection(dev, false);
> +
>  	return 0;
>  }
>  
> @@ -293,6 +464,9 @@ static int eqos_start_clks_rk(struct udevice *dev)
>  		udelay(eqos->reset_delays[2]);
>  	}
>  
> +	if (data->ops->set_clock_selection)
> +		data->ops->set_clock_selection(dev, true);
> +
>  	tx_delay = dev_read_u32_default(dev, "tx_delay", 0x30);
>  	rx_delay = dev_read_u32_default(dev, "rx_delay", 0x10);


More information about the U-Boot mailing list