[PATCH] net: zynq_gem: Don't hardcode the MDC clock divisor

Venkatesh Yadav Abbarapu venkatesh.abbarapu at amd.com
Mon Jun 19 05:49:22 CEST 2023


As per spec MDC must not exceed 2.5MHz, read the pclk clock
from the device tree and update the MDC clock divisor.
GEM devices support larger clock divisors and have a different
range of divisors.  Program the MDIO clock divisors based on
the clock rate of the pclk clock.

Signed-off-by: Venkatesh Yadav Abbarapu <venkatesh.abbarapu at amd.com>
---
 drivers/net/zynq_gem.c | 57 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 49 insertions(+), 8 deletions(-)

diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index 211b2c6e55..f3cdfb0275 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -30,6 +30,7 @@
 #include <asm/arch/hardware.h>
 #include <asm/arch/sys_proto.h>
 #include <dm/device_compat.h>
+#include <linux/bitfield.h>
 #include <linux/bitops.h>
 #include <linux/err.h>
 #include <linux/errno.h>
@@ -67,11 +68,6 @@
 #define ZYNQ_GEM_NWCFG_FSREM		0x00020000 /* FCS removal */
 #define ZYNQ_GEM_NWCFG_SGMII_ENBL	0x08000000 /* SGMII Enable */
 #define ZYNQ_GEM_NWCFG_PCS_SEL		0x00000800 /* PCS select */
-#ifdef CONFIG_ARM64
-#define ZYNQ_GEM_NWCFG_MDCCLKDIV	0x00100000 /* Div pclk by 64, max 160MHz */
-#else
-#define ZYNQ_GEM_NWCFG_MDCCLKDIV	0x000c0000 /* Div pclk by 48, max 120MHz */
-#endif
 
 #ifdef CONFIG_ARM64
 # define ZYNQ_GEM_DBUS_WIDTH	(1 << 21) /* 64 bit bus */
@@ -81,8 +77,7 @@
 
 #define ZYNQ_GEM_NWCFG_INIT		(ZYNQ_GEM_DBUS_WIDTH | \
 					ZYNQ_GEM_NWCFG_FDEN | \
-					ZYNQ_GEM_NWCFG_FSREM | \
-					ZYNQ_GEM_NWCFG_MDCCLKDIV)
+					ZYNQ_GEM_NWCFG_FSREM)
 
 #define ZYNQ_GEM_NWSR_MDIOIDLE_MASK	0x00000004 /* PHY management idle */
 
@@ -141,6 +136,18 @@
 
 #define RXCLK_EN		BIT(0)
 
+/* GEM specific constants for CLK. */
+#define GEM_CLK_DIV8		0
+#define GEM_CLK_DIV16		1
+#define GEM_CLK_DIV32		2
+#define GEM_CLK_DIV48		3
+#define GEM_CLK_DIV64		4
+#define GEM_CLK_DIV96		5
+#define GEM_CLK_DIV128		6
+#define GEM_CLK_DIV224		7
+
+#define GEM_MDC_SET(val)	FIELD_PREP(GENMASK(20, 18), val)
+
 /* Device registers */
 struct zynq_gem_regs {
 	u32 nwctrl; /* 0x0 - Network Control reg */
@@ -220,6 +227,7 @@ struct zynq_gem_priv {
 	struct mii_dev *bus;
 	struct clk rx_clk;
 	struct clk tx_clk;
+	struct clk pclk;
 	u32 max_speed;
 	bool int_pcs;
 	bool dma_64bit;
@@ -352,6 +360,32 @@ static int zynq_phy_init(struct udevice *dev)
 	return phy_config(priv->phydev);
 }
 
+static u32 gem_mdc_clk_div(struct zynq_gem_priv *priv)
+{
+	u32 config;
+	unsigned long pclk_hz;
+
+	pclk_hz = clk_get_rate(&priv->pclk);
+	if (pclk_hz <= 20000000)
+		config = GEM_MDC_SET(GEM_CLK_DIV8);
+	else if (pclk_hz <= 40000000)
+		config = GEM_MDC_SET(GEM_CLK_DIV16);
+	else if (pclk_hz <= 80000000)
+		config = GEM_MDC_SET(GEM_CLK_DIV32);
+	else if (pclk_hz <= 120000000)
+		config = GEM_MDC_SET(GEM_CLK_DIV48);
+	else if (pclk_hz <= 160000000)
+		config = GEM_MDC_SET(GEM_CLK_DIV64);
+	else if (pclk_hz <= 240000000)
+		config = GEM_MDC_SET(GEM_CLK_DIV96);
+	else if (pclk_hz <= 320000000)
+		config = GEM_MDC_SET(GEM_CLK_DIV128);
+	else
+		config = GEM_MDC_SET(GEM_CLK_DIV224);
+
+	return config;
+}
+
 static int zynq_gem_init(struct udevice *dev)
 {
 	u32 i, nwconfig;
@@ -460,7 +494,8 @@ static int zynq_gem_init(struct udevice *dev)
 		return -1;
 	}
 
-	nwconfig = ZYNQ_GEM_NWCFG_INIT;
+	nwconfig = gem_mdc_clk_div(priv);
+	nwconfig |= ZYNQ_GEM_NWCFG_INIT;
 
 	/*
 	 * Set SGMII enable PCS selection only if internal PCS/PMA
@@ -828,6 +863,12 @@ static int zynq_gem_probe(struct udevice *dev)
 		}
 	}
 
+	ret = clk_get_by_name(dev, "pclk", &priv->pclk);
+	if (ret < 0) {
+		dev_err(dev, "failed to get pclk clock\n");
+		goto err2;
+	}
+
 	if (IS_ENABLED(CONFIG_DM_ETH_PHY))
 		priv->bus = eth_phy_get_mdio_bus(dev);
 
-- 
2.17.1



More information about the U-Boot mailing list