From 926a72ba0438806a341cfe3a90683bc02d904e55 Mon Sep 17 00:00:00 2001 From: Prasad Kummari Date: Wed, 19 Feb 2025 17:23:01 +0530 Subject: xilinx: versal: add firmware access to CRP Boot mode register Added extended support for retrieving the boot mode register via the firmware interface, which is preferred when U-Boot runs in EL2 and cannot directly access CRP registers via raw reads. Ideally, all secure registers should be accessed via xilinx_pm_request(). Introduced the secure zynqmp_pm_get_bootmode_reg() call, which uses xilinx_pm_request() to read the boot mode register. When CONFIG_ZYNQMP_FIRMWARE is enabled, the secure zynqmp_pm_get_bootmode_reg() call is used; otherwise, direct raw reads are performed in the case of mini U-Boot. Signed-off-by: Prasad Kummari Link: https://lore.kernel.org/r/20250219115301.3661036-1-prasad.kummari@amd.com Signed-off-by: Michal Simek --- drivers/firmware/firmware-zynqmp.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'drivers') diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index 4b1b80d7abe..2adc132b4cc 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -195,6 +195,29 @@ int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value) return ret; } +u32 zynqmp_pm_get_bootmode_reg(void) +{ + int ret; + u32 ret_payload[PAYLOAD_ARG_CNT]; + + ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_READ_REG); + if (ret) { + printf("%s: IOCTL_READ_REG is not supported failed with error code: %d\n" + , __func__, ret); + return 0; + } + + ret = xilinx_pm_request(PM_IOCTL, CRP_BOOT_MODE_REG_NODE, IOCTL_READ_REG, + CRP_BOOT_MODE_REG_OFFSET, 0, ret_payload); + if (ret) { + printf("%s: node 0x%x: get_bootmode 0x%x failed\n", + __func__, CRP_BOOT_MODE_REG_NODE, CRP_BOOT_MODE_REG_OFFSET); + return 0; + } + + return ret_payload[1]; +} + int zynqmp_pm_feature(const u32 api_id) { int ret; -- cgit v1.3.1 From 5ffab6ee1279fe86ab21b529a04b1638a6664eaf Mon Sep 17 00:00:00 2001 From: Prasad Kummari Date: Wed, 5 Mar 2025 19:18:46 +0530 Subject: xilinx: versal: add firmware access to PMC multi Boot mode register Added extended support for retrieving the PMC muti boot mode register via the firmware interface, which is preferred when U-Boot runs in EL2 and cannot directly access PMC registers via raw reads. Ideally, all secure registers should be accessed via xilinx_pm_request(). Introduced the secure zynqmp_pm_get_pmc_multi_boot_reg() call, which uses xilinx_pm_request() to read the PMC multi boot mode register. BootROM increments the MultiBoot register (PMC_MULTI_BOOT) read address offset by 32 KB and retries. For SD and eMMC boot modes, it can search up to 8191 FAT files for the identification string. A 13-bit mask (0x1FFF) is applied to PMC_MULTI_BOOT_MASK to obtain the correct values in BootROM. Signed-off-by: Prasad Kummari Link: https://lore.kernel.org/r/20250305134845.3182193-1-prasad.kummari@amd.com Signed-off-by: Michal Simek --- arch/arm/mach-versal/include/mach/hardware.h | 2 ++ board/xilinx/versal/board.c | 8 +++++++- drivers/firmware/firmware-zynqmp.c | 23 +++++++++++++++++++++++ include/zynqmp_firmware.h | 4 ++++ 4 files changed, 36 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/arch/arm/mach-versal/include/mach/hardware.h b/arch/arm/mach-versal/include/mach/hardware.h index 9d1c2f0dcfc..b5f80a8e3a9 100644 --- a/arch/arm/mach-versal/include/mach/hardware.h +++ b/arch/arm/mach-versal/include/mach/hardware.h @@ -87,6 +87,8 @@ struct crp_regs { #define JTAG_MODE 0x00000000 #define BOOT_MODE_USE_ALT 0x100 #define BOOT_MODE_ALT_SHIFT 12 +#define PMC_MULTI_BOOT_REG 0xF1110004 +#define PMC_MULTI_BOOT_MASK 0x1FFF #define FLASH_RESET_GPIO 0xc #define WPROT_CRP 0xF126001C diff --git a/board/xilinx/versal/board.c b/board/xilinx/versal/board.c index f6cf3c228e6..8ea9eee9a1f 100644 --- a/board/xilinx/versal/board.c +++ b/board/xilinx/versal/board.c @@ -61,12 +61,18 @@ static u8 versal_get_bootmode(void) static u32 versal_multi_boot(void) { u8 bootmode = versal_get_bootmode(); + u32 reg = 0; /* Mostly workaround for QEMU CI pipeline */ if (bootmode == JTAG_MODE) return 0; - return readl(0xF1110004); + if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE) && current_el() != 3) + reg = zynqmp_pm_get_pmc_multi_boot_reg(); + else + reg = readl(PMC_MULTI_BOOT_REG); + + return reg & PMC_MULTI_BOOT_MASK; } int board_init(void) diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index 2adc132b4cc..584397ba29a 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -218,6 +218,29 @@ u32 zynqmp_pm_get_bootmode_reg(void) return ret_payload[1]; } +u32 zynqmp_pm_get_pmc_multi_boot_reg(void) +{ + int ret; + u32 ret_payload[PAYLOAD_ARG_CNT]; + + ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_READ_REG); + if (ret) { + printf("%s: IOCTL_READ_REG is not supported failed with error code: %d\n" + , __func__, ret); + return 0; + } + + ret = xilinx_pm_request(PM_IOCTL, PM_REG_PMC_GLOBAL_NODE, IOCTL_READ_REG, + PMC_MULTI_BOOT_MODE_REG_OFFSET, 0, ret_payload); + if (ret) { + printf("%s: node 0x%x: get_bootmode 0x%x failed\n", + __func__, PM_REG_PMC_GLOBAL_NODE, PMC_MULTI_BOOT_MODE_REG_OFFSET); + return 0; + } + + return ret_payload[1]; +} + int zynqmp_pm_feature(const u32 api_id) { int ret; diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h index e7275f72fac..82781dfd16b 100644 --- a/include/zynqmp_firmware.h +++ b/include/zynqmp_firmware.h @@ -458,6 +458,7 @@ int zynqmp_mmio_read(const u32 address, u32 *value); int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value); int zynqmp_pm_feature(const u32 api_id); u32 zynqmp_pm_get_bootmode_reg(void); +u32 zynqmp_pm_get_pmc_multi_boot_reg(void); /* Type of Config Object */ #define PM_CONFIG_OBJECT_TYPE_BASE 0x1U @@ -504,4 +505,7 @@ struct zynqmp_ipi_msg { #define CRP_BOOT_MODE_REG_NODE 0x30000001 #define CRP_BOOT_MODE_REG_OFFSET 0x200 +#define PM_REG_PMC_GLOBAL_NODE 0x30000004 +#define PMC_MULTI_BOOT_MODE_REG_OFFSET 0x4 + #endif /* _ZYNQMP_FIRMWARE_H_ */ -- cgit v1.3.1 From 3243f71b64db89b8a6c045d41379b65aceabdd3c Mon Sep 17 00:00:00 2001 From: Venkatesh Yadav Abbarapu Date: Tue, 11 Mar 2025 09:43:17 +0530 Subject: spi: cadence_ospi: Add device reset via OSPI controller Add support for flash device reset via OSPI controller instead of using GPIO, as OSPI IP has device reset feature on Versal Gen2 platform. Also add compatible string for Versal Gen2 platform. Signed-off-by: Venkatesh Yadav Abbarapu Link: https://lore.kernel.org/r/20250311041317.2992862-1-venkatesh.abbarapu@amd.com Signed-off-by: Michal Simek --- drivers/spi/cadence_ospi_versal.c | 19 +++++++++++++++++++ drivers/spi/cadence_qspi.c | 9 +++++++++ drivers/spi/cadence_qspi.h | 3 +++ 3 files changed, 31 insertions(+) (limited to 'drivers') diff --git a/drivers/spi/cadence_ospi_versal.c b/drivers/spi/cadence_ospi_versal.c index 816916de16d..fbeb0c6a85c 100644 --- a/drivers/spi/cadence_ospi_versal.c +++ b/drivers/spi/cadence_ospi_versal.c @@ -204,3 +204,22 @@ void cadence_qspi_apb_enable_linear_mode(bool enable) ~VERSAL_OSPI_LINEAR_MODE, VERSAL_AXI_MUX_SEL); } } + +int cadence_device_reset(struct udevice *bus) +{ + struct cadence_spi_priv *priv = dev_get_priv(bus); + u32 reg; + + reg = readl(priv->regbase + CQSPI_REG_CONFIG); + reg |= CQSPI_REG_CONFIG_RESET_CFG_FLD_MASK; + writel(reg, priv->regbase + CQSPI_REG_CONFIG); + + writel(reg & ~CQSPI_REG_CONFIG_RESET_PIN_FLD_MASK, priv->regbase + CQSPI_REG_CONFIG); + udelay(5); + writel(reg | CQSPI_REG_CONFIG_RESET_PIN_FLD_MASK, priv->regbase + CQSPI_REG_CONFIG); + udelay(150); + writel(reg & ~CQSPI_REG_CONFIG_RESET_PIN_FLD_MASK, priv->regbase + CQSPI_REG_CONFIG); + udelay(1200); + + return 0; +} diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index 623904ecdad..a78c00db4ff 100644 --- a/drivers/spi/cadence_qspi.c +++ b/drivers/spi/cadence_qspi.c @@ -33,6 +33,11 @@ __weak int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv, return 0; } +__weak int cadence_device_reset(struct udevice *dev) +{ + return 0; +} + __weak int cadence_qspi_flash_reset(struct udevice *dev) { return 0; @@ -251,6 +256,9 @@ static int cadence_spi_probe(struct udevice *bus) priv->wr_delay = 50 * DIV_ROUND_UP(NSEC_PER_SEC, priv->ref_clk_hz); + if (device_is_compatible(bus, "amd,versal2-ospi")) + return cadence_device_reset(bus); + /* Reset ospi flash device */ return cadence_qspi_flash_reset(bus); @@ -452,6 +460,7 @@ static const struct dm_spi_ops cadence_spi_ops = { static const struct udevice_id cadence_spi_ids[] = { { .compatible = "cdns,qspi-nor" }, { .compatible = "ti,am654-ospi" }, + { .compatible = "amd,versal2-ospi" }, { } }; diff --git a/drivers/spi/cadence_qspi.h b/drivers/spi/cadence_qspi.h index 1f9125cd239..731b6527cf3 100644 --- a/drivers/spi/cadence_qspi.h +++ b/drivers/spi/cadence_qspi.h @@ -45,6 +45,8 @@ #define CQSPI_REG_CONFIG_CLK_POL BIT(1) #define CQSPI_REG_CONFIG_CLK_PHA BIT(2) #define CQSPI_REG_CONFIG_PHY_ENABLE_MASK BIT(3) +#define CQSPI_REG_CONFIG_RESET_PIN_FLD_MASK BIT(5) +#define CQSPI_REG_CONFIG_RESET_CFG_FLD_MASK BIT(6) #define CQSPI_REG_CONFIG_DIRECT BIT(7) #define CQSPI_REG_CONFIG_DECODE BIT(9) #define CQSPI_REG_CONFIG_ENBL_DMA BIT(15) @@ -310,5 +312,6 @@ int cadence_qspi_apb_exec_flash_cmd(void *reg_base, unsigned int reg); int cadence_qspi_flash_reset(struct udevice *dev); ofnode cadence_qspi_get_subnode(struct udevice *dev); void cadence_qspi_apb_enable_linear_mode(bool enable); +int cadence_device_reset(struct udevice *dev); #endif /* __CADENCE_QSPI_H__ */ -- cgit v1.3.1 From b58d34064ca1424132d4d48385a62d987fc169b5 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Thu, 13 Mar 2025 13:23:46 +0100 Subject: serial: Setup default base and frequency for Versal platforms Add useful default debug uart values for all Versal platforms to simplify and speed up debug uart enabling. The similar change has been done for Zynq/ZynqMP by commit ad55d99e3cc3 ("serial: Setup serial base and freq for zynq/zynqmp"). Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/86edf3dbb6de16337aac36f5121f306f83149fc0.1741868624.git.michal.simek@amd.com --- drivers/serial/Kconfig | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 84130524c2d..589b526381f 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -519,6 +519,8 @@ config DEBUG_UART_BASE default 0x0 if DEBUG_UART_SANDBOX default 0xff000000 if DEBUG_UART_ZYNQ && ARCH_ZYNQMP default 0xe0000000 if DEBUG_UART_ZYNQ && ARCH_ZYNQ + default 0xff000000 if DEBUG_UART_PL011 && ARCH_VERSAL + default 0xf1920000 if DEBUG_UART_PL011 && (ARCH_VERSAL_NET || ARCH_VERSAL2) help This is the base address of your UART for memory-mapped UARTs. @@ -554,6 +556,7 @@ config DEBUG_UART_CLOCK default 0 if DEBUG_MVEBU_A3700_UART default 100000000 if DEBUG_UART_ZYNQ && ARCH_ZYNQMP default 50000000 if DEBUG_UART_ZYNQ && ARCH_ZYNQ + default 100000000 if DEBUG_UART_PL011 && (ARCH_VERSAL || ARCH_VERSAL_NET || ARCH_VERSAL2) help The UART input clock determines the speed of the internal UART circuitry. The baud rate is derived from this by dividing the input -- cgit v1.3.1 From 5b8d6dcf7ce1b9629cec02e8d17db530776de5b4 Mon Sep 17 00:00:00 2001 From: Venkatesh Yadav Abbarapu Date: Thu, 20 Mar 2025 10:13:24 +0100 Subject: ufs: amd-versal2: Use raw read/write for SLCR/CACHE registers Update the firmware driver UFS APIs zynqmp_pm_ufs_* to directly read/write to the pmc_iou_slcr and efuse_cache registers. Replace these raw reads/writes with the xilinx_pm_request() API with the correct arguments once the PM related changes are done. Signed-off-by: Venkatesh Yadav Abbarapu Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/ee2d1ad2e07e96f1948ab6ffe8f3c50a3b8f9be9.1742462001.git.michal.simek@amd.com --- arch/arm/mach-versal2/include/mach/hardware.h | 6 +++ drivers/firmware/firmware-zynqmp.c | 28 ++++++++++++ drivers/ufs/ufs-amd-versal2.c | 66 ++++++--------------------- include/zynqmp_firmware.h | 4 ++ 4 files changed, 52 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-versal2/include/mach/hardware.h b/arch/arm/mach-versal2/include/mach/hardware.h index a961032b4d5..7ca2bbb7550 100644 --- a/arch/arm/mach-versal2/include/mach/hardware.h +++ b/arch/arm/mach-versal2/include/mach/hardware.h @@ -97,3 +97,9 @@ enum versal2_platform { #define MIO_PIN_12 0xF1060030 #define BANK0_OUTPUT 0xF1020040 #define BANK0_TRI 0xF1060200 + +#define PMXC_EFUSE_CACHE_BASE_ADDRESS 0xF1250000 +#define PMXC_SLCR_BASE_ADDRESS 0xF1061000 +#define PMXC_UFS_CAL_1_OFFSET 0xBE8 +#define PMXC_SRAM_CSR 0x4C +#define PMXC_TX_RX_CFG_RDY 0x54 diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index 584397ba29a..2940181e83e 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -5,6 +5,8 @@ * Copyright (C) 2018-2019 Xilinx, Inc. */ +#include +#include #include #include #include @@ -169,6 +171,32 @@ unsigned int zynqmp_firmware_version(void) return pm_api_version; }; +#if defined(CONFIG_ARCH_VERSAL2) +int zynqmp_pm_ufs_get_txrx_cfgrdy(u32 *value) +{ + *value = readl(PMXC_SLCR_BASE_ADDRESS + PMXC_TX_RX_CFG_RDY); + return 0; +} + +int zynqmp_pm_ufs_sram_csr_read(u32 *value) +{ + *value = readl(PMXC_SLCR_BASE_ADDRESS + PMXC_SRAM_CSR); + return 0; +} + +int zynqmp_pm_ufs_sram_csr_write(u32 *value) +{ + writel(*value, PMXC_SLCR_BASE_ADDRESS + PMXC_SRAM_CSR); + return 0; +} + +int zynqmp_pm_ufs_cal_reg(u32 *value) +{ + *value = readl(PMXC_EFUSE_CACHE_BASE_ADDRESS + PMXC_UFS_CAL_1_OFFSET); + return 0; +} +#endif + int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, u32 value) { int ret; diff --git a/drivers/ufs/ufs-amd-versal2.c b/drivers/ufs/ufs-amd-versal2.c index bfd844e4193..1c5ed538370 100644 --- a/drivers/ufs/ufs-amd-versal2.c +++ b/drivers/ufs/ufs-amd-versal2.c @@ -19,8 +19,6 @@ #include "ufshcd-dwc.h" #include "ufshci-dwc.h" -#define VERSAL2_UFS_DEVICE_ID 4 - #define SRAM_CSR_INIT_DONE_MASK BIT(0) #define SRAM_CSR_EXT_LD_DONE_MASK BIT(1) #define SRAM_CSR_BYPASS_MASK BIT(2) @@ -32,19 +30,12 @@ #define TIMEOUT_MICROSEC 1000000L -#define IOCTL_UFS_TXRX_CFGRDY_GET 40 -#define IOCTL_UFS_SRAM_CSR_SEL 41 - -#define PM_UFS_SRAM_CSR_WRITE 0 -#define PM_UFS_SRAM_CSR_READ 1 - struct ufs_versal2_priv { struct ufs_hba *hba; struct reset_ctl *rstc; struct reset_ctl *rstphy; u32 phy_mode; u32 host_clk; - u32 pd_dev_id; u8 attcompval0; u8 attcompval1; u8 ctlecompval0; @@ -102,41 +93,6 @@ static int ufs_versal2_phy_reg_read(struct ufs_hba *hba, u32 addr, u32 *val) return 0; } -int versal2_pm_ufs_get_txrx_cfgrdy(u32 node_id, u32 *value) -{ - u32 ret_payload[PAYLOAD_ARG_CNT]; - int ret; - - if (!value) - return -EINVAL; - - ret = xilinx_pm_request(PM_IOCTL, node_id, IOCTL_UFS_TXRX_CFGRDY_GET, - 0, 0, ret_payload); - *value = ret_payload[1]; - - return ret; -} - -int versal2_pm_ufs_sram_csr_sel(u32 node_id, u32 type, u32 *value) -{ - u32 ret_payload[PAYLOAD_ARG_CNT]; - int ret; - - if (!value) - return -EINVAL; - - if (type == PM_UFS_SRAM_CSR_READ) { - ret = xilinx_pm_request(PM_IOCTL, node_id, IOCTL_UFS_SRAM_CSR_SEL, - type, 0, ret_payload); - *value = ret_payload[1]; - } else { - ret = xilinx_pm_request(PM_IOCTL, node_id, IOCTL_UFS_SRAM_CSR_SEL, - type, *value, 0); - } - - return ret; -} - static int ufs_versal2_enable_phy(struct ufs_hba *hba) { u32 offset, reg; @@ -281,7 +237,7 @@ static int ufs_versal2_phy_init(struct ufs_hba *hba) time_left = TIMEOUT_MICROSEC; do { time_left--; - ret = versal2_pm_ufs_get_txrx_cfgrdy(priv->pd_dev_id, ®); + ret = zynqmp_pm_ufs_get_txrx_cfgrdy(®); if (ret) return ret; @@ -312,8 +268,7 @@ static int ufs_versal2_phy_init(struct ufs_hba *hba) time_left = TIMEOUT_MICROSEC; do { time_left--; - ret = versal2_pm_ufs_sram_csr_sel(priv->pd_dev_id, - PM_UFS_SRAM_CSR_READ, ®); + ret = zynqmp_pm_ufs_sram_csr_read(®); if (ret) return ret; @@ -341,10 +296,10 @@ static int ufs_versal2_init(struct ufs_hba *hba) struct ufs_versal2_priv *priv = dev_get_priv(hba->dev); struct clk clk; unsigned long core_clk_rate = 0; + u32 cal; int ret = 0; priv->phy_mode = UFSHCD_DWC_PHY_MODE_ROM; - priv->pd_dev_id = VERSAL2_UFS_DEVICE_ID; ret = clk_get_by_name(hba->dev, "core_clk", &clk); if (ret) { @@ -371,6 +326,15 @@ static int ufs_versal2_init(struct ufs_hba *hba) return PTR_ERR(priv->rstphy); } + ret = zynqmp_pm_ufs_cal_reg(&cal); + if (ret) + return ret; + + priv->attcompval0 = (u8)cal; + priv->attcompval1 = (u8)(cal >> 8); + priv->ctlecompval0 = (u8)(cal >> 16); + priv->ctlecompval1 = (u8)(cal >> 24); + return ret; } @@ -397,8 +361,7 @@ static int ufs_versal2_hce_enable_notify(struct ufs_hba *hba, return ret; } - ret = versal2_pm_ufs_sram_csr_sel(priv->pd_dev_id, - PM_UFS_SRAM_CSR_READ, &sram_csr); + ret = zynqmp_pm_ufs_sram_csr_read(&sram_csr); if (ret) return ret; @@ -410,8 +373,7 @@ static int ufs_versal2_hce_enable_notify(struct ufs_hba *hba, return -EINVAL; } - ret = versal2_pm_ufs_sram_csr_sel(priv->pd_dev_id, - PM_UFS_SRAM_CSR_WRITE, &sram_csr); + ret = zynqmp_pm_ufs_sram_csr_write(&sram_csr); if (ret) return ret; diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h index 82781dfd16b..dc06abc52fc 100644 --- a/include/zynqmp_firmware.h +++ b/include/zynqmp_firmware.h @@ -458,6 +458,10 @@ int zynqmp_mmio_read(const u32 address, u32 *value); int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value); int zynqmp_pm_feature(const u32 api_id); u32 zynqmp_pm_get_bootmode_reg(void); +int zynqmp_pm_ufs_get_txrx_cfgrdy(u32 *value); +int zynqmp_pm_ufs_sram_csr_read(u32 *value); +int zynqmp_pm_ufs_sram_csr_write(u32 *value); +int zynqmp_pm_ufs_cal_reg(u32 *value); u32 zynqmp_pm_get_pmc_multi_boot_reg(void); /* Type of Config Object */ -- cgit v1.3.1 From 82dd190807e42f25d0bd2f5c20b5cfb90d353040 Mon Sep 17 00:00:00 2001 From: Muhammad Hazim Izzat Zamri Date: Thu, 13 Mar 2025 19:19:52 -0700 Subject: drivers: fpga: Add FPGA configuration during bootm for Intel SOCFPGA Enabling the capability to automatically perform FPGA configuration when booting Linux FIT image via bootm command. The FPGA configuration bitstream shall be packed within the FIT image. The FPGA data (full or partial) is checked by the SDM hardware, for Intel SDM Mailbox based devices. Hence always return full bitstream. Second function is to enable the HPS to FPGA bridges when FPGA load is completed successfully. This is to ensure the FPGA is accessible by the HPS. Signed-off-by: Muhammad Hazim Izzat Zamri Link: https://lore.kernel.org/r/20250314021953.18379-2-muhammad.hazim.izzat.zamri@altera.com Signed-off-by: Michal Simek --- drivers/fpga/altera.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'drivers') diff --git a/drivers/fpga/altera.c b/drivers/fpga/altera.c index ae06f0123a0..136ccfc2de4 100644 --- a/drivers/fpga/altera.c +++ b/drivers/fpga/altera.c @@ -12,6 +12,10 @@ /* * Altera FPGA support */ +#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX) || \ + IS_ENABLED(CONFIG_TARGET_SOCFPGA_STRATIX10) +#include +#endif #include #include #include @@ -47,6 +51,42 @@ static const struct altera_fpga { #endif }; +#if IS_ENABLED(CONFIG_TARGET_SOCFPGA_AGILEX) || \ + IS_ENABLED(CONFIG_TARGET_SOCFPGA_STRATIX10) +int fpga_is_partial_data(int devnum, size_t img_len) +{ + /* + * The FPGA data (full or partial) is checked by + * the SDM hardware, for Intel SDM Mailbox based + * devices. Hence always return full bitstream. + * + * For Cyclone V and Arria 10 family, the bitstream + * type parameter is not handled by the driver. + */ + return 0; +} + +int fpga_loadbitstream(int devnum, char *fpgadata, size_t size, + bitstream_type bstype) +{ + int ret_val; + + ret_val = fpga_load(devnum, (void *)fpgadata, size, bstype); + + /* + * Enable the HPS to FPGA bridges when FPGA load is completed + * successfully. This is to ensure the FPGA is accessible + * by the HPS. + */ + if (!ret_val) { + printf("Enable FPGA bridges\n"); + do_bridge_reset(1, ~0); + } + + return ret_val; +} +#endif + static int altera_validate(Altera_desc *desc, const char *fn) { if (!desc) { -- cgit v1.3.1 From b5a88e9d95369537876bef1e84e591f583bf7d85 Mon Sep 17 00:00:00 2001 From: Muhammad Hazim Izzat Zamri Date: Thu, 13 Mar 2025 19:19:53 -0700 Subject: drivers: fpga: Follow mainline to pass compatible flags to fpga_load Introducing additional flag to check whether an FPGA driver is able to load a particular FPGA bitstream image. Generally, flag variable is used to enable or disable certain features, specify additional parameters (such as error handling), or modify how the function operates. Hence, in this function flags is an integer that can be used to pass configuration options to the fpga_load function. Here, it's initialized to 0, meaning no special options are enabled, but it could modify the flags to influence the function's behavior. Signed-off-by: Muhammad Hazim Izzat Zamri Link: https://lore.kernel.org/r/20250314021953.18379-3-muhammad.hazim.izzat.zamri@altera.com Signed-off-by: Michal Simek --- drivers/fpga/altera.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/fpga/altera.c b/drivers/fpga/altera.c index 136ccfc2de4..64fda3a307c 100644 --- a/drivers/fpga/altera.c +++ b/drivers/fpga/altera.c @@ -70,8 +70,9 @@ int fpga_loadbitstream(int devnum, char *fpgadata, size_t size, bitstream_type bstype) { int ret_val; + int flags = 0; - ret_val = fpga_load(devnum, (void *)fpgadata, size, bstype); + ret_val = fpga_load(devnum, (void *)fpgadata, size, bstype, flags); /* * Enable the HPS to FPGA bridges when FPGA load is completed -- cgit v1.3.1 From 44a26da8d91b72746b364d414adf5092143f826f Mon Sep 17 00:00:00 2001 From: Prasad Kummari Date: Thu, 27 Mar 2025 16:21:59 +0530 Subject: arm64: versal2: Add PL bit stream load support Add support for loading the secure & non-secure pdi images and PL bitstream on the Versal Gen2 platform. The FPGA driver is enabled to load the bitstream in PDI format on the AMD Versal Gen2 device. PDI is the new programmable device image format for Versal Gen2, and the bitstream for the Versal Gen2 platform is generated exclusively in this format. With the enhanced SMC format in TF-A ensuring transparent payload forwarding for Versal Gen2, the u-boot driver must now handle the word swapping of PDI address that was previously done in TF-A for this API. The source code for the Versal2 loadpdi command and the CONFIG_CMD_VERSAL2 configuration has been removed. It now utilizes the fpga load
command to load secure & non-secure pdi images. Signed-off-by: Prasad Kummari Link: https://lore.kernel.org/r/20250327105200.1262615-3-prasad.kummari@amd.com Signed-off-by: Michal Simek --- arch/arm/mach-versal2/Kconfig | 1 - board/amd/versal2/Kconfig | 16 -------- board/amd/versal2/Makefile | 1 - board/amd/versal2/board.c | 13 +++++++ board/amd/versal2/cmds.c | 80 -------------------------------------- configs/amd_versal2_virt_defconfig | 2 + drivers/fpga/versalpl.c | 11 +++++- include/xilinx.h | 1 + 8 files changed, 25 insertions(+), 100 deletions(-) delete mode 100644 board/amd/versal2/Kconfig delete mode 100644 board/amd/versal2/cmds.c (limited to 'drivers') diff --git a/arch/arm/mach-versal2/Kconfig b/arch/arm/mach-versal2/Kconfig index 3f18e3351aa..2a595151d6f 100644 --- a/arch/arm/mach-versal2/Kconfig +++ b/arch/arm/mach-versal2/Kconfig @@ -50,6 +50,5 @@ config ZYNQ_SDHCI_MAX_FREQ default 200000000 source "board/xilinx/Kconfig" -source "board/amd/versal2/Kconfig" endif diff --git a/board/amd/versal2/Kconfig b/board/amd/versal2/Kconfig deleted file mode 100644 index ab46af6935e..00000000000 --- a/board/amd/versal2/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Copyright (C) 2020 - 2022, Xilinx, Inc. -# Copyright (C) 2022 - 2024, Advanced Micro Devices, Inc. -# -if ARCH_VERSAL2 - -config CMD_VERSAL2 - bool "Enable Versal Gen 2 specific commands" - default y - depends on ZYNQMP_FIRMWARE - help - Select this to enable AMD Versal Gen 2 specific commands. - Commands like versal2 loadpdi are enabled by this. - -endif diff --git a/board/amd/versal2/Makefile b/board/amd/versal2/Makefile index 3a044517f0c..1673be4a6df 100644 --- a/board/amd/versal2/Makefile +++ b/board/amd/versal2/Makefile @@ -8,4 +8,3 @@ obj-y := board.o -obj-$(CONFIG_CMD_VERSAL2) += cmds.o diff --git a/board/amd/versal2/board.c b/board/amd/versal2/board.c index c99620d03ef..aea3bf02260 100644 --- a/board/amd/versal2/board.c +++ b/board/amd/versal2/board.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "../../xilinx/common/board.h" #include @@ -28,10 +29,22 @@ DECLARE_GLOBAL_DATA_PTR; +#if defined(CONFIG_FPGA_VERSALPL) +static xilinx_desc versalpl = { + xilinx_versal2, csu_dma, 1, &versal_op, 0, &versal_op, NULL, + FPGA_LEGACY +}; +#endif + int board_init(void) { printf("EL Level:\tEL%d\n", current_el()); +#if defined(CONFIG_FPGA_VERSALPL) + fpga_init(); + fpga_add(fpga_xilinx, &versalpl); +#endif + return 0; } diff --git a/board/amd/versal2/cmds.c b/board/amd/versal2/cmds.c deleted file mode 100644 index 56ae39bc6a1..00000000000 --- a/board/amd/versal2/cmds.c +++ /dev/null @@ -1,80 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Copyright (C) 2024, Advanced Micro Devices, Inc. - * - * Michal Simek - */ - -#include -#include -#include -#include -#include -#include -#include - -/** - * do_versal2_load_pdi - Handle the "versal2 load pdi" command-line command - * @cmdtp: Command data struct pointer - * @flag: Command flag - * @argc: Command-line argument count - * @argv: Array of command-line arguments - * - * Processes the versal2 load pdi command - * - * Return: return 0 on success, Error value if command fails. - * CMD_RET_USAGE incase of incorrect/missing parameters. - */ -static int do_versal2_load_pdi(struct cmd_tbl *cmdtp, int flag, int argc, - char * const argv[]) -{ - u32 buf_lo, buf_hi; - u32 ret_payload[PAYLOAD_ARG_CNT]; - ulong addr, *pdi_buf; - size_t len; - int ret; - - if (argc != cmdtp->maxargs) { - debug("pdi_load: incorrect parameters passed\n"); - return CMD_RET_USAGE; - } - - addr = simple_strtol(argv[1], NULL, 16); - if (!addr) { - debug("pdi_load: zero pdi_data address\n"); - return CMD_RET_USAGE; - } - - len = hextoul(argv[2], NULL); - if (!len) { - debug("pdi_load: zero size\n"); - return CMD_RET_USAGE; - } - - pdi_buf = (ulong *)ALIGN((ulong)addr, ARCH_DMA_MINALIGN); - if ((ulong)addr != (ulong)pdi_buf) { - memcpy((void *)pdi_buf, (void *)addr, len); - debug("Pdi addr:0x%lx aligned to 0x%lx\n", - addr, (ulong)pdi_buf); - } - - flush_dcache_range((ulong)pdi_buf, (ulong)pdi_buf + len); - - buf_lo = lower_32_bits((ulong)pdi_buf); - buf_hi = upper_32_bits((ulong)pdi_buf); - - ret = xilinx_pm_request(VERSAL_PM_LOAD_PDI, VERSAL_PM_PDI_TYPE, buf_lo, - buf_hi, 0, ret_payload); - if (ret) - printf("PDI load failed with err: 0x%08x\n", ret); - - return cmd_process_error(cmdtp, ret); -} - -U_BOOT_LONGHELP(versal2, - "loadpdi addr len - Load pdi image\n" - "load pdi image at ddr address 'addr' with pdi image size 'len'\n"); - -U_BOOT_CMD_WITH_SUBCMDS(versal2, "Versal Gen 2 sub-system", versal2_help_text, - U_BOOT_SUBCMD_MKENT(loadpdi, 3, 1, - do_versal2_load_pdi)); diff --git a/configs/amd_versal2_virt_defconfig b/configs/amd_versal2_virt_defconfig index 087c7f04733..6946b2b181e 100644 --- a/configs/amd_versal2_virt_defconfig +++ b/configs/amd_versal2_virt_defconfig @@ -72,6 +72,8 @@ CONFIG_CLK_CCF=y CONFIG_CLK_SCMI=y CONFIG_DFU_RAM=y CONFIG_ARM_FFA_TRANSPORT=y +CONFIG_FPGA_XILINX=y +CONFIG_FPGA_VERSALPL=y CONFIG_DM_I2C=y CONFIG_SYS_I2C_CADENCE=y CONFIG_I2C_MUX=y diff --git a/drivers/fpga/versalpl.c b/drivers/fpga/versalpl.c index 1957e8dcaca..d691f135e89 100644 --- a/drivers/fpga/versalpl.c +++ b/drivers/fpga/versalpl.c @@ -41,8 +41,15 @@ static int versal_load(xilinx_desc *desc, const void *buf, size_t bsize, buf_lo = lower_32_bits(bin_buf); buf_hi = upper_32_bits(bin_buf); - ret = xilinx_pm_request(VERSAL_PM_LOAD_PDI, VERSAL_PM_PDI_TYPE, buf_lo, - buf_hi, 0, ret_payload); + + if (desc->family == xilinx_versal2) { + ret = xilinx_pm_request(VERSAL_PM_LOAD_PDI, VERSAL_PM_PDI_TYPE, buf_hi, + buf_lo, 0, ret_payload); + } else { + ret = xilinx_pm_request(VERSAL_PM_LOAD_PDI, VERSAL_PM_PDI_TYPE, buf_lo, + buf_hi, 0, ret_payload); + } + if (ret) printf("PL FPGA LOAD failed with err: 0x%08x\n", ret); diff --git a/include/xilinx.h b/include/xilinx.h index 2b4d6c9bb06..c54d6dc1453 100644 --- a/include/xilinx.h +++ b/include/xilinx.h @@ -35,6 +35,7 @@ typedef enum { /* typedef xilinx_family */ xilinx_zynqmp, /* ZynqMP Family */ xilinx_versal, /* Versal Family */ xilinx_versal_net, /* Versal NET Family */ + xilinx_versal2, /* Versal Gen 2 Family */ max_xilinx_type /* insert all new types before this */ } xilinx_family; /* end, typedef xilinx_family */ -- cgit v1.3.1