summaryrefslogtreecommitdiff
path: root/drivers/net/zynq_gem.c
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2023-07-21 09:57:59 -0400
committerTom Rini <trini@konsulko.com>2023-07-21 09:57:59 -0400
commite7f7e2e1e22fd719a8810ba488a9451635b13d1b (patch)
tree0dda2ed98b772b44ae61b041d402f9618cd18670 /drivers/net/zynq_gem.c
parente896279ac39ebb97f23e6132bf7668a61e1cd86b (diff)
parenta1190b4d6a9bf3a45038e3eba4a11de4be2b1cca (diff)
Merge tag 'xilinx-for-v2023.10-rc1-v2' of https://source.denx.de/u-boot/custodians/u-boot-microblaze
Xilinx changes for v2023.10-rc1 v2 axi_emac: - Change return value if RX packet is not ready cadence_qspi: - Enable flash reset for Versal NET dt: - Various DT syncups with Linux kernel - SOM - reserved pmufw memory location fpga: - Add load event mtd: - Add missing dependency for FLASH_CFI_MTD spi/nand: - Minor cleanup in Xilinx drivers versal-net: - Prioritize boot device in boot_targets - Wire mini ospi/qspi/emmc configurations watchdog: - Use new versal-wwdt property xilinx: - fix sparse warnings in various places ps7_init* - add missing headers - consolidate code around zynqmp_mmio_read/write - switch to amd.com email zynqmp_clk: - Add handling for gem rx/tsu clocks zynq_gem: - Configure mdio clock at run time zynq: - Enable fdt overlay support zynq_sdhci: - Call dll reset only for ZynqMP SOCs
Diffstat (limited to 'drivers/net/zynq_gem.c')
-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 211b2c6e556..f3cdfb0275d 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);