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
This commit is contained in:
Tom Rini
2026-06-08 08:36:57 -06:00
23 changed files with 637 additions and 23 deletions
@@ -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
@@ -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
+8 -2
View File
@@ -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 {
+3
View File
@@ -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);
+130 -1
View File
@@ -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 <michal.simek@amd.com>
*/
#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
+73
View File
@@ -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)
+41 -1
View File
@@ -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
-4
View File
@@ -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();
+13 -2
View File
@@ -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
+2
View File
@@ -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
+2
View File
@@ -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
+1
View File
@@ -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
+53 -1
View File
@@ -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)
+34
View File
@@ -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);
+11
View File
@@ -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[] = {
+14
View File
@@ -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);
+58
View File
@@ -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;
}
+4 -12
View File
@@ -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);
ret = reset_reset_bulk(priv->resets, CQSPI_RESET_DELAY_US);
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);
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;
}
}
+5
View File
@@ -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 \
+19
View File
@@ -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.
*
+49
View File
@@ -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;
+4
View File
@@ -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_ */
+107
View File
@@ -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;