[U-Boot] [PATCH 3/6] net: dwc_eth_qos: add Ethernet stm32mp1 support

Patrick DELAUNAY patrick.delaunay at st.com
Fri Apr 19 15:12:09 UTC 2019


Hi Christophe,

> 
> Synopsys GMAC 4.20 is used. And Phy mode for eval and disco is RMII with PHY
> Realtek RTL8211 (RGMII) We also support some other PHY config on
> stm32mp157c
> PHY_MODE	(MII,GMII, RMII, RGMII) and in normal,
> PHY wo crystal (25Mhz and 50Mhz), No 125Mhz from PHY config
> 
> Signed-off-by: Christophe Roullier <christophe.roullier at st.com>
> ---
> 
>  drivers/net/dwc_eth_qos.c | 435
> ++++++++++++++++++++++++++++++++++++++++------
>  1 file changed, 383 insertions(+), 52 deletions(-)
> 
> diff --git a/drivers/net/dwc_eth_qos.c b/drivers/net/dwc_eth_qos.c index
> 9f1c5af..a6546d5 100644
> --- a/drivers/net/dwc_eth_qos.c
> +++ b/drivers/net/dwc_eth_qos.c
> @@ -26,7 +26,6 @@
>   *    supports a single RGMII PHY. This configuration also has SW control over
>   *    all clock and reset signals to the HW block.
>   */
> -
>  #include <common.h>
>  #include <clk.h>
>  #include <dm.h>
> @@ -95,6 +94,7 @@ struct eqos_mac_regs {
>  #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK			3
>  #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_NOT_ENABLED		0
>  #define EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB		2
> +#define EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV		1
> 
>  #define EQOS_MAC_RXQ_CTRL2_PSRQ0_SHIFT			0
>  #define EQOS_MAC_RXQ_CTRL2_PSRQ0_MASK			0xff
> @@ -108,6 +108,7 @@ struct eqos_mac_regs {
>  #define EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT			16
>  #define EQOS_MAC_MDIO_ADDRESS_CR_SHIFT			8
>  #define EQOS_MAC_MDIO_ADDRESS_CR_20_35			2
> +#define EQOS_MAC_MDIO_ADDRESS_CR_250_300		5
>  #define EQOS_MAC_MDIO_ADDRESS_SKAP			BIT(4)
>  #define EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT			2
>  #define EQOS_MAC_MDIO_ADDRESS_GOC_READ			3
> @@ -260,6 +261,29 @@ struct eqos_desc {
> 
>  struct eqos_config {
>  	bool reg_access_always_ok;
> +	int mdio_wait;
> +	int swr_wait;
> +	int config_mac;
> +	int config_mac_mdio;
> +	int (*interface)(struct udevice *dev);
> +	struct eqos_ops *ops;
> +};
> +
> +struct eqos_ops {
> +	void (*eqos_inval_desc)(void *desc);
> +	void (*eqos_flush_desc)(void *desc);
> +	void (*eqos_inval_buffer)(void *buf, size_t size);
> +	void (*eqos_flush_buffer)(void *buf, size_t size);
> +	int (*eqos_probe_resources)(struct udevice *dev);
> +	int (*eqos_remove_resources)(struct udevice *dev);
> +	int (*eqos_stop_resets)(struct udevice *dev);
> +	int (*eqos_start_resets)(struct udevice *dev);
> +	void (*eqos_stop_clks)(struct udevice *dev);
> +	int (*eqos_start_clks)(struct udevice *dev);
> +	int (*eqos_calibrate_pads)(struct udevice *dev);
> +	int (*eqos_disable_calibration)(struct udevice *dev);
> +	int (*eqos_set_tx_clk_speed)(struct udevice *dev);
> +	ulong (*eqos_get_tick_clk_rate)(struct udevice *dev);
>  };
> 
>  struct eqos_priv {
> @@ -276,6 +300,7 @@ struct eqos_priv {
>  	struct clk clk_rx;
>  	struct clk clk_ptp_ref;
>  	struct clk clk_tx;
> +	struct clk clk_ck;
>  	struct clk clk_slave_bus;
>  	struct mii_dev *mii;
>  	struct phy_device *phy;
> @@ -327,7 +352,7 @@ static void eqos_free_descs(void *descs)  #endif  }
> 
> -static void eqos_inval_desc(void *desc)
> +static void eqos_inval_desc_tegra186(void *desc)
>  {
>  #ifndef CONFIG_SYS_NONCACHED_MEMORY
>  	unsigned long start = (unsigned long)desc & ~(ARCH_DMA_MINALIGN -
> 1); @@ -338,14 +363,36 @@ static void eqos_inval_desc(void *desc)  #endif  }
> 
> -static void eqos_flush_desc(void *desc)
> +static void eqos_inval_desc_stm32(void *desc) { #ifndef
> +CONFIG_SYS_NONCACHED_MEMORY
> +	unsigned long start = rounddown((unsigned long)desc,
> ARCH_DMA_MINALIGN);
> +	unsigned long end = roundup((unsigned long)desc +
> EQOS_DESCRIPTOR_SIZE,
> +				    ARCH_DMA_MINALIGN);
> +
> +	invalidate_dcache_range(start, end);
> +#endif
> +}
> +
> +static void eqos_flush_desc_tegra186(void *desc)
>  {
>  #ifndef CONFIG_SYS_NONCACHED_MEMORY
>  	flush_cache((unsigned long)desc, EQOS_DESCRIPTOR_SIZE);  #endif  }
> 
> -static void eqos_inval_buffer(void *buf, size_t size)
> +static void eqos_flush_desc_stm32(void *desc) { #ifndef
> +CONFIG_SYS_NONCACHED_MEMORY
> +	unsigned long start = rounddown((unsigned long)desc,
> ARCH_DMA_MINALIGN);
> +	unsigned long end = roundup((unsigned long)desc +
> EQOS_DESCRIPTOR_SIZE,
> +				    ARCH_DMA_MINALIGN);
> +
> +	flush_dcache_range(start, end);
> +#endif
> +}
> +
> +static void eqos_inval_buffer_tegra186(void *buf, size_t size)
>  {
>  	unsigned long start = (unsigned long)buf & ~(ARCH_DMA_MINALIGN -
> 1);
>  	unsigned long end = ALIGN(start + size, ARCH_DMA_MINALIGN); @@ -
> 353,11 +400,29 @@ static void eqos_inval_buffer(void *buf, size_t size)
>  	invalidate_dcache_range(start, end);
>  }
> 
> -static void eqos_flush_buffer(void *buf, size_t size)
> +static void eqos_inval_buffer_stm32(void *buf, size_t size) {
> +	unsigned long start = rounddown((unsigned long)buf,
> ARCH_DMA_MINALIGN);
> +	unsigned long end = roundup((unsigned long)buf + size,
> +				    ARCH_DMA_MINALIGN);
> +
> +	invalidate_dcache_range(start, end);
> +}
> +
> +static void eqos_flush_buffer_tegra186(void *buf, size_t size)
>  {
>  	flush_cache((unsigned long)buf, size);  }
> 
> +static void eqos_flush_buffer_stm32(void *buf, size_t size) {
> +	unsigned long start = rounddown((unsigned long)buf,
> ARCH_DMA_MINALIGN);
> +	unsigned long end = roundup((unsigned long)buf + size,
> +				    ARCH_DMA_MINALIGN);
> +
> +	flush_dcache_range(start, end);
> +}
> +
>  static int eqos_mdio_wait_idle(struct eqos_priv *eqos)  {
>  	return wait_for_bit_le32(&eqos->mac_regs->mdio_address,
> @@ -386,14 +451,14 @@ static int eqos_mdio_read(struct mii_dev *bus, int
> mdio_addr, int mdio_devad,
>  		EQOS_MAC_MDIO_ADDRESS_C45E;
>  	val |= (mdio_addr << EQOS_MAC_MDIO_ADDRESS_PA_SHIFT) |
>  		(mdio_reg << EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT) |
> -		(EQOS_MAC_MDIO_ADDRESS_CR_20_35 <<
> +		(eqos->config->config_mac_mdio <<
>  		 EQOS_MAC_MDIO_ADDRESS_CR_SHIFT) |
>  		(EQOS_MAC_MDIO_ADDRESS_GOC_READ <<
>  		 EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT) |
>  		EQOS_MAC_MDIO_ADDRESS_GB;
>  	writel(val, &eqos->mac_regs->mdio_address);
> 
> -	udelay(10);
> +	udelay(eqos->config->mdio_wait);
> 
>  	ret = eqos_mdio_wait_idle(eqos);
>  	if (ret) {
> @@ -432,14 +497,14 @@ static int eqos_mdio_write(struct mii_dev *bus, int
> mdio_addr, int mdio_devad,
>  		EQOS_MAC_MDIO_ADDRESS_C45E;
>  	val |= (mdio_addr << EQOS_MAC_MDIO_ADDRESS_PA_SHIFT) |
>  		(mdio_reg << EQOS_MAC_MDIO_ADDRESS_RDA_SHIFT) |
> -		(EQOS_MAC_MDIO_ADDRESS_CR_20_35 <<
> +		(eqos->config->config_mac_mdio <<
>  		 EQOS_MAC_MDIO_ADDRESS_CR_SHIFT) |
>  		(EQOS_MAC_MDIO_ADDRESS_GOC_WRITE <<
>  		 EQOS_MAC_MDIO_ADDRESS_GOC_SHIFT) |
>  		EQOS_MAC_MDIO_ADDRESS_GB;
>  	writel(val, &eqos->mac_regs->mdio_address);
> 
> -	udelay(10);
> +	udelay(eqos->config->mdio_wait);
> 
>  	ret = eqos_mdio_wait_idle(eqos);
>  	if (ret) {
> @@ -509,6 +574,53 @@ err:
>  	return ret;
>  }
> 
> +static int eqos_start_clks_stm32(struct udevice *dev) {
> +	struct eqos_priv *eqos = dev_get_priv(dev);
> +	int ret;
> +
> +	debug("%s(dev=%p):\n", __func__, dev);
> +
> +	ret = clk_enable(&eqos->clk_master_bus);
> +	if (ret < 0) {
> +		pr_err("clk_enable(clk_master_bus) failed: %d", ret);
> +		goto err;
> +	}
> +
> +	ret = clk_enable(&eqos->clk_rx);
> +	if (ret < 0) {
> +		pr_err("clk_enable(clk_rx) failed: %d", ret);
> +		goto err_disable_clk_master_bus;
> +	}
> +
> +	ret = clk_enable(&eqos->clk_tx);
> +	if (ret < 0) {
> +		pr_err("clk_enable(clk_tx) failed: %d", ret);
> +		goto err_disable_clk_rx;
> +	}
> +
> +	if (clk_valid(&eqos->clk_ck)) {
> +		ret = clk_enable(&eqos->clk_ck);
> +		if (ret < 0) {
> +			pr_err("clk_enable(clk_ck) failed: %d", ret);
> +			goto err_disable_clk_tx;
> +		}
> +	}
> +
> +	debug("%s: OK\n", __func__);
> +	return 0;
> +
> +err_disable_clk_tx:
> +	clk_disable(&eqos->clk_tx);
> +err_disable_clk_rx:
> +	clk_disable(&eqos->clk_rx);
> +err_disable_clk_master_bus:
> +	clk_disable(&eqos->clk_master_bus);
> +err:
> +	debug("%s: FAILED: %d\n", __func__, ret);
> +	return ret;
> +}
> +
>  void eqos_stop_clks_tegra186(struct udevice *dev)  {
>  	struct eqos_priv *eqos = dev_get_priv(dev); @@ -524,6 +636,21 @@
> void eqos_stop_clks_tegra186(struct udevice *dev)
>  	debug("%s: OK\n", __func__);
>  }
> 
> +void eqos_stop_clks_stm32(struct udevice *dev) {
> +	struct eqos_priv *eqos = dev_get_priv(dev);
> +
> +	debug("%s(dev=%p):\n", __func__, dev);
> +
> +	clk_disable(&eqos->clk_tx);
> +	clk_disable(&eqos->clk_rx);
> +	clk_disable(&eqos->clk_master_bus);
> +	if (clk_valid(&eqos->clk_ck))
> +		clk_disable(&eqos->clk_ck);
> +
> +	debug("%s: OK\n", __func__);
> +}
> +
>  static int eqos_start_resets_tegra186(struct udevice *dev)  {
>  	struct eqos_priv *eqos = dev_get_priv(dev); @@ -563,6 +690,11 @@
> static int eqos_start_resets_tegra186(struct udevice *dev)
>  	return 0;
>  }
> 
> +static int eqos_start_resets_stm32(struct udevice *dev) {
> +	return 0;
> +}
> +
>  static int eqos_stop_resets_tegra186(struct udevice *dev)  {
>  	struct eqos_priv *eqos = dev_get_priv(dev); @@ -573,6 +705,11 @@
> static int eqos_stop_resets_tegra186(struct udevice *dev)
>  	return 0;
>  }
> 
> +static int eqos_stop_resets_stm32(struct udevice *dev) {
> +	return 0;
> +}
> +
>  static int eqos_calibrate_pads_tegra186(struct udevice *dev)  {
>  	struct eqos_priv *eqos = dev_get_priv(dev); @@ -632,6 +769,23 @@
> static ulong eqos_get_tick_clk_rate_tegra186(struct udevice *dev)
>  	return clk_get_rate(&eqos->clk_slave_bus);
>  }
> 
> +static ulong eqos_get_tick_clk_rate_stm32(struct udevice *dev) {
> +	struct eqos_priv *eqos = dev_get_priv(dev);
> +
> +	return clk_get_rate(&eqos->clk_master_bus);
> +}
> +
> +static int eqos_calibrate_pads_stm32(struct udevice *dev) {
> +	return 0;
> +}
> +
> +static int eqos_disable_calibration_stm32(struct udevice *dev) {
> +	return 0;
> +}
> +
>  static int eqos_set_full_duplex(struct udevice *dev)  {
>  	struct eqos_priv *eqos = dev_get_priv(dev); @@ -726,6 +880,11 @@
> static int eqos_set_tx_clk_speed_tegra186(struct udevice *dev)
>  	return 0;
>  }
> 
> +static int eqos_set_tx_clk_speed_stm32(struct udevice *dev) {
> +	return 0;
> +}
> +
>  static int eqos_adjust_link(struct udevice *dev)  {
>  	struct eqos_priv *eqos = dev_get_priv(dev); @@ -766,23 +925,23 @@
> static int eqos_adjust_link(struct udevice *dev)
>  	}
> 
>  	if (en_calibration) {
> -		ret = eqos_calibrate_pads_tegra186(dev);
> +		ret = eqos->config->ops->eqos_calibrate_pads(dev);
>  		if (ret < 0) {
> -			pr_err("eqos_calibrate_pads_tegra186() failed: %d", ret);
> +			pr_err("eqos_calibrate_pads() failed: %d",
> +			       ret);
>  			return ret;
>  		}
>  	} else {
> -		ret = eqos_disable_calibration_tegra186(dev);
> +		ret = eqos->config->ops->eqos_disable_calibration(dev);
>  		if (ret < 0) {
> -			pr_err("eqos_disable_calibration_tegra186() failed: %d",
> -			      ret);
> +			pr_err("eqos_disable_calibration() failed: %d",
> +			       ret);
>  			return ret;
>  		}
>  	}
> -
> -	ret = eqos_set_tx_clk_speed_tegra186(dev);
> +	ret = eqos->config->ops->eqos_set_tx_clk_speed(dev);
>  	if (ret < 0) {
> -		pr_err("eqos_set_tx_clk_speed_tegra186() failed: %d", ret);
> +		pr_err("eqos_set_tx_clk_speed() failed: %d", ret);
>  		return ret;
>  	}
> 
> @@ -846,15 +1005,15 @@ static int eqos_start(struct udevice *dev)
>  	eqos->tx_desc_idx = 0;
>  	eqos->rx_desc_idx = 0;
> 
> -	ret = eqos_start_clks_tegra186(dev);
> +	ret = eqos->config->ops->eqos_start_clks(dev);
>  	if (ret < 0) {
> -		pr_err("eqos_start_clks_tegra186() failed: %d", ret);
> +		pr_err("eqos_start_clks() failed: %d", ret);
>  		goto err;
>  	}
> 
> -	ret = eqos_start_resets_tegra186(dev);
> +	ret = eqos->config->ops->eqos_start_resets(dev);
>  	if (ret < 0) {
> -		pr_err("eqos_start_resets_tegra186() failed: %d", ret);
> +		pr_err("eqos_start_resets() failed: %d", ret);
>  		goto err_stop_clks;
>  	}
> 
> @@ -863,32 +1022,41 @@ static int eqos_start(struct udevice *dev)
>  	eqos->reg_access_ok = true;
> 
>  	ret = wait_for_bit_le32(&eqos->dma_regs->mode,
> -				EQOS_DMA_MODE_SWR, false, 10, false);
> +				EQOS_DMA_MODE_SWR, false,
> +				eqos->config->swr_wait, false);
>  	if (ret) {
>  		pr_err("EQOS_DMA_MODE_SWR stuck");
>  		goto err_stop_resets;
>  	}
> 
> -	ret = eqos_calibrate_pads_tegra186(dev);
> +	ret = eqos->config->ops->eqos_calibrate_pads(dev);
>  	if (ret < 0) {
> -		pr_err("eqos_calibrate_pads_tegra186() failed: %d", ret);
> +		pr_err("eqos_calibrate_pads() failed: %d", ret);
>  		goto err_stop_resets;
>  	}
> +	rate = eqos->config->ops->eqos_get_tick_clk_rate(dev);
> 
> -	rate = eqos_get_tick_clk_rate_tegra186(dev);
>  	val = (rate / 1000000) - 1;
>  	writel(val, &eqos->mac_regs->us_tic_counter);
> 
> -	eqos->phy = phy_connect(eqos->mii, 0, dev, 0);
> +	/*
> +	 * if PHY was already connected and configured,
> +	 * don't need to reconnect/reconfigure again
> +	 */
>  	if (!eqos->phy) {
> -		pr_err("phy_connect() failed");
> -		goto err_stop_resets;
> -	}
> -	ret = phy_config(eqos->phy);
> -	if (ret < 0) {
> -		pr_err("phy_config() failed: %d", ret);
> -		goto err_shutdown_phy;
> +		eqos->phy = phy_connect(eqos->mii, 0, dev,
> +					eqos->config->interface(dev));
> +		if (!eqos->phy) {
> +			pr_err("phy_connect() failed");
> +			goto err_stop_resets;
> +		}
> +		ret = phy_config(eqos->phy);
> +		if (ret < 0) {
> +			pr_err("phy_config() failed: %d", ret);
> +			goto err_shutdown_phy;
> +		}
>  	}
> +
>  	ret = phy_startup(eqos->phy);
>  	if (ret < 0) {
>  		pr_err("phy_startup() failed: %d", ret); @@ -993,7 +1161,7 @@
> static int eqos_start(struct udevice *dev)
>  	clrsetbits_le32(&eqos->mac_regs->rxq_ctrl0,
>  			EQOS_MAC_RXQ_CTRL0_RXQ0EN_MASK <<
>  			EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT,
> -			EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB <<
> +			eqos->config->config_mac <<
>  			EQOS_MAC_RXQ_CTRL0_RXQ0EN_SHIFT);
> 
>  	/* Set TX flow control parameters */
> @@ -1074,7 +1242,7 @@ static int eqos_start(struct udevice *dev)
>  					     (i * EQOS_MAX_PACKET_SIZE));
>  		rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
>  	}
> -	flush_cache((unsigned long)eqos->descs, EQOS_DESCRIPTORS_SIZE);
> +	eqos->config->ops->eqos_flush_desc(eqos->descs);
> 
>  	writel(0, &eqos->dma_regs->ch0_txdesc_list_haddress);
>  	writel((ulong)eqos->tx_descs, &eqos->dma_regs-
> >ch0_txdesc_list_address);
> @@ -1113,11 +1281,10 @@ static int eqos_start(struct udevice *dev)
> 
>  err_shutdown_phy:
>  	phy_shutdown(eqos->phy);
> -	eqos->phy = NULL;
>  err_stop_resets:
> -	eqos_stop_resets_tegra186(dev);
> +	eqos->config->ops->eqos_stop_resets(dev);
>  err_stop_clks:
> -	eqos_stop_clks_tegra186(dev);
> +	eqos->config->ops->eqos_stop_clks(dev);
>  err:
>  	pr_err("FAILED: %d", ret);
>  	return ret;
> @@ -1170,10 +1337,9 @@ void eqos_stop(struct udevice *dev)
> 
>  	if (eqos->phy) {
>  		phy_shutdown(eqos->phy);
> -		eqos->phy = NULL;
>  	}
> -	eqos_stop_resets_tegra186(dev);
> -	eqos_stop_clks_tegra186(dev);
> +	eqos->config->ops->eqos_stop_resets(dev);
> +	eqos->config->ops->eqos_stop_clks(dev);
> 
>  	debug("%s: OK\n", __func__);
>  }
> @@ -1188,7 +1354,7 @@ int eqos_send(struct udevice *dev, void *packet, int
> length)
>  	      length);
> 
>  	memcpy(eqos->tx_dma_buf, packet, length);
> -	eqos_flush_buffer(eqos->tx_dma_buf, length);
> +	eqos->config->ops->eqos_flush_buffer(eqos->tx_dma_buf, length);
> 
>  	tx_desc = &(eqos->tx_descs[eqos->tx_desc_idx]);
>  	eqos->tx_desc_idx++;
> @@ -1203,12 +1369,12 @@ int eqos_send(struct udevice *dev, void *packet, int
> length)
>  	 */
>  	mb();
>  	tx_desc->des3 = EQOS_DESC3_OWN | EQOS_DESC3_FD |
> EQOS_DESC3_LD | length;
> -	eqos_flush_desc(tx_desc);
> +	eqos->config->ops->eqos_flush_desc(tx_desc);
> 
>  	writel((ulong)(tx_desc + 1), &eqos->dma_regs->ch0_txdesc_tail_pointer);
> 
>  	for (i = 0; i < 1000000; i++) {
> -		eqos_inval_desc(tx_desc);
> +		eqos->config->ops->eqos_inval_desc(tx_desc);
>  		if (!(readl(&tx_desc->des3) & EQOS_DESC3_OWN))
>  			return 0;
>  		udelay(1);
> @@ -1238,7 +1404,7 @@ int eqos_recv(struct udevice *dev, int flags, uchar
> **packetp)
>  	length = rx_desc->des3 & 0x7fff;
>  	debug("%s: *packetp=%p, length=%d\n", __func__, *packetp, length);
> 
> -	eqos_inval_buffer(*packetp, length);
> +	eqos->config->ops->eqos_inval_buffer(*packetp, length);
> 
>  	return length;
>  }
> @@ -1269,7 +1435,7 @@ int eqos_free_pkt(struct udevice *dev, uchar *packet,
> int length)
>  	 */
>  	mb();
>  	rx_desc->des3 |= EQOS_DESC3_OWN | EQOS_DESC3_BUF1V;
> -	eqos_flush_desc(rx_desc);
> +	eqos->config->ops->eqos_flush_desc(rx_desc);
> 
>  	writel((ulong)rx_desc, &eqos->dma_regs->ch0_rxdesc_tail_pointer);
> 
> @@ -1304,7 +1470,7 @@ static int eqos_probe_resources_core(struct udevice
> *dev)
>  		ret = -ENOMEM;
>  		goto err_free_descs;
>  	}
> -	debug("%s: rx_dma_buf=%p\n", __func__, eqos->rx_dma_buf);
> +	debug("%s: tx_dma_buf=%p\n", __func__, eqos->tx_dma_buf);
> 
>  	eqos->rx_dma_buf = memalign(EQOS_BUFFER_ALIGN,
> EQOS_RX_BUFFER_SIZE);
>  	if (!eqos->rx_dma_buf) {
> @@ -1312,7 +1478,7 @@ static int eqos_probe_resources_core(struct udevice
> *dev)
>  		ret = -ENOMEM;
>  		goto err_free_tx_dma_buf;
>  	}
> -	debug("%s: tx_dma_buf=%p\n", __func__, eqos->tx_dma_buf);
> +	debug("%s: rx_dma_buf=%p\n", __func__, eqos->rx_dma_buf);
> 
>  	eqos->rx_pkt = malloc(EQOS_MAX_PACKET_SIZE);
>  	if (!eqos->rx_pkt) {
> @@ -1424,6 +1590,98 @@ err_free_reset_eqos:
>  	return ret;
>  }
> 
> +/* board-specific Ethernet Interface initializations. */ __weak int
> +board_interface_eth_init(int interface_type, bool eth_clk_sel_reg,
> +				    bool eth_ref_clk_sel_reg)
> +{
> +	return 0;
> +}
> +
> +static int eqos_probe_resources_stm32(struct udevice *dev) {
> +	struct eqos_priv *eqos = dev_get_priv(dev);
> +	int ret;
> +	int interface;
> +	bool eth_clk_sel_reg = false;
> +	bool eth_ref_clk_sel_reg = false;
> +
> +	debug("%s(dev=%p):\n", __func__, dev);
> +
> +	interface = eqos->config->interface(dev);
> +
> +	if (interface == -1) {
> +		pr_err("Invalid PHY interface\n");
> +		return -EINVAL;
> +	}
> +
> +	/* Gigabit Ethernet 125MHz clock selection. */
> +	eth_clk_sel_reg = dev_read_bool(dev, "st,eth_clk_sel");
> +
> +	/* Ethernet 50Mhz RMII clock selection */
> +	eth_ref_clk_sel_reg =
> +		dev_read_bool(dev, "st,eth_ref_clk_sel");
> +
> +	ret = board_interface_eth_init(interface, eth_clk_sel_reg,
> +				       eth_ref_clk_sel_reg);
> +	if (ret)
> +		return -EINVAL;
> +
> +	ret = clk_get_by_name(dev, "stmmaceth", &eqos->clk_master_bus);
> +	if (ret) {
> +		pr_err("clk_get_by_name(master_bus) failed: %d", ret);
> +		goto err_probe;
> +	}
> +
> +	ret = clk_get_by_name(dev, "mac-clk-rx", &eqos->clk_rx);
> +	if (ret) {
> +		pr_err("clk_get_by_name(rx) failed: %d", ret);
> +		goto err_free_clk_master_bus;
> +	}
> +
> +	ret = clk_get_by_name(dev, "mac-clk-tx", &eqos->clk_tx);
> +	if (ret) {
> +		pr_err("clk_get_by_name(tx) failed: %d", ret);
> +		goto err_free_clk_rx;
> +	}
> +
> +	/*  Get ETH_CLK clocks (optional) */
> +	ret = clk_get_by_name(dev, "eth-ck", &eqos->clk_ck);
> +	if (ret)
> +		pr_warn("No phy clock provided %d", ret);
> +
> +	debug("%s: OK\n", __func__);
> +	return 0;
> +
> +err_free_clk_rx:
> +	clk_free(&eqos->clk_rx);
> +err_free_clk_master_bus:
> +	clk_free(&eqos->clk_master_bus);
> +err_probe:
> +
> +	debug("%s: returns %d\n", __func__, ret);
> +	return ret;
> +}
> +
> +static int eqos_get_interface_stm32(struct udevice *dev) {
> +	const char *phy_mode;
> +	int interface = -1;
> +
> +	debug("%s(dev=%p):\n", __func__, dev);
> +
> +	phy_mode = fdt_getprop(gd->fdt_blob, dev_of_offset(dev), "phy-mode",
> +			       NULL);
> +	if (phy_mode)
> +		interface = phy_get_interface_by_name(phy_mode);
> +
> +	return interface;
> +}
> +
> +static int eqos_get_interface_tegra186(struct udevice *dev) {
> +	return 0;
> +}
> +
>  static int eqos_remove_resources_tegra186(struct udevice *dev)  {
>  	struct eqos_priv *eqos = dev_get_priv(dev); @@ -1442,6 +1700,22 @@
> static int eqos_remove_resources_tegra186(struct udevice *dev)
>  	return 0;
>  }
> 
> +static int eqos_remove_resources_stm32(struct udevice *dev) {
> +	struct eqos_priv *eqos = dev_get_priv(dev);
> +
> +	debug("%s(dev=%p):\n", __func__, dev);
> +
> +	clk_free(&eqos->clk_tx);
> +	clk_free(&eqos->clk_rx);
> +	clk_free(&eqos->clk_master_bus);
> +	if (clk_valid(&eqos->clk_ck))
> +		clk_free(&eqos->clk_ck);
> +
> +	debug("%s: OK\n", __func__);
> +	return 0;
> +}
> +
>  static int eqos_probe(struct udevice *dev)  {
>  	struct eqos_priv *eqos = dev_get_priv(dev); @@ -1468,15 +1742,16 @@
> static int eqos_probe(struct udevice *dev)
>  		return ret;
>  	}
> 
> -	ret = eqos_probe_resources_tegra186(dev);
> +	ret = eqos->config->ops->eqos_probe_resources(dev);
>  	if (ret < 0) {
> -		pr_err("eqos_probe_resources_tegra186() failed: %d", ret);
> +		pr_err("eqos_probe_resources() failed: %d", ret);
>  		goto err_remove_resources_core;
>  	}
> 
>  	eqos->mii = mdio_alloc();
>  	if (!eqos->mii) {
>  		pr_err("mdio_alloc() failed");
> +		ret = -ENOMEM;
>  		goto err_remove_resources_tegra;
>  	}
>  	eqos->mii->read = eqos_mdio_read;
> @@ -1496,7 +1771,7 @@ static int eqos_probe(struct udevice *dev)
>  err_free_mdio:
>  	mdio_free(eqos->mii);
>  err_remove_resources_tegra:
> -	eqos_remove_resources_tegra186(dev);
> +	eqos->config->ops->eqos_remove_resources(dev);
>  err_remove_resources_core:
>  	eqos_remove_resources_core(dev);
> 
> @@ -1512,7 +1787,8 @@ static int eqos_remove(struct udevice *dev)
> 
>  	mdio_unregister(eqos->mii);
>  	mdio_free(eqos->mii);
> -	eqos_remove_resources_tegra186(dev);
> +	eqos->config->ops->eqos_remove_resources(dev);
> +
>  	eqos_probe_resources_core(dev);
> 
>  	debug("%s: OK\n", __func__);
> @@ -1528,8 +1804,58 @@ static const struct eth_ops eqos_ops = {
>  	.write_hwaddr = eqos_write_hwaddr,
>  };
> 
> +static struct eqos_ops eqos_tegra186_ops = {
> +	.eqos_inval_desc = eqos_inval_desc_tegra186,
> +	.eqos_flush_desc = eqos_flush_desc_tegra186,
> +	.eqos_inval_buffer = eqos_inval_buffer_tegra186,
> +	.eqos_flush_buffer = eqos_flush_buffer_tegra186,
> +	.eqos_probe_resources = eqos_probe_resources_tegra186,
> +	.eqos_remove_resources = eqos_remove_resources_tegra186,
> +	.eqos_stop_resets = eqos_stop_resets_tegra186,
> +	.eqos_start_resets = eqos_start_resets_tegra186,
> +	.eqos_stop_clks = eqos_stop_clks_tegra186,
> +	.eqos_start_clks = eqos_start_clks_tegra186,
> +	.eqos_calibrate_pads = eqos_calibrate_pads_tegra186,
> +	.eqos_disable_calibration = eqos_disable_calibration_tegra186,
> +	.eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_tegra186,
> +	.eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_tegra186 };
> +
>  static const struct eqos_config eqos_tegra186_config = {
>  	.reg_access_always_ok = false,
> +	.mdio_wait = 10,
> +	.swr_wait = 10,
> +	.config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_DCB,
> +	.config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_20_35,
> +	.interface = eqos_get_interface_tegra186,
> +	.ops = &eqos_tegra186_ops
> +};
> +
> +static struct eqos_ops eqos_stm32_ops = {
> +	.eqos_inval_desc = eqos_inval_desc_stm32,
> +	.eqos_flush_desc = eqos_flush_desc_stm32,
> +	.eqos_inval_buffer = eqos_inval_buffer_stm32,
> +	.eqos_flush_buffer = eqos_flush_buffer_stm32,
> +	.eqos_probe_resources = eqos_probe_resources_stm32,
> +	.eqos_remove_resources = eqos_remove_resources_stm32,
> +	.eqos_stop_resets = eqos_stop_resets_stm32,
> +	.eqos_start_resets = eqos_start_resets_stm32,
> +	.eqos_stop_clks = eqos_stop_clks_stm32,
> +	.eqos_start_clks = eqos_start_clks_stm32,
> +	.eqos_calibrate_pads = eqos_calibrate_pads_stm32,
> +	.eqos_disable_calibration = eqos_disable_calibration_stm32,
> +	.eqos_set_tx_clk_speed = eqos_set_tx_clk_speed_stm32,
> +	.eqos_get_tick_clk_rate = eqos_get_tick_clk_rate_stm32 };
> +
> +static const struct eqos_config eqos_stm32_config = {
> +	.reg_access_always_ok = false,
> +	.mdio_wait = 10000,
> +	.swr_wait = 50,
> +	.config_mac = EQOS_MAC_RXQ_CTRL0_RXQ0EN_ENABLED_AV,
> +	.config_mac_mdio = EQOS_MAC_MDIO_ADDRESS_CR_250_300,
> +	.interface = eqos_get_interface_stm32,
> +	.ops = &eqos_stm32_ops
>  };
> 
>  static const struct udevice_id eqos_ids[] = { @@ -1537,6 +1863,11 @@ static
> const struct udevice_id eqos_ids[] = {
>  		.compatible = "nvidia,tegra186-eqos",
>  		.data = (ulong)&eqos_tegra186_config
>  	},
> +	{
> +		.compatible = "snps,dwmac-4.20a",
> +		.data = (ulong)&eqos_stm32_config
> +	},
> +
>  	{ }
>  };
> 
> --
> 2.7.4

For stm32mp1 boards EV1 and DK2
Test done with master (SHA1 = 75ce8c938d39bd22460be66e6bf318bd2410c17b)

Tested-by: Patrick Delaunay <patrick.delaunay at st.com>
Reviewed-by: Patrick Delaunay <patrick.delaunay at st.com>

Regards
Patrick


More information about the U-Boot mailing list