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.abbar...@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