From f2390069d45b3490cfd87de6d6bac6e646796b6b Mon Sep 17 00:00:00 2001 From: Padmarao Begari Date: Thu, 14 May 2026 15:52:19 +0530 Subject: firmware: zynqmp: Add PMC PGGS register read API Add zynqmp_pm_get_pmc_global_pggs_reg() to read PMC Global PGGS3 and PGGS4 registers via firmware IOCTL. Supports IOCTL_READ_PGGS as the preferred path and falls back to IOCTL_READ_REG for older PLM firmware versions that do not support IOCTL_READ_PGGS. Signed-off-by: Padmarao Begari Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/20260514102601.1759779-3-padmarao.begari@amd.com --- include/zynqmp_firmware.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include') 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_ */ -- cgit v1.3.1 From 818c06faa119f3101c9df24c0ef1b815c2abd929 Mon Sep 17 00:00:00 2001 From: Padmarao Begari Date: Thu, 14 May 2026 15:52:21 +0530 Subject: board: amd: Add capsule and FWU support Add configure_capsule_updates() supporting MMC, SD and QSPI/OSPI boot modes for DFU string generation. Add set_dfu_alt_info() for FWU multi-bank mode to generate DFU alt info from NOR flash MTD partitions. Add XILINX_BOOT_IMAGE_GUID for the capsule updatable firmware image. Signed-off-by: Padmarao Begari Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/20260514102601.1759779-5-padmarao.begari@amd.com --- board/amd/versal2/board.c | 131 +++++++++++++++++++++++++++++++++++++++++- include/configs/amd_versal2.h | 5 ++ 2 files changed, 135 insertions(+), 1 deletion(-) (limited to 'include') 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 */ #include +#include +#include +#include #include +#include #include #include #include #include +#include +#include +#include #include #include #include @@ -26,6 +33,7 @@ #include "../../xilinx/common/board.h" #include +#include #include #include #include @@ -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/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 \ -- cgit v1.3.1 From 19f7def2646f2ec2926e8a0fcff50d4b754eec92 Mon Sep 17 00:00:00 2001 From: Michal Simek Date: Mon, 25 May 2026 13:45:42 +0200 Subject: reset: Add reset_reset() and reset_reset_bulk() API Add reset_reset() and reset_reset_bulk() functions to the reset controller API. These functions assert and then deassert reset signals in a single call, providing a convenient way to pulse/toggle a reset line. This mimics the Linux kernel's reset_control_reset() and reset_control_bulk_reset() APIs. The new functions are useful for drivers that need to cycle a reset line during initialization or error recovery but with also passing delay parameter. If a driver implements the rst_reset op, it will be called directly with the delay parameter. Otherwise, the reset core performs reset_assert(), optional udelay(), and reset_deassert() as fallback. Reviewed-by: Simon Glass Signed-off-by: Michal Simek Link: https://lore.kernel.org/r/55ddd313c9e7b2d4dc79ab36bdd0040f871610f6.1779709539.git.michal.simek@amd.com --- drivers/reset/reset-uclass.c | 34 ++++++++++++++++++++++++++++++ include/reset-uclass.h | 19 +++++++++++++++++ include/reset.h | 49 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+) (limited to 'include') 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 #include #include +#include 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/include/reset-uclass.h b/include/reset-uclass.h index 9a0696dd1e3..7af090b60b5 100644 --- a/include/reset-uclass.h +++ b/include/reset-uclass.h @@ -76,6 +76,25 @@ struct reset_ops { * @return 0 if OK, or a negative error code. */ 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. * diff --git a/include/reset.h b/include/reset.h index 036a786d2ac..58574b983f6 100644 --- a/include/reset.h +++ b/include/reset.h @@ -320,6 +320,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. * @@ -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; -- cgit v1.3.1