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>
This commit is contained in:
Venkatesh Yadav Abbarapu 2023-06-19 09:19:22 +05:30 committed by Michal Simek
parent 9a45365ae9
commit 22836f088d

View file

@ -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);