summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorVenkatesh Yadav Abbarapu <venkatesh.abbarapu@amd.com>2023-06-19 06:49:22 +0300
committerMichal Simek <michal.simek@amd.com>2023-07-21 10:00:38 +0300
commit22836f088d6027ee8e4bde17abbf71644a8388f5 (patch)
treefffd731ad7e173db95662cf6c9591e502be8b576 /drivers
parent9a45365ae9cd80e0f060e480c544c17bb9a81e51 (diff)
downloadu-boot-22836f088d6027ee8e4bde17abbf71644a8388f5.tar.xz
net: zynq_gem: Don't hardcode the MDC clock divisor
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@amd.com> Link: https://lore.kernel.org/r/20230619034922.24019-1-venkatesh.abbarapu@amd.com Signed-off-by: Michal Simek <michal.simek@amd.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/zynq_gem.c57
1 files 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);