diff options
| author | Tom Rini <[email protected]> | 2026-06-08 08:36:57 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2026-06-08 08:36:57 -0600 |
| commit | 5d4d6e331d3f056ecc7ab11b72098a3cf4fdb099 (patch) | |
| tree | bd545cc373e2646007a97ab90bdb5be52f481982 | |
| parent | 9e87893c24d1f21350e69bc222e6a3214c933b3b (diff) | |
| parent | 8efa173b389e5cef6eece991351442baea0264fd (diff) | |
Merge tag 'xilinx-for-v2026.10-rc1-v2' of https://source.denx.de/u-boot/custodians/u-boot-microblaze into next
AMD/Xilinx/FPGA changes for v2026.10-rc1 v2
zynqmp:
- Clean up USB gadget configuration
mbv:
- Reduce SPL size
versal:
- Add support for A/B capsule update
versal2:
- Add support for A/B capsule update
reset:
- Introduce reset_reset_bulk() generic interface
- zynqmp: Implement reset_reset_bulk() interface
spi:
- cadence: Switch to reset_reset_bulk() interface
| -rw-r--r-- | arch/arm/mach-versal/include/mach/hardware.h | 3 | ||||
| -rw-r--r-- | arch/arm/mach-versal2/include/mach/hardware.h | 3 | ||||
| -rw-r--r-- | arch/sandbox/dts/test.dts | 10 | ||||
| -rw-r--r-- | arch/sandbox/include/asm/reset.h | 3 | ||||
| -rw-r--r-- | board/amd/versal2/board.c | 131 | ||||
| -rw-r--r-- | board/xilinx/common/board.c | 73 | ||||
| -rw-r--r-- | board/xilinx/versal/board.c | 42 | ||||
| -rw-r--r-- | board/xilinx/zynqmp/zynqmp.c | 4 | ||||
| -rw-r--r-- | configs/amd_versal2_virt_defconfig | 15 | ||||
| -rw-r--r-- | configs/xilinx_mbv32_defconfig | 2 | ||||
| -rw-r--r-- | configs/xilinx_versal_virt_defconfig | 2 | ||||
| -rw-r--r-- | configs/xilinx_zynqmp_virt_defconfig | 1 | ||||
| -rw-r--r-- | drivers/firmware/firmware-zynqmp.c | 54 | ||||
| -rw-r--r-- | drivers/reset/reset-uclass.c | 34 | ||||
| -rw-r--r-- | drivers/reset/reset-zynqmp.c | 11 | ||||
| -rw-r--r-- | drivers/reset/sandbox-reset-test.c | 14 | ||||
| -rw-r--r-- | drivers/reset/sandbox-reset.c | 58 | ||||
| -rw-r--r-- | drivers/spi/cadence_qspi.c | 16 | ||||
| -rw-r--r-- | include/configs/amd_versal2.h | 5 | ||||
| -rw-r--r-- | include/reset-uclass.h | 19 | ||||
| -rw-r--r-- | include/reset.h | 49 | ||||
| -rw-r--r-- | include/zynqmp_firmware.h | 4 | ||||
| -rw-r--r-- | test/dm/reset.c | 107 |
23 files changed, 637 insertions, 23 deletions
diff --git a/arch/arm/mach-versal/include/mach/hardware.h b/arch/arm/mach-versal/include/mach/hardware.h index b5f80a8e3a9..66eca18998a 100644 --- a/arch/arm/mach-versal/include/mach/hardware.h +++ b/arch/arm/mach-versal/include/mach/hardware.h @@ -100,3 +100,6 @@ struct crp_regs { #define MIO_PIN_12 0xF1060030 #define BANK0_OUTPUT 0xF1020040 #define BANK0_TRI 0xF1060200 + +#define PMC_GLOBAL_PGGS3_REG 0xF111005C +#define PMC_GLOBAL_PGGS4_REG 0xF1110060 diff --git a/arch/arm/mach-versal2/include/mach/hardware.h b/arch/arm/mach-versal2/include/mach/hardware.h index 81a0df89357..1bebf20910a 100644 --- a/arch/arm/mach-versal2/include/mach/hardware.h +++ b/arch/arm/mach-versal2/include/mach/hardware.h @@ -105,3 +105,6 @@ enum versal2_platform { #define PMXC_UFS_CAL_1_OFFSET 0xBE8 #define PMXC_SRAM_CSR 0x4C #define PMXC_TX_RX_CFG_RDY 0x54 + +#define PMC_GLOBAL_PGGS3_REG 0xF111005C +#define PMC_GLOBAL_PGGS4_REG 0xF1110060 diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts index 0887de4333b..074e5c06ec8 100644 --- a/arch/sandbox/dts/test.dts +++ b/arch/sandbox/dts/test.dts @@ -1530,10 +1530,16 @@ #reset-cells = <1>; }; + resetc_fb: reset-ctl-fallback { + compatible = "sandbox,reset-ctl-fallback-only"; + #reset-cells = <1>; + }; + reset-ctl-test { compatible = "sandbox,reset-ctl-test"; - resets = <&resetc 100>, <&resetc 2>, <&resetc 20>, <&resetc 40>; - reset-names = "other", "test", "test2", "test3"; + resets = <&resetc 100>, <&resetc 2>, <&resetc 20>, <&resetc 40>, + <&resetc_fb 5>; + reset-names = "other", "test", "test2", "test3", "fallback"; }; rng { diff --git a/arch/sandbox/include/asm/reset.h b/arch/sandbox/include/asm/reset.h index f0709b41c09..2890e0dc09b 100644 --- a/arch/sandbox/include/asm/reset.h +++ b/arch/sandbox/include/asm/reset.h @@ -10,6 +10,7 @@ struct udevice; int sandbox_reset_query(struct udevice *dev, unsigned long id); int sandbox_reset_is_requested(struct udevice *dev, unsigned long id); +int sandbox_reset_get_count(struct udevice *dev, unsigned long id); int sandbox_reset_test_get(struct udevice *dev); int sandbox_reset_test_get_devm(struct udevice *dev); @@ -19,6 +20,8 @@ int sandbox_reset_test_assert(struct udevice *dev); int sandbox_reset_test_assert_bulk(struct udevice *dev); int sandbox_reset_test_deassert(struct udevice *dev); int sandbox_reset_test_deassert_bulk(struct udevice *dev); +int sandbox_reset_test_reset(struct udevice *dev); +int sandbox_reset_test_reset_bulk(struct udevice *dev); int sandbox_reset_test_free(struct udevice *dev); int sandbox_reset_test_release_bulk(struct udevice *dev); diff --git a/board/amd/versal2/board.c b/board/amd/versal2/board.c index 81daba1c5ef..ec28e60c410 100644 --- a/board/amd/versal2/board.c +++ b/board/amd/versal2/board.c @@ -1,17 +1,24 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2021 - 2022, Xilinx, Inc. - * Copyright (C) 2022 - 2025, Advanced Micro Devices, Inc. + * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc. * * Michal Simek <[email protected]> */ #include <cpu_func.h> +#include <dfu.h> +#include <env.h> +#include <efi_loader.h> #include <fdtdec.h> +#include <fwu.h> #include <init.h> #include <env_internal.h> #include <log.h> #include <malloc.h> +#include <memalign.h> +#include <mmc.h> +#include <mtd.h> #include <time.h> #include <asm/cache.h> #include <asm/global_data.h> @@ -26,6 +33,7 @@ #include "../../xilinx/common/board.h" #include <linux/bitfield.h> +#include <linux/sizes.h> #include <debug_uart.h> #include <generated/dt.h> #include <linux/ioport.h> @@ -348,6 +356,10 @@ int board_late_init(void) int ret; u32 multiboot; + if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) && + !IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) + configure_capsule_updates(); + if (!(gd->flags & GD_FLG_ENV_DEFAULT)) { debug("Saved variables - Skipping\n"); return 0; @@ -476,3 +488,120 @@ enum env_location env_get_location(enum env_operation op, int prio) } } #endif + +#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; + + mtd_probe_devices(); + + mtd = get_mtd_device_nm("nor0"); + if (!IS_ERR_OR_NULL(mtd)) { + list_for_each_entry(part, &mtd->partitions, node) { + debug("0x%012llx-0x%012llx : \"%s\"\n", + part->offset, part->offset + part->size, + part->name); + + if (*base >= part->offset && + *base < part->offset + part->size) { + debug("Found my partition: %d/%s\n", + part->index, part->name); + *base = part->offset; + *size = part->size; + break; + } + } + } +} + +void configure_capsule_updates(void) +{ + int bootseq = 0, len = 0; + u32 multiboot = versal2_multi_boot(); + u32 bootmode = versal2_get_bootmode(); + + ALLOC_CACHE_ALIGN_BUFFER(char, buf, DFU_ALT_BUF_LEN); + + memset(buf, 0, DFU_ALT_BUF_LEN); + + multiboot = env_get_hex("multiboot", multiboot); + + switch (bootmode) { + case EMMC_MODE: + case SD_MODE: + case SD1_LSHFT_MODE: + case SD_MODE1: + bootseq = mmc_get_env_dev(); + + len += snprintf(buf + len, DFU_ALT_BUF_LEN, "mmc %d=boot", + bootseq); + + if (multiboot) + len += snprintf(buf + len, DFU_ALT_BUF_LEN, + "%04d", multiboot); + + len += snprintf(buf + len, DFU_ALT_BUF_LEN, ".bin fat %d 1", + bootseq); + break; + case QSPI_MODE_24BIT: + case QSPI_MODE_32BIT: + case OSPI_MODE: + { + u32 base = multiboot * SZ_32K; + u32 size = 0x1500000; + u32 limit = size; + + mtd_found_part(&base, &limit); + + len += snprintf(buf + len, DFU_ALT_BUF_LEN, + "sf 0:0=boot.bin raw 0x%x 0x%x", + base, limit); + } + break; + default: + return; + } + + 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/board/xilinx/common/board.c b/board/xilinx/common/board.c index 89562ef77fc..52a2e8767d8 100644 --- a/board/xilinx/common/board.c +++ b/board/xilinx/common/board.c @@ -14,8 +14,12 @@ #include <init.h> #include <jffs2/load_kernel.h> #include <log.h> +#include <asm/io.h> #include <asm/global_data.h> #include <asm/sections.h> +#if defined(CONFIG_ARCH_VERSAL) || defined(CONFIG_ARCH_VERSAL2) +#include <asm/arch/hardware.h> +#endif #include <dm/uclass.h> #include <i2c.h> #include <linux/sizes.h> @@ -30,6 +34,8 @@ #include <rng.h> #include <slre.h> #include <soc.h> +#include <zynqmp_firmware.h> +#include <linux/bitfield.h> #include <linux/ctype.h> #include <linux/kernel.h> #include <u-boot/uuid.h> @@ -718,7 +724,74 @@ phys_addr_t board_get_usable_ram_top(phys_size_t total_size) return reg + size; } +#endif + +#if defined(CONFIG_FWU_MULTI_BANK_UPDATE) + +#if defined(CONFIG_ARCH_VERSAL) || defined(CONFIG_ARCH_VERSAL2) +/* + * The Versal and Versal Gen 2 PMC Global pggs4 register contains below + * information in each byte as: + * + * Byte[3]: Magic number + * Byte[2]: Boot counter value + * Byte[1]: Boot partition value - boot index + * Byte[0]: Rollback counter value + */ + +#define MAGIC_NUM 0x1D +#define MAGIC_MASK GENMASK(31, 24) +#define BOOTINDEX_MASK GENMASK(15, 8) + +static int plat_get_boot_index(void) +{ + u32 val; + + if (IS_ENABLED(CONFIG_ZYNQMP_FIRMWARE)) + val = zynqmp_pm_get_pmc_global_pggs_reg(PMC_GLOBAL_PGGS4_REG); + else + val = readl(PMC_GLOBAL_PGGS4_REG); + + if (FIELD_GET(MAGIC_MASK, val) != MAGIC_NUM) { + log_err("FWU requires PMC magic number 0x%x\n", MAGIC_NUM); + return -EINVAL; + } + + return FIELD_GET(BOOTINDEX_MASK, val); +} +#endif + +int fwu_plat_get_alt_num(struct udevice __always_unused *dev, + efi_guid_t *image_id, u8 *alt_num) +{ + int ret; + + ret = fwu_mtd_get_alt_num(image_id, alt_num, "nor0"); + debug("%s: return %d\n", __func__, ret); + + return ret; +} +void fwu_plat_get_bootidx(uint *boot_idx) +{ + int ret; + u32 active_idx; + + ret = fwu_get_active_index(&active_idx); + if (ret < 0) + printf("%s: failed to read active index\n", __func__); + + ret = plat_get_boot_index(); + if (ret < 0) { + *boot_idx = 0; + printf("%s: failed and setup boot index to 0\n", __func__); + } else { + *boot_idx = ret; + } + + debug("%s: boot_idx: %d, active_idx: %d\n", + __func__, *boot_idx, active_idx); +} #endif #if IS_ENABLED(CONFIG_BOARD_RNG_SEED) diff --git a/board/xilinx/versal/board.c b/board/xilinx/versal/board.c index 9371c30ea27..8666f2ceff4 100644 --- a/board/xilinx/versal/board.c +++ b/board/xilinx/versal/board.c @@ -10,6 +10,7 @@ #include <env.h> #include <efi_loader.h> #include <fdtdec.h> +#include <fwu.h> #include <init.h> #include <env_internal.h> #include <log.h> @@ -293,7 +294,8 @@ int board_late_init(void) { int ret; - if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) + if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) && + !IS_ENABLED(CONFIG_FWU_MULTI_BANK_UPDATE)) configure_capsule_updates(); if (!(gd->flags & GD_FLG_ENV_DEFAULT)) { @@ -374,6 +376,8 @@ 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; @@ -450,3 +454,39 @@ 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/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c index a1d8ae26673..eb41f84c198 100644 --- a/board/xilinx/zynqmp/zynqmp.c +++ b/board/xilinx/zynqmp/zynqmp.c @@ -541,10 +541,6 @@ int board_late_init(void) { int ret, multiboot; -#if defined(CONFIG_USB_ETHER) && !defined(CONFIG_USB_GADGET_DOWNLOAD) - usb_ether_init(); -#endif - if (IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)) configure_capsule_updates(); diff --git a/configs/amd_versal2_virt_defconfig b/configs/amd_versal2_virt_defconfig index 61e3671ea4f..00ccc81a83b 100644 --- a/configs/amd_versal2_virt_defconfig +++ b/configs/amd_versal2_virt_defconfig @@ -1,10 +1,11 @@ CONFIG_ARM=y CONFIG_COUNTER_FREQUENCY=100000000 CONFIG_POSITION_INDEPENDENT=y -CONFIG_SYS_INIT_SP_BSS_OFFSET=0x180000 +CONFIG_SYS_INIT_SP_BSS_OFFSET=0x200000 CONFIG_ARCH_VERSAL2=y CONFIG_TEXT_BASE=0x40000000 -CONFIG_SYS_MALLOC_F_LEN=0x100000 +CONFIG_SYS_MALLOC_LEN=0x4000000 +CONFIG_SYS_MALLOC_F_LEN=0x180000 CONFIG_NR_DRAM_BANKS=36 CONFIG_DEFAULT_DEVICE_TREE="amd-versal2-virt" CONFIG_OF_LIBFDT_OVERLAY=y @@ -17,6 +18,10 @@ CONFIG_PCI=y CONFIG_SYS_MEMTEST_START=0x00000000 CONFIG_SYS_MEMTEST_END=0x00001000 CONFIG_REMAKE_ELF=y +CONFIG_EFI_RUNTIME_UPDATE_CAPSULE=y +CONFIG_EFI_CAPSULE_ON_DISK=y +CONFIG_EFI_CAPSULE_ON_DISK_EARLY=y +CONFIG_EFI_CAPSULE_FIRMWARE_RAW=y CONFIG_EFI_HTTP_BOOT=y CONFIG_FIT=y CONFIG_FIT_VERBOSE=y @@ -81,7 +86,12 @@ CONFIG_SIMPLE_PM_BUS=y CONFIG_CLK_CCF=y CONFIG_CLK_SCMI=y CONFIG_CLK_VERSAL=y +CONFIG_DFU_TIMEOUT=y +CONFIG_DFU_MMC=y +CONFIG_DFU_MTD=y CONFIG_DFU_RAM=y +CONFIG_DFU_SF=y +CONFIG_SYS_DFU_DATA_BUF_SIZE=0x1800000 CONFIG_ARM_FFA_TRANSPORT=y CONFIG_SCMI_FIRMWARE=y CONFIG_FPGA_XILINX=y @@ -106,6 +116,7 @@ CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ZYNQ=y CONFIG_ZYNQ_SDHCI_MIN_FREQ=100000 CONFIG_MTD=y +CONFIG_DM_MTD=y CONFIG_DM_SPI_FLASH=y CONFIG_SPI_FLASH_GIGADEVICE=y CONFIG_SPI_FLASH_ISSI=y diff --git a/configs/xilinx_mbv32_defconfig b/configs/xilinx_mbv32_defconfig index 4ff3bd6b687..9d0111fe8e5 100644 --- a/configs/xilinx_mbv32_defconfig +++ b/configs/xilinx_mbv32_defconfig @@ -18,6 +18,8 @@ CONFIG_BOOT_SCRIPT_OFFSET=0x0 CONFIG_TARGET_XILINX_MBV=y # CONFIG_RISCV_ISA_F is not set # CONFIG_SPL_SMP is not set +# CONFIG_AVAILABLE_HARTS is not set +CONFIG_SPL_OPTIMIZE_INLINING=y CONFIG_REMAKE_ELF=y # CONFIG_EFI_LOADER is not set CONFIG_FIT=y diff --git a/configs/xilinx_versal_virt_defconfig b/configs/xilinx_versal_virt_defconfig index 7c9b1577875..a94468d9b9b 100644 --- a/configs/xilinx_versal_virt_defconfig +++ b/configs/xilinx_versal_virt_defconfig @@ -80,6 +80,7 @@ CONFIG_SIMPLE_PM_BUS=y CONFIG_CLK_VERSAL=y CONFIG_DFU_TIMEOUT=y CONFIG_DFU_MMC=y +CONFIG_DFU_MTD=y CONFIG_DFU_RAM=y CONFIG_DFU_SF=y CONFIG_SYS_DFU_DATA_BUF_SIZE=0x1800000 @@ -106,6 +107,7 @@ CONFIG_MMC_SDHCI=y CONFIG_MMC_SDHCI_ZYNQ=y CONFIG_ZYNQ_SDHCI_MIN_FREQ=100000 CONFIG_MTD=y +CONFIG_DM_MTD=y CONFIG_DM_SPI_FLASH=y CONFIG_SPI_FLASH_SOFT_RESET=y CONFIG_SPI_FLASH_SOFT_RESET_ON_BOOT=y diff --git a/configs/xilinx_zynqmp_virt_defconfig b/configs/xilinx_zynqmp_virt_defconfig index a13ae0c857b..c5472112b91 100644 --- a/configs/xilinx_zynqmp_virt_defconfig +++ b/configs/xilinx_zynqmp_virt_defconfig @@ -222,6 +222,7 @@ CONFIG_USB_GADGET=y CONFIG_USB_GADGET_MANUFACTURER="Xilinx" CONFIG_USB_GADGET_VENDOR_NUM=0x03FD CONFIG_USB_GADGET_PRODUCT_NUM=0x0300 +CONFIG_USB_GADGET_DOWNLOAD=y CONFIG_USB_ETHER=y CONFIG_USB_ETH_CDC=y CONFIG_VIDEO=y diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c index fb583580ebe..ea14ed4ef95 100644 --- a/drivers/firmware/firmware-zynqmp.c +++ b/drivers/firmware/firmware-zynqmp.c @@ -3,7 +3,7 @@ * Xilinx Zynq MPSoC Firmware driver * * Copyright (C) 2018-2019 Xilinx, Inc. - * Copyright (C) 2022 - 2025, Advanced Micro Devices, Inc. + * Copyright (C) 2022 - 2026, Advanced Micro Devices, Inc. */ #include <asm/arch/hardware.h> @@ -197,6 +197,58 @@ int zynqmp_pm_ufs_cal_reg(u32 *value) *value = readl(PMXC_EFUSE_CACHE_BASE_ADDRESS + PMXC_UFS_CAL_1_OFFSET); return 0; } +#endif /* CONFIG_ARCH_VERSAL2 */ + +#if defined(CONFIG_ARCH_VERSAL) || defined(CONFIG_ARCH_VERSAL2) +u32 zynqmp_pm_get_pmc_global_pggs_reg(u32 reg_addr) +{ + int ret; + u32 value = 0; + u32 ret_payload[PAYLOAD_ARG_CNT]; + + if (reg_addr == PMC_GLOBAL_PGGS3_REG) { + value = 0; + } else if (reg_addr == PMC_GLOBAL_PGGS4_REG) { + value = 1; + } else { + printf("%s: not supported pggs register 0x%x\n", + __func__, reg_addr); + return 0; + } + + ret = zynqmp_pm_is_function_supported(PM_IOCTL, IOCTL_READ_PGGS); + if (ret) { + 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; + } + + /* find node ID from the pggs3 offset */ + value = PM_REG_PGGS3 + value; + + ret = xilinx_pm_request(PM_IOCTL, value, + IOCTL_READ_REG, 0, 0, 0, 0, + ret_payload); + if (ret) { + printf("%s: node 0x%x get pggs register failed\n", + __func__, value); + return 0; + } + } else { + ret = xilinx_pm_request(PM_IOCTL, PMC_GLOBAL_PGGS3_REG_NODE, + IOCTL_READ_PGGS, value, 0, 0, 0, + ret_payload); + if (ret) { + printf("%s: node 0x%x get pggs register failed\n", + __func__, PMC_GLOBAL_PGGS3_REG_NODE); + return 0; + } + } + + return ret_payload[1]; +} #endif int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, u32 value) diff --git a/drivers/reset/reset-uclass.c b/drivers/reset/reset-uclass.c index fe4cebf54f1..c199e3e5da7 100644 --- a/drivers/reset/reset-uclass.c +++ b/drivers/reset/reset-uclass.c @@ -13,6 +13,7 @@ #include <reset-uclass.h> #include <dm/devres.h> #include <dm/lists.h> +#include <linux/delay.h> static inline struct reset_ops *reset_dev_ops(struct udevice *dev) { @@ -225,6 +226,39 @@ int reset_deassert_bulk(struct reset_ctl_bulk *bulk) return 0; } +int reset_reset(struct reset_ctl *reset_ctl, ulong delay_us) +{ + struct reset_ops *ops = reset_dev_ops(reset_ctl->dev); + int ret; + + debug("%s(reset_ctl=%p, delay_us=%lu)\n", __func__, reset_ctl, + delay_us); + + if (ops->rst_reset) + return ops->rst_reset(reset_ctl, delay_us); + + ret = reset_assert(reset_ctl); + if (ret < 0) + return ret; + + udelay(delay_us); + + return reset_deassert(reset_ctl); +} + +int reset_reset_bulk(struct reset_ctl_bulk *bulk, ulong delay_us) +{ + int i, ret; + + for (i = 0; i < bulk->count; i++) { + ret = reset_reset(&bulk->resets[i], delay_us); + if (ret < 0) + return ret; + } + + return 0; +} + int reset_status(struct reset_ctl *reset_ctl) { struct reset_ops *ops = reset_dev_ops(reset_ctl->dev); diff --git a/drivers/reset/reset-zynqmp.c b/drivers/reset/reset-zynqmp.c index d04e8eef3bb..2b58f3a75b4 100644 --- a/drivers/reset/reset-zynqmp.c +++ b/drivers/reset/reset-zynqmp.c @@ -45,6 +45,16 @@ static int zynqmp_reset_deassert(struct reset_ctl *rst) PM_RESET_ACTION_RELEASE); } +static int zynqmp_reset_reset(struct reset_ctl *rst, ulong delay_us) +{ + struct zynqmp_reset_priv *priv = dev_get_priv(rst->dev); + + dev_dbg(rst->dev, "%s(rst=%p) (id=%lu)\n", __func__, rst, rst->id); + + return zynqmp_pm_reset_assert(priv->reset_id + rst->id, + PM_RESET_ACTION_PULSE); +} + static int zynqmp_reset_request(struct reset_ctl *rst) { struct zynqmp_reset_priv *priv = dev_get_priv(rst->dev); @@ -74,6 +84,7 @@ const struct reset_ops zynqmp_reset_ops = { .request = zynqmp_reset_request, .rst_assert = zynqmp_reset_assert, .rst_deassert = zynqmp_reset_deassert, + .rst_reset = zynqmp_reset_reset, }; static const struct udevice_id zynqmp_reset_ids[] = { diff --git a/drivers/reset/sandbox-reset-test.c b/drivers/reset/sandbox-reset-test.c index dfacb764bc7..64c205596c5 100644 --- a/drivers/reset/sandbox-reset-test.c +++ b/drivers/reset/sandbox-reset-test.c @@ -96,6 +96,20 @@ int sandbox_reset_test_deassert_bulk(struct udevice *dev) return reset_deassert_bulk(sbrt->bulkp); } +int sandbox_reset_test_reset(struct udevice *dev) +{ + struct sandbox_reset_test *sbrt = dev_get_priv(dev); + + return reset_reset(sbrt->ctlp, 0); +} + +int sandbox_reset_test_reset_bulk(struct udevice *dev) +{ + struct sandbox_reset_test *sbrt = dev_get_priv(dev); + + return reset_reset_bulk(sbrt->bulkp, 0); +} + int sandbox_reset_test_free(struct udevice *dev) { struct sandbox_reset_test *sbrt = dev_get_priv(dev); diff --git a/drivers/reset/sandbox-reset.c b/drivers/reset/sandbox-reset.c index 1c0ea7390df..12812f0f340 100644 --- a/drivers/reset/sandbox-reset.c +++ b/drivers/reset/sandbox-reset.c @@ -9,12 +9,14 @@ #include <reset-uclass.h> #include <asm/io.h> #include <asm/reset.h> +#include <linux/delay.h> #define SANDBOX_RESET_SIGNALS 101 struct sandbox_reset_signal { bool asserted; bool requested; + int reset_count; }; struct sandbox_reset { @@ -31,6 +33,7 @@ static int sandbox_reset_request(struct reset_ctl *reset_ctl) return -EINVAL; sbr->signals[reset_ctl->id].requested = true; + sbr->signals[reset_ctl->id].reset_count = 0; return 0; } @@ -66,6 +69,21 @@ static int sandbox_reset_deassert(struct reset_ctl *reset_ctl) return 0; } +static int sandbox_reset_reset(struct reset_ctl *reset_ctl, ulong delay_us) +{ + struct sandbox_reset *sbr = dev_get_priv(reset_ctl->dev); + + debug("%s(reset_ctl=%p, delay_us=%lu)\n", __func__, reset_ctl, + delay_us); + + sbr->signals[reset_ctl->id].asserted = true; + udelay(delay_us); + sbr->signals[reset_ctl->id].asserted = false; + sbr->signals[reset_ctl->id].reset_count++; + + return 0; +} + static int sandbox_reset_bind(struct udevice *dev) { debug("%s(dev=%p)\n", __func__, dev); @@ -90,6 +108,7 @@ static const struct reset_ops sandbox_reset_reset_ops = { .rfree = sandbox_reset_free, .rst_assert = sandbox_reset_assert, .rst_deassert = sandbox_reset_deassert, + .rst_reset = sandbox_reset_reset, }; U_BOOT_DRIVER(sandbox_reset) = { @@ -102,6 +121,33 @@ U_BOOT_DRIVER(sandbox_reset) = { .ops = &sandbox_reset_reset_ops, }; +/* + * Second sandbox reset controller for tests: same assert/deassert + * behaviour as sandbox_reset, but no rst_reset so reset_reset() uses + * the core assert / udelay / deassert fallback (reset_count never bumps). + */ +static const struct udevice_id sandbox_reset_fallback_ids[] = { + { .compatible = "sandbox,reset-ctl-fallback-only" }, + { } +}; + +static const struct reset_ops sandbox_reset_fallback_reset_ops = { + .request = sandbox_reset_request, + .rfree = sandbox_reset_free, + .rst_assert = sandbox_reset_assert, + .rst_deassert = sandbox_reset_deassert, +}; + +U_BOOT_DRIVER(sandbox_reset_fallback) = { + .name = "sandbox_reset_fallback", + .id = UCLASS_RESET, + .of_match = sandbox_reset_fallback_ids, + .bind = sandbox_reset_bind, + .probe = sandbox_reset_probe, + .priv_auto = sizeof(struct sandbox_reset), + .ops = &sandbox_reset_fallback_reset_ops, +}; + int sandbox_reset_query(struct udevice *dev, unsigned long id) { struct sandbox_reset *sbr = dev_get_priv(dev); @@ -125,3 +171,15 @@ int sandbox_reset_is_requested(struct udevice *dev, unsigned long id) return sbr->signals[id].requested; } + +int sandbox_reset_get_count(struct udevice *dev, unsigned long id) +{ + struct sandbox_reset *sbr = dev_get_priv(dev); + + debug("%s(dev=%p, id=%ld)\n", __func__, dev, id); + + if (id >= SANDBOX_RESET_SIGNALS) + return -EINVAL; + + return sbr->signals[id].reset_count; +} diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c index 2a4a49c5f1c..984d4a39ded 100644 --- a/drivers/spi/cadence_qspi.c +++ b/drivers/spi/cadence_qspi.c @@ -31,6 +31,8 @@ #define CQSPI_DISABLE_STIG_MODE BIT(0) #define CQSPI_DMA_MODE BIT(1) +#define CQSPI_RESET_DELAY_US 10 + __weak int cadence_qspi_apb_dma_read(struct cadence_spi_priv *priv, const struct spi_mem_op *op) { @@ -256,19 +258,9 @@ static int cadence_spi_probe(struct udevice *bus) priv->resets = devm_reset_bulk_get_optional(bus); if (priv->resets) { - /* Assert all OSPI reset lines */ - ret = reset_assert_bulk(priv->resets); - if (ret) { - dev_err(bus, "Failed to assert OSPI reset: %d\n", ret); - return ret; - } - - udelay(10); - - /* Deassert all OSPI reset lines */ - ret = reset_deassert_bulk(priv->resets); + ret = reset_reset_bulk(priv->resets, CQSPI_RESET_DELAY_US); if (ret) { - dev_err(bus, "Failed to deassert OSPI reset: %d\n", ret); + dev_err(bus, "Failed to reset OSPI: %d\n", ret); return ret; } } diff --git a/include/configs/amd_versal2.h b/include/configs/amd_versal2.h index fccc786219f..a07e12bd146 100644 --- a/include/configs/amd_versal2.h +++ b/include/configs/amd_versal2.h @@ -23,6 +23,11 @@ #define CFG_SYS_BAUDRATE_TABLE \ { 4800, 9600, 19200, 38400, 57600, 115200 } +/* GUID for capsule updatable firmware image */ +#define XILINX_BOOT_IMAGE_GUID \ + EFI_GUID(0xed9e7fcf, 0x47b3, 0x40cd, 0xb6, 0xe3, \ + 0x56, 0x5f, 0x14, 0x67, 0x6d, 0x82) + #if defined(CONFIG_CMD_DFU) #define DFU_DEFAULT_POLL_TIMEOUT 300 #define DFU_ALT_INFO_RAM \ diff --git a/include/reset-uclass.h b/include/reset-uclass.h index 9a0696dd1e3..7af090b60b5 100644 --- a/include/reset-uclass.h +++ b/include/reset-uclass.h @@ -77,6 +77,25 @@ struct reset_ops { */ int (*rst_deassert)(struct reset_ctl *reset_ctl); /** + * rst_reset - Reset a HW module. + * + * This optional function triggers a reset pulse on the reset line. + * If not implemented, reset_reset() falls back to rst_assert(), + * udelay(@delay_us), then rst_deassert(); that delay is therefore + * observed only on the fallback path. + * + * When rst_reset is provided, @delay_us is controller-specific: the + * implementation should honour it if the hardware needs a minimum + * assertion time before release. It may ignore @delay_us when the + * pulse shape is fixed elsewhere (for example a firmware pulse). + * + * @reset_ctl: The reset signal to pulse. + * @delay_us: Minimum delay in microseconds between assert and + * deassert where applicable; see above. + * @return 0 if OK, or a negative error code. + */ + int (*rst_reset)(struct reset_ctl *reset_ctl, ulong delay_us); + /** * rst_status - Check reset signal status. * * @reset_ctl: The reset signal to check. diff --git a/include/reset.h b/include/reset.h index 036a786d2ac..58574b983f6 100644 --- a/include/reset.h +++ b/include/reset.h @@ -321,6 +321,45 @@ int reset_deassert(struct reset_ctl *reset_ctl); int reset_deassert_bulk(struct reset_ctl_bulk *bulk); /** + * reset_reset - Reset a HW module by asserting and deasserting a reset signal. + * + * This function will assert and then deassert the specified reset signal, + * thus resetting the affected HW module. This is a convenience function + * that combines reset_assert() and reset_deassert(). + * + * If the controller implements struct reset_ops.rst_reset, that callback + * is used and @delay_us is interpreted as documented there. Otherwise the + * core performs reset_assert(), udelay(@delay_us), then reset_deassert(). + * + * @reset_ctl: A reset control struct that was previously successfully + * requested by reset_get_by_*(). + * @delay_us: Delay in microseconds between assert and deassert on the + * fallback path; meaning is driver-specific when rst_reset is used. + * Use 0 for no delay on the fallback path. + * Return: 0 if OK, or a negative error code. + */ +int reset_reset(struct reset_ctl *reset_ctl, ulong delay_us); + +/** + * reset_reset_bulk - Reset all HW modules in a reset control bulk struct. + * + * This calls reset_reset() on each entry in order. Each line therefore + * completes its own assert/delay/deassert (or controller rst_reset) before + * the next entry starts. That matches Linux reset_control_bulk_reset(). + * + * When several lines must stay asserted together for @delay_us (typical + * multi-reset controllers), use reset_assert_bulk(), udelay(@delay_us), + * and reset_deassert_bulk() instead. + * + * @bulk: A reset control bulk struct that was previously successfully + * requested by reset_get_bulk(). + * @delay_us: Delay in microseconds passed to each reset_reset(); see + * reset_reset() and struct reset_ops.rst_reset. + * Return: 0 if OK, or a negative error code. + */ +int reset_reset_bulk(struct reset_ctl_bulk *bulk, ulong delay_us); + +/** * rst_status - Check reset signal status. * * @reset_ctl: The reset signal to check. @@ -443,6 +482,16 @@ static inline int reset_deassert_bulk(struct reset_ctl_bulk *bulk) return 0; } +static inline int reset_reset(struct reset_ctl *reset_ctl, ulong delay_us) +{ + return -ENOSYS; +} + +static inline int reset_reset_bulk(struct reset_ctl_bulk *bulk, ulong delay_us) +{ + return -ENOSYS; +} + static inline int reset_status(struct reset_ctl *reset_ctl) { return -ENOTSUPP; diff --git a/include/zynqmp_firmware.h b/include/zynqmp_firmware.h index f5e72625e53..0e545e3db1b 100644 --- a/include/zynqmp_firmware.h +++ b/include/zynqmp_firmware.h @@ -470,6 +470,7 @@ 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); /* Type of Config Object */ #define PM_CONFIG_OBJECT_TYPE_BASE 0x1U @@ -534,4 +535,7 @@ extern smc_call_handler_t __data smc_call_handler; #define PM_DEV_OSPI (0x1822402aU) +#define PM_REG_PGGS3 0x30004003 +#define PMC_GLOBAL_PGGS3_REG_NODE 0x1824C005 + #endif /* _ZYNQMP_FIRMWARE_H_ */ diff --git a/test/dm/reset.c b/test/dm/reset.c index dceb6a1dad3..91fa7ff723b 100644 --- a/test/dm/reset.c +++ b/test/dm/reset.c @@ -19,6 +19,9 @@ /* This is the other reset phandle specifier handled by bulk */ #define OTHER_RESET_ID 2 +/* Line on reset-ctl-fallback (sandbox,reset-ctl-fallback-only); see test.dts */ +#define FALLBACK_RESET_ID 5 + /* Base test of the reset uclass */ static int dm_test_reset_base(struct unit_test_state *uts) { @@ -120,6 +123,110 @@ static int dm_test_reset_devm(struct unit_test_state *uts) } DM_TEST(dm_test_reset_devm, UTF_SCAN_FDT); +static int dm_test_reset_reset(struct unit_test_state *uts) +{ + struct udevice *dev_reset; + struct udevice *dev_test; + + ut_assertok(uclass_get_device_by_name(UCLASS_RESET, "reset-ctl", + &dev_reset)); + ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "reset-ctl-test", + &dev_test)); + ut_assertok(sandbox_reset_test_get(dev_test)); + + /* Verify reset_count starts at 0 */ + ut_asserteq(0, sandbox_reset_get_count(dev_reset, TEST_RESET_ID)); + + ut_assertok(sandbox_reset_test_assert(dev_test)); + ut_asserteq(1, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + + ut_assertok(sandbox_reset_test_reset(dev_test)); + + /* Verify reset was pulsed (count incremented) */ + ut_asserteq(1, sandbox_reset_get_count(dev_reset, TEST_RESET_ID)); + ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + + ut_assertok(sandbox_reset_test_free(dev_test)); + + return 0; +} +DM_TEST(dm_test_reset_reset, UTF_SCAN_FDT); + +/* + * reset_reset() fallback path: controller has no rst_reset op, so the + * core does assert -> udelay -> deassert. rst_reset-only accounting + * (reset_count) stays zero. Leave the line asserted before reset_reset() + * so we verify the fallback actually pulses it back to deasserted. + */ +static int dm_test_reset_reset_fallback_path(struct unit_test_state *uts) +{ + struct udevice *dev_reset_fb; + struct udevice *dev_test; + struct reset_ctl ctl; + + ut_assertok(uclass_get_device_by_name(UCLASS_RESET, "reset-ctl-fallback", + &dev_reset_fb)); + ut_asserteq(0, sandbox_reset_query(dev_reset_fb, FALLBACK_RESET_ID)); + ut_asserteq(0, sandbox_reset_get_count(dev_reset_fb, FALLBACK_RESET_ID)); + + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "reset-ctl-test", + &dev_test)); + ut_assertok(reset_get_by_name(dev_test, "fallback", &ctl)); + ut_asserteq_ptr(ctl.dev, dev_reset_fb); + ut_asserteq(FALLBACK_RESET_ID, ctl.id); + + ut_assertok(reset_assert(&ctl)); + ut_asserteq(1, sandbox_reset_query(dev_reset_fb, FALLBACK_RESET_ID)); + ut_asserteq(0, sandbox_reset_get_count(dev_reset_fb, FALLBACK_RESET_ID)); + + ut_assertok(reset_reset(&ctl, 1)); + ut_asserteq(0, sandbox_reset_get_count(dev_reset_fb, FALLBACK_RESET_ID)); + ut_asserteq(0, sandbox_reset_query(dev_reset_fb, FALLBACK_RESET_ID)); + + ut_assertok(reset_free(&ctl)); + + return 0; +} +DM_TEST(dm_test_reset_reset_fallback_path, UTF_SCAN_FDT); + +static int dm_test_reset_reset_bulk(struct unit_test_state *uts) +{ + struct udevice *dev_reset; + struct udevice *dev_test; + + ut_assertok(uclass_get_device_by_name(UCLASS_RESET, "reset-ctl", + &dev_reset)); + ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + ut_asserteq(0, sandbox_reset_query(dev_reset, OTHER_RESET_ID)); + + ut_assertok(uclass_get_device_by_name(UCLASS_MISC, "reset-ctl-test", + &dev_test)); + ut_assertok(sandbox_reset_test_get_bulk(dev_test)); + + /* Verify reset_count starts at 0 */ + ut_asserteq(0, sandbox_reset_get_count(dev_reset, TEST_RESET_ID)); + ut_asserteq(0, sandbox_reset_get_count(dev_reset, OTHER_RESET_ID)); + + ut_assertok(sandbox_reset_test_assert_bulk(dev_test)); + ut_asserteq(1, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + ut_asserteq(1, sandbox_reset_query(dev_reset, OTHER_RESET_ID)); + + ut_assertok(sandbox_reset_test_reset_bulk(dev_test)); + + /* Verify resets were pulsed (counts incremented) */ + ut_asserteq(1, sandbox_reset_get_count(dev_reset, TEST_RESET_ID)); + ut_asserteq(1, sandbox_reset_get_count(dev_reset, OTHER_RESET_ID)); + ut_asserteq(0, sandbox_reset_query(dev_reset, TEST_RESET_ID)); + ut_asserteq(0, sandbox_reset_query(dev_reset, OTHER_RESET_ID)); + + ut_assertok(sandbox_reset_test_release_bulk(dev_test)); + + return 0; +} +DM_TEST(dm_test_reset_reset_bulk, UTF_SCAN_FDT); + static int dm_test_reset_bulk(struct unit_test_state *uts) { struct udevice *dev_reset; |
