diff options
| author | Tom Rini <[email protected]> | 2026-08-12 08:31:54 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2026-08-12 08:31:54 -0600 |
| commit | 0b581a9612e46310ee52bf8359165950d38b2a2b (patch) | |
| tree | 3f7519c37681014044639dc902dbea0dea3f6f1f | |
| parent | 77bc0326456d9d6a83aa7adac201d1c97a008b61 (diff) | |
| parent | 86cc9f2fb5637d64e2da78c43fdccf4c50daef8c (diff) | |
Merge tag 'xilinx-for-v2026.10-rc3' of https://git.u-boot-project.org/u-boot/custodians/u-boot-amd
AMD/Xilinx changes for v2026.10-rc3
Versal Gen 2:
- Add support for 2VM3654 device
- Add missing MAINTAINERS fragment
AMD:
- Fix fwu dfu_string generation not to alter with generic DFU
Firmware/ufs:
- UFS interface cleanup
- Remove ZynqMP firmware dependency from UFS
zynqmp_gqspi:
- Fix quad mode bus conflict
MB-V:
- shrink SPL size and enforce size limits
- remake ELF from BIN
| -rw-r--r-- | MAINTAINERS | 6 | ||||
| -rw-r--r-- | arch/arm/mach-versal2/Makefile | 1 | ||||
| -rw-r--r-- | arch/arm/mach-versal2/cpu.c | 40 | ||||
| -rw-r--r-- | arch/arm/mach-versal2/include/mach/hardware.h | 87 | ||||
| -rw-r--r-- | arch/arm/mach-versal2/include/mach/sys_proto.h | 7 | ||||
| -rw-r--r-- | arch/arm/mach-versal2/lowlevel_init.S | 40 | ||||
| -rw-r--r-- | board/amd/versal2/board.c | 39 | ||||
| -rw-r--r-- | board/xilinx/common/board.c | 37 | ||||
| -rw-r--r-- | board/xilinx/versal/board.c | 39 | ||||
| -rw-r--r-- | configs/xilinx_mbv32_defconfig | 5 | ||||
| -rw-r--r-- | configs/xilinx_zynqmp_mini_defconfig | 20 | ||||
| -rw-r--r-- | configs/xilinx_zynqmp_mini_qspi_defconfig | 6 | ||||
| -rw-r--r-- | drivers/firmware/firmware-zynqmp.c | 104 | ||||
| -rw-r--r-- | drivers/spi/zynqmp_gqspi.c | 43 | ||||
| -rw-r--r-- | drivers/ufs/Kconfig | 2 | ||||
| -rw-r--r-- | drivers/ufs/ufs-amd-versal2.c | 133 | ||||
| -rw-r--r-- | include/configs/amd_versal2.h | 9 | ||||
| -rw-r--r-- | include/zynqmp_firmware.h | 13 |
18 files changed, 388 insertions, 243 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index e1379a6a3e7..eb48eea55c5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -821,6 +821,12 @@ F: drivers/spi/cadence_ospi_versal.c F: drivers/watchdog/xilinx_wwdt.c N: (?<!uni)versal +ARM VERSAL GEN 2 +M: Michal Simek <[email protected]> +S: Maintained +T: git https://git.u-boot-project.org/u-boot/custodians/u-boot-microblaze.git +F: arch/arm/mach-versal2/ + ARM VERSATILE EXPRESS DRIVERS M: Liviu Dudau <[email protected]> S: Maintained diff --git a/arch/arm/mach-versal2/Makefile b/arch/arm/mach-versal2/Makefile index 96497b1dfd0..73b3c8a6f35 100644 --- a/arch/arm/mach-versal2/Makefile +++ b/arch/arm/mach-versal2/Makefile @@ -8,3 +8,4 @@ obj-y += clk.o obj-y += cpu.o +obj-y += lowlevel_init.o diff --git a/arch/arm/mach-versal2/cpu.c b/arch/arm/mach-versal2/cpu.c index 6cc6592b0fc..d72f66f4fba 100644 --- a/arch/arm/mach-versal2/cpu.c +++ b/arch/arm/mach-versal2/cpu.c @@ -11,6 +11,7 @@ #include <malloc.h> #include <time.h> #include <vsprintf.h> +#include <wait_bit.h> #include <asm/armv8/mmu.h> #include <asm/cache.h> #include <asm/global_data.h> @@ -160,6 +161,45 @@ u8 __weak versal2_get_bootmode(void) return bootmode; } +/* + * Wait for the M-PHY TX/RX config-ready status to settle (all bits cleared) or + * @timeout_us to elapse. The direct-MMIO fallback owns the poll loop, mirroring + * the EEMI backend; the timeout budget is owned by the caller. + */ +int __weak zynqmp_pm_wait_mphy_tx_rx_config_ready(u32 timeout_us) +{ + return wait_for_bit_le32((void *)(uintptr_t)(PMXC_SLCR_BASE_ADDRESS + + PMXC_TX_RX_CFG_RDY), + TX_RX_CFG_RDY_MASK, false, timeout_us / 1000, + false); +} + +int __weak zynqmp_pm_wait_sram_init_done(u32 timeout_us) +{ + return wait_for_bit_le32((void *)(uintptr_t)(PMXC_SLCR_BASE_ADDRESS + + PMXC_SRAM_CSR), + SRAM_CSR_INIT_DONE_MASK, true, timeout_us / 1000, + false); +} + +int __weak zynqmp_pm_set_sram_bypass(void) +{ + u32 sram_csr; + + sram_csr = readl(PMXC_SLCR_BASE_ADDRESS + PMXC_SRAM_CSR); + sram_csr &= ~SRAM_CSR_EXT_LD_DONE_MASK; + sram_csr |= SRAM_CSR_BYPASS_MASK; + writel(sram_csr, PMXC_SLCR_BASE_ADDRESS + PMXC_SRAM_CSR); + + return 0; +} + +int __weak zynqmp_pm_get_ufs_calibration_values(u32 *value) +{ + *value = readl(PMXC_EFUSE_CACHE_BASE_ADDRESS + PMXC_UFS_CAL_1_OFFSET); + return 0; +} + void versal2_timer_setup(void) { u32 val; diff --git a/arch/arm/mach-versal2/include/mach/hardware.h b/arch/arm/mach-versal2/include/mach/hardware.h index 1bebf20910a..4ff732d660f 100644 --- a/arch/arm/mach-versal2/include/mach/hardware.h +++ b/arch/arm/mach-versal2/include/mach/hardware.h @@ -4,34 +4,6 @@ * Copyright (C) 2022 - 2025, Advanced Micro Devices, Inc. */ -#ifndef __ASSEMBLY__ -#include <linux/bitops.h> -#endif - -struct crlapb_regs { - u32 reserved0[67]; - u32 cpu_r5_ctrl; - u32 reserved; - u32 iou_switch_ctrl; /* 0x114 */ - u32 reserved1[13]; - u32 timestamp_ref_ctrl; /* 0x14c */ - u32 reserved3[108]; - u32 rst_cpu_r5; - u32 reserved2[17]; - u32 rst_timestamp; /* 0x348 */ -}; - -struct iou_scntrs_regs { - u32 counter_control_register; /* 0x0 */ - u32 reserved0[7]; - u32 base_frequency_id_register; /* 0x20 */ -}; - -struct crp_regs { - u32 reserved0[128]; - u32 boot_mode_usr; /* 0x200 */ -}; - #define VERSAL2_CRL_APB_BASEADDR 0xEB5E0000 #define VERSAL2_CRP_BASEADDR 0xF1260000 #define VERSAL2_IOU_SCNTR_SECURE 0xEC920000 @@ -41,10 +13,6 @@ struct crp_regs { #define IOU_SWITCH_CTRL_DIVISOR0_SHIFT 8 #define IOU_SCNTRS_CONTROL_EN 1 -#define crlapb_base ((struct crlapb_regs *)VERSAL2_CRL_APB_BASEADDR) -#define crp_base ((struct crp_regs *)VERSAL2_CRP_BASEADDR) -#define iou_scntr_secure ((struct iou_scntrs_regs *)VERSAL2_IOU_SCNTR_SECURE) - #define PMC_TAP 0xF11A0000 #define PMC_TAP_IDCODE (PMC_TAP + 0) @@ -76,15 +44,6 @@ struct crp_regs { #define PMC_MULTI_BOOT_REG 0xF1110004 #define PMC_MULTI_BOOT_MASK 0x1FFF -enum versal2_platform { - VERSAL2_SILICON = 0, - VERSAL2_SPP = 1, - VERSAL2_EMU = 2, - VERSAL2_QEMU = 3, - VERSAL2_SPP_MMD = 5, - VERSAL2_EMU_MMD = 6, -}; - #define VERSAL2_SLCR_BASEADDR 0xF1060000 #define VERSAL_AXI_MUX_SEL (VERSAL2_SLCR_BASEADDR + 0x504) #define VERSAL_OSPI_LINEAR_MODE BIT(1) @@ -106,5 +65,51 @@ enum versal2_platform { #define PMXC_SRAM_CSR 0x4C #define PMXC_TX_RX_CFG_RDY 0x54 +#define SRAM_CSR_INIT_DONE_MASK BIT(0) +#define SRAM_CSR_EXT_LD_DONE_MASK BIT(1) +#define SRAM_CSR_BYPASS_MASK BIT(2) +#define TX_RX_CFG_RDY_MASK GENMASK(3, 0) + #define PMC_GLOBAL_PGGS3_REG 0xF111005C #define PMC_GLOBAL_PGGS4_REG 0xF1110060 + +#ifndef __ASSEMBLY__ +#include <linux/bitops.h> + +struct crlapb_regs { + u32 reserved0[67]; + u32 cpu_r5_ctrl; + u32 reserved; + u32 iou_switch_ctrl; /* 0x114 */ + u32 reserved1[13]; + u32 timestamp_ref_ctrl; /* 0x14c */ + u32 reserved3[108]; + u32 rst_cpu_r5; + u32 reserved2[17]; + u32 rst_timestamp; /* 0x348 */ +}; + +struct iou_scntrs_regs { + u32 counter_control_register; /* 0x0 */ + u32 reserved0[7]; + u32 base_frequency_id_register; /* 0x20 */ +}; + +struct crp_regs { + u32 reserved0[128]; + u32 boot_mode_usr; /* 0x200 */ +}; + +#define crlapb_base ((struct crlapb_regs *)VERSAL2_CRL_APB_BASEADDR) +#define crp_base ((struct crp_regs *)VERSAL2_CRP_BASEADDR) +#define iou_scntr_secure ((struct iou_scntrs_regs *)VERSAL2_IOU_SCNTR_SECURE) + +enum versal2_platform { + VERSAL2_SILICON = 0, + VERSAL2_SPP = 1, + VERSAL2_EMU = 2, + VERSAL2_QEMU = 3, + VERSAL2_SPP_MMD = 5, + VERSAL2_EMU_MMD = 6, +}; +#endif /* __ASSEMBLY__ */ diff --git a/arch/arm/mach-versal2/include/mach/sys_proto.h b/arch/arm/mach-versal2/include/mach/sys_proto.h index b8d12d1dd3b..d678adf9c26 100644 --- a/arch/arm/mach-versal2/include/mach/sys_proto.h +++ b/arch/arm/mach-versal2/include/mach/sys_proto.h @@ -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. */ #ifndef _ASM_ARCH_SYS_PROTO_H @@ -22,4 +22,9 @@ u8 versal2_get_bootmode(void); /* EL3 clock/timer register setup, called from board_early_init_r() */ void versal2_timer_setup(void); +int zynqmp_pm_wait_mphy_tx_rx_config_ready(u32 timeout_us); +int zynqmp_pm_wait_sram_init_done(u32 timeout_us); +int zynqmp_pm_set_sram_bypass(void); +int zynqmp_pm_get_ufs_calibration_values(u32 *value); + #endif /* _ASM_ARCH_SYS_PROTO_H */ diff --git a/arch/arm/mach-versal2/lowlevel_init.S b/arch/arm/mach-versal2/lowlevel_init.S new file mode 100644 index 00000000000..8bfe50b806e --- /dev/null +++ b/arch/arm/mach-versal2/lowlevel_init.S @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * SoC specific lowlevel_init for AMD Versal Gen 2 + * + * Copyright (C) 2026, Advanced Micro Devices, Inc. + */ + +#include <asm-offsets.h> +#include <config.h> +#include <linux/linkage.h> +#include <asm/macro.h> +#include <asm/arch/hardware.h> + +ENTRY(lowlevel_init) + mov x29, lr /* Save LR */ + +#if defined(CONFIG_GICV3) + branch_if_slave x0, 1f + ldr x0, =GICD_BASE + bl gic_init_secure +1: + /* + * Pick the redistributor base for this part. Default to GICR_BASE + * and switch to GICR_BASE_2VM3654 when the PMC TAP IDCODE matches + * the 2VM3654 device. + */ + ldr x0, =GICR_BASE + ldr x1, =PMC_TAP_IDCODE + ldr w1, [x1] + ldr w2, =GICR_IDCODE_2VM3654 + cmp w1, w2 + b.ne 3f + ldr x0, =GICR_BASE_2VM3654 +3: + bl gic_init_secure_percpu +#endif + + mov lr, x29 /* Restore LR */ + ret +ENDPROC(lowlevel_init) diff --git a/board/amd/versal2/board.c b/board/amd/versal2/board.c index 2afd283b8dd..15b79bbea69 100644 --- a/board/amd/versal2/board.c +++ b/board/amd/versal2/board.c @@ -11,7 +11,6 @@ #include <env.h> #include <efi_loader.h> #include <fdtdec.h> -#include <fwu.h> #include <init.h> #include <env_internal.h> #include <log.h> @@ -362,8 +361,6 @@ enum env_location env_get_location(enum env_operation op, int prio) #define DFU_ALT_BUF_LEN SZ_1K -#if defined(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) && \ - !defined(CONFIG_FWU_MULTI_BANK_UPDATE) static void mtd_found_part(u32 *base, u32 *size) { struct mtd_info *part, *mtd; @@ -440,42 +437,6 @@ void configure_capsule_updates(void) update_info.dfu_string = strdup(buf); debug("Capsule DFU: %s\n", update_info.dfu_string); } -#endif - -#if defined(CONFIG_FWU_MULTI_BANK_UPDATE) - -/* Generate dfu_alt_info from partitions */ -void set_dfu_alt_info(char *interface, char *devstr) -{ - int ret; - struct mtd_info *mtd; - - /* - * It is called multiple times for every image - * per bank that's why enough to set it up once. - */ - if (env_get("dfu_alt_info")) - return; - - ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN); - memset(buf, 0, DFU_ALT_BUF_LEN); - - mtd_probe_devices(); - - mtd = get_mtd_device_nm("nor0"); - if (IS_ERR_OR_NULL(mtd)) - return; - - ret = fwu_gen_alt_info_from_mtd(buf, DFU_ALT_BUF_LEN, mtd); - if (ret < 0) { - log_err("Error: Failed to generate dfu_alt_info. (%d)\n", ret); - return; - } - log_debug("Make dfu_alt_info: '%s'\n", buf); - - env_set("dfu_alt_info", buf); -} -#endif int spi_get_env_dev(void) { diff --git a/board/xilinx/common/board.c b/board/xilinx/common/board.c index 52a2e8767d8..f45b879736e 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2014 - 2022, Xilinx, Inc. - * (C) Copyright 2022 - 2025, Advanced Micro Devices, Inc. + * (C) Copyright 2022 - 2026, Advanced Micro Devices, Inc. * * Michal Simek <[email protected]> */ @@ -14,6 +14,8 @@ #include <init.h> #include <jffs2/load_kernel.h> #include <log.h> +#include <memalign.h> +#include <mtd.h> #include <asm/io.h> #include <asm/global_data.h> #include <asm/sections.h> @@ -22,6 +24,7 @@ #endif #include <dm/uclass.h> #include <i2c.h> +#include <linux/err.h> #include <linux/sizes.h> #include <malloc.h> #include <memtop.h> @@ -65,6 +68,8 @@ struct efi_capsule_update_info update_info = { .images = fw_images, }; +#define DFU_ALT_BUF_LEN SZ_1K + #endif /* EFI_HAVE_CAPSULE_SUPPORT */ #define EEPROM_HEADER_MAGIC 0xdaaddeed @@ -846,6 +851,36 @@ int fwu_platform_hook(struct udevice *dev, struct fwu_data *data) /* Copy image type GUID */ memcpy(&fw_images[0].image_type_id, &img_entry->image_type_guid, 16); + /* + * Generate the capsule DFU string from the FWU metadata. This has to + * happen here, and not in configure_capsule_updates() called from + * board_late_init(), because the FWU data is only populated by + * fwu_boottime_checks() at EVT_POST_PREBOOT. + */ + { + ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN); + struct mtd_info *mtd; + int ret; + + memset(buf, 0, DFU_ALT_BUF_LEN); + + mtd_probe_devices(); + + mtd = get_mtd_device_nm("nor0"); + if (IS_ERR_OR_NULL(mtd)) + return -ENODEV; + + ret = fwu_gen_alt_info_from_mtd(buf, DFU_ALT_BUF_LEN, mtd); + if (ret < 0) { + log_err("Error: Failed to generate dfu_alt_info. (%d)\n", ret); + return ret; + } + log_debug("Make dfu_alt_info: '%s'\n", buf); + + update_info.dfu_string = strdup(buf); + debug("Capsule DFU: %s\n", update_info.dfu_string); + } + if (IS_ENABLED(CONFIG_EFI_ESRT)) { efi_status_t ret; diff --git a/board/xilinx/versal/board.c b/board/xilinx/versal/board.c index 0537517b1b2..e3e1085fce7 100644 --- a/board/xilinx/versal/board.c +++ b/board/xilinx/versal/board.c @@ -10,7 +10,6 @@ #include <env.h> #include <efi_loader.h> #include <fdtdec.h> -#include <fwu.h> #include <init.h> #include <env_internal.h> #include <log.h> @@ -314,8 +313,6 @@ enum env_location env_get_location(enum env_operation op, int prio) #define DFU_ALT_BUF_LEN SZ_1K -#if defined(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) && \ - !defined(CONFIG_FWU_MULTI_BANK_UPDATE) static void mtd_found_part(u32 *base, u32 *size) { struct mtd_info *part, *mtd; @@ -392,39 +389,3 @@ void configure_capsule_updates(void) update_info.dfu_string = strdup(buf); debug("Capsule DFU: %s\n", update_info.dfu_string); } -#endif - -#if defined(CONFIG_FWU_MULTI_BANK_UPDATE) - -/* Generate dfu_alt_info from partitions */ -void set_dfu_alt_info(char *interface, char *devstr) -{ - int ret; - struct mtd_info *mtd; - - /* - * It is called multiple times for every image - * per bank that's why enough to set it up once. - */ - if (env_get("dfu_alt_info")) - return; - - ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN); - memset(buf, 0, DFU_ALT_BUF_LEN); - - mtd_probe_devices(); - - mtd = get_mtd_device_nm("nor0"); - if (IS_ERR_OR_NULL(mtd)) - return; - - ret = fwu_gen_alt_info_from_mtd(buf, DFU_ALT_BUF_LEN, mtd); - if (ret < 0) { - log_err("Error: Failed to generate dfu_alt_info. (%d)\n", ret); - return; - } - log_debug("Make dfu_alt_info: '%s'\n", buf); - - env_set("dfu_alt_info", buf); -} -#endif diff --git a/configs/xilinx_mbv32_defconfig b/configs/xilinx_mbv32_defconfig index 097d6095df2..82bbba6d0f0 100644 --- a/configs/xilinx_mbv32_defconfig +++ b/configs/xilinx_mbv32_defconfig @@ -1,4 +1,7 @@ CONFIG_RISCV=y +# CONFIG_SPL_USE_ARCH_MEMCPY is not set +# CONFIG_SPL_USE_ARCH_MEMMOVE is not set +# CONFIG_SPL_USE_ARCH_MEMSET is not set CONFIG_SYS_MALLOC_LEN=0xe00000 CONFIG_NR_DRAM_BANKS=1 CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y @@ -38,6 +41,8 @@ CONFIG_SPL_SYS_MALLOC=y CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0x80000000 CONFIG_SPL_SYS_MALLOC_SIZE=0x200000 +# CONFIG_SPL_CPU is not set +CONFIG_SPL_REMAKE_ELF=y # CONFIG_CMD_MII is not set CONFIG_CMD_SNTP=y CONFIG_CMD_TIMER=y diff --git a/configs/xilinx_zynqmp_mini_defconfig b/configs/xilinx_zynqmp_mini_defconfig index 20e2ae0f003..35385d0079a 100644 --- a/configs/xilinx_zynqmp_mini_defconfig +++ b/configs/xilinx_zynqmp_mini_defconfig @@ -2,19 +2,27 @@ CONFIG_ARM=y CONFIG_SYS_CONFIG_NAME="xilinx_zynqmp_mini" CONFIG_SYS_ICACHE_OFF=y CONFIG_ARCH_ZYNQMP=y -CONFIG_TEXT_BASE=0xFFFC0000 +CONFIG_TEXT_BASE=0xFFFE0000 CONFIG_SYS_MALLOC_LEN=0x1a00 CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y CONFIG_CUSTOM_SYS_INIT_SP_ADDR=0xfffe0000 CONFIG_ENV_SIZE=0x80 CONFIG_DEFAULT_DEVICE_TREE="zynqmp-mini" +CONFIG_SPL_STACK=0xfffffffc +CONFIG_SPL_BSS_MAX_SIZE=0x80000 CONFIG_SYS_LOAD_ADDR=0x8000000 +CONFIG_SPL=y +# CONFIG_SPL_FS_FAT is not set +# CONFIG_SPL_LIBDISK_SUPPORT is not set CONFIG_XILINX_MINI=y CONFIG_SYS_MEM_RSVD_FOR_MMU=y # CONFIG_PSCI_RESET is not set CONFIG_SYS_MEMTEST_START=0x00000000 CONFIG_SYS_MEMTEST_END=0x00001000 +CONFIG_SKIP_RELOCATE=y CONFIG_REMAKE_ELF=y +CONFIG_HAS_BOARD_SIZE_LIMIT=y +CONFIG_BOARD_SIZE_LIMIT=131072 # CONFIG_LEGACY_IMAGE_FORMAT is not set # CONFIG_AUTOBOOT is not set CONFIG_SYS_CBSIZE=1024 @@ -22,6 +30,14 @@ CONFIG_SYS_PBSIZE=1049 # CONFIG_DISPLAY_CPUINFO is not set # CONFIG_BOARD_LATE_INIT is not set CONFIG_CLOCKS=y +CONFIG_SPL_MAX_SIZE=0x40000 +# CONFIG_SPL_BINMAN_SYMBOLS is not set +# CONFIG_SPL_SHARES_INIT_SP_ADDR is not set +CONFIG_SPL_HAVE_INIT_STACK=y +CONFIG_SPL_SYS_MALLOC=y +CONFIG_SPL_HAS_CUSTOM_MALLOC_START=y +CONFIG_SPL_CUSTOM_SYS_MALLOC_ADDR=0x20000000 +CONFIG_SPL_SYS_MALLOC_SIZE=0x1000000 # CONFIG_CMDLINE_EDITING is not set # CONFIG_AUTO_COMPLETE is not set # CONFIG_SYS_LONGHELP is not set @@ -50,10 +66,12 @@ CONFIG_SYS_ALT_MEMTEST=y # CONFIG_CMD_SETEXPR is not set CONFIG_CMD_CACHE=y # CONFIG_CMD_SLEEP is not set +CONFIG_SPL_OF_CONTROL=y CONFIG_OF_EMBED=y CONFIG_ENV_RELOC_GD_ENV_ADDR=y CONFIG_NO_NET=y # CONFIG_DM_DEVICE_REMOVE is not set +CONFIG_SPL_DM_SEQ_ALIAS=y # CONFIG_SIMPLE_BUS is not set # CONFIG_DM_MAILBOX is not set # CONFIG_MMC is not set diff --git a/configs/xilinx_zynqmp_mini_qspi_defconfig b/configs/xilinx_zynqmp_mini_qspi_defconfig index 03366a3b05a..9457dd0a672 100644 --- a/configs/xilinx_zynqmp_mini_qspi_defconfig +++ b/configs/xilinx_zynqmp_mini_qspi_defconfig @@ -2,7 +2,7 @@ CONFIG_ARM=y CONFIG_SYS_CONFIG_NAME="xilinx_zynqmp_mini" CONFIG_SYS_ICACHE_OFF=y CONFIG_ARCH_ZYNQMP=y -CONFIG_TEXT_BASE=0xFFFC0000 +CONFIG_TEXT_BASE=0xFFFE0000 CONFIG_SYS_MALLOC_LEN=0x1b00 CONFIG_NR_DRAM_BANKS=1 CONFIG_HAS_CUSTOM_SYS_INIT_SP_ADDR=y @@ -19,8 +19,10 @@ CONFIG_XILINX_MINI=y CONFIG_SYS_MEM_RSVD_FOR_MMU=y CONFIG_ZYNQMP_NO_DDR=y # CONFIG_PSCI_RESET is not set -# CONFIG_EXPERT is not set +CONFIG_SKIP_RELOCATE=y CONFIG_REMAKE_ELF=y +CONFIG_HAS_BOARD_SIZE_LIMIT=y +CONFIG_BOARD_SIZE_LIMIT=131072 # CONFIG_LEGACY_IMAGE_FORMAT is not set # CONFIG_AUTOBOOT is not set # CONFIG_ARCH_FIXUP_FDT_MEMORY is not set diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index 6052a31b5b4..fae66ccb3d8 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -19,10 +19,10 @@ #include <asm/ptrace.h> #include <asm/system.h> #include <linux/bitfield.h> +#include <linux/delay.h> #if defined(CONFIG_ZYNQMP_IPI) #include <mailbox.h> -#include <asm/arch/sys_proto.h> #define PMUFW_PAYLOAD_ARG_CNT 8 @@ -176,28 +176,106 @@ unsigned int zynqmp_firmware_version(void) }; #if defined(CONFIG_ARCH_VERSAL2) -int zynqmp_pm_ufs_get_txrx_cfgrdy(u32 *value) +/* + * Poll the M-PHY TX/RX config-ready status until it settles or @timeout_us + * elapses. Legacy EEMI firmware only offers the per-read status primitive, so + * the poll loop lives here rather than in the UFS driver; the timeout budget is + * owned by the caller. + */ +int zynqmp_pm_wait_mphy_tx_rx_config_ready(u32 timeout_us) { - *value = readl(PMXC_SLCR_BASE_ADDRESS + PMXC_TX_RX_CFG_RDY); - return 0; + u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + while (timeout_us--) { + ret = xilinx_pm_request(PM_IOCTL, PM_REGNODE_PMC_IOU_SLCR, + IOCTL_READ_REG, TXRX_CFGRDY_OFFSET, 0, 0, + 0, ret_payload); + if (ret) + return ret; + + if (!(ret_payload[1] & TX_RX_CFG_RDY_MASK)) + return 0; + + udelay(1); + } + + return -ETIMEDOUT; } -int zynqmp_pm_ufs_sram_csr_read(u32 *value) +int zynqmp_pm_wait_sram_init_done(u32 timeout_us) { - *value = readl(PMXC_SLCR_BASE_ADDRESS + PMXC_SRAM_CSR); - return 0; + u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + while (timeout_us--) { + ret = xilinx_pm_request(PM_IOCTL, PM_REGNODE_PMC_IOU_SLCR, + IOCTL_READ_REG, SRAM_CSR_OFFSET, 0, 0, + 0, ret_payload); + if (ret) + return ret; + + if (ret_payload[1] & SRAM_CSR_INIT_DONE_MASK) + return 0; + + udelay(1); + } + + return -ETIMEDOUT; } -int zynqmp_pm_ufs_sram_csr_write(u32 *value) +int zynqmp_pm_set_sram_bypass(void) { - writel(*value, PMXC_SLCR_BASE_ADDRESS + PMXC_SRAM_CSR); - return 0; + u32 ret_payload[PAYLOAD_ARG_CNT]; + u32 sram_csr; + int ret; + + ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_MASK_WRITE_REG); + if (ret) { + printf("%s: IOCTL_MASK_WRITE_REG is not supported : %d\n" + , __func__, ret); + return 0; + } + + ret = xilinx_pm_request(PM_IOCTL, PM_REGNODE_PMC_IOU_SLCR, + IOCTL_READ_REG, SRAM_CSR_OFFSET, 0, 0, + 0, ret_payload); + if (ret) + return ret; + + sram_csr = ret_payload[1]; + sram_csr &= ~SRAM_CSR_EXT_LD_DONE_MASK; + sram_csr |= SRAM_CSR_BYPASS_MASK; + + return xilinx_pm_request(PM_IOCTL, PM_REGNODE_PMC_IOU_SLCR, + IOCTL_MASK_WRITE_REG, SRAM_CSR_OFFSET, + GENMASK(2, 1), sram_csr, 0, NULL); } -int zynqmp_pm_ufs_cal_reg(u32 *value) +int zynqmp_pm_get_ufs_calibration_values(u32 *value) { - *value = readl(PMXC_EFUSE_CACHE_BASE_ADDRESS + PMXC_UFS_CAL_1_OFFSET); - return 0; + u32 ret_payload[PAYLOAD_ARG_CNT]; + int ret; + + if (!value) + return -EINVAL; + + ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_READ_REG); + if (ret) { + printf("%s: IOCTL_READ_REG is not supported : %d\n" + , __func__, ret); + return 0; + } + + ret = xilinx_pm_request(PM_IOCTL, PM_REGNODE_EFUSE_CACHE, + IOCTL_READ_REG, UFS_CAL_1_OFFSET, 0, 0, + 0, ret_payload); + if (ret) + return ret; + + *value = ret_payload[1]; + + return ret; } #endif /* CONFIG_ARCH_VERSAL2 */ diff --git a/drivers/spi/zynqmp_gqspi.c b/drivers/spi/zynqmp_gqspi.c index 2a095d0c58e..f572f2b3f15 100644 --- a/drivers/spi/zynqmp_gqspi.c +++ b/drivers/spi/zynqmp_gqspi.c @@ -283,16 +283,21 @@ static u32 zynqmp_qspi_genfifo_mode(u8 buswidth) } } -static void zynqmp_qspi_fill_gen_fifo(struct zynqmp_qspi_priv *priv, - u32 gqspi_fifo_reg) +static void zynqmp_qspi_write_gen_fifo(struct zynqmp_qspi_priv *priv, + u32 gqspi_fifo_reg) { struct zynqmp_qspi_regs *regs = priv->regs; - u32 config_reg, ier; - int ret = 0; log_content("%s, GFIFO_CMD: 0x%X\n", __func__, gqspi_fifo_reg); writel(gqspi_fifo_reg, ®s->genfifo); +} + +static int zynqmp_qspi_start_gen_fifo(struct zynqmp_qspi_priv *priv) +{ + struct zynqmp_qspi_regs *regs = priv->regs; + u32 config_reg, ier; + int ret = 0; config_reg = readl(®s->confr); /* Manual start if needed */ @@ -310,6 +315,15 @@ static void zynqmp_qspi_fill_gen_fifo(struct zynqmp_qspi_priv *priv, if (ret) log_warning("%s, Timeout\n", __func__); + return ret; +} + +static int zynqmp_qspi_fill_gen_fifo(struct zynqmp_qspi_priv *priv, + u32 gqspi_fifo_reg) +{ + zynqmp_qspi_write_gen_fifo(priv, gqspi_fifo_reg); + + return zynqmp_qspi_start_gen_fifo(priv); } static void zynqmp_qspi_chipselect(struct zynqmp_qspi_priv *priv, int is_on) @@ -573,7 +587,7 @@ static void zynqmp_qspi_genfifo_cmd(struct zynqmp_qspi_priv *priv) gen_fifo_cmd |= zynqmp_qspi_genfifo_mode(op->cmd.buswidth); gen_fifo_cmd |= GQSPI_GFIFO_TX; gen_fifo_cmd |= op->cmd.opcode; - zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); + zynqmp_qspi_write_gen_fifo(priv, gen_fifo_cmd); /* Send address */ for (i = 0; i < op->addr.nbytes; i++) { @@ -584,7 +598,7 @@ static void zynqmp_qspi_genfifo_cmd(struct zynqmp_qspi_priv *priv) gen_fifo_cmd |= GQSPI_GFIFO_TX; gen_fifo_cmd |= addr; - zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); + zynqmp_qspi_write_gen_fifo(priv, gen_fifo_cmd); } /* Send dummy */ @@ -596,7 +610,7 @@ static void zynqmp_qspi_genfifo_cmd(struct zynqmp_qspi_priv *priv) gen_fifo_cmd &= ~(GQSPI_GFIFO_TX | GQSPI_GFIFO_RX); gen_fifo_cmd |= GQSPI_GFIFO_DATA_XFR_MASK; gen_fifo_cmd |= dummy_cycles; - zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); + zynqmp_qspi_write_gen_fifo(priv, gen_fifo_cmd); } } @@ -644,7 +658,9 @@ static int zynqmp_qspi_genfifo_fill_tx(struct zynqmp_qspi_priv *priv) while (priv->len) { len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); - zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); + ret = zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); + if (ret) + return ret; if (gen_fifo_cmd & GQSPI_GFIFO_EXP_MASK) ret = zynqmp_qspi_fill_tx_fifo(priv, 1 << len); @@ -666,6 +682,7 @@ static int zynqmp_qspi_start_io(struct zynqmp_qspi_priv *priv, struct zynqmp_qspi_regs *regs = priv->regs; u32 last_bits; u32 *traverse = buf; + int ret; while (priv->len) { len = zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); @@ -674,7 +691,9 @@ static int zynqmp_qspi_start_io(struct zynqmp_qspi_priv *priv, priv->bytes_to_receive = (1 << len); else priv->bytes_to_receive = len; - zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); + ret = zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); + if (ret) + return ret; /* Manual start */ config_reg = readl(®s->confr); @@ -741,7 +760,9 @@ static int zynqmp_qspi_start_dma(struct zynqmp_qspi_priv *priv, while (priv->len) { zynqmp_qspi_calc_exp(priv, &gen_fifo_cmd); - zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); + ret = zynqmp_qspi_fill_gen_fifo(priv, gen_fifo_cmd); + if (ret) + return ret; } ret = wait_for_bit_le32(&dma_regs->dmaisr, @@ -886,6 +907,8 @@ static int zynqmp_qspi_exec_op(struct spi_slave *slave, ret = zynqmp_qspi_genfifo_fill_rx(priv); else if (op->data.dir == SPI_MEM_DATA_OUT) ret = zynqmp_qspi_genfifo_fill_tx(priv); + else + ret = zynqmp_qspi_start_gen_fifo(priv); zynqmp_qspi_chipselect(priv, 0); diff --git a/drivers/ufs/Kconfig b/drivers/ufs/Kconfig index c1b84bd7559..6dffdc00b32 100644 --- a/drivers/ufs/Kconfig +++ b/drivers/ufs/Kconfig @@ -10,7 +10,7 @@ config UFS config UFS_AMD_VERSAL2 bool "AMD Versal Gen 2 UFS controller platform driver" - depends on UFS && ZYNQMP_FIRMWARE + depends on UFS && ARCH_VERSAL2 help This selects the AMD specific additions to UFSHCD platform driver. UFS host on AMD needs some vendor specific configuration before accessing diff --git a/drivers/ufs/ufs-amd-versal2.c b/drivers/ufs/ufs-amd-versal2.c index 3369d32d924..48854792cbf 100644 --- a/drivers/ufs/ufs-amd-versal2.c +++ b/drivers/ufs/ufs-amd-versal2.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * Copyright (C) 2024-2025 Advanced Micro Devices, Inc. + * Copyright (C) 2024-2026 Advanced Micro Devices, Inc. */ #include <clk.h> @@ -14,14 +14,12 @@ #include <linux/time.h> #include <reset.h> +#include <asm/arch/sys_proto.h> + #include "ufs.h" #include "ufshcd-dwc.h" #include "ufshci-dwc.h" -#define SRAM_CSR_INIT_DONE_MASK BIT(0) -#define SRAM_CSR_EXT_LD_DONE_MASK BIT(1) -#define SRAM_CSR_BYPASS_MASK BIT(2) - #define MPHY_FAST_RX_AFE_CAL BIT(2) #define MPHY_FW_CALIB_CFG_VAL BIT(8) @@ -29,8 +27,6 @@ #define MPHY_RX_OVRD_VAL BIT(2) #define MPHY_RX_ACK_MASK BIT(0) -#define TX_RX_CFG_RDY_MASK GENMASK(3, 0) - #define TIMEOUT_MICROSEC 1000000L struct ufs_versal2_priv { @@ -227,7 +223,6 @@ static int ufs_versal2_setup_phy(struct ufs_hba *hba) static int ufs_versal2_phy_init(struct ufs_hba *hba) { struct ufs_versal2_priv *priv = dev_get_priv(hba->dev); - u32 reg, time_left; int ret; static const struct ufshcd_dme_attr_val rmmi_attrs[] = { { UIC_ARG_MIB(CBREFCLKCTRL2), CBREFREFCLK_GATE_OVR_EN, DME_LOCAL }, @@ -236,24 +231,15 @@ static int ufs_versal2_phy_init(struct ufs_hba *hba) { UIC_ARG_MIB(VS_MPHYCFGUPDT), 1, DME_LOCAL } }; - /* Wait for Tx/Rx config_rdy */ - time_left = TIMEOUT_MICROSEC; - do { - time_left--; - ret = zynqmp_pm_ufs_get_txrx_cfgrdy(®); - if (ret) - return ret; - - reg &= TX_RX_CFG_RDY_MASK; - if (!reg) - break; - - mdelay(5); - } while (time_left); - - if (!time_left) { + /* + * Wait for Tx/Rx config_rdy. The poll loop lives in the firmware + * backend (IO, EEMI or SCMI) so this driver stays backend-agnostic; + * the timeout budget stays here with the consumer. + */ + ret = zynqmp_pm_wait_mphy_tx_rx_config_ready(TIMEOUT_MICROSEC); + if (ret) { dev_err(hba->dev, "Tx/Rx configuration signal busy.\n"); - return -ETIMEDOUT; + return ret; } ret = ufshcd_dwc_dme_set_attrs(hba, rmmi_attrs, ARRAY_SIZE(rmmi_attrs)); @@ -267,24 +253,11 @@ static int ufs_versal2_phy_init(struct ufs_hba *hba) return ret; } - /* Wait for SRAM init done */ - time_left = TIMEOUT_MICROSEC; - do { - time_left--; - ret = zynqmp_pm_ufs_sram_csr_read(®); - if (ret) - return ret; - - reg &= SRAM_CSR_INIT_DONE_MASK; - if (reg) - break; - - mdelay(5); - } while (time_left); - - if (!time_left) { + /* Wait for SRAM init done (poll handled by the firmware backend). */ + ret = zynqmp_pm_wait_sram_init_done(TIMEOUT_MICROSEC); + if (ret) { dev_err(hba->dev, "SRAM initialization failed.\n"); - return -ETIMEDOUT; + return ret; } ret = ufs_versal2_setup_phy(hba); @@ -329,7 +302,32 @@ static int ufs_versal2_init(struct ufs_hba *hba) return PTR_ERR(priv->rstphy); } - ret = zynqmp_pm_ufs_cal_reg(&cal); + /* Assert RST_UFS Reset for UFS block in PMX_IOU */ + ret = reset_assert(priv->rstc); + if (ret) { + dev_err(hba->dev, "host reset assert failed, err = %d\n", ret); + return ret; + } + + /* Assert PHY reset */ + ret = reset_assert(priv->rstphy); + if (ret) { + dev_err(hba->dev, "phy reset assert failed, err = %d\n", ret); + return ret; + } + + ret = zynqmp_pm_set_sram_bypass(); + if (ret) { + dev_err(hba->dev, "Bypass SRAM interface failed, err = %d\n", ret); + return ret; + } + + /* De Assert RST_UFS Reset for UFS block in PMX_IOU */ + ret = reset_deassert(priv->rstc); + if (ret) + dev_err(hba->dev, "host reset deassert failed, err = %d\n", ret); + + ret = zynqmp_pm_get_ufs_calibration_values(&cal); if (ret) return ret; @@ -344,57 +342,12 @@ static int ufs_versal2_init(struct ufs_hba *hba) static int ufs_versal2_hce_enable_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { - struct ufs_versal2_priv *priv = dev_get_priv(hba->dev); - u32 sram_csr; - int ret; - - switch (status) { - case PRE_CHANGE: - /* Assert RST_UFS Reset for UFS block in PMX_IOU */ - ret = reset_assert(priv->rstc); - if (ret) { - dev_err(hba->dev, "ufshc reset assert failed, err = %d\n", ret); - return ret; - } - - /* Assert PHY reset */ - ret = reset_assert(priv->rstphy); - if (ret) { - dev_err(hba->dev, "ufsphy reset assert failed, err = %d\n", ret); - return ret; - } - - ret = zynqmp_pm_ufs_sram_csr_read(&sram_csr); - if (ret) - return ret; - - if (!priv->phy_mode) { - sram_csr &= ~SRAM_CSR_EXT_LD_DONE_MASK; - sram_csr |= SRAM_CSR_BYPASS_MASK; - } else { - dev_err(hba->dev, "Invalid phy-mode %d.\n", priv->phy_mode); - return -EINVAL; - } - - ret = zynqmp_pm_ufs_sram_csr_write(&sram_csr); - if (ret) - return ret; - - /* De Assert RST_UFS Reset for UFS block in PMX_IOU */ - ret = reset_deassert(priv->rstc); - if (ret) - dev_err(hba->dev, "ufshc reset deassert failed, err = %d\n", ret); + int ret = 0; - break; - case POST_CHANGE: + if (status == POST_CHANGE) { ret = ufs_versal2_phy_init(hba); if (ret) dev_err(hba->dev, "Phy init failed (%d)\n", ret); - - break; - default: - ret = -EINVAL; - break; } return ret; diff --git a/include/configs/amd_versal2.h b/include/configs/amd_versal2.h index a07e12bd146..00627dcd943 100644 --- a/include/configs/amd_versal2.h +++ b/include/configs/amd_versal2.h @@ -19,6 +19,15 @@ #define GICD_BASE 0xe2000000 #define GICR_BASE 0xe2060000 +/* + * The 2VM3654 part has 4 APU cores and 3 GIC ITS blocks (vs 8 cores and a + * single ITS on the base part), which moves the redistributor region up by + * the two extra ITS blocks. The right base is selected at runtime in + * lowlevel_init() based on the PMC TAP IDCODE. + */ +#define GICR_BASE_2VM3654 0xe20a0000 +#define GICR_IDCODE_2VM3654 0x04d98093 + /* Serial setup */ #define CFG_SYS_BAUDRATE_TABLE \ { 4800, 9600, 19200, 38400, 57600, 115200 } diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h index 0e545e3db1b..f753a67ac27 100644 --- a/include/zynqmp_firmware.h +++ b/include/zynqmp_firmware.h @@ -465,10 +465,6 @@ 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); u32 zynqmp_pm_get_pmc_global_pggs_reg(u32 reg_addr); @@ -535,7 +531,14 @@ extern smc_call_handler_t __data smc_call_handler; #define PM_DEV_OSPI (0x1822402aU) -#define PM_REG_PGGS3 0x30004003 +#define PM_REGNODE_PMC_IOU_SLCR 0x30000002 +#define PM_REGNODE_EFUSE_CACHE 0x30000003 +#define PM_REG_PGGS3 0x30004003 + +#define SRAM_CSR_OFFSET 0x104C +#define TXRX_CFGRDY_OFFSET 0x1054 +#define UFS_CAL_1_OFFSET 0xBE8 + #define PMC_GLOBAL_PGGS3_REG_NODE 0x1824C005 #endif /* _ZYNQMP_FIRMWARE_H_ */ |
