diff options
| author | Tom Rini <[email protected]> | 2026-04-23 07:46:01 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2026-04-23 07:46:01 -0600 |
| commit | 03fcc16d580342667da61ac87ecb12c4f1995be7 (patch) | |
| tree | 9b7e479dfe8b55d1832f498c16f0e31a87a2a4b7 | |
| parent | bfe90a308a94caa9d855440683521ff04122ae2a (diff) | |
| parent | 9e0511261221b63458bc0d4cfd08596f5c8840d4 (diff) | |
Merge tag 'xilinx-for-v2026.07-rc1-v3' of https://source.denx.de/u-boot/custodians/u-boot-microblaze
AMD/Xilinx/FPGA changes for v2026.07-rc1 v3. The biggest part is new
pcie driver for Versal Gen 2 SOC. Others are small fixes and
adjustments.
versal2:
- Wire PCIe IP
cmd/fpga:
- Fix loadb help text guarding
- Add support for skipping fpga ID check
zynqmp:
- Describe missing devices/IDs
- Fix issue around zu63dr_SE
clk/versal:
- Fix out-of-bounds parent id for DUMMY_PARENT
net/gem:
- Add support for 10GBE
- Clear stale speed bits in NWCFG
net/axi_emac:
- Filter out broadcast and multicast packets
pci:
- Add driver for AMD PCIe IP based on DesignWare core
| -rw-r--r-- | MAINTAINERS | 5 | ||||
| -rw-r--r-- | arch/arm/mach-versal2/cpu.c | 18 | ||||
| -rw-r--r-- | board/xilinx/zynqmp/zynqmp.c | 17 | ||||
| -rw-r--r-- | cmd/fpga.c | 2 | ||||
| -rw-r--r-- | configs/amd_versal2_virt_defconfig | 6 | ||||
| -rw-r--r-- | drivers/clk/clk_versal.c | 1 | ||||
| -rw-r--r-- | drivers/fpga/xilinx.c | 7 | ||||
| -rw-r--r-- | drivers/net/xilinx_axi_emac.c | 20 | ||||
| -rw-r--r-- | drivers/net/zynq_gem.c | 61 | ||||
| -rw-r--r-- | drivers/pci/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/pci/Makefile | 1 | ||||
| -rw-r--r-- | drivers/pci/pcie_dw_amd.c | 250 | ||||
| -rw-r--r-- | drivers/soc/soc_xilinx_zynqmp.c | 45 | ||||
| -rw-r--r-- | include/configs/amd_versal2.h | 9 |
14 files changed, 425 insertions, 28 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 056902f6ef2..fc5cd553ec3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -65,6 +65,11 @@ F: include/alist.h F: lib/alist.c F: test/lib/alist.c +AMD VERSAL2 PCIE DRIVER +M: Pranav Sanwal <[email protected]> +S: Maintained +F: drivers/pci/pcie_dw_amd.c + ANDROID AB M: Mattijs Korpershoek <[email protected]> R: Igor Opaniuk <[email protected]> diff --git a/arch/arm/mach-versal2/cpu.c b/arch/arm/mach-versal2/cpu.c index 9a02fe40733..a81609cdec7 100644 --- a/arch/arm/mach-versal2/cpu.c +++ b/arch/arm/mach-versal2/cpu.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2021 - 2022, Xilinx, Inc. - * Copyright (C) 2022 - 2024, Advanced Micro Devices, Inc. + * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc. * * Michal Simek <[email protected]> */ @@ -18,7 +18,11 @@ DECLARE_GLOBAL_DATA_PTR; +#if CONFIG_IS_ENABLED(PCIE_DW_AMD) +#define VERSAL2_MEM_MAP_USED 6 +#else #define VERSAL2_MEM_MAP_USED 5 +#endif #define DRAM_BANKS CONFIG_NR_DRAM_BANKS @@ -60,6 +64,16 @@ static struct mm_region versal2_mem_map[VERSAL2_MEM_MAP_MAX] = { .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | PTE_BLOCK_NON_SHARE | PTE_BLOCK_PXN | PTE_BLOCK_UXN +#if CONFIG_IS_ENABLED(PCIE_DW_AMD) + }, { + /* PCIe DBI (1 MB) and config space (255 MB) are contiguous */ + .virt = 0x100000000000UL, + .phys = 0x100000000000UL, + .size = 0x10000000UL, + .attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) | + PTE_BLOCK_NON_SHARE | + PTE_BLOCK_PXN | PTE_BLOCK_UXN +#endif } }; @@ -69,7 +83,7 @@ static struct mm_region versal2_mem_map[VERSAL2_MEM_MAP_MAX] = { * @num_banks: Number of valid DRAM banks in bank_info array * * Copies DRAM bank information into the global versal2_mem_map[] array - * starting at index VERSAL2_MEM_MAP_USED (5), which is after the fixed + * starting at index VERSAL2_MEM_MAP_USED, which is after the fixed * device mappings. This must be called early in boot before MMU * initialization so that get_page_table_size() can calculate the * required page table size based on actual memory configuration. diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index 769e52bcfb5..a1d8ae26673 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -183,6 +183,23 @@ int board_init(void) zynqmppl.name = strdup(name); fpga_init(); fpga_add(fpga_xilinx, &zynqmppl); + + /* + * zu63dr_SE and zu67dr_SE share ID 0x046D7093. + * Register zu63dr_SE as alternate device. + */ + if (!strcmp(name, "zu67dr_SE")) { + xilinx_desc *alt; + + alt = calloc(1, sizeof(*alt)); + if (!alt) { + log_err("Failed to allocate alt FPGA descriptor\n"); + } else { + *alt = zynqmppl; + alt->name = "zu63dr_SE"; + fpga_add(fpga_xilinx, alt); + } + } } } #endif diff --git a/cmd/fpga.c b/cmd/fpga.c index d51c380d7b3..d347a700290 100644 --- a/cmd/fpga.c +++ b/cmd/fpga.c @@ -417,7 +417,7 @@ U_BOOT_CMD(fpga, 6, 1, do_fpga_wrapper, "info [dev] List known device information\n" "fpga dump <dev> <address> <size> Load device to memory buffer\n" "fpga load <dev> <address> <size> Load device from memory buffer\n" -#if defined(CONFIG_CMD_FPGA_LOADP) +#if defined(CONFIG_CMD_FPGA_LOADB) "fpga loadb <dev> <address> <size> Load device from bitstream buffer\n" #endif #if defined(CONFIG_CMD_FPGA_LOADP) diff --git a/configs/amd_versal2_virt_defconfig b/configs/amd_versal2_virt_defconfig index 0f4b75c72e1..bf3caf22167 100644 --- a/configs/amd_versal2_virt_defconfig +++ b/configs/amd_versal2_virt_defconfig @@ -13,6 +13,7 @@ CONFIG_SYS_BOOTM_LEN=0x6400000 CONFIG_SYS_LOAD_ADDR=0x8000000 CONFIG_XILINX_OF_BOARD_DTB_ADDR=0x1000000 CONFIG_CMD_FRU=y +CONFIG_PCI=y CONFIG_SYS_MEMTEST_START=0x00000000 CONFIG_SYS_MEMTEST_END=0x00001000 CONFIG_REMAKE_ELF=y @@ -40,10 +41,12 @@ CONFIG_CMD_CLK=y CONFIG_CMD_DFU=y CONFIG_CMD_GPIO=y CONFIG_CMD_I2C=y +CONFIG_CMD_LSBLK=y CONFIG_CMD_MMC=y CONFIG_MMC_SPEED_MODE_SET=y CONFIG_CMD_OPTEE=y CONFIG_CMD_MTD=y +CONFIG_CMD_PCI=y CONFIG_CMD_POWEROFF=y CONFIG_CMD_SF_TEST=y CONFIG_CMD_SPI=y @@ -84,6 +87,7 @@ CONFIG_SCMI_FIRMWARE=y CONFIG_FPGA_XILINX=y CONFIG_FPGA_VERSALPL=y CONFIG_GPIO_DELAY=y +CONFIG_DM_PCA953X=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_CADENCE=y CONFIG_I2C_MUX=y @@ -123,6 +127,8 @@ CONFIG_DM_ETH_PHY=y CONFIG_PHY_GIGE=y CONFIG_XILINX_AXIEMAC=y CONFIG_ZYNQ_GEM=y +CONFIG_NVME_PCI=y +CONFIG_PCIE_DW_AMD=y CONFIG_POWER_DOMAIN=y CONFIG_ZYNQMP_POWER_DOMAIN=y CONFIG_RESET_SCMI=y diff --git a/drivers/clk/clk_versal.c b/drivers/clk/clk_versal.c index 78a2410ca21..2e0c382ef30 100644 --- a/drivers/clk/clk_versal.c +++ b/drivers/clk/clk_versal.c @@ -326,6 +326,7 @@ static int __versal_clock_get_parents(struct clock_parent *parents, u32 *data, parent = &parents[i]; parent->id = data[i] & CLK_PARENTS_ID_MASK; if (data[i] == DUMMY_PARENT) { + parent->id = 0; strcpy(parent->name, "dummy_name"); parent->flag = 0; } else { diff --git a/drivers/fpga/xilinx.c b/drivers/fpga/xilinx.c index 25b348648ef..44d7ad6bd54 100644 --- a/drivers/fpga/xilinx.c +++ b/drivers/fpga/xilinx.c @@ -11,6 +11,7 @@ * Xilinx FPGA support */ +#include <env.h> #include <fpga.h> #include <log.h> #include <virtex2.h> @@ -92,7 +93,11 @@ int fpga_loadbitstream(int devnum, char *fpgadata, size_t size, __func__); printf("%s: Bitstream ID %s, current device ID %d/%s\n", __func__, dataptr, devnum, xdesc->name); - return FPGA_FAIL; + if (!CONFIG_IS_ENABLED(ENV_SUPPORT) || + env_get_yesno("fpga_skip_idcheck") != 1) + return FPGA_FAIL; + + printf("%s: Skipping ID check\n", __func__); } } else { printf("%s: Please fill correct device ID to xilinx_desc\n", diff --git a/drivers/net/xilinx_axi_emac.c b/drivers/net/xilinx_axi_emac.c index e9cc5db52d2..1ea81fe1830 100644 --- a/drivers/net/xilinx_axi_emac.c +++ b/drivers/net/xilinx_axi_emac.c @@ -28,6 +28,10 @@ #define XAE_EMMC_LINKSPD_100 0x40000000 /* Link Speed mask for 100 Mbit */ #define XAE_EMMC_LINKSPD_1000 0x80000000 /* Link Speed mask for 1000 Mbit */ +/* Reset and Address Filter (RAF) Register bit definitions */ +#define XAE_RAF_MCSTREJ_MASK 0x00000002 /* Reject rx multicast dst addr */ +#define XAE_RAF_BCSTREJ_MASK 0x00000004 /* Reject rx broadcast dst addr */ + /* Interrupt Status/Enable/Mask Registers bit definitions */ #define XAE_INT_RXRJECT_MASK 0x00000008 /* Rx frame rejected */ #define XAE_INT_MGTRDY_MASK 0x00000080 /* MGT clock Lock */ @@ -153,7 +157,8 @@ static struct axidma_bd tx_bd __attribute((aligned(DMAALIGN))); static struct axidma_bd rx_bd __attribute((aligned(DMAALIGN))); struct axi_regs { - u32 reserved[3]; + u32 raf; /* 0x0: Reset and Address Filter */ + u32 reserved[2]; u32 is; /* 0xC: Interrupt status */ u32 reserved2; u32 ie; /* 0x14: Interrupt enable */ @@ -528,6 +533,19 @@ static int axi_ethernet_init(struct axidma_priv *priv) /* Set default MDIO divisor */ writel(XAE_MDIO_DIV_DFT | XAE_MDIO_MC_MDIOEN_MASK, ®s->mdio_mc); + /* + * Reject broadcast and multicast frames at MAC level to reduce + * unnecessary traffic processing. Multicast rejection is only + * enabled when IPv6 is not configured because IPv6 Neighbor + * Discovery and DHCPv6 rely on multicast. + */ + if (!IS_ENABLED(CONFIG_IPV6)) + writel(readl(®s->raf) | XAE_RAF_MCSTREJ_MASK | + XAE_RAF_BCSTREJ_MASK, ®s->raf); + else + writel(readl(®s->raf) | XAE_RAF_BCSTREJ_MASK, + ®s->raf); + debug("axiemac: InitHw done\n"); return 0; } diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c index a50d5aee03f..f570ae9ee73 100644 --- a/drivers/net/zynq_gem.c +++ b/drivers/net/zynq_gem.c @@ -69,10 +69,13 @@ #define ZYNQ_GEM_NWCFG_SGMII_ENBL 0x08000000 /* SGMII Enable */ #define ZYNQ_GEM_NWCFG_PCS_SEL 0x00000800 /* PCS select */ +#define ZYNQ_GEM_DBUS_WIDTH_MASK (3 << 21) /* bits 22:21 */ #ifdef CONFIG_ARM64 # define ZYNQ_GEM_DBUS_WIDTH (1 << 21) /* 64 bit bus */ +# define ZYNQ_GEM_DBUS_WIDTH_128 (2 << 21) /* 128 bit bus */ #else # define ZYNQ_GEM_DBUS_WIDTH (0 << 21) /* 32 bit bus */ +# define ZYNQ_GEM_DBUS_WIDTH_128 (0 << 21) /* 32 bit bus */ #endif #define ZYNQ_GEM_NWCFG_INIT (ZYNQ_GEM_DBUS_WIDTH | \ @@ -134,6 +137,7 @@ #define ZYNQ_GEM_FREQUENCY_10 2500000UL #define ZYNQ_GEM_FREQUENCY_100 25000000UL #define ZYNQ_GEM_FREQUENCY_1000 125000000UL +#define ZYNQ_GEM_FREQUENCY_10000 150000000UL #define RXCLK_EN BIT(0) @@ -470,28 +474,6 @@ static int zynq_gem_init(struct udevice *dev) for (i = 0; i < STAT_SIZE; i++) readl(®s->stat[i]); - /* Setup RxBD space */ - memset(priv->rx_bd, 0, RX_BUF * sizeof(struct emac_bd)); - - for (i = 0; i < RX_BUF; i++) { - priv->rx_bd[i].status = 0xF0000000; - priv->rx_bd[i].addr = - (lower_32_bits((ulong)(priv->rxbuffers) - + (i * PKTSIZE_ALIGN))); -#if defined(CONFIG_PHYS_64BIT) - priv->rx_bd[i].addr_hi = - (upper_32_bits((ulong)(priv->rxbuffers) - + (i * PKTSIZE_ALIGN))); -#endif - } - /* WRAP bit to last BD */ - priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK; - /* Write RxBDs to IP */ - writel(lower_32_bits((ulong)priv->rx_bd), ®s->rxqbase); -#if defined(CONFIG_PHYS_64BIT) - writel(upper_32_bits((ulong)priv->rx_bd), ®s->upper_rxqbase); -#endif - /* Setup for DMA Configuration register */ writel(ZYNQ_GEM_DMACR_INIT, ®s->dmacr); @@ -520,6 +502,35 @@ static int zynq_gem_init(struct udevice *dev) priv->init++; } + /* + * Reinitialize RX BDs on every init. The 10GBE USX block asserts + * RX_SYNC_RESET during setup which resets the GEM RX DMA pointer + * back to rxqbase, so BDs and rxqbase must be refreshed each time + * to keep the hardware and driver ring indices in sync. + */ + priv->rxbd_current = 0; + priv->rx_first_buf = 0; + memset(priv->rx_bd, 0, RX_BUF * sizeof(struct emac_bd)); + for (i = 0; i < RX_BUF; i++) { + priv->rx_bd[i].status = 0xF0000000; + priv->rx_bd[i].addr = + (lower_32_bits((ulong)(priv->rxbuffers) + + (i * PKTSIZE_ALIGN))); +#if defined(CONFIG_PHYS_64BIT) + priv->rx_bd[i].addr_hi = + (upper_32_bits((ulong)(priv->rxbuffers) + + (i * PKTSIZE_ALIGN))); +#endif + } + /* WRAP bit to last BD */ + priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK; + + /* Write RxBDs to IP */ + writel(lower_32_bits((ulong)priv->rx_bd), ®s->rxqbase); +#if defined(CONFIG_PHYS_64BIT) + writel(upper_32_bits((ulong)priv->rx_bd), ®s->upper_rxqbase); +#endif + ret = phy_startup(priv->phydev); if (ret) return ret; @@ -532,6 +543,8 @@ static int zynq_gem_init(struct udevice *dev) nwconfig = ZYNQ_GEM_NWCFG_INIT; if (device_is_compatible(dev, "amd,versal2-10gbe")) { + nwconfig &= ~ZYNQ_GEM_DBUS_WIDTH_MASK; + nwconfig |= ZYNQ_GEM_DBUS_WIDTH_128; if (priv->interface == PHY_INTERFACE_MODE_10GBASER) { ctrl = readl(®s->nwcfg); ctrl |= PCSSEL; @@ -602,6 +615,9 @@ static int zynq_gem_init(struct udevice *dev) } switch (priv->phydev->speed) { + case SPEED_10000: + clk_rate = ZYNQ_GEM_FREQUENCY_10000; + break; case SPEED_1000: nwconfig |= ZYNQ_GEM_NWCFG_SPEED1000; clk_rate = ZYNQ_GEM_FREQUENCY_1000; @@ -615,6 +631,7 @@ static int zynq_gem_init(struct udevice *dev) break; } nwcfg = readl(®s->nwcfg); + nwcfg &= ~(ZYNQ_GEM_NWCFG_SPEED100 | ZYNQ_GEM_NWCFG_SPEED1000); nwcfg |= nwconfig; if (nwcfg) writel(nwcfg, ®s->nwcfg); diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 8fc57895a78..39df0e776df 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -456,6 +456,17 @@ config PCIE_STARFIVE_JH7110 Say Y here if you want to enable PLDA XpressRich PCIe controller support on StarFive JH7110 SoC. +config PCIE_DW_AMD + bool "AMD Versal2 DW PCIe host controller" + depends on ARCH_VERSAL2 + depends on DM_GPIO + select PCIE_DW_COMMON + select SYS_PCI_64BIT + help + Say Y here to enable support for the AMD Versal Gen 2 PCIe + host controller. This is a DesignWare-based PCIe controller + used in AMD Versal Gen 2 SoCs. + config PCIE_DW_IMX bool "i.MX DW PCIe controller support" depends on ARCH_IMX8M || ARCH_IMX9 diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile index 98f3c226f63..e6d71fd172b 100644 --- a/drivers/pci/Makefile +++ b/drivers/pci/Makefile @@ -56,4 +56,5 @@ obj-$(CONFIG_PCIE_UNIPHIER) += pcie_uniphier.o obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o obj-$(CONFIG_PCIE_PLDA_COMMON) += pcie_plda_common.o obj-$(CONFIG_PCIE_STARFIVE_JH7110) += pcie_starfive_jh7110.o +obj-$(CONFIG_PCIE_DW_AMD) += pcie_dw_amd.o obj-$(CONFIG_PCIE_DW_IMX) += pcie_dw_imx.o diff --git a/drivers/pci/pcie_dw_amd.c b/drivers/pci/pcie_dw_amd.c new file mode 100644 index 00000000000..81c6d8f2817 --- /dev/null +++ b/drivers/pci/pcie_dw_amd.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * AMD Versal2 DesignWare PCIe host controller driver + * + * Copyright (C) 2025 - 2026, Advanced Micro Devices, Inc. + * Author: Pranav Sanwal <[email protected]> + */ + +#include <dm.h> +#include <log.h> +#include <pci.h> +#include <wait_bit.h> + +#include <asm/gpio.h> +#include <asm/io.h> +#include <dm/device_compat.h> +#include <dm/ofnode.h> +#include <linux/delay.h> + +#include "pcie_dw_common.h" + +/* + * SLCR (System Level Control Register) Interrupt Register Offsets + * These are relative to the SLCR base address from device tree + */ +#define AMD_DW_TLP_IR_STATUS_MISC 0x4c0 +#define AMD_DW_TLP_IR_DISABLE_MISC 0x4cc + +/* Interrupt bit definitions */ +#define AMD_DW_PCIE_INTR_CMPL_TIMEOUT 15 +#define AMD_DW_PCIE_INTR_PM_PME_RCVD 24 +#define AMD_DW_PCIE_INTR_PME_TO_ACK_RCVD 25 +#define AMD_DW_PCIE_INTR_MISC_CORRECTABLE 26 +#define AMD_DW_PCIE_INTR_NONFATAL 27 +#define AMD_DW_PCIE_INTR_FATAL 28 + +#define AMD_DW_PCIE_INTR_INTX_MASK GENMASK(23, 16) + +#define AMD_DW_PCIE_IMR_ALL_MASK \ + (BIT(AMD_DW_PCIE_INTR_CMPL_TIMEOUT) | \ + BIT(AMD_DW_PCIE_INTR_PM_PME_RCVD) | \ + BIT(AMD_DW_PCIE_INTR_PME_TO_ACK_RCVD) | \ + BIT(AMD_DW_PCIE_INTR_MISC_CORRECTABLE) | \ + BIT(AMD_DW_PCIE_INTR_NONFATAL) | \ + BIT(AMD_DW_PCIE_INTR_FATAL) | \ + AMD_DW_PCIE_INTR_INTX_MASK) + +/* DW PCIe Debug Registers (in DBI space) */ +#define AMD_DW_PCIE_PORT_DEBUG1 0x72c +#define AMD_DW_PCIE_PORT_DEBUG1_LINK_UP BIT(4) +#define AMD_DW_PCIE_PORT_DEBUG1_LINK_IN_TRAINING BIT(29) +#define AMD_DW_PCIE_DBI_64BIT_MEM_DECODE BIT(0) + +/* Link training timeout */ +#define LINK_WAIT_MSLEEP_MAX 1000 + +/* PCIe spec timing requirements */ +#define PCIE_RESET_CONFIG_WAIT_MS 100 +#define PCIE_T_PERST_WAIT_MS 1 + +/** + * struct amd_dw_pcie - AMD DesignWare PCIe controller private data + * @dw: DesignWare PCIe common structure + * @slcr_base: System Level Control Register base (for interrupts) + */ +struct amd_dw_pcie { + struct pcie_dw dw; + void __iomem *slcr_base; +}; + +static void amd_dw_pcie_init_port(struct amd_dw_pcie *pcie) +{ + u32 val; + + if (!pcie->slcr_base) + return; + + /* Disable all TLP interrupts */ + writel(AMD_DW_PCIE_IMR_ALL_MASK, + pcie->slcr_base + AMD_DW_TLP_IR_DISABLE_MISC); + + /* Clear any pending TLP interrupts */ + val = readl(pcie->slcr_base + AMD_DW_TLP_IR_STATUS_MISC); + val &= AMD_DW_PCIE_IMR_ALL_MASK; + writel(val, pcie->slcr_base + AMD_DW_TLP_IR_STATUS_MISC); +} + +static void amd_dw_pcie_start_link(struct amd_dw_pcie *pcie) +{ + void __iomem *reg = pcie->dw.dbi_base + AMD_DW_PCIE_PORT_DEBUG1; + struct udevice *dev = pcie->dw.dev; + struct pcie_dw *pci = &pcie->dw; + int ret; + + ret = wait_for_bit_le32(reg, AMD_DW_PCIE_PORT_DEBUG1_LINK_UP, + true, LINK_WAIT_MSLEEP_MAX, + false); + if (!ret) + ret = wait_for_bit_le32(reg, + AMD_DW_PCIE_PORT_DEBUG1_LINK_IN_TRAINING, + false, LINK_WAIT_MSLEEP_MAX, false); + if (ret) + dev_warn(dev, "PCIE-%d: Link down\n", dev_seq(dev)); + else + dev_dbg(dev, "PCIE-%d: Link up (Gen%d-x%d, Bus%d)\n", + dev_seq(dev), pcie_dw_get_link_speed(pci), + pcie_dw_get_link_width(pci), pci->first_busno); +} + +static void amd_dw_pcie_host_init(struct amd_dw_pcie *pcie) +{ + struct pcie_dw *pci = &pcie->dw; + + /* + * Set 64-bit prefetchable memory decode capability. U-Boot's pci_auto.c + * reads this bit before assigning prefetchable BARs. If cleared, it skips + * PCI_PREF_BASE_UPPER32 programming, causing 64-bit BAR assignment to fail. + */ + dw_pcie_dbi_write_enable(pci, true); + setbits_le32(pci->dbi_base + PCI_PREF_MEMORY_BASE, + AMD_DW_PCIE_DBI_64BIT_MEM_DECODE); + dw_pcie_dbi_write_enable(pci, false); + + amd_dw_pcie_init_port(pcie); + pcie_dw_setup_host(pci); +} + +static void amd_dw_pcie_request_gpio(struct udevice *dev) +{ + struct gpio_desc perst_gpio; + ofnode child_node; + int ret; + + /* + * PERST# reset GPIO is optional. Child PCI endpoint nodes may carry a + * 'reset-gpios' property to toggle the endpoint reset signal during + * initialization. If absent, the endpoint is assumed to be already + * released from reset. + */ + ofnode_for_each_subnode(child_node, dev_ofnode(dev)) { + ret = gpio_request_by_name_nodev(child_node, "reset-gpios", 0, + &perst_gpio, GPIOD_IS_OUT); + if (!ret) { + dev_dbg(dev, "Found reset-gpios in child node %s\n", + ofnode_get_name(child_node)); + dm_gpio_set_value(&perst_gpio, 1); + mdelay(PCIE_T_PERST_WAIT_MS); + dm_gpio_set_value(&perst_gpio, 0); + mdelay(PCIE_RESET_CONFIG_WAIT_MS); + dm_gpio_free(dev, &perst_gpio); + } + } +} + +static int amd_dw_pcie_of_to_plat(struct udevice *dev) +{ + struct pci_region *io_region, *mem_region, *pref_region; + struct amd_dw_pcie *pcie = dev_get_priv(dev); + struct pcie_dw *pci = &pcie->dw; + int ret; + + pci->dev = dev; + + pci->dbi_base = dev_read_addr_name_ptr(dev, "dbi"); + if (!pci->dbi_base) { + dev_err(dev, "Missing 'dbi' register region\n"); + return -EINVAL; + } + + pci->cfg_base = dev_read_addr_size_name_ptr(dev, "config", &pci->cfg_size); + if (!pci->cfg_base) { + dev_err(dev, "Missing 'config' register region\n"); + return -EINVAL; + } + + pci->atu_base = dev_read_addr_name_ptr(dev, "atu"); + if (!pci->atu_base) { + dev_dbg(dev, "No 'atu' region, using default offset from DBI\n"); + pci->atu_base = pci->dbi_base + DEFAULT_DBI_ATU_OFFSET; + } + + pcie->slcr_base = dev_read_addr_name_ptr(dev, "slcr"); + if (!pcie->slcr_base) + dev_dbg(dev, "No 'slcr' region, interrupt features disabled\n"); + + ret = pci_get_regions(dev, &io_region, &mem_region, &pref_region); + if (ret < 0) { + dev_err(dev, "Failed to get PCI regions: %d\n", ret); + return ret; + } + + if (mem_region) + pci->mem = *mem_region; + + return 0; +} + +static int amd_dw_pcie_probe(struct udevice *dev) +{ + struct amd_dw_pcie *pcie = dev_get_priv(dev); + struct pcie_dw *pci = &pcie->dw; + + /* Set first bus number */ + pci->first_busno = dev_seq(dev); + + amd_dw_pcie_request_gpio(dev); + amd_dw_pcie_host_init(pcie); + amd_dw_pcie_start_link(pcie); + + if (pci->mem.size) { + dev_dbg(dev, "Programming ATU region 0 for MEM: phys=0x%llx bus=0x%llx size=0x%llx\n", + (unsigned long long)pci->mem.phys_start, + (unsigned long long)pci->mem.bus_start, + (unsigned long long)pci->mem.size); + pcie_dw_prog_outbound_atu_unroll(pci, + PCIE_ATU_REGION_INDEX0, + PCIE_ATU_TYPE_MEM, + pci->mem.phys_start, + pci->mem.bus_start, + pci->mem.size); + } else { + dev_warn(dev, "No MEM region configured!\n"); + } + + dev_dbg(dev, "dbi: 0x%lx | config: 0x%lx | atu: 0x%lx | slcr: 0x%lx\n", + (long)pci->dbi_base, (long)pci->cfg_base, + (long)pci->atu_base, (long)pcie->slcr_base); + + return 0; +} + +static const struct dm_pci_ops amd_dw_pcie_ops = { + .read_config = pcie_dw_read_config, + .write_config = pcie_dw_write_config, +}; + +static const struct udevice_id amd_dw_pcie_ids[] = { + { .compatible = "amd,versal2-mdb-host" }, + { } +}; + +U_BOOT_DRIVER(pcie_dw_amd) = { + .name = "pcie_dw_amd", + .id = UCLASS_PCI, + .of_match = amd_dw_pcie_ids, + .ops = &amd_dw_pcie_ops, + .of_to_plat = amd_dw_pcie_of_to_plat, + .probe = amd_dw_pcie_probe, + .priv_auto = sizeof(struct amd_dw_pcie), +}; diff --git a/drivers/soc/soc_xilinx_zynqmp.c b/drivers/soc/soc_xilinx_zynqmp.c index b97cd443c60..4abc73013eb 100644 --- a/drivers/soc/soc_xilinx_zynqmp.c +++ b/drivers/soc/soc_xilinx_zynqmp.c @@ -71,6 +71,11 @@ static const struct zynqmp_device zynqmp_devices[] = { .variants = ZYNQMP_VARIANT_EG_LR, }, { + .id = 0x0468A093, + .device = 1, + .variants = ZYNQMP_VARIANT_EG_LR, + }, + { .id = 0x04711093, .device = 2, .variants = ZYNQMP_VARIANT_EG | ZYNQMP_VARIANT_CG, @@ -209,6 +214,16 @@ static const struct zynqmp_device zynqmp_devices[] = { .variants = ZYNQMP_VARIANT_DR, }, { + .id = 0x047F9093, + .device = 58, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x047FC093, + .device = 59, + .variants = ZYNQMP_VARIANT_DR, + }, + { .id = 0x046d0093, .device = 67, .variants = ZYNQMP_VARIANT_DR, @@ -219,6 +234,36 @@ static const struct zynqmp_device zynqmp_devices[] = { .variants = ZYNQMP_VARIANT_DR_SE, }, { + .id = 0x046D1093, + .device = 65, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046D2093, + .device = 55, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046D3093, + .device = 57, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046D4093, + .device = 42, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046D5093, + .device = 63, + .variants = ZYNQMP_VARIANT_DR, + }, + { + .id = 0x046D6093, + .device = 64, + .variants = ZYNQMP_VARIANT_DR, + }, + { .id = 0x04712093, .device = 24, .variants = 0, diff --git a/include/configs/amd_versal2.h b/include/configs/amd_versal2.h index 38d0bfc315b..fccc786219f 100644 --- a/include/configs/amd_versal2.h +++ b/include/configs/amd_versal2.h @@ -2,7 +2,7 @@ /* * Configuration for AMD Versal Gen 2 * Copyright (C) 2016 - 2022, Xilinx, Inc. - * Copyright (C) 2022 - 2024, Advanced Micro Devices, Inc. + * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc. * * Michal Simek <[email protected]> * @@ -132,11 +132,18 @@ #define BOOT_TARGET_DEVICES_USB(func) #endif +#if defined(CONFIG_NVME) +# define BOOT_TARGET_DEVICES_NVME(func) func(NVME, nvme, 0) +#else +# define BOOT_TARGET_DEVICES_NVME(func) +#endif + #define BOOT_TARGET_DEVICES(func) \ BOOT_TARGET_DEVICES_JTAG(func) \ BOOT_TARGET_DEVICES_MMC(func) \ BOOT_TARGET_DEVICES_UFS(func) \ BOOT_TARGET_DEVICES_XSPI(func) \ + BOOT_TARGET_DEVICES_NVME(func) \ BOOT_TARGET_DEVICES_DFU_USB(func) \ BOOT_TARGET_DEVICES_USB(func) \ BOOT_TARGET_DEVICES_PXE(func) \ |
