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(&params, &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,
 };