From 266875ead0e81ead2a10179ec8498a683e2e2b32 Mon Sep 17 00:00:00 2001 From: Immo Birnbaum Date: Thu, 15 Jul 2021 13:10:33 +0200 Subject: [PATCH] drivers: ethernet: xlnx_gem: Zynq-7000 support for the Xilinx GEM driver Add support for the Xilinx Zynq-7000 SoC family to this driver. This includes some SoC-specific register accesses when setting an updated TX clock divider, also, the device tree binding now supports higher MDC clock divisor values when the current target SoC is a Zynq rather than a ZynqMP. With regards to the use of this driver in a QEMU simulation of the Zynq-7000, the Kconfig file is modified so that the driver is not enabled unless QEMU networking is set to Ethernet mode. Signed-off-by: Immo Birnbaum --- drivers/ethernet/Kconfig.xlnx_gem | 3 +- drivers/ethernet/eth_xlnx_gem.c | 31 +++++++++++++++- drivers/ethernet/eth_xlnx_gem_priv.h | 48 +++++++++++++++++++++---- include/dt-bindings/ethernet/xlnx_gem.h | 14 +++++--- 4 files changed, 84 insertions(+), 12 deletions(-) diff --git a/drivers/ethernet/Kconfig.xlnx_gem b/drivers/ethernet/Kconfig.xlnx_gem index 9657c5a905d..66799f10b57 100644 --- a/drivers/ethernet/Kconfig.xlnx_gem +++ b/drivers/ethernet/Kconfig.xlnx_gem @@ -11,7 +11,8 @@ DT_COMPAT_XLNX_GEM := xlnx,gem menuconfig ETH_XLNX_GEM bool "Xilinx GEM Ethernet driver" default $(dt_compat_enabled,$(DT_COMPAT_XLNX_GEM)) - depends on SOC_XILINX_ZYNQMP_RPU + depends on SOC_XILINX_ZYNQMP_RPU || SOC_SERIES_XILINX_ZYNQ7000 + depends on !QEMU_TARGET || (QEMU_TARGET && NET_QEMU_ETHERNET) help Enable Xilinx GEM Ethernet driver. diff --git a/drivers/ethernet/eth_xlnx_gem.c b/drivers/ethernet/eth_xlnx_gem.c index 0701a958555..30ea341d9fc 100644 --- a/drivers/ethernet/eth_xlnx_gem.c +++ b/drivers/ethernet/eth_xlnx_gem.c @@ -114,11 +114,18 @@ static int eth_xlnx_gem_dev_init(const struct device *dev) "%s invalid max./nominal link speed value %u", dev->name, (uint32_t)dev_conf->max_link_speed); - /* MDC clock divider validity check */ + /* MDC clock divider validity check, SoC dependent */ +#if defined(CONFIG_SOC_XILINX_ZYNQMP) __ASSERT(dev_conf->mdc_divider <= MDC_DIVIDER_48, "%s invalid MDC clock divider value %u, must be in " "range 0 to %u", dev->name, dev_conf->mdc_divider, (uint32_t)MDC_DIVIDER_48); +#elif defined(CONFIG_SOC_SERIES_XILINX_ZYNQ7000) + __ASSERT(dev_conf->mdc_divider <= MDC_DIVIDER_224, + "%s invalid MDC clock divider value %u, must be in " + "range 0 to %u", dev->name, dev_conf->mdc_divider, + (uint32_t)MDC_DIVIDER_224); +#endif /* AMBA AHB configuration options */ __ASSERT((dev_conf->amba_dbus_width == AMBA_AHB_DBUS_WIDTH_32BIT || @@ -775,6 +782,7 @@ static void eth_xlnx_gem_configure_clocks(const struct device *dev) } } +#if defined(CONFIG_SOC_XILINX_ZYNQMP) /* * ZynqMP register crl_apb.GEMx_REF_CTRL: * RX_CLKACT bit [26] @@ -808,6 +816,27 @@ static void eth_xlnx_gem_configure_clocks(const struct device *dev) if ((tmp & ETH_XLNX_CRL_APB_WPROT_BIT) > 0) { sys_write32(tmp, ETH_XLNX_CRL_APB_WPROT_REGISTER_ADDRESS); } +# elif defined(CONFIG_SOC_SERIES_XILINX_ZYNQ7000) + clk_ctrl_reg = sys_read32(dev_conf->clk_ctrl_reg_address); + clk_ctrl_reg &= ~((ETH_XLNX_SLCR_GEMX_CLK_CTRL_DIVISOR_MASK << + ETH_XLNX_SLCR_GEMX_CLK_CTRL_DIVISOR0_SHIFT) | + (ETH_XLNX_SLCR_GEMX_CLK_CTRL_DIVISOR_MASK << + ETH_XLNX_SLCR_GEMX_CLK_CTRL_DIVISOR1_SHIFT)); + clk_ctrl_reg |= ((div0 & ETH_XLNX_SLCR_GEMX_CLK_CTRL_DIVISOR_MASK) << + ETH_XLNX_SLCR_GEMX_CLK_CTRL_DIVISOR0_SHIFT) | + ((div1 & ETH_XLNX_SLCR_GEMX_CLK_CTRL_DIVISOR_MASK) << + ETH_XLNX_SLCR_GEMX_CLK_CTRL_DIVISOR1_SHIFT); + + /* + * SLCR must be unlocked prior to and locked after writing to + * the clock configuration register. + */ + sys_write32(ETH_XLNX_SLCR_UNLOCK_KEY, + ETH_XLNX_SLCR_UNLOCK_REGISTER_ADDRESS); + sys_write32(clk_ctrl_reg, dev_conf->clk_ctrl_reg_address); + sys_write32(ETH_XLNX_SLCR_LOCK_KEY, + ETH_XLNX_SLCR_LOCK_REGISTER_ADDRESS); +#endif /* CONFIG_SOC_XILINX_ZYNQMP / CONFIG_SOC_SERIES_XILINX_ZYNQ7000 */ LOG_DBG("%s set clock dividers div0/1 %u/%u for target " "frequency %u Hz", dev->name, div0, div1, target); diff --git a/drivers/ethernet/eth_xlnx_gem_priv.h b/drivers/ethernet/eth_xlnx_gem_priv.h index ef0b7361c88..c6f8a4b798a 100644 --- a/drivers/ethernet/eth_xlnx_gem_priv.h +++ b/drivers/ethernet/eth_xlnx_gem_priv.h @@ -110,8 +110,30 @@ #define ETH_XLNX_GEM_CKSUM_NOT_TCP_OR_UDP_ERROR 0x00000006 #define ETH_XLNX_GEM_CKSUM_PREMATURE_END_ERROR 0x00000007 +#if defined(CONFIG_SOC_SERIES_XILINX_ZYNQ7000) /* - * TX clock configuration: comp. + * Zynq-7000 TX clock configuration: + * + * SLCR unlock & lock registers, magic words: + * comp. Zynq-7000 TRM, chapter B.28, registers SLCR_LOCK and SLCR_UNLOCK, + * p. 1576f. + * + * GEMx_CLK_CTRL (SLCR) registers: + * [25 .. 20] Reference clock divisor 1 + * [13 .. 08] Reference clock divisor 0 + * [00] Clock active bit + */ +#define ETH_XLNX_SLCR_LOCK_REGISTER_ADDRESS 0xF8000004 +#define ETH_XLNX_SLCR_UNLOCK_REGISTER_ADDRESS 0xF8000008 +#define ETH_XLNX_SLCR_LOCK_KEY 0x767B +#define ETH_XLNX_SLCR_UNLOCK_KEY 0xDF0D +#define ETH_XLNX_SLCR_GEMX_CLK_CTRL_DIVISOR_MASK 0x0000003F +#define ETH_XLNX_SLCR_GEMX_CLK_CTRL_DIVISOR1_SHIFT 20 +#define ETH_XLNX_SLCR_GEMX_CLK_CTRL_DIVISOR0_SHIFT 8 +#define ETH_XLNX_CRL_APB_GEMX_REF_CTRL_CLKACT_BIT 0x02000000 +#elif defined(CONFIG_SOC_XILINX_ZYNQMP) +/* + * UltraScale TX clock configuration: comp. * https://www.xilinx.com/html_docs/registers/ug1087/ug1087-zynq-ultrascale-registers.html * * CRL_WPROT (CRL_APB) register: @@ -130,6 +152,7 @@ #define ETH_XLNX_CRL_APB_GEMX_REF_CTRL_DIVISOR0_SHIFT 8 #define ETH_XLNX_CRL_APB_GEMX_REF_CTRL_RX_CLKACT_BIT 0x04000000 #define ETH_XLNX_CRL_APB_GEMX_REF_CTRL_CLKACT_BIT 0x02000000 +#endif /* CONFIG_SOC_SERIES_XILINX_ZYNQ7000 || CONFIG_SOC_XILINX_ZYNQMP */ /* * Register offsets within the respective GEM's address space: @@ -495,9 +518,15 @@ struct eth_xlnx_dma_area_gem##port {\ }; /* DMA memory area instantiation macro */ +#ifdef CONFIG_SOC_SERIES_XILINX_ZYNQ7000 #define ETH_XLNX_GEM_DMA_AREA_INST(port) \ -static struct eth_xlnx_dma_area_gem##port eth_xlnx_gem##port##_dma_area \ +static struct eth_xlnx_dma_area_gem##port eth_xlnx_gem##port##_dma_area\ + __ocm_bss_section __aligned(4096); +#else +#define ETH_XLNX_GEM_DMA_AREA_INST(port) \ +static struct eth_xlnx_dma_area_gem##port eth_xlnx_gem##port##_dma_area\ __aligned(4096); +#endif /* Interrupt configuration function macro */ #define ETH_XLNX_GEM_CONFIG_IRQ_FUNC(port) \ @@ -564,16 +593,23 @@ enum eth_xlnx_amba_dbus_width { * @brief MDC clock divider configuration enumeration type. * * Enumeration type containing the supported clock divider values - * used to generate the MDIO interface clock (MDC) from the ZynqMP's - * LPD LSBUS clock. This is a configuration item in the controller's - * net_cfg register. + * used to generate the MDIO interface clock (MDC) from either the + * cpu_1x clock (Zynq-7000) or the LPD LSBUS clock (UltraScale). + * This is a configuration item in the controller's net_cfg register. */ enum eth_xlnx_mdc_clock_divider { /* The values of this enum are consecutively numbered */ MDC_DIVIDER_8 = 0, MDC_DIVIDER_16, MDC_DIVIDER_32, - MDC_DIVIDER_48 + MDC_DIVIDER_48, +#ifdef CONFIG_SOC_SERIES_XILINX_ZYNQ7000 + /* Dividers > 48 are only available in the Zynq-7000 */ + MDC_DIVIDER_64, + MDC_DIVIDER_96, + MDC_DIVIDER_128, + MDC_DIVIDER_224 +#endif }; /** diff --git a/include/dt-bindings/ethernet/xlnx_gem.h b/include/dt-bindings/ethernet/xlnx_gem.h index 1ebe2b3f688..a1dbff07b03 100644 --- a/include/dt-bindings/ethernet/xlnx_gem.h +++ b/include/dt-bindings/ethernet/xlnx_gem.h @@ -10,14 +10,20 @@ #define XLNX_GEM_PHY_AUTO_DETECT 0 /* MDC divider values */ -#define XLNX_GEM_MDC_DIVIDER_8 0 /* LPD_LSBUS_CLK < 20 MHz */ -#define XLNX_GEM_MDC_DIVIDER_16 1 /* LPD_LSBUS_CLK 20 - 40 MHz */ -#define XLNX_GEM_MDC_DIVIDER_32 2 /* LPD_LSBUS_CLK 40 - 80 MHz */ +/* The following values are supported by both the Zynq-7000 and the ZynqMP */ +#define XLNX_GEM_MDC_DIVIDER_8 0 /* cpu_1x or LPD_LSBUS_CLK < 20 MHz */ +#define XLNX_GEM_MDC_DIVIDER_16 1 /* cpu_1x or LPD_LSBUS_CLK 20 - 40 MHz */ +#define XLNX_GEM_MDC_DIVIDER_32 2 /* cpu_1x or LPD_LSBUS_CLK 40 - 80 MHz */ /* * According to the ZynqMP's gem.network_config register documentation, * divider /32 is to be used for a 100 MHz LPD LSBUS clock. */ -#define XLNX_GEM_MDC_DIVIDER_48 3 /* LPD_LSBUS_CLK 80 - 120 MHz */ +/* The following values are supported by the Zynq-7000 only */ +#define XLNX_GEM_MDC_DIVIDER_48 3 /* cpu_1x 80 - 120 MHz */ +#define XLNX_GEM_MDC_DIVIDER_64 4 /* cpu_1x 120 - 160 MHz */ +#define XLNX_GEM_MDC_DIVIDER_96 5 /* cpu_1x 160 - 240 MHz */ +#define XLNX_GEM_MDC_DIVIDER_128 6 /* cpu_1x 240 - 320 MHz */ +#define XLNX_GEM_MDC_DIVIDER_224 7 /* cpu_1x 320 - 540 MHz */ /* Link speed values */ #define XLNX_GEM_LINK_SPEED_10MBIT 1