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 <Immo.Birnbaum@weidmueller.com>
This commit is contained in:
Immo Birnbaum 2021-07-15 13:10:33 +02:00 committed by Carles Cufí
commit 266875ead0
4 changed files with 84 additions and 12 deletions

View file

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

View file

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

View file

@ -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
};
/**

View file

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