Merge changes from topic "bk/errata_speed" into integration
* changes:
refactor(cpus): declare runtime errata correctly
perf(cpus): make reset errata do fewer branches
perf(cpus): inline the init_cpu_data_ptr function
perf(cpus): inline the reset function
perf(cpus): inline the cpu_get_rev_var call
perf(cpus): inline cpu_rev_var checks
refactor(cpus): register DSU errata with the errata framework's wrappers
refactor(cpus): convert checker functions to standard helpers
refactor(cpus): convert the Cortex-A65 to use the errata framework
fix(cpus): declare reset errata correctly
diff --git a/drivers/arm/gic/v3/gic600_multichip.c b/drivers/arm/gic/v3/gic600_multichip.c
index 5e44aa9..6e9567e 100644
--- a/drivers/arm/gic/v3/gic600_multichip.c
+++ b/drivers/arm/gic/v3/gic600_multichip.c
@@ -322,12 +322,40 @@
}
/*******************************************************************************
+ * Initialize GIC-600 and GIC-700 Multichip operation in LCA mode by setting up
+ * the routing table first.
+ ******************************************************************************/
+static void gic600_multichip_lca_init(
+ struct gic600_multichip_data *multichip_data)
+{
+ unsigned int i, j;
+ unsigned int rt_owner = multichip_data->rt_owner;
+
+ for (i = 0; i < multichip_data->chip_count; i++) {
+ for (j = 0; j < multichip_data->chip_count; j++) {
+ INFO("RT(LCA): CHIP%u -> CHIP%u 0x%lx\n", i, j,
+ multichip_data->chip_addrs[i][j]);
+ set_gicd_chipr_n(multichip_data->base_addrs[i], j,
+ multichip_data->chip_addrs[i][j],
+ multichip_data->spi_ids[j].spi_id_min,
+ multichip_data->spi_ids[j].spi_id_max);
+ }
+ }
+
+ /* Initialize the GICD which is marked as routing table owner last */
+ set_gicd_dchipr_rt_owner(multichip_data->base_addrs[rt_owner],
+ rt_owner);
+}
+
+/*******************************************************************************
* Initialize GIC-600 and GIC-700 Multichip operation.
******************************************************************************/
void gic600_multichip_init(struct gic600_multichip_data *multichip_data)
{
unsigned int i;
- uint32_t gicd_iidr_val = gicd_read_iidr(multichip_data->rt_owner_base);
+ unsigned int rt_owner = multichip_data->rt_owner;
+ uint32_t gicd_iidr_val =
+ gicd_read_iidr(multichip_data->base_addrs[rt_owner]);
if ((gicd_iidr_val & IIDR_MODEL_MASK) == IIDR_MODEL_ARM_GIC_600) {
gic600_multichip_validate_data(multichip_data);
@@ -341,16 +369,16 @@
* Ensure that G0/G1S/G1NS interrupts are disabled. This also ensures
* that GIC-600 Multichip configuration is done first.
*/
- if ((gicd_read_ctlr(multichip_data->rt_owner_base) &
- (CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT |
- CTLR_ENABLE_G1NS_BIT | GICD_CTLR_RWP_BIT)) != 0) {
+ if ((gicd_read_ctlr(multichip_data->base_addrs[rt_owner]) &
+ (CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT |
+ CTLR_ENABLE_G1NS_BIT | GICD_CTLR_RWP_BIT)) != 0) {
ERROR("GICD_CTLR group interrupts are either enabled or have "
"pending writes.\n");
panic();
}
/* Ensure that the routing table owner is in disconnected state */
- if (((read_gicd_chipsr(multichip_data->rt_owner_base) &
+ if (((read_gicd_chipsr(multichip_data->base_addrs[rt_owner]) &
GICD_CHIPSR_RTS_MASK) >> GICD_CHIPSR_RTS_SHIFT) !=
GICD_CHIPSR_RTS_STATE_DISCONNECTED) {
ERROR("GIC-600 routing table owner is not in disconnected "
@@ -358,25 +386,34 @@
panic();
}
- /* Initialize the GICD which is marked as routing table owner first */
- set_gicd_dchipr_rt_owner(multichip_data->rt_owner_base,
- multichip_data->rt_owner);
+ /* If LCA is not enabled */
+ if ((read_gicd_cfgid(multichip_data->base_addrs[rt_owner]) &
+ GICD_CFGID_LCA_BIT) == 0) {
+ /*
+ * Initialize the GICD which is marked as routing table
+ * owner first.
+ */
+ set_gicd_dchipr_rt_owner(multichip_data->base_addrs[rt_owner],
+ rt_owner);
- set_gicd_chipr_n(multichip_data->rt_owner_base, multichip_data->rt_owner,
- multichip_data->chip_addrs[multichip_data->rt_owner],
- multichip_data->
- spi_ids[multichip_data->rt_owner].spi_id_min,
- multichip_data->
- spi_ids[multichip_data->rt_owner].spi_id_max);
+ set_gicd_chipr_n(multichip_data->base_addrs[rt_owner], rt_owner,
+ multichip_data->chip_addrs[rt_owner][rt_owner],
+ multichip_data->spi_ids[rt_owner].spi_id_min,
+ multichip_data->spi_ids[rt_owner].spi_id_max);
- for (i = 0; i < multichip_data->chip_count; i++) {
- if (i == multichip_data->rt_owner)
- continue;
-
- set_gicd_chipr_n(multichip_data->rt_owner_base, i,
- multichip_data->chip_addrs[i],
+ for (i = 0; i < multichip_data->chip_count; i++) {
+ if (i == rt_owner)
+ continue;
+ set_gicd_chipr_n(
+ multichip_data->base_addrs[rt_owner], i,
+ multichip_data->chip_addrs[rt_owner][i],
multichip_data->spi_ids[i].spi_id_min,
multichip_data->spi_ids[i].spi_id_max);
+ }
+ } else {
+ /* If LCA is enabled */
+ INFO("GIC Local chip addressing is enabled\n");
+ gic600_multichip_lca_init(multichip_data);
}
plat_gic_multichip_data = multichip_data;
diff --git a/drivers/arm/gic/v3/gic600_multichip_private.h b/drivers/arm/gic/v3/gic600_multichip_private.h
index fd1cb57..33030b3 100644
--- a/drivers/arm/gic/v3/gic600_multichip_private.h
+++ b/drivers/arm/gic/v3/gic600_multichip_private.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019-2023, ARM Limited. All rights reserved.
+ * Copyright (c) 2019-2024, ARM Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -15,12 +15,14 @@
#define GICD_CHIPSR U(0xC000)
#define GICD_DCHIPR U(0xC004)
#define GICD_CHIPR U(0xC008)
+#define GICD_CFGID U(0xF000)
/* GIC600 GICD multichip related masks */
#define GICD_CHIPRx_PUP_BIT BIT_64(1)
#define GICD_CHIPRx_SOCKET_STATE BIT_64(0)
#define GICD_DCHIPR_PUP_BIT BIT_32(0)
#define GICD_CHIPSR_RTS_MASK (BIT_32(4) | BIT_32(5))
+#define GICD_CFGID_LCA_BIT BIT_64(21)
/* GIC600 GICD multichip related shifts */
#define GICD_CHIPRx_ADDR_SHIFT 16
@@ -98,6 +100,11 @@
return mmio_read_32(base + GICD_CHIPSR);
}
+static inline uint64_t read_gicd_cfgid(uintptr_t base)
+{
+ return mmio_read_64(base + GICD_CFGID);
+}
+
static inline void write_gicd_dchipr(uintptr_t base, uint32_t val)
{
mmio_write_32(base + GICD_DCHIPR, val);
diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h
index fdf5a21..b1d1f09 100644
--- a/include/arch/aarch64/arch.h
+++ b/include/arch/aarch64/arch.h
@@ -1530,6 +1530,11 @@
#define SCTLR2_EL1 S3_0_C1_C0_3
/*******************************************************************************
+ * FEAT_BRBE - Branch Record Buffer Extension Registers
+ ******************************************************************************/
+#define BRBCR_EL2 S2_4_C9_C0_0
+
+/*******************************************************************************
* FEAT_LS64_ACCDATA - LoadStore64B with status data
******************************************************************************/
#define ACCDATA_EL1 S3_0_C13_C0_5
diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h
index 4b08337..abe379d 100644
--- a/include/arch/aarch64/arch_helpers.h
+++ b/include/arch/aarch64/arch_helpers.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2025, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -716,6 +716,9 @@
DEFINE_RENAME_SYSREG_RW_FUNCS(cpuppmcr_el3, CPUPPMCR_EL3)
DEFINE_RENAME_SYSREG_RW_FUNCS(cpumpmmcr_el3, CPUMPMMCR_EL3)
+/* Armv9.1 FEAT_BRBE Registers */
+DEFINE_RENAME_SYSREG_RW_FUNCS(brbcr_el2, BRBCR_EL2)
+
/* Armv9.2 RME Registers */
DEFINE_RENAME_SYSREG_RW_FUNCS(gptbr_el3, GPTBR_EL3)
DEFINE_RENAME_SYSREG_RW_FUNCS(gpccr_el3, GPCCR_EL3)
diff --git a/include/drivers/arm/gic600_multichip.h b/include/drivers/arm/gic600_multichip.h
index 978d735..d0f9027 100644
--- a/include/drivers/arm/gic600_multichip.h
+++ b/include/drivers/arm/gic600_multichip.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, ARM Limited. All rights reserved.
+ * Copyright (c) 2019-2024, ARM Limited. All rights reserved.
* Copyright (c) 2023, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
@@ -49,10 +49,10 @@
* value of {0, 0, 0} should be passed.
******************************************************************************/
struct gic600_multichip_data {
- uintptr_t rt_owner_base;
+ uintptr_t base_addrs[GIC600_MAX_MULTICHIP];
unsigned int rt_owner;
unsigned int chip_count;
- uint64_t chip_addrs[GIC600_MAX_MULTICHIP];
+ uint64_t chip_addrs[GIC600_MAX_MULTICHIP][GIC600_MAX_MULTICHIP];
multichip_spi_ids_desc_t spi_ids[GIC600_MAX_MULTICHIP];
};
diff --git a/include/lib/el3_runtime/context_el2.h b/include/lib/el3_runtime/context_el2.h
index f35a091..672f533 100644
--- a/include/lib/el3_runtime/context_el2.h
+++ b/include/lib/el3_runtime/context_el2.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2025, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -142,6 +142,10 @@
uint64_t sctlr2_el2;
} el2_sctlr2_regs_t;
+typedef struct el2_brbe_regs {
+ uint64_t brbcr_el2;
+} el2_brbe_regs_t;
+
typedef struct el2_sysregs {
el2_common_regs_t common;
@@ -214,6 +218,10 @@
el2_sctlr2_regs_t sctlr2;
#endif
+#if ENABLE_BRBE_FOR_NS
+ el2_brbe_regs_t brbe;
+#endif
+
} el2_sysregs_t;
/*
@@ -384,6 +392,15 @@
#define write_el2_ctx_sctlr2(ctx, reg, val)
#endif /* ENABLE_FEAT_SCTLR2 */
+#if ENABLE_BRBE_FOR_NS
+#define read_el2_ctx_brbe(ctx, reg) (((ctx)->brbe).reg)
+#define write_el2_ctx_brbe(ctx, reg, val) ((((ctx)->brbe).reg) \
+ = (uint64_t) (val))
+#else
+#define read_el2_ctx_brbe(ctx, reg) ULL(0)
+#define write_el2_ctx_brbe(ctx, reg, val)
+#endif /* ENABLE_BRBE_FOR_NS */
+
/******************************************************************************/
#endif /* __ASSEMBLER__ */
diff --git a/lib/el3_runtime/aarch64/context.S b/lib/el3_runtime/aarch64/context.S
index fed24f0..6415cb3 100644
--- a/lib/el3_runtime/aarch64/context.S
+++ b/lib/el3_runtime/aarch64/context.S
@@ -75,6 +75,9 @@
*/
#if CTX_INCLUDE_FPREGS
func fpregs_context_save
+ /* Save x0 and pass its original value to fpregs_state_save */
+ mov x1, x0
+
stp q0, q1, [x0], #32
stp q2, q3, [x0], #32
stp q4, q5, [x0], #32
@@ -92,7 +95,7 @@
stp q28, q29, [x0], #32
stp q30, q31, [x0], #32
- fpregs_state_save x0, x9
+ fpregs_state_save x1, x9
ret
endfunc fpregs_context_save
@@ -112,6 +115,9 @@
* ------------------------------------------------------------------
*/
func fpregs_context_restore
+ /* Save x0 and pass its original value to fpregs_state_restore */
+ mov x1, x0
+
ldp q0, q1, [x0], #32
ldp q2, q3, [x0], #32
ldp q4, q5, [x0], #32
@@ -129,7 +135,7 @@
ldp q28, q29, [x0], #32
ldp q30, q31, [x0], #32
- fpregs_state_restore x0, x9
+ fpregs_state_restore x1, x9
ret
endfunc fpregs_context_restore
diff --git a/lib/el3_runtime/aarch64/context_mgmt.c b/lib/el3_runtime/aarch64/context_mgmt.c
index 2e6bce0..dfd14b6 100644
--- a/lib/el3_runtime/aarch64/context_mgmt.c
+++ b/lib/el3_runtime/aarch64/context_mgmt.c
@@ -200,6 +200,9 @@
debugv8p9_extended_bp_wp_enable(ctx);
}
+ if (is_feat_brbe_supported()) {
+ brbe_enable(ctx);
+ }
}
#endif /* ENABLE_RME */
@@ -1521,6 +1524,10 @@
write_el2_ctx_sxpoe(el2_sysregs_ctx, por_el2, read_por_el2());
}
+ if (is_feat_brbe_supported()) {
+ write_el2_ctx_brbe(el2_sysregs_ctx, brbcr_el2, read_brbcr_el2());
+ }
+
if (is_feat_s2pie_supported()) {
write_el2_ctx_s2pie(el2_sysregs_ctx, s2pir_el2, read_s2pir_el2());
}
@@ -1624,6 +1631,10 @@
if (is_feat_sctlr2_supported()) {
write_sctlr2_el2(read_el2_ctx_sctlr2(el2_sysregs_ctx, sctlr2_el2));
}
+
+ if (is_feat_brbe_supported()) {
+ write_brbcr_el2(read_el2_ctx_brbe(el2_sysregs_ctx, brbcr_el2));
+ }
}
#endif /* (CTX_INCLUDE_EL2_REGS && IMAGE_BL31) */
diff --git a/plat/amd/versal2/include/plat_pm_common.h b/plat/amd/versal2/include/plat_pm_common.h
index 5e68472..c325d74 100644
--- a/plat/amd/versal2/include/plat_pm_common.h
+++ b/plat/amd/versal2/include/plat_pm_common.h
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -22,4 +22,17 @@
#define NON_SECURE_FLAG 1U
#define SECURE_FLAG 0U
+/* Processor core device IDs */
+#define PM_DEV_CLUSTER0_ACPU_0 (0x1810C0AFU)
+#define PM_DEV_CLUSTER0_ACPU_1 (0x1810C0B0U)
+
+#define PM_DEV_CLUSTER1_ACPU_0 (0x1810C0B3U)
+#define PM_DEV_CLUSTER1_ACPU_1 (0x1810C0B4U)
+
+#define PM_DEV_CLUSTER2_ACPU_0 (0x1810C0B7U)
+#define PM_DEV_CLUSTER2_ACPU_1 (0x1810C0B8U)
+
+#define PM_DEV_CLUSTER3_ACPU_0 (0x1810C0BBU)
+#define PM_DEV_CLUSTER3_ACPU_1 (0x1810C0BCU)
+
#endif /* PLAT_PM_COMMON_H */
diff --git a/plat/amd/versal2/include/plat_private.h b/plat/amd/versal2/include/plat_private.h
index 4be2061..98f7e08 100644
--- a/plat/amd/versal2/include/plat_private.h
+++ b/plat/amd/versal2/include/plat_private.h
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -45,7 +45,7 @@
void board_detection(void);
const char *board_name_decode(void);
uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
- uint64_t x4, void *cookie, void *handle, uint64_t flags);
+ uint64_t x4, const void *cookie, void *handle, uint64_t flags);
int32_t sip_svc_setup_init(void);
/*
* Register handler to specific GIC entrance
diff --git a/plat/amd/versal2/include/platform_def.h b/plat/amd/versal2/include/platform_def.h
index 8f694f7..2b65363 100644
--- a/plat/amd/versal2/include/platform_def.h
+++ b/plat/amd/versal2/include/platform_def.h
@@ -11,6 +11,7 @@
#include <arch.h>
#include "def.h"
+#include <plat_common.h>
/*******************************************************************************
* Generic platform constants
@@ -122,6 +123,8 @@
#define PLAT_GICD_BASE_VALUE U(0xE2000000)
#define PLAT_GICR_BASE_VALUE U(0xE2060000)
+#define PLAT_ARM_GICR_BASE PLAT_GICR_BASE_VALUE
+#define PLAT_ARM_GICD_BASE PLAT_GICD_BASE_VALUE
/*
* Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
@@ -138,6 +141,8 @@
#define PLAT_G0_IRQ_PROPS(grp) \
INTR_PROP_DESC(PLAT_VERSAL_IPI_IRQ, GIC_HIGHEST_SEC_PRIORITY, grp, \
GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(CPU_PWR_DOWN_REQ_INTR, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE)
#define IRQ_MAX 200U
diff --git a/plat/amd/versal2/plat_psci.c b/plat/amd/versal2/plat_psci.c
index 55842cc..d53d751 100644
--- a/plat/amd/versal2/plat_psci.c
+++ b/plat/amd/versal2/plat_psci.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2020, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -200,7 +200,7 @@
}
static uint64_t no_pm_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
- uint64_t x4, void *cookie, void *handle, uint64_t flags)
+ uint64_t x4, const void *cookie, void *handle, uint64_t flags)
{
int32_t ret;
uint32_t arg[4], api_id;
@@ -240,7 +240,7 @@
}
uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
- void *cookie, void *handle, uint64_t flags)
+ const void *cookie, void *handle, uint64_t flags)
{
return no_pm_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
}
diff --git a/plat/amd/versal2/plat_psci_pm.c b/plat/amd/versal2/plat_psci_pm.c
new file mode 100644
index 0000000..50614d5
--- /dev/null
+++ b/plat/amd/versal2/plat_psci_pm.c
@@ -0,0 +1,340 @@
+/*
+ * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <plat_arm.h>
+
+#include "def.h"
+#include <ipi.h>
+#include <plat_private.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include <pm_common.h>
+#include "pm_defs.h"
+#include "pm_svc_main.h"
+
+static uintptr_t sec_entry;
+
+static int32_t versal2_pwr_domain_on(u_register_t mpidr)
+{
+ int32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
+ int32_t ret = (int32_t) PSCI_E_INTERN_FAIL;
+ enum pm_ret_status pm_ret;
+ const struct pm_proc *proc;
+
+ if (cpu_id != -1) {
+ proc = pm_get_proc((uint32_t)cpu_id);
+ if (proc != NULL) {
+ pm_ret = pm_req_wakeup(proc->node_id,
+ (uint32_t)
+ ((sec_entry & 0xFFFFFFFFU) | 0x1U),
+ sec_entry >> 32, 0, 0);
+
+ if (pm_ret == PM_RET_SUCCESS) {
+ /* Clear power down request */
+ pm_client_wakeup(proc);
+ ret = (int32_t) PSCI_E_SUCCESS;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * versal2_pwr_domain_off() - Turn off core.
+ * @target_state: Targeted state.
+ */
+static void versal2_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ const struct pm_proc *proc;
+ uint32_t cpu_id = plat_my_core_pos();
+ enum pm_ret_status pm_ret;
+ size_t i;
+
+ proc = pm_get_proc(cpu_id);
+ if (proc == NULL) {
+ ERROR("Failed to get proc %d\n", cpu_id);
+ goto err;
+ }
+
+ for (i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+ }
+
+ plat_gic_cpuif_disable();
+ /*
+ * Send request to PMC to power down the appropriate APU CPU
+ * core.
+ * According to PSCI specification, CPU_off function does not
+ * have resume address and CPU core can only be woken up
+ * invoking CPU_on function, during which resume address will
+ * be set.
+ */
+ pm_ret = pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0,
+ SECURE_FLAG);
+
+ if (pm_ret != PM_RET_SUCCESS) {
+ ERROR("Failed to power down CPU %d\n", cpu_id);
+ }
+err:
+ return;
+}
+
+/**
+ * versal2_system_reset() - Send the reset request to firmware for the
+ * system to reset. This function does not
+ * return as it resets system.
+ */
+static void __dead2 versal2_system_reset(void)
+{
+ uint32_t timeout = 10000U;
+ enum pm_ret_status pm_ret;
+ int32_t ret;
+
+ request_cpu_pwrdwn();
+
+ /*
+ * Send the system reset request to the firmware if power down request
+ * is not received from firmware.
+ */
+ if (pwrdwn_req_received == true) {
+ /*
+ * TODO: shutdown scope for this reset needs be revised once
+ * we have a clearer understanding of the overall reset scoping
+ * including the implementation of SYSTEM_RESET2.
+ */
+ pm_ret = pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET,
+ pm_get_shutdown_scope(), SECURE_FLAG);
+
+ if (pm_ret != PM_RET_SUCCESS) {
+ WARN("System shutdown failed\n");
+ }
+
+ /*
+ * Wait for system shutdown request completed and idle callback
+ * not received.
+ */
+ do {
+ ret = ipi_mb_enquire_status(primary_proc->ipi->local_ipi_id,
+ primary_proc->ipi->remote_ipi_id);
+ udelay(100);
+ timeout--;
+ } while ((ret != (int32_t)IPI_MB_STATUS_RECV_PENDING) && (timeout > 0U));
+ }
+
+ (void)psci_cpu_off();
+
+ while (true) {
+ wfi();
+ }
+}
+
+/**
+ * versal2_pwr_domain_suspend() - Send request to PMC to suspend core.
+ * @target_state: Targeted state.
+ */
+static void versal2_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+ const struct pm_proc *proc;
+ uint32_t cpu_id = plat_my_core_pos();
+ uint32_t state;
+ enum pm_ret_status ret;
+ size_t i;
+
+ proc = pm_get_proc(cpu_id);
+ if (proc == NULL) {
+ ERROR("Failed to get proc %d\n", cpu_id);
+ goto err;
+ }
+
+ for (i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+ }
+
+ plat_gic_cpuif_disable();
+
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ plat_gic_save();
+ }
+
+ state = (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) ?
+ PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE;
+
+ /* Send request to PMC to suspend this core */
+ ret = pm_self_suspend(proc->node_id, MAX_LATENCY, state, sec_entry,
+ SECURE_FLAG);
+
+ if (ret != PM_RET_SUCCESS) {
+ ERROR("Failed to power down CPU %d\n", cpu_id);
+ }
+
+err:
+ return;
+}
+
+static void versal2_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ (void)target_state;
+
+ /* Enable the gic cpu interface */
+ plat_gic_pcpu_init();
+
+ /* Program the gic per-cpu distributor or re-distributor interface */
+ plat_gic_cpuif_enable();
+}
+
+/**
+ * versal2_pwr_domain_suspend_finish() - Performs actions to finish
+ * suspend procedure.
+ * @target_state: Targeted state.
+ */
+static void versal2_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+ const struct pm_proc *proc;
+ uint32_t cpu_id = plat_my_core_pos();
+ size_t i;
+
+ proc = pm_get_proc(cpu_id);
+ if (proc == NULL) {
+ ERROR("Failed to get proc %d\n", cpu_id);
+ goto err;
+ }
+
+ for (i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+ }
+
+ /* Clear the APU power control register for this cpu */
+ pm_client_wakeup(proc);
+
+ /* APU was turned off, so restore GIC context */
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ plat_gic_resume();
+ }
+
+ plat_gic_cpuif_enable();
+
+err:
+ return;
+}
+
+/**
+ * versal2_system_off() - Send the system off request to firmware.
+ * This function does not return as it puts core into WFI
+ */
+static void __dead2 versal2_system_off(void)
+{
+ enum pm_ret_status ret;
+
+ /* Send the power down request to the PMC */
+ ret = pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN,
+ pm_get_shutdown_scope(), SECURE_FLAG);
+
+ if (ret != PM_RET_SUCCESS) {
+ ERROR("System shutdown failed\n");
+ }
+
+ while (true) {
+ wfi();
+ }
+}
+
+/**
+ * versal2_validate_power_state() - Ensure that the power state
+ * parameter in request is valid.
+ * @power_state: Power state of core.
+ * @req_state: Requested state.
+ *
+ * Return: Returns status, either PSCI_E_SUCCESS or reason.
+ */
+static int32_t versal2_validate_power_state(unsigned int power_state,
+ psci_power_state_t *req_state)
+{
+ uint32_t pstate = psci_get_pstate_type(power_state);
+ int32_t ret = PSCI_E_SUCCESS;
+
+ VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
+
+ assert(req_state);
+
+ /* Sanity check the requested state */
+ if (pstate == PSTATE_TYPE_STANDBY) {
+ req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
+ } else {
+ req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
+ }
+
+ /* The 'state_id' is expected to be zero */
+ if (psci_get_pstate_id(power_state) != 0U) {
+ ret = PSCI_E_INVALID_PARAMS;
+ }
+
+ return ret;
+}
+
+/**
+ * versal2_get_sys_suspend_power_state() - Get power state for system
+ * suspend.
+ * @req_state: Requested state.
+ */
+static void versal2_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+ uint64_t i;
+
+ for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) {
+ req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
+ }
+}
+
+/**
+ * Export the platform specific power ops.
+ */
+static const struct plat_psci_ops versal2_nopmc_psci_ops = {
+ .pwr_domain_on = versal2_pwr_domain_on,
+ .pwr_domain_off = versal2_pwr_domain_off,
+ .pwr_domain_on_finish = versal2_pwr_domain_on_finish,
+ .pwr_domain_suspend = versal2_pwr_domain_suspend,
+ .pwr_domain_suspend_finish = versal2_pwr_domain_suspend_finish,
+ .system_off = versal2_system_off,
+ .system_reset = versal2_system_reset,
+ .validate_power_state = versal2_validate_power_state,
+ .get_sys_suspend_power_state = versal2_get_sys_suspend_power_state,
+};
+
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const struct plat_psci_ops **psci_ops)
+{
+ sec_entry = sec_entrypoint;
+
+ VERBOSE("Setting up entry point %lx\n", sec_entry);
+
+ *psci_ops = &versal2_nopmc_psci_ops;
+
+ return 0;
+}
+
+int32_t sip_svc_setup_init(void)
+{
+ return pm_setup();
+}
+
+uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
+ const void *cookie, void *handle, uint64_t flags)
+{
+ return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
+}
diff --git a/plat/amd/versal2/platform.mk b/plat/amd/versal2/platform.mk
index 4aedd8a..489a063 100644
--- a/plat/amd/versal2/platform.mk
+++ b/plat/amd/versal2/platform.mk
@@ -28,6 +28,9 @@
IPI_CRC_CHECK := 0
GIC_ENABLE_V4_EXTN := 0
GICV3_SUPPORT_GIC600 := 1
+TFA_NO_PM := 0
+CPU_PWRDWN_SGI ?= 6
+$(eval $(call add_define_val,CPU_PWR_DOWN_REQ_INTR,ARM_IRQ_SEC_SGI_${CPU_PWRDWN_SGI}))
override CTX_INCLUDE_AARCH32_REGS := 0
@@ -35,6 +38,10 @@
override PLAT_XLAT_TABLES_DYNAMIC := 1
$(eval $(call add_define,PLAT_XLAT_TABLES_DYNAMIC))
+ifdef TFA_NO_PM
+ $(eval $(call add_define,TFA_NO_PM))
+endif
+
ifdef MEM_BASE
$(eval $(call add_define,MEM_BASE))
@@ -129,8 +136,17 @@
drivers/scmi-msg/reset_domain.c \
${PLAT_PATH}/scmi.c
+ifeq ($(TFA_NO_PM), 0)
+BL31_SOURCES += plat/xilinx/common/pm_service/pm_api_sys.c \
+ plat/xilinx/common/pm_service/pm_ipi.c \
+ ${PLAT_PATH}/plat_psci_pm.c \
+ ${PLAT_PATH}/pm_service/pm_svc_main.c \
+ ${PLAT_PATH}/pm_service/pm_client.c
+else
+BL31_SOURCES += ${PLAT_PATH}/plat_psci.c
+endif
+
-BL31_SOURCES += ${PLAT_PATH}/plat_psci.c \
- common/fdt_wrappers.c \
+BL31_SOURCES += common/fdt_wrappers.c \
plat/xilinx/common/plat_console.c \
plat/xilinx/common/plat_startup.c \
plat/xilinx/common/ipi.c \
diff --git a/plat/amd/versal2/pm_service/pm_client.c b/plat/amd/versal2/pm_service/pm_client.c
new file mode 100644
index 0000000..8d6b9b1
--- /dev/null
+++ b/plat/amd/versal2/pm_service/pm_client.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * APU specific definition of processors in the subsystem as well as functions
+ * for getting information about and changing state of the APU.
+ */
+
+#include <assert.h>
+
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include <platform_def.h>
+#include "def.h"
+#include <plat_ipi.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+
+#define UNDEFINED_CPUID UINT32_MAX
+
+DEFINE_RENAME_SYSREG_RW_FUNCS(cpu_pwrctrl_val, S3_0_C15_C2_7)
+
+/*
+ * ARM v8.2, the cache will turn off automatically when cpu
+ * power down. Therefore, there is no doubt to use the spin_lock here.
+ */
+static spinlock_t pm_client_secure_lock;
+static inline void pm_client_lock_get(void)
+{
+ spin_lock(&pm_client_secure_lock);
+}
+
+static inline void pm_client_lock_release(void)
+{
+ spin_unlock(&pm_client_secure_lock);
+}
+
+static const struct pm_ipi apu_ipi = {
+ .local_ipi_id = IPI_LOCAL_ID,
+ .remote_ipi_id = IPI_REMOTE_ID,
+ .buffer_base = IPI_BUFFER_LOCAL_BASE,
+};
+
+/* Order in pm_procs_all array must match cpu ids */
+static const struct pm_proc pm_procs_all[] = {
+ {
+ .node_id = PM_DEV_CLUSTER0_ACPU_0,
+ .ipi = &apu_ipi,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER0_ACPU_1,
+ .ipi = &apu_ipi,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER1_ACPU_0,
+ .ipi = &apu_ipi,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER1_ACPU_1,
+ .ipi = &apu_ipi,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER2_ACPU_0,
+ .ipi = &apu_ipi,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER2_ACPU_1,
+ .ipi = &apu_ipi,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER3_ACPU_0,
+ .ipi = &apu_ipi,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER3_ACPU_1,
+ .ipi = &apu_ipi,
+ },
+};
+
+const struct pm_proc *primary_proc = &pm_procs_all[0];
+
+/**
+ * pm_get_proc() - returns pointer to the proc structure.
+ * @cpuid: id of the cpu whose proc struct pointer should be returned.
+ *
+ * Return: Pointer to a proc structure if proc is found, otherwise NULL.
+ */
+const struct pm_proc *pm_get_proc(uint32_t cpuid)
+{
+ const struct pm_proc *proc = NULL;
+
+ if (cpuid < ARRAY_SIZE(pm_procs_all)) {
+ proc = &pm_procs_all[cpuid];
+ } else {
+ ERROR("cpuid: %d proc NULL\n", cpuid);
+ }
+
+ return proc;
+}
+
+/**
+ * irq_to_pm_node_idx - Get PM node index corresponding to the interrupt number.
+ * @irq: Interrupt number.
+ *
+ * Return: PM node index corresponding to the specified interrupt.
+ */
+enum pm_device_node_idx irq_to_pm_node_idx(uint32_t irq)
+{
+ enum pm_device_node_idx dev_idx = XPM_NODEIDX_DEV_MIN;
+
+ assert(irq <= IRQ_MAX);
+
+ switch (irq) {
+ case 11:
+ dev_idx = XPM_NODEIDX_DEV_I2C_2;
+ break;
+ case 12:
+ dev_idx = XPM_NODEIDX_DEV_I2C_3;
+ break;
+ case 13:
+ dev_idx = XPM_NODEIDX_DEV_I2C_4;
+ break;
+ case 20:
+ dev_idx = XPM_NODEIDX_DEV_GPIO;
+ break;
+ case 21:
+ dev_idx = XPM_NODEIDX_DEV_I2C_0;
+ break;
+ case 22:
+ dev_idx = XPM_NODEIDX_DEV_I2C_1;
+ break;
+ case 23:
+ dev_idx = XPM_NODEIDX_DEV_SPI_0;
+ break;
+ case 24:
+ dev_idx = XPM_NODEIDX_DEV_SPI_1;
+ break;
+ case 25:
+ dev_idx = XPM_NODEIDX_DEV_UART_0;
+ break;
+ case 26:
+ dev_idx = XPM_NODEIDX_DEV_UART_1;
+ break;
+ case 27:
+ dev_idx = XPM_NODEIDX_DEV_CAN_FD_0;
+ break;
+ case 28:
+ dev_idx = XPM_NODEIDX_DEV_CAN_FD_1;
+ break;
+ case 29:
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 98:
+ dev_idx = XPM_NODEIDX_DEV_USB_0;
+ break;
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+ case 99:
+ dev_idx = XPM_NODEIDX_DEV_USB_1;
+ break;
+ case 39:
+ case 40:
+ dev_idx = XPM_NODEIDX_DEV_GEM_0;
+ break;
+ case 41:
+ case 42:
+ dev_idx = XPM_NODEIDX_DEV_GEM_1;
+ break;
+ case 43:
+ dev_idx = XPM_NODEIDX_DEV_TTC_0;
+ break;
+ case 44:
+ dev_idx = XPM_NODEIDX_DEV_TTC_1;
+ break;
+ case 45:
+ dev_idx = XPM_NODEIDX_DEV_TTC_2;
+ break;
+ case 46:
+ dev_idx = XPM_NODEIDX_DEV_TTC_3;
+ break;
+ case 47:
+ dev_idx = XPM_NODEIDX_DEV_TTC_4;
+ break;
+ case 48:
+ dev_idx = XPM_NODEIDX_DEV_TTC_5;
+ break;
+ case 49:
+ dev_idx = XPM_NODEIDX_DEV_TTC_6;
+ break;
+ case 50:
+ dev_idx = XPM_NODEIDX_DEV_TTC_7;
+ break;
+ case 72:
+ dev_idx = XPM_NODEIDX_DEV_ADMA_0;
+ break;
+ case 73:
+ dev_idx = XPM_NODEIDX_DEV_ADMA_1;
+ break;
+ case 74:
+ dev_idx = XPM_NODEIDX_DEV_ADMA_2;
+ break;
+ case 75:
+ dev_idx = XPM_NODEIDX_DEV_ADMA_3;
+ break;
+ case 76:
+ dev_idx = XPM_NODEIDX_DEV_ADMA_4;
+ break;
+ case 77:
+ dev_idx = XPM_NODEIDX_DEV_ADMA_5;
+ break;
+ case 78:
+ dev_idx = XPM_NODEIDX_DEV_ADMA_6;
+ break;
+ case 79:
+ dev_idx = XPM_NODEIDX_DEV_ADMA_7;
+ break;
+ case 95:
+ dev_idx = XPM_NODEIDX_DEV_CAN_FD_2;
+ break;
+ case 96:
+ dev_idx = XPM_NODEIDX_DEV_CAN_FD_3;
+ break;
+ case 100:
+ dev_idx = XPM_NODEIDX_DEV_I2C_5;
+ break;
+ case 101:
+ dev_idx = XPM_NODEIDX_DEV_I2C_6;
+ break;
+ case 102:
+ dev_idx = XPM_NODEIDX_DEV_I2C_7;
+ break;
+ case 200:
+ dev_idx = XPM_NODEIDX_DEV_RTC;
+ break;
+ case 218:
+ dev_idx = XPM_NODEIDX_DEV_SDIO_0;
+ break;
+ case 220:
+ dev_idx = XPM_NODEIDX_DEV_SDIO_1;
+ break;
+ default:
+ dev_idx = XPM_NODEIDX_DEV_MIN;
+ break;
+ }
+
+ return dev_idx;
+}
+
+/**
+ * pm_client_suspend() - Client-specific suspend actions. This function
+ * perform actions required prior to sending suspend
+ * request.
+ * Actions taken depend on the state system is
+ * suspending to.
+ * @proc: processor which need to suspend.
+ * @state: desired suspend state.
+ */
+void pm_client_suspend(const struct pm_proc *proc, uint32_t state)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+ uintptr_t val;
+ /*
+ * Get the core index, use it calculate offset for secondary cores
+ * to match with register database
+ */
+ uint32_t core_index = cpu_id + ((cpu_id / 2U) * 2U);
+
+ pm_client_lock_get();
+
+ if (state == PM_STATE_SUSPEND_TO_RAM) {
+ pm_client_set_wakeup_sources((uint32_t)proc->node_id);
+ }
+
+ val = read_cpu_pwrctrl_val();
+ val |= CORE_PWRDN_EN_BIT_MASK;
+ write_cpu_pwrctrl_val(val);
+
+ isb();
+
+ /* Enable power down interrupt */
+ mmio_write_32(APU_PCIL_CORE_X_IEN_POWER_REG(core_index),
+ APU_PCIL_CORE_X_IEN_POWER_MASK);
+ /* Enable wake interrupt */
+ mmio_write_32(APU_PCIL_CORE_X_IEN_WAKE_REG(core_index),
+ APU_PCIL_CORE_X_IEN_WAKE_MASK);
+
+ pm_client_lock_release();
+}
+
+/**
+ * pm_get_cpuid() - get the local cpu ID for a global node ID.
+ * @nid: node id of the processor.
+ *
+ * Return: the cpu ID (starting from 0) for the subsystem.
+ */
+static uint32_t pm_get_cpuid(uint32_t nid)
+{
+ uint32_t ret = (uint32_t) UNDEFINED_CPUID;
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
+ if (pm_procs_all[i].node_id == nid) {
+ ret = (uint32_t)i;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * pm_client_wakeup() - Client-specific wakeup actions.
+ * @proc: Processor which need to wakeup.
+ *
+ * This function should contain any PU-specific actions
+ * required for waking up another APU core.
+ */
+void pm_client_wakeup(const struct pm_proc *proc)
+{
+ uint32_t cpuid = pm_get_cpuid(proc->node_id);
+ uintptr_t val;
+
+ if (cpuid != (uint32_t) UNDEFINED_CPUID) {
+ pm_client_lock_get();
+
+ /* Clear powerdown request */
+ val = read_cpu_pwrctrl_val();
+ val &= ~CORE_PWRDN_EN_BIT_MASK;
+ write_cpu_pwrctrl_val(val);
+
+ isb();
+
+ /* Disabled power down interrupt */
+ mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpuid),
+ APU_PCIL_CORE_X_IDS_POWER_MASK);
+ /* Disable wake interrupt */
+ mmio_write_32(APU_PCIL_CORE_X_IDS_WAKE_REG(cpuid),
+ APU_PCIL_CORE_X_IDS_WAKE_MASK);
+
+ pm_client_lock_release();
+ }
+}
+
+/**
+ * pm_client_abort_suspend() - Client-specific abort-suspend actions.
+ *
+ * This function should contain any PU-specific actions
+ * required for aborting a prior suspend request.
+ */
+void pm_client_abort_suspend(void)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+ uintptr_t val;
+
+ /* Enable interrupts at processor level (for current cpu) */
+ gicv3_cpuif_enable(plat_my_core_pos());
+
+ pm_client_lock_get();
+
+ /* Clear powerdown request */
+ val = read_cpu_pwrctrl_val();
+ val &= ~CORE_PWRDN_EN_BIT_MASK;
+ write_cpu_pwrctrl_val(val);
+
+ isb();
+
+ /* Disabled power down interrupt */
+ mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id),
+ APU_PCIL_CORE_X_IDS_POWER_MASK);
+
+ pm_client_lock_release();
+}
diff --git a/plat/amd/versal2/pm_service/pm_svc_main.c b/plat/amd/versal2/pm_service/pm_svc_main.c
new file mode 100644
index 0000000..88848e2
--- /dev/null
+++ b/plat/amd/versal2/pm_service/pm_svc_main.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Top-level SMC handler for Versal2 power management calls and
+ * IPI setup functions for communication with PMC.
+ */
+
+#include <errno.h>
+#include <stdbool.h>
+
+#include "../drivers/arm/gic/v3/gicv3_private.h"
+
+#include <common/runtime_svc.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_ipi.h"
+#include "pm_svc_main.h"
+
+#define MODE 0x80000000U
+
+#define INVALID_SGI 0xFFU
+#define PM_INIT_SUSPEND_CB (30U)
+#define PM_NOTIFY_CB (32U)
+#define EVENT_CPU_PWRDWN (4U)
+#define MBOX_SGI_SHARED_IPI (7U)
+
+/**
+ * upper_32_bits - return bits 32-63 of a number
+ * @n: the number we're accessing
+ */
+#define upper_32_bits(n) ((uint32_t)((n) >> 32U))
+
+/**
+ * lower_32_bits - return bits 0-31 of a number
+ * @n: the number we're accessing
+ */
+#define lower_32_bits(n) ((uint32_t)((n) & 0xffffffffU))
+
+/**
+ * EXTRACT_SMC_ARGS - extracts 32-bit payloads from 64-bit SMC arguments
+ * @pm_arg: array of 32-bit payloads
+ * @x: array of 64-bit SMC arguments
+ */
+#define EXTRACT_ARGS(pm_arg, x) \
+ for (uint32_t i = 0U; i < (PAYLOAD_ARG_CNT - 1U); i++) { \
+ if ((i % 2U) != 0U) { \
+ pm_arg[i] = lower_32_bits(x[(i / 2U) + 1U]); \
+ } else { \
+ pm_arg[i] = upper_32_bits(x[i / 2U]); \
+ } \
+ }
+
+/* 1 sec of wait timeout for secondary core down */
+#define PWRDWN_WAIT_TIMEOUT (1000U)
+DEFINE_RENAME_SYSREG_RW_FUNCS(icc_asgi1r_el1, S3_0_C12_C11_6)
+
+/* pm_up = true - UP, pm_up = false - DOWN */
+static bool pm_up;
+static uint32_t sgi = (uint32_t)INVALID_SGI;
+bool pwrdwn_req_received;
+
+static void notify_os(void)
+{
+ plat_ic_raise_ns_sgi((int)sgi, read_mpidr_el1());
+}
+
+static uint64_t cpu_pwrdwn_req_handler(uint32_t id, uint32_t flags,
+ void *handle, void *cookie)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+
+ VERBOSE("Powering down CPU %d\n", cpu_id);
+
+ /* Deactivate CPU power down SGI */
+ plat_ic_end_of_interrupt(CPU_PWR_DOWN_REQ_INTR);
+
+ return (uint64_t) psci_cpu_off();
+}
+
+/**
+ * raise_pwr_down_interrupt() - Callback function to raise SGI.
+ * @mpidr: MPIDR for the target CPU.
+ *
+ * Raise SGI interrupt to trigger the CPU power down sequence on all the
+ * online secondary cores.
+ */
+static void raise_pwr_down_interrupt(u_register_t mpidr)
+{
+ plat_ic_raise_el3_sgi((int)CPU_PWR_DOWN_REQ_INTR, mpidr);
+}
+
+void request_cpu_pwrdwn(void)
+{
+ int ret;
+
+ VERBOSE("CPU power down request received\n");
+
+ /* Send powerdown request to online secondary core(s) */
+ ret = psci_stop_other_cores(plat_my_core_pos(), (unsigned int)PWRDWN_WAIT_TIMEOUT, raise_pwr_down_interrupt);
+ if (ret != (int)PSCI_E_SUCCESS) {
+ ERROR("Failed to powerdown secondary core(s)\n");
+ }
+
+ /* Clear IPI IRQ */
+ pm_ipi_irq_clear(primary_proc);
+
+ /* Deactivate IPI IRQ */
+ plat_ic_end_of_interrupt(PLAT_VERSAL_IPI_IRQ);
+}
+
+static uint64_t ipi_fiq_handler(uint32_t id, uint32_t flags, void *handle,
+ void *cookie)
+{
+ uint32_t payload[4] = {0};
+ enum pm_ret_status ret;
+ uint32_t ipi_status, i;
+
+ VERBOSE("Received IPI FIQ from firmware\n");
+
+ console_flush();
+ (void)plat_ic_acknowledge_interrupt();
+
+ /* Check status register for each IPI except PMC */
+ for (i = IPI_ID_APU; i <= IPI_ID_5; i++) {
+ ipi_status = (uint32_t)ipi_mb_enquire_status(IPI_ID_APU, i);
+
+ /* If any agent other than PMC has generated IPI FIQ then send SGI to mbox driver */
+ if ((ipi_status & (uint32_t)IPI_MB_STATUS_RECV_PENDING) > (uint32_t) 0) {
+ plat_ic_raise_ns_sgi((int)MBOX_SGI_SHARED_IPI, read_mpidr_el1());
+ break;
+ }
+ }
+
+ /* If PMC has not generated interrupt then end ISR */
+ ipi_status = (uint32_t)ipi_mb_enquire_status(IPI_ID_APU, IPI_ID_PMC);
+ if ((ipi_status & (uint32_t) IPI_MB_STATUS_RECV_PENDING) == (uint32_t) 0) {
+ plat_ic_end_of_interrupt(id);
+ goto end;
+ }
+
+ /* Handle PMC case */
+ ret = pm_get_callbackdata(payload, ARRAY_SIZE(payload), 0, 0);
+ if (ret != PM_RET_SUCCESS) {
+ payload[0] = (uint32_t) ret;
+ }
+
+ switch (payload[0]) {
+ case PM_INIT_SUSPEND_CB:
+ if (sgi != INVALID_SGI) {
+ notify_os();
+ }
+ break;
+ case PM_NOTIFY_CB:
+ if (sgi != INVALID_SGI) {
+ if (payload[2] == EVENT_CPU_PWRDWN) {
+ if (pwrdwn_req_received) {
+ pwrdwn_req_received = false;
+ request_cpu_pwrdwn();
+ (void)psci_cpu_off();
+ break;
+ } else {
+ /* No action needed, added for MISRA
+ * complaince
+ */
+ }
+ pwrdwn_req_received = true;
+
+ } else {
+ /* No action needed, added for MISRA
+ * complaince
+ */
+ }
+ notify_os();
+ } else if (payload[2] == EVENT_CPU_PWRDWN) {
+ request_cpu_pwrdwn();
+ (void)psci_cpu_off();
+ } else {
+ /* No action needed, added for MISRA
+ * complaince
+ */
+ }
+ break;
+ case (uint32_t) PM_RET_ERROR_INVALID_CRC:
+ pm_ipi_irq_clear(primary_proc);
+ WARN("Invalid CRC in the payload\n");
+ break;
+
+ default:
+ pm_ipi_irq_clear(primary_proc);
+ WARN("Invalid IPI payload\n");
+ break;
+ }
+
+ /* Clear FIQ */
+ plat_ic_end_of_interrupt(id);
+
+end:
+ return 0;
+}
+
+/**
+ * pm_register_sgi() - PM register the IPI interrupt.
+ * @sgi_num: SGI number to be used for communication.
+ * @reset: Reset to invalid SGI when reset=1.
+ *
+ * Return: On success, the initialization function must return 0.
+ * Any other return value will cause the framework to ignore
+ * the service.
+ *
+ * Update the SGI number to be used.
+ *
+ */
+int32_t pm_register_sgi(uint32_t sgi_num, uint32_t reset)
+{
+ int32_t ret;
+
+ if (reset == 1U) {
+ sgi = INVALID_SGI;
+ ret = 0;
+ goto end;
+ }
+
+ if (sgi != INVALID_SGI) {
+ ret = -EBUSY;
+ goto end;
+ }
+
+ if (sgi_num >= GICV3_MAX_SGI_TARGETS) {
+ ret = -EINVAL;
+ goto end;
+ }
+
+ sgi = (uint32_t)sgi_num;
+ ret = 0;
+end:
+ return ret;
+}
+
+/**
+ * pm_setup() - PM service setup.
+ *
+ * Return: On success, the initialization function must return 0.
+ * Any other return value will cause the framework to ignore
+ * the service.
+ *
+ * Initialization functions for Versal power management for
+ * communicaton with PMC.
+ *
+ * Called from sip_svc_setup initialization function with the
+ * rt_svc_init signature.
+ *
+ */
+int32_t pm_setup(void)
+{
+ int32_t ret = 0;
+
+ pm_ipi_init(primary_proc);
+ pm_up = true;
+
+ /* register SGI handler for CPU power down request */
+ ret = request_intr_type_el3(CPU_PWR_DOWN_REQ_INTR, cpu_pwrdwn_req_handler);
+ if (ret != 0) {
+ WARN("BL31: registering SGI interrupt failed\n");
+ }
+
+ /*
+ * Enable IPI IRQ
+ * assume the rich OS is OK to handle callback IRQs now.
+ * Even if we were wrong, it would not enable the IRQ in
+ * the GIC.
+ */
+ pm_ipi_irq_enable(primary_proc);
+
+ ret = request_intr_type_el3(PLAT_VERSAL_IPI_IRQ, ipi_fiq_handler);
+ if (ret != 0) {
+ WARN("BL31: registering IPI interrupt failed\n");
+ }
+
+ gicd_write_irouter(gicv3_driver_data->gicd_base, PLAT_VERSAL_IPI_IRQ, MODE);
+
+ /* Register for idle callback during force power down/restart */
+ ret = (int32_t)pm_register_notifier(primary_proc->node_id, EVENT_CPU_PWRDWN,
+ 0x0U, 0x1U, SECURE_FLAG);
+ if (ret != 0) {
+ WARN("BL31: registering idle callback for restart/force power down failed\n");
+ }
+
+ return ret;
+}
+
+/**
+ * eemi_psci_debugfs_handler() - EEMI API invoked from PSCI.
+ * @api_id: identifier for the API being called.
+ * @pm_arg: pointer to the argument data for the API call.
+ * @handle: Pointer to caller's context structure.
+ * @security_flag: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * These EEMI APIs performs CPU specific power management tasks.
+ * These EEMI APIs are invoked either from PSCI or from debugfs in kernel.
+ * These calls require CPU specific processing before sending IPI request to
+ * Platform Management Controller. For example enable/disable CPU specific
+ * interrupts. This requires separate handler for these calls and may not be
+ * handled using common eemi handler.
+ *
+ * Return: If EEMI API found then, uintptr_t type address, else 0.
+ *
+ */
+static uintptr_t eemi_psci_debugfs_handler(uint32_t api_id, uint32_t *pm_arg,
+ void *handle, uint32_t security_flag)
+{
+ enum pm_ret_status ret;
+
+ switch (api_id) {
+
+ case (uint32_t)PM_SELF_SUSPEND:
+ ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ case (uint32_t)PM_FORCE_POWERDOWN:
+ ret = pm_force_powerdown(pm_arg[0], (uint8_t)pm_arg[1], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ case (uint32_t)PM_REQ_SUSPEND:
+ ret = pm_req_suspend(pm_arg[0], (uint8_t)pm_arg[1], pm_arg[2],
+ pm_arg[3], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ case (uint32_t)PM_ABORT_SUSPEND:
+ ret = pm_abort_suspend(pm_arg[0], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ case (uint32_t)PM_SYSTEM_SHUTDOWN:
+ ret = pm_system_shutdown(pm_arg[0], pm_arg[1], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ default:
+ return (uintptr_t)0;
+ }
+}
+
+/**
+ * TF_A_specific_handler() - SMC handler for TF-A specific functionality.
+ * @api_id: identifier for the API being called.
+ * @pm_arg: pointer to the argument data for the API call.
+ * @handle: Pointer to caller's context structure.
+ * @security_flag: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * These EEMI calls performs functionality that does not require
+ * IPI transaction. The handler ends in TF-A and returns requested data to
+ * kernel from TF-A.
+ *
+ * Return: If TF-A specific API found then, uintptr_t type address, else 0
+ *
+ */
+static uintptr_t TF_A_specific_handler(uint32_t api_id, uint32_t *pm_arg,
+ void *handle, uint32_t security_flag)
+{
+ switch (api_id) {
+
+ case TF_A_FEATURE_CHECK:
+ {
+ enum pm_ret_status ret;
+ uint32_t result[PAYLOAD_ARG_CNT] = {0U};
+
+ ret = eemi_feature_check(pm_arg[0], result);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U));
+ }
+
+ case TF_A_PM_REGISTER_SGI:
+ {
+ int32_t ret;
+
+ ret = pm_register_sgi(pm_arg[0], pm_arg[1]);
+ if (ret != 0) {
+ SMC_RET1(handle, (uint32_t)PM_RET_ERROR_ARGS);
+ }
+
+ SMC_RET1(handle, (uint32_t)PM_RET_SUCCESS);
+ }
+
+ case PM_GET_CALLBACK_DATA:
+ {
+ uint32_t result[4] = {0};
+ enum pm_ret_status ret;
+
+ ret = pm_get_callbackdata(result, ARRAY_SIZE(result), security_flag, 1U);
+ if (ret != PM_RET_SUCCESS) {
+ result[0] = (uint32_t) ret;
+ }
+
+ SMC_RET2(handle,
+ (uint64_t)result[0] | ((uint64_t)result[1] << 32U),
+ (uint64_t)result[2] | ((uint64_t)result[3] << 32U));
+ }
+
+ case PM_GET_TRUSTZONE_VERSION:
+ SMC_RET1(handle, ((uint64_t)PM_RET_SUCCESS) |
+ (((uint64_t)TZ_VERSION) << 32U));
+
+ default:
+ return (uintptr_t)0U;
+ }
+}
+
+/**
+ * eemi_api_handler() - Prepare EEMI payload and perform IPI transaction.
+ * @api_id: identifier for the API being called.
+ * @pm_arg: pointer to the argument data for the API call.
+ * @handle: Pointer to caller's context structure.
+ * @security_flag: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * EEMI - Embedded Energy Management Interface is AMD-Xilinx proprietary
+ * protocol to allow communication between power management controller and
+ * different processing clusters.
+ *
+ * This handler prepares EEMI protocol payload received from kernel and performs
+ * IPI transaction.
+ *
+ * Return: If EEMI API found then, uintptr_t type address, else 0
+ */
+static uintptr_t eemi_api_handler(uint32_t api_id, const uint32_t *pm_arg,
+ void *handle, uint32_t security_flag)
+{
+ enum pm_ret_status ret;
+ uint32_t buf[RET_PAYLOAD_ARG_CNT] = {0U};
+ uint32_t payload[PAYLOAD_ARG_CNT] = {0U};
+ uint32_t module_id;
+
+ module_id = (api_id & MODULE_ID_MASK) >> 8U;
+
+ PM_PACK_PAYLOAD7(payload, module_id, security_flag, api_id,
+ pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3],
+ pm_arg[4], pm_arg[5]);
+
+ ret = pm_ipi_send_sync(primary_proc, payload, (uint32_t *)buf,
+ RET_PAYLOAD_ARG_CNT);
+
+ SMC_RET4(handle, (uint64_t)ret | ((uint64_t)buf[0] << 32U),
+ (uint64_t)buf[1] | ((uint64_t)buf[2] << 32U),
+ (uint64_t)buf[3] | ((uint64_t)buf[4] << 32U),
+ (uint64_t)buf[5]);
+}
+
+/**
+ * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
+ * @smc_fid: Function Identifier.
+ * @x1: SMC64 Arguments from kernel.
+ * @x2: SMC64 Arguments from kernel.
+ * @x3: SMC64 Arguments from kernel (upper 32-bits).
+ * @x4: Unused.
+ * @cookie: Unused.
+ * @handle: Pointer to caller's context structure.
+ * @flags: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * Return: Unused.
+ *
+ * Determines that smc_fid is valid and supported PM SMC Function ID from the
+ * list of pm_api_ids, otherwise completes the request with
+ * the unknown SMC Function ID.
+ *
+ * The SMC calls for PM service are forwarded from SIP Service SMC handler
+ * function with rt_svc_handle signature.
+ *
+ */
+uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+ uint64_t x4, const void *cookie, void *handle, uint64_t flags)
+{
+ uintptr_t ret;
+ uint32_t pm_arg[PAYLOAD_ARG_CNT] = {0};
+ uint32_t security_flag = NON_SECURE_FLAG;
+ uint32_t api_id;
+ bool status = false, status_tmp = false;
+ uint64_t x[4] = {x1, x2, x3, x4};
+
+ /* Handle case where PM wasn't initialized properly */
+ if (pm_up == false) {
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ /*
+ * Mark BIT24 payload (i.e 1st bit of pm_arg[3] ) as secure (0)
+ * if smc called is secure
+ *
+ * Add redundant macro call to immune the code from glitches
+ */
+ SECURE_REDUNDANT_CALL(status, status_tmp, is_caller_secure, flags);
+ if ((status != false) && (status_tmp != false)) {
+ security_flag = SECURE_FLAG;
+ }
+
+ if ((smc_fid & FUNCID_NUM_MASK) == PASS_THROUGH_FW_CMD_ID) {
+ api_id = lower_32_bits(x[0]);
+
+ EXTRACT_ARGS(pm_arg, x);
+
+ return eemi_api_handler(api_id, pm_arg, handle, security_flag);
+ }
+
+ pm_arg[0] = (uint32_t)x1;
+ pm_arg[1] = (uint32_t)(x1 >> 32U);
+ pm_arg[2] = (uint32_t)x2;
+ pm_arg[3] = (uint32_t)(x2 >> 32U);
+ pm_arg[4] = (uint32_t)x3;
+ (void)(x4);
+ api_id = smc_fid & FUNCID_NUM_MASK;
+
+ ret = eemi_psci_debugfs_handler(api_id, pm_arg, handle, (uint32_t)flags);
+ if (ret != (uintptr_t)0)
+ goto error;
+
+ ret = TF_A_specific_handler(api_id, pm_arg, handle, security_flag);
+ if (ret != (uintptr_t)0)
+ goto error;
+
+error:
+ return ret;
+}
diff --git a/plat/amd/versal2/sip_svc_setup.c b/plat/amd/versal2/sip_svc_setup.c
index 4a1be3e..9e81af0 100644
--- a/plat/amd/versal2/sip_svc_setup.c
+++ b/plat/amd/versal2/sip_svc_setup.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.
* Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -27,7 +27,7 @@
/* SiP Service Calls version numbers */
#define SIP_SVC_VERSION_MAJOR (0U)
-#define SIP_SVC_VERSION_MINOR (1U)
+#define SIP_SVC_VERSION_MINOR (2U)
/* These macros are used to identify PM calls from the SMC function ID */
#define SIP_FID_MASK GENMASK(23, 16)
diff --git a/plat/arm/board/fvp/fvp_common.c b/plat/arm/board/fvp/fvp_common.c
index 19a340f..7d76814 100644
--- a/plat/arm/board/fvp/fvp_common.c
+++ b/plat/arm/board/fvp/fvp_common.c
@@ -52,7 +52,7 @@
#define MAP_DEVICE0 MAP_REGION_FLAT(DEVICE0_BASE, \
DEVICE0_SIZE, \
- MT_DEVICE | MT_RW | MT_SECURE)
+ MT_DEVICE | MT_RW | EL3_PAS)
#define MAP_DEVICE1 MAP_REGION_FLAT(DEVICE1_BASE, \
DEVICE1_SIZE, \
diff --git a/plat/arm/board/n1sdp/n1sdp_bl31_setup.c b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
index 27ea7f7..d8d60ef 100644
--- a/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
+++ b/plat/arm/board/n1sdp/n1sdp_bl31_setup.c
@@ -17,6 +17,8 @@
#include "n1sdp_private.h"
#include <platform_def.h>
+#define RT_OWNER 0
+
/*
* Platform information structure stored in SDS.
* This structure holds information about platform's DDR
@@ -44,12 +46,16 @@
};
static struct gic600_multichip_data n1sdp_multichip_data __init = {
- .rt_owner_base = PLAT_ARM_GICD_BASE,
- .rt_owner = 0,
+ .base_addrs = {
+ PLAT_ARM_GICD_BASE
+ },
+ .rt_owner = RT_OWNER,
.chip_count = 1,
.chip_addrs = {
- PLAT_ARM_GICD_BASE >> 16,
- PLAT_ARM_GICD_BASE >> 16
+ [RT_OWNER] = {
+ PLAT_ARM_GICD_BASE >> 16,
+ PLAT_ARM_GICD_BASE >> 16
+ }
},
.spi_ids = {
{PLAT_ARM_GICD_BASE, 32, 511},
diff --git a/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_plat.c b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_plat.c
index ccabe22..5cbdd5f 100644
--- a/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_plat.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn1edge/rdn1edge_plat.c
@@ -11,6 +11,8 @@
#include <nrd_plat.h>
+#define RT_OWNER 0
+
#if defined(IMAGE_BL31)
static const mmap_region_t rdn1edge_dynamic_mmap[] = {
NRD_CSS_SHARED_RAM_MMAP(1),
@@ -19,12 +21,17 @@
};
static struct gic600_multichip_data rdn1e1_multichip_data __init = {
- .rt_owner_base = PLAT_ARM_GICD_BASE,
- .rt_owner = 0,
+ .base_addrs = {
+ PLAT_ARM_GICD_BASE
+ },
+ .rt_owner = RT_OWNER,
.chip_count = NRD_CHIP_COUNT,
.chip_addrs = {
- PLAT_ARM_GICD_BASE >> 16,
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16
+ [RT_OWNER] = {
+ PLAT_ARM_GICD_BASE >> 16,
+ (PLAT_ARM_GICD_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16
+ }
},
.spi_ids = {
{PLAT_ARM_GICD_BASE,
diff --git a/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c
index b1046d6..cf820b8 100644
--- a/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c
+++ b/plat/arm/board/neoverse_rd/platform/rdn2/rdn2_plat.c
@@ -13,6 +13,12 @@
#include <nrd_plat.h>
#include <rdn2_ras.h>
+#define RT_OWNER 0
+#define A4SID_CHIP_0 0x0
+#define A4SID_CHIP_1 0x1
+#define A4SID_CHIP_2 0x2
+#define A4SID_CHIP_3 0x3
+
#if defined(IMAGE_BL31)
#if (NRD_PLATFORM_VARIANT == 2)
static const mmap_region_t rdn2mc_dynamic_mmap[] = {
@@ -33,19 +39,50 @@
#if (NRD_PLATFORM_VARIANT == 2)
static struct gic600_multichip_data rdn2mc_multichip_data __init = {
- .rt_owner_base = PLAT_ARM_GICD_BASE,
- .rt_owner = 0,
+ .base_addrs = {
+ PLAT_ARM_GICD_BASE,
+#if NRD_CHIP_COUNT > 1
+ PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1),
+#endif
+#if NRD_CHIP_COUNT > 2
+ PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2),
+#endif
+#if NRD_CHIP_COUNT > 3
+ PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3),
+#endif
+ },
+ .rt_owner = RT_OWNER,
.chip_count = NRD_CHIP_COUNT,
.chip_addrs = {
- PLAT_ARM_GICD_BASE >> 16,
+ {
+ A4SID_CHIP_0,
+ A4SID_CHIP_1,
+ A4SID_CHIP_2,
+ A4SID_CHIP_3
+ },
#if NRD_CHIP_COUNT > 1
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+ {
+ A4SID_CHIP_0,
+ A4SID_CHIP_1,
+ A4SID_CHIP_2,
+ A4SID_CHIP_3
+ },
#endif
#if NRD_CHIP_COUNT > 2
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+ {
+ A4SID_CHIP_0,
+ A4SID_CHIP_1,
+ A4SID_CHIP_2,
+ A4SID_CHIP_3
+ },
#endif
#if NRD_CHIP_COUNT > 3
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+ {
+ A4SID_CHIP_0,
+ A4SID_CHIP_1,
+ A4SID_CHIP_2,
+ A4SID_CHIP_3
+ }
#endif
},
.spi_ids = {
diff --git a/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_plat.c b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_plat.c
index 5713cb9..0a40762 100644
--- a/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_plat.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv1mc/rdv1mc_plat.c
@@ -11,6 +11,8 @@
#include <nrd_plat.h>
+#define RT_OWNER 0
+
#if defined(IMAGE_BL31)
static const mmap_region_t rdv1mc_dynamic_mmap[] = {
NRD_CSS_SHARED_RAM_MMAP(1),
@@ -29,18 +31,25 @@
};
static struct gic600_multichip_data rdv1mc_multichip_data __init = {
- .rt_owner_base = PLAT_ARM_GICD_BASE,
- .rt_owner = 0,
+ .base_addrs = {
+ PLAT_ARM_GICD_BASE
+ },
+ .rt_owner = RT_OWNER,
.chip_count = NRD_CHIP_COUNT,
.chip_addrs = {
- PLAT_ARM_GICD_BASE >> 16,
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+ [RT_OWNER] = {
+ PLAT_ARM_GICD_BASE >> 16,
+ (PLAT_ARM_GICD_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
#if (NRD_CHIP_COUNT > 2)
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+ (PLAT_ARM_GICD_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
#endif
#if (NRD_CHIP_COUNT > 3)
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+ (PLAT_ARM_GICD_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
#endif
+ }
},
.spi_ids = {
{PLAT_ARM_GICD_BASE,
diff --git a/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_bl31_setup.c b/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_bl31_setup.c
index a5d687e..e32e761 100644
--- a/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_bl31_setup.c
+++ b/plat/arm/board/neoverse_rd/platform/rdv3/rdv3_bl31_setup.c
@@ -15,6 +15,15 @@
#include <nrd_variant.h>
#include <rdv3_rse_comms.h>
+#define RT_OWNER 0
+
+/*
+ * Base addr of the frame that allocated by the platform
+ * intended for remote gic to local gic interrupt
+ * message communication
+ */
+#define NRD_RGIC2LGIC_MESSREG_HNI_BASE UL(0x5FFF0000)
+
#if (NRD_PLATFORM_VARIANT == 2)
static const mmap_region_t rdv3mc_dynamic_mmap[] = {
#if NRD_CHIP_COUNT > 1
@@ -32,19 +41,62 @@
};
static struct gic600_multichip_data rdv3mc_multichip_data __init = {
- .rt_owner_base = PLAT_ARM_GICD_BASE,
- .rt_owner = 0,
+ .base_addrs = {
+ PLAT_ARM_GICD_BASE,
+#if NRD_CHIP_COUNT > 1
+ PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1),
+#endif
+#if NRD_CHIP_COUNT > 2
+ PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2),
+#endif
+#if NRD_CHIP_COUNT > 3
+ PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3),
+#endif
+ },
+ .rt_owner = RT_OWNER,
.chip_count = NRD_CHIP_COUNT,
.chip_addrs = {
- PLAT_ARM_GICD_BASE >> 16,
+ {
+ NRD_RGIC2LGIC_MESSREG_HNI_BASE >> 16,
+ (NRD_RGIC2LGIC_MESSREG_HNI_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+ (NRD_RGIC2LGIC_MESSREG_HNI_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+ (NRD_RGIC2LGIC_MESSREG_HNI_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+ },
#if NRD_CHIP_COUNT > 1
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+ {
+ NRD_RGIC2LGIC_MESSREG_HNI_BASE >> 16,
+ (NRD_RGIC2LGIC_MESSREG_HNI_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+ (NRD_RGIC2LGIC_MESSREG_HNI_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+ (NRD_RGIC2LGIC_MESSREG_HNI_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+ },
#endif
#if NRD_CHIP_COUNT > 2
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+ {
+ NRD_RGIC2LGIC_MESSREG_HNI_BASE >> 16,
+ (NRD_RGIC2LGIC_MESSREG_HNI_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+ (NRD_RGIC2LGIC_MESSREG_HNI_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+ (NRD_RGIC2LGIC_MESSREG_HNI_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+ },
#endif
#if NRD_CHIP_COUNT > 3
- (PLAT_ARM_GICD_BASE + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+ {
+ NRD_RGIC2LGIC_MESSREG_HNI_BASE >> 16,
+ (NRD_RGIC2LGIC_MESSREG_HNI_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(1)) >> 16,
+ (NRD_RGIC2LGIC_MESSREG_HNI_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(2)) >> 16,
+ (NRD_RGIC2LGIC_MESSREG_HNI_BASE
+ + NRD_REMOTE_CHIP_MEM_OFFSET(3)) >> 16,
+ }
#endif
},
.spi_ids = {
diff --git a/plat/intel/soc/agilex5/bl2_plat_setup.c b/plat/intel/soc/agilex5/bl2_plat_setup.c
index fe5dc6e..f4010f9 100644
--- a/plat/intel/soc/agilex5/bl2_plat_setup.c
+++ b/plat/intel/soc/agilex5/bl2_plat_setup.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2019-2021, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
- * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -31,6 +31,8 @@
#include "nand/nand.h"
#include "qspi/cadence_qspi.h"
#include "sdmmc/sdmmc.h"
+/* TODO: DTB not available */
+// #include "socfpga_dt.h"
#include "socfpga_emac.h"
#include "socfpga_f2sdram_manager.h"
#include "socfpga_handoff.h"
@@ -138,6 +140,12 @@
/* DDR and IOSSM driver init */
agilex5_ddr_init(&reverse_handoff_ptr);
+ /* TODO: DTB not available */
+ // if (socfpga_dt_open_and_check(SOCFPGA_DTB_BASE, DT_COMPATIBLE_STR) < 0) {
+ // ERROR("SOCFPGA: Failed to open device tree\n");
+ // panic();
+ // }
+
if (combo_phy_init(&reverse_handoff_ptr) != 0) {
ERROR("SOCFPGA: Combo Phy initialization failed\n");
}
@@ -165,13 +173,13 @@
switch (boot_source) {
case BOOT_SOURCE_SDMMC:
- NOTICE("SDMMC boot\n");
+ NOTICE("SOCFPGA: SDMMC boot\n");
cdns_mmc_init(¶ms, &mmc_info);
socfpga_io_setup(boot_source, PLAT_SDMMC_DATA_BASE);
break;
case BOOT_SOURCE_QSPI:
- NOTICE("QSPI boot\n");
+ NOTICE("SOCFPGA: QSPI boot\n");
cad_qspi_init(0, QSPI_CONFIG_CPHA, QSPI_CONFIG_CPOL,
QSPI_CONFIG_CSDA, QSPI_CONFIG_CSDADS,
QSPI_CONFIG_CSEOT, QSPI_CONFIG_CSSOT, 0);
@@ -182,13 +190,13 @@
break;
case BOOT_SOURCE_NAND:
- NOTICE("NAND boot\n");
+ NOTICE("SOCFPGA: SOCFPGA: NAND boot\n");
nand_init(&reverse_handoff_ptr);
socfpga_io_setup(boot_source, PLAT_NAND_DATA_BASE);
break;
default:
- ERROR("Unsupported boot source\n");
+ ERROR("SOCFPGA: Unsupported boot source\n");
panic();
break;
}
@@ -230,7 +238,7 @@
ret = socfpga_vab_init(image_id);
if (ret < 0) {
- ERROR("SOCFPGA VAB Authentication failed\n");
+ ERROR("SOCFPGA: VAB Authentication failed\n");
wfi();
}
#endif
diff --git a/plat/intel/soc/agilex5/bl31_plat_setup.c b/plat/intel/soc/agilex5/bl31_plat_setup.c
index 03559e1..17d955a 100644
--- a/plat/intel/soc/agilex5/bl31_plat_setup.c
+++ b/plat/intel/soc/agilex5/bl31_plat_setup.c
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2019-2024, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
- * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -21,6 +21,7 @@
#include "agilex5_cache.h"
#include "agilex5_power_manager.h"
#include "ccu/ncore_ccu.h"
+#include "socfpga_dt.h"
#include "socfpga_mailbox.h"
#include "socfpga_private.h"
#include "socfpga_reset_manager.h"
@@ -146,7 +147,7 @@
PLAT_INTEL_SOCFPGA_G0_IRQ_PROPS(INTR_GROUP0)
};
-static const gicv3_driver_data_t plat_gicv3_gic_data = {
+gicv3_driver_data_t plat_gicv3_gic_data = {
.gicd_base = PLAT_INTEL_SOCFPGA_GICD_BASE,
.gicr_base = PLAT_INTEL_SOCFPGA_GICR_BASE,
.interrupt_props = agx5_interrupt_props,
@@ -162,6 +163,11 @@
{
socfpga_delay_timer_init();
+ /* TODO: DTB not available */
+ // socfpga_dt_populate_gicv3_config(SOCFPGA_DTB_BASE, &plat_gicv3_gic_data);
+ // NOTICE("SOCFPGA: GIC GICD base address 0x%lx\n", plat_gicv3_gic_data.gicd_base);
+ // NOTICE("SOCFPGA: GIC GICR base address 0x%lx\n", plat_gicv3_gic_data.gicr_base);
+
/* Initialize the gic cpu and distributor interfaces */
gicv3_driver_init(&plat_gicv3_gic_data);
gicv3_distif_init();
@@ -192,9 +198,9 @@
cpuid = MPIDR_AFFLVL1_VAL(read_mpidr());
boot_core = ((mmio_read_32(AGX5_PWRMGR(MPU_BOOTCONFIG)) & 0xC00) >> 10);
- NOTICE("BL31: Boot Core = %x\n", boot_core);
- NOTICE("BL31: CPU ID = %x\n", cpuid);
- INFO("BL31: Invalidate Data cache\n");
+ NOTICE("SOCFPGA: Boot Core = %x\n", boot_core);
+ NOTICE("SOCFPGA: CPU ID = %x\n", cpuid);
+ INFO("SOCFPGA: Invalidate Data cache\n");
invalidate_dcache_all();
/* Invalidate for NS EL2 and EL1 */
@@ -282,6 +288,11 @@
mmio_write_32(AGX5_PWRMGR(MPU_PCHCTLR), pch_cpu);
}
+void bl31_plat_runtime_setup(void)
+{
+ console_switch_state(CONSOLE_FLAG_RUNTIME|CONSOLE_FLAG_BOOT);
+}
+
void bl31_plat_enable_mmu(uint32_t flags)
{
/* TODO: Enable mmu when needed */
diff --git a/plat/intel/soc/agilex5/include/socfpga_plat_def.h b/plat/intel/soc/agilex5/include/socfpga_plat_def.h
index 282958a..42d8ccf 100644
--- a/plat/intel/soc/agilex5/include/socfpga_plat_def.h
+++ b/plat/intel/soc/agilex5/include/socfpga_plat_def.h
@@ -1,7 +1,7 @@
/*
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
- * Copyright (c) 2024, Altera Corporation. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -29,6 +29,8 @@
#define PLAT_L2_RESET_REQ 0xB007C0DE
#define PLAT_HANDOFF_OFFSET 0x0007F000
#define PLAT_TIMER_BASE_ADDR 0x10D01000
+#define SOCFPGA_DTB_BASE 0x80020000
+#define DT_COMPATIBLE_STR "arm,altera socfpga-agilex5"
/* System Counter */
/* TODO: Update back to 400MHz.
diff --git a/plat/intel/soc/agilex5/platform.mk b/plat/intel/soc/agilex5/platform.mk
index a831c39..58d4b2e 100644
--- a/plat/intel/soc/agilex5/platform.mk
+++ b/plat/intel/soc/agilex5/platform.mk
@@ -1,11 +1,12 @@
#
# Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2019-2023, Intel Corporation. All rights reserved.
-# Copyright (c) 2024, Altera Corporation. All rights reserved.
+# Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
include lib/xlat_tables_v2/xlat_tables.mk
+include lib/libfdt/libfdt.mk
PLAT_INCLUDES := \
-Iplat/intel/soc/agilex5/include/ \
-Iplat/intel/soc/common/drivers/ \
@@ -22,6 +23,7 @@
PLAT_BL_COMMON_SOURCES := \
${AGX5_GICv3_SOURCES} \
+ common/fdt_wrappers.c \
drivers/cadence/combo_phy/cdns_combo_phy.c \
drivers/cadence/emmc/cdns_sdmmc.c \
drivers/cadence/nand/cdns_nand.c \
@@ -36,7 +38,8 @@
plat/intel/soc/common/drivers/ddr/ddr.c \
plat/intel/soc/common/drivers/nand/nand.c \
plat/intel/soc/common/lib/sha/sha.c \
- plat/intel/soc/common/socfpga_delay_timer.c
+ plat/intel/soc/common/socfpga_delay_timer.c \
+ plat/intel/soc/common/socfpga_dt.c
BL2_SOURCES += \
common/desc_image_load.c \
diff --git a/plat/intel/soc/common/fdts/agilex5_fdt.dts b/plat/intel/soc/common/fdts/agilex5_fdt.dts
new file mode 100644
index 0000000..e16034f
--- /dev/null
+++ b/plat/intel/soc/common/fdts/agilex5_fdt.dts
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2019-2024, Intel Corporation. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/dts-v1/;
+
+/ {
+ model = "ALTERA SOCFPGA AGILEX5";
+ compatible = "arm,altera socfpga-agilex5";
+ owner = "jit.loon.lim@intel.com";
+ interrupt-parent = <&gic>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ psci {
+ compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci";
+ method = "smc";
+
+ cpu_on = <0xdeadc0de>;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ enable-method = "psci";
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <0>;
+ };
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <1>;
+ };
+ cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <2>;
+ };
+ cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a5";
+ reg = <3>;
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ reg = <0x80000000 0x90000000>;
+ };
+
+ gic: interrupt-controller@2c010000 {
+ compatible = "arm,gic-600", "arm,gic-v3";
+ #address-cells = <2>;
+ #interrupt-cells = <3>;
+ #size-cells = <1>;
+ #ranges;
+ interrupt-controller;
+ reg = <0x1D000000 0>, /* GICD */
+ <0x1D060000 0>; /* GICR */
+ interrupts = <0x1 0x9 0x4>;
+ };
+
+ serial0: uart@1a200000 {
+ compatible = "arm,console-16550";
+ reg = <0x10C02000 0x1000>;
+ interrupt-parent = <&gic>;
+ interrupts = <0 8 0xf04>;
+ clock-frequency = <100000000>;
+ uart-baudrate = <115200>;
+ };
+
+ timer0: timer@1a040000 {
+ compatible = "arm,armv7-timer-mem";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+ reg = <0x1a040000 0x1000>;
+ clock-frequency = <7500000>;
+
+ frame@1a050000 {
+ frame-number = <0>;
+ interrupts = <0 2 0xf04>;
+ reg = <0x1a050000 0x1000>;
+ };
+ };
+
+};
diff --git a/plat/intel/soc/common/include/socfpga_dt.h b/plat/intel/soc/common/include/socfpga_dt.h
new file mode 100644
index 0000000..3ff4cb7
--- /dev/null
+++ b/plat/intel/soc/common/include/socfpga_dt.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SOCFPGA_DT_H
+#define SOCFPGA_DT_H
+
+
+#include <stdlib.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/delay_timer.h>
+/*
+ * This macro takes three arguments:
+ * config: Configuration identifier
+ * name: property namespace
+ * callback: populate() function
+ */
+#define SOCFPGA_REGISTER_POPULATOR(config, name, callback) \
+ __section(".socfpga_populator") __used \
+ static const struct socfpga_populator (name##__populator) = { \
+ .config_type = (#config), \
+ .info = (#name), \
+ .populate = (callback) \
+ }
+
+/*
+ * Populator callback
+ *
+ * This structure are used by the fconf_populate function and should only be
+ * defined by the SOCFPGA_REGISTER_POPULATOR macro.
+ */
+struct socfpga_populator {
+ /* Description of the data loaded by the callback */
+ const char *config_type;
+ const char *info;
+
+ /* Callback used by fconf_populate function with a provided config dtb.
+ * Return 0 on success, err_code < 0 otherwise.
+ */
+ int (*populate)(uintptr_t config);
+};
+
+/* Hardware Config related getter */
+#define hw_config__gicv3_config_getter(prop) plat_gicv3_gic_data.prop
+
+/* Function Definitions */
+int socfpga_dt_open_and_check(uintptr_t dt_addr, char *compatible_str);
+int socfpga_dt_populate_gicv3_config(uintptr_t dt_addr, gicv3_driver_data_t *plat_driver_data);
+int socfpga_dt_populate_dram_layout(uintptr_t dt_addr);
+
+#endif
diff --git a/plat/intel/soc/common/socfpga_dt.c b/plat/intel/soc/common/socfpga_dt.c
new file mode 100644
index 0000000..0333b9b
--- /dev/null
+++ b/plat/intel/soc/common/socfpga_dt.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2024-2025, Altera Corporation. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <common/fdt_wrappers.h>
+#include <common/tbbr/tbbr_img_def.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <libfdt.h>
+#include <platform_def.h>
+#include <tools_share/firmware_image_package.h>
+
+#include "socfpga_dt.h"
+
+static const void *fdt;
+/*******************************************************************************
+ * This function checks device tree file with its header.
+ * Returns 0 on success and a negative FDT error code on failure.
+ ******************************************************************************/
+int socfpga_dt_open_and_check(uintptr_t dt_addr, char *compatible_str)
+{
+ int ret = 0;
+ int node = 1;
+
+ ret = fdt_check_header((void *)dt_addr);
+
+ if (ret != 0) {
+ ERROR("SOCFPGA: FDT Header invalid\n");
+ return ret;
+ }
+
+ fdt = (const void *)dt_addr;
+
+ /* As libfdt use void *, we can't avoid this cast */
+ const void *dtb = (void *)dt_addr;
+
+ /* Assert the node offset point to compatible property */
+ node = fdt_node_offset_by_compatible(dtb, -1, compatible_str);
+ if (node < 0) {
+ ERROR("SOCFPGA: Can't find `%s` compatible in dtb\n",
+ compatible_str);
+ return node;
+ }
+
+ NOTICE("SOCFPGA: Successfully open and check FDT\n");
+
+ return ret;
+}
+
+int socfpga_dt_populate_gicv3_config(uintptr_t dt_addr, gicv3_driver_data_t *plat_driver_data)
+{
+ int err;
+ int node;
+ uintptr_t addr;
+
+ /* Necessary to work with libfdt APIs */
+ const void *hw_config_dtb = (const void *)dt_addr;
+ /*
+ * Find the offset of the node containing "arm,gic-v3" compatible property.
+ * Populating fconf strucutures dynamically is not supported for legacy
+ * systems which use GICv2 IP. Simply skip extracting GIC properties.
+ */
+ node = fdt_node_offset_by_compatible(hw_config_dtb, -1, "arm,gic-v3");
+ if (node < 0) {
+ ERROR("SOCFPGA: Unable to locate node with arm,gic-v3 compatible property\n");
+ return 0;
+ }
+ /* The GICv3 DT binding holds at least two address/size pairs,
+ * the first describing the distributor, the second the redistributors.
+ * See: bindings/interrupt-controller/arm,gic-v3.yaml
+ */
+ err = fdt_get_reg_props_by_index(hw_config_dtb, node, 0, &addr, NULL);
+ if (err < 0) {
+ ERROR("SOCFPGA: Failed to read GICD reg property of GIC node\n");
+ } else {
+ plat_driver_data->gicd_base = addr;
+ }
+
+ err = fdt_get_reg_props_by_index(hw_config_dtb, node, 1, &addr, NULL);
+ if (err < 0) {
+ ERROR("SOCFPGA: Failed to read GICR reg property of GIC node\n");
+ } else {
+ plat_driver_data->gicr_base = addr;
+ }
+ return err;
+}
+
+int socfpga_dt_populate_dram_layout(uintptr_t dt_addr)
+{
+ int node;
+ uintptr_t addr;
+ size_t size;
+
+ /* Necessary to work with libfdt APIs */
+ const void *hw_config_dtb = (const void *)dt_addr;
+
+ /* Find 'memory' node */
+ node = fdt_node_offset_by_prop_value(hw_config_dtb, -1, "device_type",
+ "memory", sizeof("memory"));
+ if (node < 0) {
+ NOTICE("SOCFPGA: Unable to locate 'memory' node\n");
+ return node;
+ }
+
+ int err = fdt_get_reg_props_by_index(
+ hw_config_dtb, node, 0,
+ &addr, (size_t *)&size);
+
+ NOTICE("SOCFPGA: Mem base 0x%lx, Mem size 0x%lx\n", addr, size);
+ if (err < 0) {
+ ERROR("SOCFPGA: Failed to read 'reg' property of 'memory' node\n");
+ return err;
+ }
+
+ return 0;
+}
diff --git a/plat/rockchip/common/params_setup.c b/plat/rockchip/common/params_setup.c
index 68054ad..a27c755 100644
--- a/plat/rockchip/common/params_setup.c
+++ b/plat/rockchip/common/params_setup.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2016-2025, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -37,7 +37,7 @@
static uint32_t rk_uart_base = PLAT_RK_UART_BASE;
static uint32_t rk_uart_baudrate = PLAT_RK_UART_BAUDRATE;
static uint32_t rk_uart_clock = PLAT_RK_UART_CLOCK;
-#define FDT_BUFFER_SIZE 0x20000
+#define FDT_BUFFER_SIZE 0x60000
static uint64_t fdt_buffer[FDT_BUFFER_SIZE / 8];
void *plat_get_fdt(void)
diff --git a/plat/rockchip/rk3399/rk3399_def.h b/plat/rockchip/rk3399/rk3399_def.h
index ba83242..8d6ecfb 100644
--- a/plat/rockchip/rk3399/rk3399_def.h
+++ b/plat/rockchip/rk3399/rk3399_def.h
@@ -17,7 +17,7 @@
/**************************************************************************
* UART related constants
**************************************************************************/
-#define RK3399_BAUDRATE 115200
+#define RK3399_BAUDRATE 1500000
#define RK3399_UART_CLOCK 24000000
/******************************************************************************
diff --git a/plat/xilinx/common/include/pm_node.h b/plat/xilinx/common/include/pm_node.h
index 46f6bcf..3ee55c2 100644
--- a/plat/xilinx/common/include/pm_node.h
+++ b/plat/xilinx/common/include/pm_node.h
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2019, Xilinx, Inc. All rights reserved.
- * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ * Copyright (c) 2022-2025, Advanced Micro Devices, Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -132,6 +132,18 @@
XPM_NODEIDX_DEV_TTC_2 = 0x26,
XPM_NODEIDX_DEV_TTC_3 = 0x27,
XPM_NODEIDX_DEV_SWDT_LPD = 0x28,
+ XPM_NODEIDX_DEV_I2C_2 = 0x117,
+ XPM_NODEIDX_DEV_I2C_3 = 0x118,
+ XPM_NODEIDX_DEV_I2C_4 = 0x119,
+ XPM_NODEIDX_DEV_I2C_5 = 0x11A,
+ XPM_NODEIDX_DEV_I2C_6 = 0x11B,
+ XPM_NODEIDX_DEV_I2C_7 = 0x11C,
+ XPM_NODEIDX_DEV_CAN_FD_2 = 0x11D,
+ XPM_NODEIDX_DEV_CAN_FD_3 = 0x11E,
+ XPM_NODEIDX_DEV_TTC_4 = 0x11F,
+ XPM_NODEIDX_DEV_TTC_5 = 0x120,
+ XPM_NODEIDX_DEV_TTC_6 = 0x121,
+ XPM_NODEIDX_DEV_TTC_7 = 0x122,
/* FPD Peripheral devices */
XPM_NODEIDX_DEV_SWDT_FPD = 0x29,
@@ -237,6 +249,11 @@
XPM_NODEIDX_DEV_FPD_SWDT_2 = 0xDD,
XPM_NODEIDX_DEV_FPD_SWDT_3 = 0xDE,
#endif
+
+#if defined(PLAT_versal2)
+ XPM_NODEIDX_DEV_USB_1 = 0xD7,
+#endif
+
XPM_NODEIDX_DEV_MAX,
};