feat(versal2): add support for AMD Versal Gen 2 platform

New SoC is a78 based with gicv3 and uart over pl011. Communication
interfaces are similar to Versal NET platform. System starts with AMD PLM
firmware which loads TF-A(bl31) to memory, which is already configured, and
jumps to it. PLM also prepare handoff structure for TF-A with information
what components were load and flags which indicate which EL level SW should
be started.

Change-Id: I5065b1b7ec4ee58e77dc4096747758480c84009c
Signed-off-by: Amit Nagal <amit.nagal@amd.com>
Signed-off-by: Akshay Belsare <akshay.belsare@amd.com>
Signed-off-by: Michal Simek <michal.simek@amd.com>
diff --git a/changelog.yaml b/changelog.yaml
index 6f2458e..101aa48 100644
--- a/changelog.yaml
+++ b/changelog.yaml
@@ -674,6 +674,13 @@
               - plat/zynqmp
               - plat/xilinx/zynqmp
 
+      - title: AMD
+        scope: amd
+
+        subsections:
+          - title: Versal Gen 2
+            scope: versal2
+
       - title: Nuvoton
         scope: nuvoton
 
diff --git a/docs/plat/amd-versal2.rst b/docs/plat/amd-versal2.rst
new file mode 100644
index 0000000..876ab3c
--- /dev/null
+++ b/docs/plat/amd-versal2.rst
@@ -0,0 +1,87 @@
+AMD Versal Gen 2
+================
+
+Trusted Firmware-A implements the EL3 firmware layer for AMD Versal Gen 2.
+The platform only uses the runtime part of TF-A as AMD Versal Gen 2 already
+has a BootROM (BL1) and PMC FW (BL2).
+
+BL31 is TF-A.
+BL32 is an optional Secure Payload.
+BL33 is the non-secure world software (U-Boot, Linux etc).
+
+To build:
+```bash
+make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal2 bl31
+```
+
+To build TF-A for JTAG DCC console:
+```bash
+make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal2 CONSOLE=dcc bl31
+```
+
+To build TF-A with Errata management interface
+```bash
+make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal2 bl31 ERRATA_ABI_SUPPORT=1
+```
+
+To build TF-A with IPI CRC check:
+```bash
+make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal2 bl31 IPI_CRC_CHECK=1
+```
+
+AMD Versal Gen 2 platform specific build options
+-------------------------------------------------
+
+*   `MEM_BASE`: Specifies the base address of the bl31 binary.
+*   `MEM_SIZE`: Specifies the size of the memory region of the bl31 binary.
+*   `BL32_MEM_BASE`: Specifies the base address of the bl32 binary.
+*   `BL32_MEM_SIZE`: Specifies the size of the memory region of the bl32 binary.
+
+*   `CONSOLE`: Select the console driver. Options:
+    -   `pl011`, `pl011_0`: ARM pl011 UART 0 (default)
+    -   `pl011_1`         : ARM pl011 UART 1
+    -   `dcc`             : JTAG Debug Communication Channel(DCC)
+
+
+Reference DEN0028E SMC calling convention
+------------------------------------------
+
+Allocated subranges of Function Identifier to SIP services
+------------------------------------------------------------
+
++-----------------------+-------------------------------------------------------+
+|    SMC Function       | Identifier Service type                               |
++-----------------------+-------------------------------------------------------+
+| 0xC2000000-0xC200FFFF | Fast SMC64 SiP Service Calls as per SMCCC Section 6.1 |
++-----------------------+-------------------------------------------------------+
+
+IPI SMC call ranges
+-------------------
+
++---------------------------+-----------------------------------------------------------+
+| SMC Function Identifier   | Service type                                              |
++---------------------------+-----------------------------------------------------------+
+| 0xc2001000-0xc2001FFF     | Fast SMC64 SiP Service call range used for AMD-Xilinx IPI |
++---------------------------+-----------------------------------------------------------+
+
+PM SMC call ranges
+------------------
+
++---------------------------+---------------------------------------------------------------------------+
+| SMC Function Identifier   |  Service type                                                             |
++---------------------------+---------------------------------------------------------------------------+
+| 0xc2000000-0xc2000FFF     | Fast SMC64 SiP Service call range used for AMD-Xilinx Platform Management |
++---------------------------+---------------------------------------------------------------------------+
+
+SMC function IDs for SiP Service queries
+----------------------------------------
+
++--------------+--------------+--------------+
+|  Service     | Call UID     | Revision     |
++--------------+--------------+--------------+
+|  SiP Service | 0x8200_FF01  | 0x8200_FF03  |
++--------------+--------------+--------------+
+
+Call UID Query – Returns a unique identifier of the service provider.
+
+Revision Query – Returns revision details of the service implementor.
diff --git a/docs/plat/index.rst b/docs/plat/index.rst
index 5c1ded0..85c97e5 100644
--- a/docs/plat/index.rst
+++ b/docs/plat/index.rst
@@ -7,6 +7,7 @@
    :hidden:
 
    allwinner
+   amd-versal2
    arm/index
    ast2700
    meson-axg
diff --git a/plat/amd/versal2/aarch64/common.c b/plat/amd/versal2/aarch64/common.c
new file mode 100644
index 0000000..3ab3dca
--- /dev/null
+++ b/plat/amd/versal2/aarch64/common.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2021-2022, 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.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+
+#include <def.h>
+#include <plat_common.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+
+uint32_t platform_id, platform_version;
+
+/*
+ * Table of regions to map using the MMU.
+ * This doesn't include TZRAM as the 'mem_layout' argument passed to
+ * configure_mmu_elx() will give the available subset of that,
+ */
+const mmap_region_t plat_mmap[] = {
+	MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(DEVICE2_BASE, DEVICE2_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(CRF_BASE, CRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(IPI_BASE, IPI_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+#if defined(TRANSFER_LIST)
+	MAP_REGION_FLAT(FW_HANDOFF_BASE, FW_HANDOFF_BASE + FW_HANDOFF_SIZE,
+			MT_MEMORY | MT_RW | MT_NS),
+#endif
+	{ 0 }
+};
+
+const mmap_region_t *plat_get_mmap(void)
+{
+	return plat_mmap;
+}
+
+/* For saving cpu clock for certain platform */
+uint32_t cpu_clock;
+
+const char *board_name_decode(void)
+{
+	const char *platform;
+
+	switch (platform_id) {
+	case SPP:
+		platform = "IPP";
+		break;
+	case EMU:
+		platform = "EMU";
+		break;
+	case SILICON:
+		platform = "Silicon";
+		break;
+	case QEMU:
+		platform = "QEMU";
+		break;
+	default:
+		platform = "Unknown";
+	}
+
+	return platform;
+}
+
+void board_detection(void)
+{
+	uint32_t version;
+
+	version = mmio_read_32(PMC_TAP_VERSION);
+	platform_id = FIELD_GET(PLATFORM_MASK, version);
+	platform_version = FIELD_GET(PLATFORM_VERSION_MASK, version);
+
+	if (platform_id == QEMU_COSIM) {
+		platform_id = QEMU;
+	}
+
+	/* Make sure that console is setup to see this message */
+	VERBOSE("Platform id: %d version: %d.%d\n", platform_id,
+		platform_version / 10U, platform_version % 10U);
+}
+
+uint32_t get_uart_clk(void)
+{
+	uint32_t uart_clock = 0;
+
+	switch (platform_id) {
+	case SPP:
+	case SPP_MMD:
+		uart_clock = cpu_clock;
+		break;
+	case EMU:
+	case EMU_MMD:
+		uart_clock = 25000000;
+		break;
+	case QEMU:
+		/* Random values now */
+		uart_clock = 25000000;
+		break;
+	case SILICON:
+		uart_clock = 100000000;
+		break;
+	default:
+		panic();
+	}
+
+	return uart_clock;
+}
+
+void config_setup(void)
+{
+	uint32_t val;
+	uintptr_t crl_base, iou_scntrs_base, psx_base;
+
+	crl_base = CRL;
+	iou_scntrs_base = IOU_SCNTRS;
+	psx_base = PSX_CRF;
+
+	/* Reset for system timestamp generator in FPX */
+	mmio_write_32(psx_base + PSX_CRF_RST_TIMESTAMP_OFFSET, 0);
+
+	/* Global timer init - Program time stamp reference clk */
+	val = mmio_read_32(crl_base + CRL_TIMESTAMP_REF_CTRL_OFFSET);
+	val |= CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT;
+	mmio_write_32(crl_base + CRL_TIMESTAMP_REF_CTRL_OFFSET, val);
+
+	/* Clear reset of timestamp reg */
+	mmio_write_32(crl_base + CRL_RST_TIMESTAMP_OFFSET, 0);
+
+	/* Program freq register in System counter and enable system counter. */
+	mmio_write_32(iou_scntrs_base + IOU_SCNTRS_BASE_FREQ_OFFSET,
+		      cpu_clock);
+	mmio_write_32(iou_scntrs_base + IOU_SCNTRS_COUNTER_CONTROL_REG_OFFSET,
+		      IOU_SCNTRS_CONTROL_EN);
+
+	generic_delay_timer_init();
+
+	/* Configure IPI data */
+	soc_ipi_config_table_init();
+}
+
+uint32_t plat_get_syscnt_freq2(void)
+{
+	return cpu_clock;
+}
diff --git a/plat/amd/versal2/aarch64/helpers.S b/plat/amd/versal2/aarch64/helpers.S
new file mode 100644
index 0000000..580bb76
--- /dev/null
+++ b/plat/amd/versal2/aarch64/helpers.S
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018-2021, 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.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/gicv3.h>
+
+#include <platform_def.h>
+
+	.globl	plat_secondary_cold_boot_setup
+	.globl	plat_is_my_cpu_primary
+	.globl	platform_mem_init
+	.globl	plat_my_core_pos
+
+	/* -----------------------------------------------------
+	 * void plat_secondary_cold_boot_setup (void);
+	 *
+	 * This function performs any platform specific actions
+	 * needed for a secondary cpu after a cold reset e.g
+	 * mark the cpu's presence, mechanism to place it in a
+	 * holding pen etc.
+	 * TODO: Should we read the PSYS register to make sure
+	 * that the request has gone through.
+	 * -----------------------------------------------------
+	 */
+func plat_secondary_cold_boot_setup
+	mrs	x0, mpidr_el1
+
+	/*
+	 * There is no sane reason to come out of this wfi. This
+	 * cpu will be powered on and reset by the cpu_on pm api
+	 */
+	dsb	sy
+	bl	plat_panic_handler
+endfunc plat_secondary_cold_boot_setup
+
+func plat_is_my_cpu_primary
+	mov	x9, x30
+	bl	plat_my_core_pos
+	cmp	x0, #PRIMARY_CPU
+	cset	x0, eq
+	ret	x9
+endfunc plat_is_my_cpu_primary
+
+	/* -----------------------------------------------------
+	 *  unsigned int plat_my_core_pos(void)
+	 *  This function uses the plat_core_pos_by_mpidr()
+	 *  definition to get the index of the calling CPU.
+	 * -----------------------------------------------------
+	 */
+func plat_my_core_pos
+	mrs	x0, mpidr_el1
+	b	plat_core_pos_by_mpidr
+endfunc plat_my_core_pos
+
+	/* ---------------------------------------------------------------------
+	 * We don't need to carry out any memory initialization on platform
+	 * The Secure RAM is accessible straight away.
+	 * ---------------------------------------------------------------------
+	 */
+func platform_mem_init
+	ret
+endfunc platform_mem_init
diff --git a/plat/amd/versal2/bl31_setup.c b/plat/amd/versal2/bl31_setup.c
new file mode 100644
index 0000000..e878863
--- /dev/null
+++ b/plat/amd/versal2/bl31_setup.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2018-2020, 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.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/dcc.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <lib/cpus/cpu_ops.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <plat_arm.h>
+#include <scmi.h>
+
+#include <def.h>
+#include <plat_fdt.h>
+#include <plat_private.h>
+#include <plat_startup.h>
+#include <pm_api_sys.h>
+#include <pm_client.h>
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/*
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ */
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+	assert(sec_state_is_valid(type));
+
+	if (type == NON_SECURE) {
+		return &bl33_image_ep_info;
+	}
+
+	return &bl32_image_ep_info;
+}
+
+/*
+ * Set the build time defaults,if we can't find any config data.
+ */
+static inline void bl31_set_default_config(void)
+{
+	bl32_image_ep_info.pc = BL32_BASE;
+	bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry();
+#if defined(SPD_opteed)
+	/* NS dtb addr passed to optee_os */
+	bl32_image_ep_info.args.arg3 = XILINX_OF_BOARD_DTB_ADDR;
+#endif
+	bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+	bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+					  DISABLE_ALL_EXCEPTIONS);
+}
+
+/*
+ * Perform any BL31 specific platform actions. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they
+ * are lost (potentially). This needs to be done before the MMU is initialized
+ * so that the memory layout can be used while creating page tables.
+ */
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+				u_register_t arg2, u_register_t arg3)
+{
+	uint32_t uart_clock;
+	int32_t rc;
+
+	board_detection();
+
+	/* FIXME */
+	switch (platform_id) {
+	case SPP:
+		switch (platform_version) {
+		case SPP_PSXC_MMI_V2_0:
+			cpu_clock = 770000;
+			break;
+		case SPP_PSXC_MMI_V3_0:
+			cpu_clock = 908000;
+			break;
+		default:
+			panic();
+		}
+		break;
+	case SPP_MMD:
+		switch (platform_version) {
+		case SPP_PSXC_ISP_AIE_V2_0:
+		case SPP_PSXC_MMD_AIE_FRZ_EA:
+		case SPP_PSXC_MMD_AIE_V3_0:
+			cpu_clock = 760000;
+			break;
+		default:
+			panic();
+		}
+		break;
+	case EMU:
+	case EMU_MMD:
+		cpu_clock = 112203;
+		break;
+	case QEMU:
+		/* Random values now */
+		cpu_clock = 3333333;
+		break;
+	case SILICON:
+		cpu_clock = 100000000;
+		break;
+	default:
+		panic();
+	}
+
+	uart_clock = get_uart_clk();
+
+	if (CONSOLE_IS(pl011_0) || CONSOLE_IS(pl011_1)) {
+		static console_t _runtime_console;
+
+		/* Initialize the console to provide early debug support */
+		rc = console_pl011_register(UART_BASE, uart_clock,
+					    UART_BAUDRATE,
+					    &_runtime_console);
+		if (rc == 0) {
+			panic();
+		}
+
+		console_set_scope(&_runtime_console, CONSOLE_FLAG_BOOT |
+				  CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH);
+	} else if (CONSOLE_IS(dcc)) {
+		/* Initialize the dcc console for debug.
+		 * dcc is over jtag and does not configures uart0 or uart1.
+		 */
+		rc = console_dcc_register();
+		if (rc == 0) {
+			panic();
+		}
+	} else {
+		/* Making MISRA C 2012 15.7 compliant */
+	}
+
+	NOTICE("TF-A running on %s %d.%d\n", board_name_decode(),
+	       platform_version / 10U, platform_version % 10U);
+
+	/* Initialize the platform config for future decision making */
+	config_setup();
+
+	/*
+	 * Do initial security configuration to allow DRAM/device access. On
+	 * Base only DRAM security is programmable (via TrustZone), but
+	 * other platforms might have more programmable security devices
+	 * present.
+	 */
+
+	/* Populate common information for BL32 and BL33 */
+	SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
+	SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+	SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0);
+	SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+	bl31_set_default_config();
+
+	long rev_var = cpu_get_rev_var();
+
+	INFO("CPU Revision = 0x%lx\n", rev_var);
+	INFO("cpu_clock = %dHz, uart_clock = %dHz\n", cpu_clock, uart_clock);
+	NOTICE("BL31: Executing from 0x%x\n", BL31_BASE);
+	NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc);
+	NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc);
+
+}
+
+static versal_intr_info_type_el3_t type_el3_interrupt_table[MAX_INTR_EL3];
+
+int request_intr_type_el3(uint32_t id, interrupt_type_handler_t handler)
+{
+	static uint32_t index;
+	uint32_t i;
+
+	/* Validate 'handler' and 'id' parameters */
+	if (handler == NULL || index >= MAX_INTR_EL3) {
+		return -EINVAL;
+	}
+
+	/* Check if a handler has already been registered */
+	for (i = 0; i < index; i++) {
+		if (id == type_el3_interrupt_table[i].id) {
+			return -EALREADY;
+		}
+	}
+
+	type_el3_interrupt_table[index].id = id;
+	type_el3_interrupt_table[index].handler = handler;
+
+	index++;
+
+	return 0;
+}
+
+static uint64_t rdo_el3_interrupt_handler(uint32_t id, uint32_t flags,
+					  void *handle, void *cookie)
+{
+	uint32_t intr_id;
+	uint32_t i;
+	interrupt_type_handler_t handler = NULL;
+
+	intr_id = plat_ic_get_pending_interrupt_id();
+
+	for (i = 0; i < MAX_INTR_EL3; i++) {
+		if (intr_id == type_el3_interrupt_table[i].id) {
+			handler = type_el3_interrupt_table[i].handler;
+		}
+	}
+
+	if (handler != NULL) {
+		(void)handler(intr_id, flags, handle, cookie);
+	}
+
+	return 0;
+}
+
+void bl31_platform_setup(void)
+{
+	prepare_dtb();
+
+	/* Initialize the gic cpu and distributor interfaces */
+	plat_gic_driver_init();
+	plat_gic_init();
+
+	if (platform_id != EMU) {
+		init_scmi_server();
+	}
+}
+
+void bl31_plat_runtime_setup(void)
+{
+	uint64_t flags = 0;
+	int32_t rc;
+
+	set_interrupt_rm_flag(flags, NON_SECURE);
+	rc = register_interrupt_type_handler(INTR_TYPE_EL3,
+					     rdo_el3_interrupt_handler, flags);
+	if (rc != 0) {
+		panic();
+	}
+}
+
+/*
+ * Perform the very early platform specific architectural setup here.
+ */
+void bl31_plat_arch_setup(void)
+{
+	const mmap_region_t bl_regions[] = {
+#if (defined(XILINX_OF_BOARD_DTB_ADDR) && !IS_TFA_IN_OCM(BL31_BASE))
+		MAP_REGION_FLAT(XILINX_OF_BOARD_DTB_ADDR, XILINX_OF_BOARD_DTB_MAX_SIZE,
+				MT_MEMORY | MT_RW | MT_NS),
+#endif
+		MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE,
+			MT_MEMORY | MT_RW | MT_SECURE),
+		MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE,
+				MT_CODE | MT_SECURE),
+		MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE,
+				MT_RO_DATA | MT_SECURE),
+		MAP_REGION_FLAT(SMT_BUFFER_BASE, 0x1000,
+			MT_DEVICE | MT_RW | MT_NON_CACHEABLE | MT_EXECUTE_NEVER | MT_NS),
+		{0}
+	};
+
+	setup_page_tables(bl_regions, plat_get_mmap());
+	enable_mmu(0);
+}
diff --git a/plat/amd/versal2/gicv3.c b/plat/amd/versal2/gicv3.c
new file mode 100644
index 0000000..c7b44e1
--- /dev/null
+++ b/plat/amd/versal2/gicv3.c
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include <plat_private.h>
+
+/******************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way the GICv3 driver is initialised and used.
+ *****************************************************************************/
+#pragma weak plat_gic_driver_init
+#pragma weak plat_gic_init
+#pragma weak plat_gic_cpuif_enable
+#pragma weak plat_gic_cpuif_disable
+#pragma weak plat_gic_pcpu_init
+#pragma weak plat_gic_redistif_on
+#pragma weak plat_gic_redistif_off
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const interrupt_prop_t _interrupt_props[] = {
+	PLAT_G1S_IRQ_PROPS(INTR_GROUP1S),
+	PLAT_G0_IRQ_PROPS(INTR_GROUP0)
+};
+
+/*
+ * We save and restore the GICv3 context on system suspend. Allocate the
+ * data in the designated EL3 Secure carve-out memory.
+ */
+static gicv3_redist_ctx_t rdist_ctx __section("._el3_tzc_dram");
+static gicv3_dist_ctx_t dist_ctx __section("._el3_tzc_dram");
+
+/*
+ * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register
+ * to core position.
+ *
+ * Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity
+ * values read from GICR_TYPER don't have an MT field. To reuse the same
+ * translation used for CPUs, we insert MT bit read from the PE's MPIDR into
+ * that read from GICR_TYPER.
+ *
+ * Assumptions:
+ *
+ *   - All CPUs implemented in the system have MPIDR_EL1.MT bit set;
+ *   - No CPUs implemented in the system use affinity level 3.
+ */
+static uint32_t _gicv3_mpidr_hash(u_register_t mpidr)
+{
+	mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
+	return plat_core_pos_by_mpidr(mpidr);
+}
+
+static const gicv3_driver_data_t _gic_data __unused = {
+	.gicd_base = PLAT_GICD_BASE_VALUE,
+	.gicr_base = PLAT_GICR_BASE_VALUE,
+	.interrupt_props = _interrupt_props,
+	.interrupt_props_num = ARRAY_SIZE(_interrupt_props),
+	.rdistif_num = PLATFORM_CORE_COUNT,
+	.rdistif_base_addrs = rdistif_base_addrs,
+	.mpidr_to_core_pos = _gicv3_mpidr_hash
+};
+
+void __init plat_gic_driver_init(void)
+{
+	/*
+	 * The GICv3 driver is initialized in EL3 and does not need
+	 * to be initialized again in SEL1. This is because the S-EL1
+	 * can use GIC system registers to manage interrupts and does
+	 * not need GIC interface base addresses to be configured.
+	 */
+#if IMAGE_BL31
+	gicv3_driver_init(&_gic_data);
+#endif
+}
+
+/******************************************************************************
+ * common helper to initialize the GIC. Only invoked by BL31
+ *****************************************************************************/
+void __init plat_gic_init(void)
+{
+	gicv3_distif_init();
+	gicv3_rdistif_init(plat_my_core_pos());
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * common helper to enable the GIC CPU interface
+ *****************************************************************************/
+void plat_gic_cpuif_enable(void)
+{
+	gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * common helper to disable the GIC CPU interface
+ *****************************************************************************/
+void plat_gic_cpuif_disable(void)
+{
+	gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * common helper to initialize the per-cpu redistributor interface in GICv3
+ *****************************************************************************/
+void plat_gic_pcpu_init(void)
+{
+	gicv3_rdistif_init(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * common helpers to power GIC redistributor interface
+ *****************************************************************************/
+void plat_gic_redistif_on(void)
+{
+	gicv3_rdistif_on(plat_my_core_pos());
+}
+
+void plat_gic_redistif_off(void)
+{
+	gicv3_rdistif_off(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * common helper to save & restore the GICv3 on resume from system suspend
+ *****************************************************************************/
+void plat_gic_save(void)
+{
+	/*
+	 * If an ITS is available, save its context before
+	 * the Redistributor using:
+	 * gicv3_its_save_disable(gits_base, &its_ctx[i])
+	 * Additionnaly, an implementation-defined sequence may
+	 * be required to save the whole ITS state.
+	 */
+
+	/*
+	 * Save the GIC Redistributors and ITS contexts before the
+	 * Distributor context. As we only handle SYSTEM SUSPEND API,
+	 * we only need to save the context of the CPU that is issuing
+	 * the SYSTEM SUSPEND call, i.e. the current CPU.
+	 */
+	gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx);
+
+	/* Save the GIC Distributor context */
+	gicv3_distif_save(&dist_ctx);
+
+	/*
+	 * From here, all the components of the GIC can be safely powered down
+	 * as long as there is an alternate way to handle wakeup interrupt
+	 * sources.
+	 */
+}
+
+void plat_gic_resume(void)
+{
+	/* Restore the GIC Distributor context */
+	gicv3_distif_init_restore(&dist_ctx);
+
+	/*
+	 * Restore the GIC Redistributor and ITS contexts after the
+	 * Distributor context. As we only handle SYSTEM SUSPEND API,
+	 * we only need to restore the context of the CPU that issued
+	 * the SYSTEM SUSPEND call.
+	 */
+	gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx);
+
+	/*
+	 * If an ITS is available, restore its context after
+	 * the Redistributor using:
+	 * gicv3_its_restore(gits_base, &its_ctx[i])
+	 * An implementation-defined sequence may be required to
+	 * restore the whole ITS state. The ITS must also be
+	 * re-enabled after this sequence has been executed.
+	 */
+}
diff --git a/plat/amd/versal2/include/def.h b/plat/amd/versal2/include/def.h
new file mode 100644
index 0000000..a8cbaaf
--- /dev/null
+++ b/plat/amd/versal2/include/def.h
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2022, 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.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DEF_H
+#define DEF_H
+
+#include <plat/arm/common/smccc_def.h>
+#include <plat/common/common_def.h>
+
+#define MAX_INTR_EL3			2
+
+/* List all consoles */
+#define CONSOLE_ID_pl011	U(1)
+#define CONSOLE_ID_pl011_0	U(1)
+#define CONSOLE_ID_pl011_1	U(2)
+#define CONSOLE_ID_dcc	U(3)
+
+#define CONSOLE_IS(con)	(CONSOLE_ID_ ## con == CONSOLE)
+
+/* List all platforms */
+#define SILICON		U(0)
+#define SPP			U(1)
+#define EMU			U(2)
+#define QEMU			U(3)
+#define SPP_MMD			U(5)
+#define EMU_MMD			U(6)
+#define QEMU_COSIM		U(7)
+
+/* For platform detection */
+#define PMC_TAP				U(0xF11A0000)
+#define PMC_TAP_VERSION			(PMC_TAP + 0x4U)
+# define PLATFORM_MASK			GENMASK(27U, 24U)
+# define PLATFORM_VERSION_MASK		GENMASK(31U, 28U)
+
+/* Global timer reset */
+#define PSX_CRF			U(0xEC200000)
+#define ACPU0_CLK_CTRL		U(0x10C)
+#define ACPU_CLK_CTRL_CLKACT	BIT(25)
+
+#define RST_APU0_OFFSET		U(0x300)
+#define RST_APU_COLD_RESET	BIT(0)
+#define RST_APU_WARN_RESET	BIT(4)
+#define RST_APU_CLUSTER_COLD_RESET	BIT(8)
+#define RST_APU_CLUSTER_WARM_RESET	BIT(9)
+
+#define PSX_CRF_RST_TIMESTAMP_OFFSET	U(0x33C)
+
+#define APU_PCLI			(0xECB10000ULL)
+#define APU_PCLI_CPU_STEP		(0x30ULL)
+#define APU_PCLI_CLUSTER_CPU_STEP	(4ULL * APU_PCLI_CPU_STEP)
+#define APU_PCLI_CLUSTER_OFFSET		U(0x8000)
+#define APU_PCLI_CLUSTER_STEP		U(0x1000)
+#define PCLI_PREQ_OFFSET		U(0x4)
+#define PREQ_CHANGE_REQUEST		BIT(0)
+#define PCLI_PSTATE_OFFSET		U(0x8)
+#define PCLI_PSTATE_VAL_SET		U(0x48)
+#define PCLI_PSTATE_VAL_CLEAR		U(0x38)
+
+/* Firmware Image Package */
+#define PRIMARY_CPU		U(0)
+
+#define CORE_0_ISR_WAKE_OFFSET			(0x00000020ULL)
+#define APU_PCIL_CORE_X_ISR_WAKE_REG(cpu_id)	(APU_PCLI + (CORE_0_ISR_WAKE_OFFSET + \
+						 (APU_PCLI_CPU_STEP * (cpu_id))))
+#define APU_PCIL_CORE_X_ISR_WAKE_MASK		(0x00000001U)
+#define CORE_0_IEN_WAKE_OFFSET			(0x00000028ULL)
+#define APU_PCIL_CORE_X_IEN_WAKE_REG(cpu_id)	(APU_PCLI + (CORE_0_IEN_WAKE_OFFSET + \
+						 (APU_PCLI_CPU_STEP * (cpu_id))))
+#define APU_PCIL_CORE_X_IEN_WAKE_MASK		(0x00000001U)
+#define CORE_0_IDS_WAKE_OFFSET			(0x0000002CULL)
+#define APU_PCIL_CORE_X_IDS_WAKE_REG(cpu_id)	(APU_PCLI + (CORE_0_IDS_WAKE_OFFSET + \
+						 (APU_PCLI_CPU_STEP * (cpu_id))))
+#define APU_PCIL_CORE_X_IDS_WAKE_MASK		(0x00000001U)
+#define CORE_0_ISR_POWER_OFFSET			(0x00000010ULL)
+#define APU_PCIL_CORE_X_ISR_POWER_REG(cpu_id)	(APU_PCLI + (CORE_0_ISR_POWER_OFFSET + \
+						 (APU_PCLI_CPU_STEP * (cpu_id))))
+#define APU_PCIL_CORE_X_ISR_POWER_MASK		U(0x00000001)
+#define CORE_0_IEN_POWER_OFFSET			(0x00000018ULL)
+#define APU_PCIL_CORE_X_IEN_POWER_REG(cpu_id)	(APU_PCLI + (CORE_0_IEN_POWER_OFFSET + \
+						 (APU_PCLI_CPU_STEP * (cpu_id))))
+#define APU_PCIL_CORE_X_IEN_POWER_MASK		(0x00000001U)
+#define CORE_0_IDS_POWER_OFFSET			(0x0000001CULL)
+#define APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id)	(APU_PCLI + (CORE_0_IDS_POWER_OFFSET + \
+						 (APU_PCLI_CPU_STEP * (cpu_id))))
+#define APU_PCIL_CORE_X_IDS_POWER_MASK		(0x00000001U)
+#define CORE_PWRDN_EN_BIT_MASK			(0x1U)
+
+/*******************************************************************************
+ * memory map related constants
+ ******************************************************************************/
+/* IPP 1.2/SPP 0.9 mapping */
+#define DEVICE0_BASE		U(0xE8000000) /* psx, crl, iou */
+#define DEVICE0_SIZE		U(0x08000000)
+#define DEVICE1_BASE		U(0xE2000000) /* gic */
+#define DEVICE1_SIZE		U(0x00800000)
+#define DEVICE2_BASE		U(0xF1000000) /* uart, pmc_tap */
+#define DEVICE2_SIZE		U(0x01000000)
+#define CRF_BASE		U(0xFD1A0000)
+#define CRF_SIZE		U(0x00600000)
+#define IPI_BASE		U(0xEB300000)
+#define IPI_SIZE		U(0x00100000)
+
+/* CRL */
+#define CRL					U(0xEB5E0000)
+#define CRL_TIMESTAMP_REF_CTRL_OFFSET	U(0x14C)
+#define CRL_RST_TIMESTAMP_OFFSET		U(0x348)
+
+#define CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT	(1U << 25U)
+
+/* IOU SCNTRS */
+#define IOU_SCNTRS					U(0xEC920000)
+#define IOU_SCNTRS_COUNTER_CONTROL_REG_OFFSET	U(0)
+#define IOU_SCNTRS_BASE_FREQ_OFFSET			U(0x20)
+
+#define IOU_SCNTRS_CONTROL_EN	U(1)
+
+#define APU_CLUSTER0		U(0xECC00000)
+#define APU_RVBAR_L_0		U(0x40)
+#define APU_RVBAR_H_0		U(0x44)
+#define APU_CLUSTER_STEP	U(0x100000)
+
+#define SLCR_OSPI_QSPI_IOU_AXI_MUX_SEL	U(0xF1060504)
+
+/*******************************************************************************
+ * IRQ constants
+ ******************************************************************************/
+#define IRQ_SEC_PHY_TIMER	U(29)
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define UART0_BASE		U(0xF1920000)
+#define UART1_BASE		U(0xF1930000)
+
+#define UART_BAUDRATE	115200
+
+#if CONSOLE_IS(pl011_1)
+#define UART_BASE		UART1_BASE
+#else
+/* Default console is UART0 */
+#define UART_BASE            UART0_BASE
+#endif
+
+#endif /* DEF_H */
diff --git a/plat/amd/versal2/include/plat_ipi.h b/plat/amd/versal2/include/plat_ipi.h
new file mode 100644
index 0000000..503ec1f
--- /dev/null
+++ b/plat/amd/versal2/include/plat_ipi.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Versal Gen 2 IPI management enums and defines */
+
+#ifndef PLAT_IPI_H
+#define PLAT_IPI_H
+
+#include <stdint.h>
+
+#include <ipi.h>
+
+/*********************************************************************
+ * IPI agent IDs macros
+ ********************************************************************/
+#define IPI_ID_PMC	1U
+#define IPI_ID_APU	2U
+#define IPI_ID_RPU0	3U
+#define IPI_ID_RPU1	4U
+#define IPI_ID_3	5U
+#define IPI_ID_4	6U
+#define IPI_ID_5	7U
+#define IPI_ID_MAX	8U
+
+/*********************************************************************
+ * IPI message buffers
+ ********************************************************************/
+#define IPI_BUFFER_BASEADDR	(0xEB3F0000U)
+
+#define IPI_LOCAL_ID		IPI_ID_APU
+#define IPI_REMOTE_ID		IPI_ID_PMC
+
+#define IPI_BUFFER_LOCAL_BASE	(IPI_BUFFER_BASEADDR + (IPI_LOCAL_ID * 0x200U))
+#define IPI_BUFFER_REMOTE_BASE	(IPI_BUFFER_BASEADDR + (IPI_REMOTE_ID * 0x200U))
+
+#define IPI_BUFFER_TARGET_LOCAL_OFFSET	(IPI_LOCAL_ID * 0x40U)
+#define IPI_BUFFER_TARGET_REMOTE_OFFSET	(IPI_REMOTE_ID * 0x40U)
+
+#define IPI_BUFFER_MAX_WORDS	8
+
+#define IPI_BUFFER_REQ_OFFSET	0x0U
+#define IPI_BUFFER_RESP_OFFSET	0x20U
+
+/*********************************************************************
+ * Platform specific IPI API declarations
+ ********************************************************************/
+
+/* Configure IPI table */
+extern void soc_ipi_config_table_init(void);
+
+/*******************************************************************************
+ * IPI registers and bitfields
+ ******************************************************************************/
+#define IPI0_REG_BASE		(0xEB330000U)
+#define IPI0_TRIG_BIT		(1 << 2)
+#define PMC_IPI_TRIG_BIT	(1 << 1)
+#define IPI1_REG_BASE		(0xEB340000U)
+#define IPI1_TRIG_BIT		(1 << 3)
+#define IPI2_REG_BASE		(0xEB350000U)
+#define IPI2_TRIG_BIT		(1 << 4)
+#define IPI3_REG_BASE		(0xEB360000U)
+#define IPI3_TRIG_BIT		(1 << 5)
+#define IPI4_REG_BASE		(0xEB370000U)
+#define IPI4_TRIG_BIT		(1 << 6)
+#define IPI5_REG_BASE		(0xEB380000U)
+#define IPI5_TRIG_BIT		(1 << 7)
+
+#endif /* PLAT_IPI_H */
diff --git a/plat/amd/versal2/include/plat_macros.S b/plat/amd/versal2/include/plat_macros.S
new file mode 100644
index 0000000..d20f693
--- /dev/null
+++ b/plat/amd/versal2/include/plat_macros.S
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+
+#include "../include/platform_def.h"
+
+.section .rodata.gic_reg_name, "aS"
+/* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */
+gicc_regs:
+	.asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+
+/* Applicable only to GICv3 with SRE enabled */
+icc_regs:
+	.asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", ""
+
+/* Registers common to both GICv2 and GICv3 */
+gicd_pend_reg:
+	.asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n"
+newline:
+	.asciz "\n"
+spacer:
+	.asciz ":\t\t0x"
+
+	/* ---------------------------------------------
+	 * The below utility macro prints out relevant GIC
+	 * registers whenever an unhandled exception is
+	 * taken in BL31 on platform.
+	 * Expects: GICD base in x16, GICC base in x17
+	 * Clobbers: x0 - x10, sp
+	 * ---------------------------------------------
+	 */
+	.macro _print_gic_regs
+	/* Check for GICv3 system register access */
+	mrs	x7, id_aa64pfr0_el1
+	ubfx	x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
+	cmp	x7, #1
+	b.ne	print_gicv2
+
+	/* Check for SRE enable */
+	mrs	x8, ICC_SRE_EL3
+	tst	x8, #ICC_SRE_SRE_BIT
+	b.eq	print_gicv2
+
+	/* Load the icc reg list to x6 */
+	adr	x6, icc_regs
+	/* Load the icc regs to gp regs used by str_in_crash_buf_print */
+	mrs	x8, ICC_HPPIR0_EL1
+	mrs	x9, ICC_HPPIR1_EL1
+	mrs	x10, ICC_CTLR_EL3
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+	b	print_gic_common
+
+print_gicv2:
+	/* Load the gicc reg list to x6 */
+	adr	x6, gicc_regs
+	/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+	ldr	w8, [x17, #GICC_HPPIR]
+	ldr	w9, [x17, #GICC_AHPPIR]
+	ldr	w10, [x17, #GICC_CTLR]
+	/* Store to the crash buf and print to console */
+	bl	str_in_crash_buf_print
+
+print_gic_common:
+	/* Print the GICD_ISPENDR regs */
+	add	x7, x16, #GICD_ISPENDR
+	adr	x4, gicd_pend_reg
+	bl	asm_print_str
+gicd_ispendr_loop:
+	sub	x4, x7, x16
+	cmp	x4, #0x280
+	b.eq	exit_print_gic_regs
+	bl	asm_print_hex
+
+	adr	x4, spacer
+	bl	asm_print_str
+
+	ldr	x4, [x7], #8
+	bl	asm_print_hex
+
+	adr	x4, newline
+	bl	asm_print_str
+	b	gicd_ispendr_loop
+exit_print_gic_regs:
+	.endm
+
+	/* ---------------------------------------------
+	 * The below required platform porting macro
+	 * prints out relevant GIC and CCI registers
+	 * whenever an unhandled exception is taken in
+	 * BL31.
+	 * Clobbers: x0 - x10, x16, x17, sp
+	 * ---------------------------------------------
+	 */
+	.macro plat_crash_print_regs
+	/*
+	 * Empty for now to handle more platforms variant.
+	 * Uncomment it when versions are stable
+	 */
+	/*
+	mov_imm	x17, PLAT_GICD_BASE_VALUE
+	mov_imm	x16, PLAT_GICR_BASE_VALUE
+	_print_gic_regs
+	*/
+	.endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/amd/versal2/include/plat_pm_common.h b/plat/amd/versal2/include/plat_pm_common.h
new file mode 100644
index 0000000..5e68472
--- /dev/null
+++ b/plat/amd/versal2/include/plat_pm_common.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Contains platform specific definitions of commonly used macros data types
+ * for PU Power Management. This file should be common for all PU's.
+ */
+
+#ifndef PLAT_PM_COMMON_H
+#define PLAT_PM_COMMON_H
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include "pm_defs.h"
+
+#define NON_SECURE_FLAG		1U
+#define SECURE_FLAG		0U
+
+#endif /* PLAT_PM_COMMON_H */
diff --git a/plat/amd/versal2/include/plat_private.h b/plat/amd/versal2/include/plat_private.h
new file mode 100644
index 0000000..5a2e5bd
--- /dev/null
+++ b/plat/amd/versal2/include/plat_private.h
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
+
+#include <bl31/interrupt_mgmt.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#define SPP_PSXC_MMI_V2_0	U(6)
+#define SPP_PSXC_MMI_V3_0	U(8)
+
+/* MMD */
+#define SPP_PSXC_ISP_AIE_V2_0	U(3)
+#define SPP_PSXC_MMD_AIE_FRZ_EA	U(4)
+#define SPP_PSXC_MMD_AIE_V3_0	U(5)
+
+typedef struct versal_intr_info_type_el3 {
+	uint32_t id;
+	interrupt_type_handler_t handler;
+} versal_intr_info_type_el3_t;
+
+void config_setup(void);
+uint32_t get_uart_clk(void);
+
+const mmap_region_t *plat_get_mmap(void);
+
+void plat_gic_driver_init(void);
+void plat_gic_init(void);
+void plat_gic_cpuif_enable(void);
+void plat_gic_cpuif_disable(void);
+void plat_gic_pcpu_init(void);
+void plat_gic_save(void);
+void plat_gic_resume(void);
+void plat_gic_redistif_on(void);
+void plat_gic_redistif_off(void);
+
+extern uint32_t cpu_clock, platform_id, platform_version;
+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);
+int32_t sip_svc_setup_init(void);
+/*
+ * Register handler to specific GIC entrance
+ * for INTR_TYPE_EL3 type of interrupt
+ */
+int request_intr_type_el3(uint32_t irq, interrupt_type_handler_t fiq_handler);
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/amd/versal2/include/platform_def.h b/plat/amd/versal2/include/platform_def.h
new file mode 100644
index 0000000..090fe46
--- /dev/null
+++ b/plat/amd/versal2/include/platform_def.h
@@ -0,0 +1,141 @@
+/*
+ * 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.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include "def.h"
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE		U(0x440)
+
+#define PLATFORM_CLUSTER_COUNT		U(4)
+#define PLATFORM_CORE_COUNT_PER_CLUSTER	U(2) /* 2 CPUs per cluster */
+
+#define PLATFORM_CORE_COUNT		(PLATFORM_CLUSTER_COUNT * PLATFORM_CORE_COUNT_PER_CLUSTER)
+
+#define PLAT_MAX_PWR_LVL		U(2)
+#define PLAT_MAX_RET_STATE		U(1)
+#define PLAT_MAX_OFF_STATE		U(2)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL31 at the top of the Trusted SRAM (just below the shared memory, if
+ * present). BL31_BASE is calculated using the current BL31 debug size plus a
+ * little space for growth.
+ */
+#ifndef MEM_BASE
+# define BL31_BASE			U(0xBBF00000)
+# define BL31_LIMIT			U(0xBC000000)
+#else
+# define BL31_BASE			U(MEM_BASE)
+# define BL31_LIMIT			U(MEM_BASE + MEM_SIZE)
+# ifdef MEM_PROGBITS_SIZE
+#  define BL31_PROGBITS_LIMIT		U(MEM_BASE + \
+					  MEM_PROGBITS_SIZE)
+# endif
+#endif
+
+/*******************************************************************************
+ * BL32 specific defines.
+ ******************************************************************************/
+#ifndef BL32_MEM_BASE
+# define BL32_BASE			U(0x60000000)
+# define BL32_LIMIT			U(0x80000000)
+#else
+# define BL32_BASE			U(BL32_MEM_BASE)
+# define BL32_LIMIT			U(BL32_MEM_BASE + BL32_MEM_SIZE)
+#endif
+
+/*******************************************************************************
+ * BL33 specific defines.
+ ******************************************************************************/
+#ifndef PRELOADED_BL33_BASE
+# define PLAT_ARM_NS_IMAGE_BASE		U(0x8000000)
+#else
+# define PLAT_ARM_NS_IMAGE_BASE		U(PRELOADED_BL33_BASE)
+#endif
+
+/*******************************************************************************
+ * TSP  specific defines.
+ ******************************************************************************/
+#define TSP_SEC_MEM_BASE		BL32_BASE
+#define TSP_SEC_MEM_SIZE		(BL32_LIMIT - BL32_BASE)
+
+/* ID of the secure physical generic timer interrupt used by the TSP */
+#define ARM_IRQ_SEC_PHY_TIMER		U(29)
+#define TSP_IRQ_SEC_PHY_TIMER		ARM_IRQ_SEC_PHY_TIMER
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_DDR_LOWMEM_MAX		U(0x80000000)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE	(1ULL << 32U)
+#define PLAT_VIRT_ADDR_SPACE_SIZE	(1ULL << 32U)
+
+#define XILINX_OF_BOARD_DTB_MAX_SIZE	U(0x200000)
+
+#define PLAT_OCM_BASE			U(0xBBF00000)
+#define PLAT_OCM_LIMIT			U(0xBC000000)
+
+#if defined(TRANSFER_LIST)
+/*
+ * FIXME: This address should come from firmware before TF-A
+ * Having this to make sure the transfer list functionality works
+ */
+#define FW_HANDOFF_BASE         U(0x70000000)
+#define FW_HANDOFF_SIZE         U(0x10000)
+#endif
+
+#define IS_TFA_IN_OCM(x)	((x >= PLAT_OCM_BASE) && (x < PLAT_OCM_LIMIT))
+
+#ifndef MAX_MMAP_REGIONS
+#if (defined(XILINX_OF_BOARD_DTB_ADDR) && !IS_TFA_IN_OCM(BL31_BASE))
+#define MAX_MMAP_REGIONS		11
+#else
+#define MAX_MMAP_REGIONS		10
+#endif
+#endif
+
+#ifndef MAX_XLAT_TABLES
+#define MAX_XLAT_TABLES			U(12)
+#endif
+
+#define CACHE_WRITEBACK_SHIFT	U(6)
+#define CACHE_WRITEBACK_GRANULE	(1 << CACHE_WRITEBACK_SHIFT)
+
+#define PLAT_GICD_BASE_VALUE	U(0xE2000000)
+#define PLAT_GICR_BASE_VALUE	U(0xE2060000)
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLAT_IPI_IRQ	89
+#define PLAT_VERSAL_IPI_IRQ	PLAT_IPI_IRQ
+
+#define PLAT_G1S_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_LEVEL)
+
+#define PLAT_G0_IRQ_PROPS(grp) \
+	INTR_PROP_DESC(PLAT_VERSAL_IPI_IRQ, GIC_HIGHEST_SEC_PRIORITY, grp, \
+			GIC_INTR_CFG_EDGE), \
+
+#define IRQ_MAX		200U
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/amd/versal2/include/scmi.h b/plat/amd/versal2/include/scmi.h
new file mode 100644
index 0000000..0ab8b34
--- /dev/null
+++ b/plat/amd/versal2/include/scmi.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2023-2024, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef SCMI_H
+#define SCMI_H
+
+#include "versal2-scmi.h"
+
+#define SIP_SCMI	(0xC200ffffU)
+#define SMT_BUFFER_BASE	0x7fffe000
+
+void init_scmi_server(void);
+
+#define SCMI_VENDOR	"AMD"
+#define SCMI_PRODUCT	"Versal Gen 2"
+
+#endif /* DEF_H */
diff --git a/plat/amd/versal2/include/versal2-scmi.h b/plat/amd/versal2/include/versal2-scmi.h
new file mode 100644
index 0000000..4d581e4
--- /dev/null
+++ b/plat/amd/versal2/include/versal2-scmi.h
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+/*
+ * Macros IDs for AMD Versal Gen 2
+ *
+ * Copyright (c) 2023-2024, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * Michal Simek <michal.simek@amd.com>
+ */
+
+#ifndef _VERSAL2_SCMI_H
+#define _VERSAL2_SCMI_H
+
+#define CLK_GEM0_0	0
+#define CLK_GEM0_1	1
+#define CLK_GEM0_2	2
+#define CLK_GEM0_3	3
+#define CLK_GEM0_4	4
+#define CLK_GEM1_0	5
+#define CLK_GEM1_1	6
+#define CLK_GEM1_2	7
+#define CLK_GEM1_3	8
+#define CLK_GEM1_4	9
+#define CLK_SERIAL0_0	10
+#define CLK_SERIAL0_1	11
+#define CLK_SERIAL1_0	12
+#define CLK_SERIAL1_1	13
+#define CLK_UFS0_0	14
+#define CLK_UFS0_1	15
+#define CLK_UFS0_2	16
+#define CLK_USB0_0	17
+#define CLK_USB0_1	18
+#define CLK_USB0_2	19
+#define CLK_USB1_0	20
+#define CLK_USB1_1	21
+#define CLK_USB1_2	22
+#define CLK_MMC0_0	23
+#define CLK_MMC0_1	24
+#define CLK_MMC0_2	25
+#define CLK_MMC1_0	26
+#define CLK_MMC1_1	27
+#define CLK_MMC1_2	28
+#define CLK_TTC0_0	29
+#define CLK_TTC1_0	30
+#define CLK_TTC2_0	31
+#define CLK_TTC3_0	32
+#define CLK_TTC4_0	33
+#define CLK_TTC5_0	34
+#define CLK_TTC6_0	35
+#define CLK_TTC7_0	36
+#define CLK_I2C0_0	37
+#define CLK_I2C1_0	38
+#define CLK_I2C2_0	39
+#define CLK_I2C3_0	40
+#define CLK_I2C4_0	41
+#define CLK_I2C5_0	42
+#define CLK_I2C6_0	43
+#define CLK_I2C7_0	44
+#define CLK_OSPI0_0	45
+#define CLK_QSPI0_0	46
+#define CLK_QSPI0_1	47
+#define CLK_WWDT0_0	48
+#define CLK_WWDT1_0	49
+#define CLK_WWDT2_0	50
+#define CLK_WWDT3_0	51
+#define CLK_ADMA0_0	52
+#define CLK_ADMA0_1	53
+#define CLK_ADMA1_0	54
+#define CLK_ADMA1_1	55
+#define CLK_ADMA2_0	56
+#define CLK_ADMA2_1	57
+#define CLK_ADMA3_0	58
+#define CLK_ADMA3_1	59
+#define CLK_ADMA4_0	60
+#define CLK_ADMA4_1	61
+#define CLK_ADMA5_0	62
+#define CLK_ADMA5_1	63
+#define CLK_ADMA6_0	64
+#define CLK_ADMA6_1	65
+#define CLK_ADMA7_0	66
+#define CLK_ADMA7_1	67
+#define CLK_CAN0_0	68
+#define CLK_CAN0_1	69
+#define CLK_CAN1_0	70
+#define CLK_CAN1_1	71
+#define CLK_CAN2_0	72
+#define CLK_CAN2_1	73
+#define CLK_CAN3_0	74
+#define CLK_CAN3_1	75
+#define CLK_PS_GPIO_0	76
+#define CLK_PMC_GPIO_0	77
+#define CLK_SPI0_0	78
+#define CLK_SPI0_1	79
+#define CLK_SPI1_0	80
+#define CLK_SPI1_1	81
+#define CLK_I3C0_0	82
+#define CLK_I3C1_0	83
+#define CLK_I3C2_0	84
+#define CLK_I3C3_0	85
+#define CLK_I3C4_0	86
+#define CLK_I3C5_0	87
+#define CLK_I3C6_0	88
+#define CLK_I3C7_0	89
+
+#define RESET_GEM0_0	0
+#define RESET_GEM1_0	1
+#define RESET_SERIAL0_0	2
+#define RESET_SERIAL1_0	3
+#define RESET_UFS0_0	4
+#define RESET_I2C0_0	5
+#define RESET_I2C1_0	6
+#define RESET_I2C2_0	7
+#define RESET_I2C3_0	8
+#define RESET_I2C4_0	9
+#define RESET_I2C5_0	10
+#define RESET_I2C6_0	11
+#define RESET_I2C7_0	12
+#define RESET_I2C8_0	13
+#define RESET_OSPI0_0	14
+#define RESET_USB0_0	15
+#define RESET_USB0_1	16
+#define RESET_USB0_2	17
+#define RESET_USB1_0	18
+#define RESET_USB1_1	19
+#define RESET_USB1_2	20
+#define RESET_MMC0_0	21
+#define RESET_MMC1_0	22
+#define RESET_SPI0_0	23
+#define RESET_SPI1_0	24
+#define RESET_QSPI0_0	25
+#define RESET_I3C0_0	26
+#define RESET_I3C1_0	27
+#define RESET_I3C2_0	28
+#define RESET_I3C3_0	29
+#define RESET_I3C4_0	30
+#define RESET_I3C5_0	31
+#define RESET_I3C6_0	32
+#define RESET_I3C7_0	33
+#define RESET_I3C8_0	34
+
+#endif /* _VERSAL2_SCMI_H */
diff --git a/plat/amd/versal2/plat_psci.c b/plat/amd/versal2/plat_psci.c
new file mode 100644
index 0000000..4faa434
--- /dev/null
+++ b/plat/amd/versal2/plat_psci.c
@@ -0,0 +1,210 @@
+/*
+ * 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.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.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 <plat_private.h>
+#include <pm_defs.h>
+
+#define PM_RET_ERROR_NOFEATURE U(19)
+#define ALWAYSTRUE true
+
+static uintptr_t _sec_entry;
+
+static void zynqmp_cpu_standby(plat_local_state_t cpu_state)
+{
+	dsb();
+	wfi();
+}
+
+#define MPIDR_MT_BIT	(24)
+
+static int32_t zynqmp_nopmu_pwr_domain_on(u_register_t mpidr)
+{
+	uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr) & ~BIT(MPIDR_MT_BIT);
+	uint32_t cpu = cpu_id % PLATFORM_CORE_COUNT_PER_CLUSTER;
+	uint32_t cluster = cpu_id / PLATFORM_CORE_COUNT_PER_CLUSTER;
+	uintptr_t apu_cluster_base = 0, apu_pcli_base, apu_pcli_cluster = 0;
+	uintptr_t rst_apu_cluster = PSX_CRF + RST_APU0_OFFSET + ((uint64_t)cluster * 0x4U);
+
+	VERBOSE("%s: mpidr: 0x%lx, cpuid: %x, cpu: %x, cluster: %x\n",
+		__func__, mpidr, cpu_id, cpu, cluster);
+
+	if (cpu_id == -1) {
+		return PSCI_E_INTERN_FAIL;
+	}
+
+	if (cluster > 3) {
+		panic();
+	}
+
+	apu_pcli_cluster = APU_PCLI + APU_PCLI_CLUSTER_OFFSET + ((uint64_t)cluster * APU_PCLI_CLUSTER_STEP);
+	apu_cluster_base = APU_CLUSTER0 + ((uint64_t)cluster * APU_CLUSTER_STEP);
+
+	/* Enable clock */
+	mmio_setbits_32(PSX_CRF + ACPU0_CLK_CTRL + ((uint64_t)cluster * 0x4U), ACPU_CLK_CTRL_CLKACT);
+
+	/* Enable cluster states */
+	mmio_setbits_32(apu_pcli_cluster + PCLI_PSTATE_OFFSET, PCLI_PSTATE_VAL_SET);
+	mmio_setbits_32(apu_pcli_cluster + PCLI_PREQ_OFFSET, PREQ_CHANGE_REQUEST);
+
+	/* assert core reset */
+	mmio_setbits_32(rst_apu_cluster, ((RST_APU_COLD_RESET|RST_APU_WARN_RESET) << cpu));
+
+	/* program RVBAR */
+	mmio_write_32(apu_cluster_base + APU_RVBAR_L_0 + (cpu << 3),
+		      (uint32_t)_sec_entry);
+	mmio_write_32(apu_cluster_base + APU_RVBAR_H_0 + (cpu << 3),
+		      _sec_entry >> 32);
+
+	/* de-assert core reset */
+	mmio_clrbits_32(rst_apu_cluster, ((RST_APU_COLD_RESET|RST_APU_WARN_RESET) << cpu));
+
+	/* clear cluster resets */
+	mmio_clrbits_32(rst_apu_cluster, RST_APU_CLUSTER_WARM_RESET);
+	mmio_clrbits_32(rst_apu_cluster, RST_APU_CLUSTER_COLD_RESET);
+
+	apu_pcli_base = APU_PCLI + (APU_PCLI_CPU_STEP * cpu) +
+			(APU_PCLI_CLUSTER_CPU_STEP * cluster);
+
+	mmio_write_32(apu_pcli_base + PCLI_PSTATE_OFFSET, PCLI_PSTATE_VAL_CLEAR);
+	mmio_write_32(apu_pcli_base + PCLI_PREQ_OFFSET, PREQ_CHANGE_REQUEST);
+
+	return PSCI_E_SUCCESS;
+}
+
+static void zynqmp_nopmu_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	plat_gic_cpuif_disable();
+}
+
+static void __dead2 zynqmp_nopmu_system_reset(void)
+{
+	while (ALWAYSTRUE) {
+		wfi();
+	}
+}
+
+static int32_t zynqmp_validate_ns_entrypoint(uint64_t ns_entrypoint)
+{
+	VERBOSE("Validate ns_entry point %lx\n", ns_entrypoint);
+
+	if ((ns_entrypoint) != 0U) {
+		return PSCI_E_SUCCESS;
+	} else {
+		return PSCI_E_INVALID_ADDRESS;
+	}
+}
+
+static void zynqmp_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+	plat_gic_pcpu_init();
+	plat_gic_cpuif_enable();
+}
+
+static void __dead2 zynqmp_system_off(void)
+{
+	while (ALWAYSTRUE) {
+		wfi();
+	}
+}
+
+static int32_t zynqmp_validate_power_state(uint32_t power_state, psci_power_state_t *req_state)
+{
+	return PSCI_E_SUCCESS;
+}
+
+static const struct plat_psci_ops _nopmc_psci_ops = {
+	.cpu_standby			= zynqmp_cpu_standby,
+	.pwr_domain_on			= zynqmp_nopmu_pwr_domain_on,
+	.pwr_domain_off			= zynqmp_nopmu_pwr_domain_off,
+	.system_reset			= zynqmp_nopmu_system_reset,
+	.validate_ns_entrypoint		= zynqmp_validate_ns_entrypoint,
+	.pwr_domain_on_finish		= zynqmp_pwr_domain_on_finish,
+	.system_off			= zynqmp_system_off,
+	.validate_power_state		= zynqmp_validate_power_state,
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops.
+ ******************************************************************************/
+int32_t 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 = &_nopmc_psci_ops;
+
+	return 0;
+}
+
+int sip_svc_setup_init(void)
+{
+	return 0;
+}
+
+static int32_t no_pm_ioctl(uint32_t device_id, uint32_t ioctl_id,
+			   uint32_t arg1, uint32_t arg2)
+{
+	VERBOSE("%s: ioctl_id: %x, arg1: %x\n", __func__, ioctl_id, arg1);
+	if (ioctl_id == IOCTL_OSPI_MUX_SELECT) {
+		mmio_write_32(SLCR_OSPI_QSPI_IOU_AXI_MUX_SEL, arg1);
+		return 0;
+	}
+	return PM_RET_ERROR_NOFEATURE;
+}
+
+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)
+{
+	int32_t ret;
+	uint32_t arg[4], api_id;
+
+	arg[0] = (uint32_t)x1;
+	arg[1] = (uint32_t)(x1 >> 32);
+	arg[2] = (uint32_t)x2;
+	arg[3] = (uint32_t)(x2 >> 32);
+
+	api_id = smc_fid & FUNCID_NUM_MASK;
+	VERBOSE("%s: smc_fid: %x, api_id=0x%x\n", __func__, smc_fid, api_id);
+
+	switch (api_id) {
+	case PM_IOCTL:
+	{
+		ret = no_pm_ioctl(arg[0], arg[1], arg[2], arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+	}
+	case PM_GET_CHIPID:
+	{
+		uint32_t idcode, version;
+
+		idcode  = mmio_read_32(PMC_TAP);
+		version = mmio_read_32(PMC_TAP_VERSION);
+		SMC_RET2(handle, ((uint64_t)idcode << 32), version);
+	}
+	default:
+		WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
+
+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)
+{
+	return no_pm_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
+}
diff --git a/plat/amd/versal2/plat_topology.c b/plat/amd/versal2/plat_topology.c
new file mode 100644
index 0000000..0763139
--- /dev/null
+++ b/plat/amd/versal2/plat_topology.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+#include <plat_private.h>
+
+static const uint8_t plat_power_domain_tree_desc[] = {
+	/* Number of root nodes */
+	1,
+	/* Number of clusters */
+	PLATFORM_CLUSTER_COUNT,
+	/* Number of children for the first cluster node */
+	PLATFORM_CORE_COUNT_PER_CLUSTER,
+	/* Number of children for the second cluster node */
+	PLATFORM_CORE_COUNT_PER_CLUSTER,
+	/* Number of children for the third cluster node */
+	PLATFORM_CORE_COUNT_PER_CLUSTER,
+	/* Number of children for the fourth cluster node */
+	PLATFORM_CORE_COUNT_PER_CLUSTER,
+};
+
+const uint8_t *plat_get_power_domain_tree_desc(void)
+{
+	return plat_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int32_t plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+	uint32_t cluster_id, cpu_id;
+
+	mpidr &= MPIDR_AFFINITY_MASK;
+
+	cluster_id = MPIDR_AFFLVL2_VAL(mpidr);
+	cpu_id = MPIDR_AFFLVL1_VAL(mpidr);
+
+	if (cluster_id >= PLATFORM_CLUSTER_COUNT) {
+		return -3;
+	}
+
+	/*
+	 * Validate cpu_id by checking whether it represents a CPU in
+	 * one of the two clusters present on the platform.
+	 */
+	if (cpu_id >= PLATFORM_CORE_COUNT_PER_CLUSTER) {
+		return -1;
+	}
+
+	return (cpu_id + (cluster_id * PLATFORM_CORE_COUNT_PER_CLUSTER));
+}
diff --git a/plat/amd/versal2/platform.mk b/plat/amd/versal2/platform.mk
new file mode 100644
index 0000000..c07fc36
--- /dev/null
+++ b/plat/amd/versal2/platform.mk
@@ -0,0 +1,127 @@
+# Copyright (c) 2018-2022, 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.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+PLAT_PATH := plat/amd/versal2
+
+# A78 Erratum for SoC
+ERRATA_A78_AE_1941500 := 1
+ERRATA_A78_AE_1951502 := 1
+ERRATA_A78_AE_2376748 := 1
+ERRATA_A78_AE_2395408 := 1
+ERRATA_ABI_SUPPORT    := 1
+
+# Platform Supports Armv8.2 extensions
+ARM_ARCH_MAJOR := 8
+ARM_ARCH_MINOR := 2
+
+override PROGRAMMABLE_RESET_ADDRESS := 1
+PSCI_EXTENDED_STATE_ID := 1
+SEPARATE_CODE_AND_RODATA := 1
+override RESET_TO_BL31 := 1
+PL011_GENERIC_UART := 1
+IPI_CRC_CHECK := 0
+GIC_ENABLE_V4_EXTN :=  0
+GICV3_SUPPORT_GIC600 := 1
+
+override CTX_INCLUDE_AARCH32_REGS    := 0
+
+ifdef MEM_BASE
+    $(eval $(call add_define,MEM_BASE))
+
+    ifndef MEM_SIZE
+        $(error "ATF_BASE defined without ATF_SIZE")
+    endif
+    $(eval $(call add_define,MEM_SIZE))
+
+    ifdef MEM_PROGBITS_SIZE
+        $(eval $(call add_define,MEM_PROGBITS_SIZE))
+    endif
+endif
+
+ifdef BL32_MEM_BASE
+    $(eval $(call add_define,BL32_MEM_BASE))
+
+    ifndef BL32_MEM_SIZE
+        $(error "BL32_BASE defined without BL32_SIZE")
+    endif
+    $(eval $(call add_define,BL32_MEM_SIZE))
+endif
+
+ifdef IPI_CRC_CHECK
+    $(eval $(call add_define,IPI_CRC_CHECK))
+endif
+
+USE_COHERENT_MEM := 0
+HW_ASSISTED_COHERENCY := 1
+
+CONSOLE	?=	pl011
+ifeq (${CONSOLE}, $(filter ${CONSOLE},pl011 pl011_0 pl011_1 dcc))
+else
+  $(error Please define CONSOLE)
+endif
+
+$(eval $(call add_define_val,CONSOLE,CONSOLE_ID_${CONSOLE}))
+
+ifdef XILINX_OF_BOARD_DTB_ADDR
+$(eval $(call add_define,XILINX_OF_BOARD_DTB_ADDR))
+endif
+
+PLAT_INCLUDES		:=	-Iinclude/plat/arm/common/			\
+				-Iplat/xilinx/common/include/			\
+				-Iplat/xilinx/common/ipi_mailbox_service/	\
+				-I${PLAT_PATH}/include/				\
+				-Iplat/xilinx/versal/pm_service/
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+include lib/xlat_tables_v2/xlat_tables.mk
+include lib/libfdt/libfdt.mk
+
+PLAT_BL_COMMON_SOURCES	:=	\
+				drivers/arm/dcc/dcc_console.c			\
+				drivers/delay_timer/delay_timer.c		\
+				drivers/delay_timer/generic_delay_timer.c	\
+				${GICV3_SOURCES}				\
+				drivers/arm/pl011/aarch64/pl011_console.S	\
+				plat/common/aarch64/crash_console_helpers.S	\
+				plat/arm/common/arm_common.c			\
+				plat/common/plat_gicv3.c			\
+				${PLAT_PATH}/aarch64/helpers.S			\
+				${PLAT_PATH}/aarch64/common.c			\
+				${PLAT_PATH}/plat_topology.c                    \
+				${XLAT_TABLES_LIB_SRCS}
+
+BL31_SOURCES		+=	drivers/arm/cci/cci.c				\
+				lib/cpus/aarch64/cortex_a78_ae.S		\
+				lib/cpus/aarch64/cortex_a78.S			\
+				plat/common/plat_psci_common.c			\
+				drivers/scmi-msg/base.c				\
+				drivers/scmi-msg/entry.c			\
+				drivers/scmi-msg/smt.c				\
+				drivers/scmi-msg/clock.c			\
+				drivers/scmi-msg/power_domain.c			\
+				drivers/scmi-msg/reset_domain.c			\
+				${PLAT_PATH}/scmi.c
+
+BL31_SOURCES		+=	${PLAT_PATH}/plat_psci.c
+
+BL31_SOURCES		+=	plat/xilinx/common/plat_fdt.c			\
+				plat/xilinx/common/plat_startup.c		\
+				plat/xilinx/common/ipi.c			\
+				plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c	\
+				${PLAT_PATH}/soc_ipi.c				\
+				plat/xilinx/common/versal.c			\
+				${PLAT_PATH}/bl31_setup.c			\
+				common/fdt_fixup.c				\
+				${LIBFDT_SRCS}					\
+				${PLAT_PATH}/sip_svc_setup.c			\
+				${PLAT_PATH}/gicv3.c
+
+ifeq (${ERRATA_ABI_SUPPORT}, 1)
+# enable the cpu macros for errata abi interface
+CORTEX_A78_AE_H_INC     := 1
+$(eval $(call add_define, CORTEX_A78_AE_H_INC))
+endif
diff --git a/plat/amd/versal2/scmi.c b/plat/amd/versal2/scmi.c
new file mode 100644
index 0000000..c3c517a
--- /dev/null
+++ b/plat/amd/versal2/scmi.c
@@ -0,0 +1,531 @@
+/*
+ * Copyright (c) 2023-2024, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <drivers/scmi-msg.h>
+#include <drivers/scmi.h>
+#include <lib/utils_def.h>
+#include <platform_def.h>
+#include <scmi.h>
+
+#include "plat_private.h"
+
+#define HIGH (1)
+#define LOW (0)
+
+struct scmi_clk {
+	unsigned long clock_id;
+	unsigned long rate;
+	const char *name;
+	bool enabled;
+};
+
+#define CLOCK_CELL(_scmi_id, _id, _name, _init_enabled, _rate) \
+	[_scmi_id] = { \
+		.clock_id = (_id), \
+		.name = (_name), \
+		.enabled = (_init_enabled), \
+		.rate = (_rate), \
+	}
+
+static struct scmi_clk scmi0_clock[] = {
+	CLOCK_CELL(CLK_GEM0_0, CLK_GEM0_0, "gem0_pclk", true, 100000000),
+	CLOCK_CELL(CLK_GEM0_1, CLK_GEM0_1, "gem0_hclk", true, 100000000),
+	CLOCK_CELL(CLK_GEM0_2, CLK_GEM0_2, "gem0_tx_clk", true, 125000000),
+	CLOCK_CELL(CLK_GEM0_3, CLK_GEM0_3, "gem0_rx_clk", true, 100000000),
+	CLOCK_CELL(CLK_GEM0_4, CLK_GEM0_4, "gem0_tsu_clk", true, 100000000),
+	CLOCK_CELL(CLK_GEM1_0, CLK_GEM1_0, "gem1_pclk", true, 100000000),
+	CLOCK_CELL(CLK_GEM1_1, CLK_GEM1_1, "gem1_hclk", true, 100000000),
+	CLOCK_CELL(CLK_GEM1_2, CLK_GEM1_2, "gem1_tx_clk", true, 125000000),
+	CLOCK_CELL(CLK_GEM1_3, CLK_GEM1_3, "gem1_rx_clk", true, 100000000),
+	CLOCK_CELL(CLK_GEM1_4, CLK_GEM1_4, "gem1_tsu_clk", true, 100000000),
+	CLOCK_CELL(CLK_SERIAL0_0, CLK_SERIAL0_0, "uart0_uartclk", true, 100000000),
+	CLOCK_CELL(CLK_SERIAL0_1, CLK_SERIAL0_1, "uart0_apb_pclk", true, 100000000),
+	CLOCK_CELL(CLK_SERIAL1_0, CLK_SERIAL1_0, "uart1_uartclk", true, 100000000),
+	CLOCK_CELL(CLK_SERIAL1_1, CLK_SERIAL1_1, "uart1_apb_pclk", true, 100000000),
+	CLOCK_CELL(CLK_UFS0_0, CLK_UFS0_0, "ufs_core_clk", true, 100000000),
+	CLOCK_CELL(CLK_UFS0_1, CLK_UFS0_1, "ufs_phy_clk", true, 100000000),
+	CLOCK_CELL(CLK_UFS0_2, CLK_UFS0_2, "ufs_ref_pclk", true, 100000000),
+	CLOCK_CELL(CLK_USB0_0, CLK_USB0_0, "usb0_bus_clk", true, 100000000),
+	CLOCK_CELL(CLK_USB0_1, CLK_USB0_1, "usb0_ref_clk", true, 100000000),
+	CLOCK_CELL(CLK_USB0_2, CLK_USB0_2, "usb0_dwc_clk", true, 100000000),
+	CLOCK_CELL(CLK_USB1_0, CLK_USB1_0, "usb1_bus_clk", true, 100000000),
+	CLOCK_CELL(CLK_USB1_1, CLK_USB1_1, "usb1_ref_clk", true, 100000000),
+	CLOCK_CELL(CLK_USB1_2, CLK_USB1_2, "usb1_dwc_clk", true, 100000000),
+	CLOCK_CELL(CLK_MMC0_0, CLK_MMC0_0, "mmc0_xin_clk", true, 100000000),
+	CLOCK_CELL(CLK_MMC0_1, CLK_MMC0_1, "mmc0_ahb_clk", true, 100000000),
+	CLOCK_CELL(CLK_MMC0_2, CLK_MMC0_2, "mmc0_gate_clk", true, 100000000),
+	CLOCK_CELL(CLK_MMC1_0, CLK_MMC1_0, "mmc1_xin_clk", true, 100000000),
+	CLOCK_CELL(CLK_MMC1_1, CLK_MMC1_1, "mmc1_ahb_clk", true, 100000000),
+	CLOCK_CELL(CLK_MMC1_2, CLK_MMC1_2, "mmc1_gate_clk", true, 100000000),
+	CLOCK_CELL(CLK_TTC0_0, CLK_TTC0_0, "ttc0_clk", true, 100000000),
+	CLOCK_CELL(CLK_TTC1_0, CLK_TTC1_0, "ttc1_clk", true, 100000000),
+	CLOCK_CELL(CLK_TTC2_0, CLK_TTC2_0, "ttc2_clk", true, 100000000),
+	CLOCK_CELL(CLK_TTC3_0, CLK_TTC3_0, "ttc3_clk", true, 100000000),
+	CLOCK_CELL(CLK_TTC4_0, CLK_TTC4_0, "ttc4_clk", true, 100000000),
+	CLOCK_CELL(CLK_TTC5_0, CLK_TTC5_0, "ttc5_clk", true, 100000000),
+	CLOCK_CELL(CLK_TTC6_0, CLK_TTC6_0, "ttc6_clk", true, 100000000),
+	CLOCK_CELL(CLK_TTC7_0, CLK_TTC7_0, "ttc7_clk", true, 100000000),
+	CLOCK_CELL(CLK_I2C0_0, CLK_I2C0_0, "i2c0_clk", true, 100000000),
+	CLOCK_CELL(CLK_I2C1_0, CLK_I2C1_0, "i2c1_clk", true, 100000000),
+	CLOCK_CELL(CLK_I2C2_0, CLK_I2C2_0, "i2c2_clk", true, 100000000),
+	CLOCK_CELL(CLK_I2C3_0, CLK_I2C3_0, "i2c3_clk", true, 100000000),
+	CLOCK_CELL(CLK_I2C4_0, CLK_I2C4_0, "i2c4_clk", true, 100000000),
+	CLOCK_CELL(CLK_I2C5_0, CLK_I2C5_0, "i2c5_clk", true, 100000000),
+	CLOCK_CELL(CLK_I2C6_0, CLK_I2C6_0, "i2c6_clk", true, 100000000),
+	CLOCK_CELL(CLK_I2C7_0, CLK_I2C7_0, "i2c7_clk", true, 100000000),
+	CLOCK_CELL(CLK_OSPI0_0, CLK_OSPI0_0, "ospi0_clk", true, 100000000),
+	CLOCK_CELL(CLK_QSPI0_0, CLK_QSPI0_0, "qpsi0_ref_clk", true, 100000000),
+	CLOCK_CELL(CLK_QSPI0_1, CLK_QSPI0_1, "qspi0_pclk", true, 100000000),
+	CLOCK_CELL(CLK_WWDT0_0, CLK_WWDT0_0, "wwdt0_clk", true, 100000000),
+	CLOCK_CELL(CLK_WWDT1_0, CLK_WWDT1_0, "wwdt1_clk", true, 100000000),
+	CLOCK_CELL(CLK_WWDT2_0, CLK_WWDT2_0, "wwdt2_clk", true, 100000000),
+	CLOCK_CELL(CLK_WWDT3_0, CLK_WWDT3_0, "wwdt3_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA0_0, CLK_ADMA0_0, "adma0_main_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA0_1, CLK_ADMA0_1, "adma0_apb_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA1_0, CLK_ADMA1_0, "adma1_main_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA1_1, CLK_ADMA1_1, "adma1_apb_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA2_0, CLK_ADMA2_0, "adma2_main_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA2_1, CLK_ADMA2_1, "adma2_apb_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA3_0, CLK_ADMA3_0, "adma3_main_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA3_1, CLK_ADMA3_1, "adma3_apb_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA4_0, CLK_ADMA4_0, "adma4_main_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA4_1, CLK_ADMA4_1, "adma4_apb_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA5_0, CLK_ADMA5_0, "adma5_main_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA5_1, CLK_ADMA5_1, "adma5_apb_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA6_0, CLK_ADMA6_0, "adma6_main_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA6_1, CLK_ADMA6_1, "adma6_apb_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA7_0, CLK_ADMA7_0, "adma7_main_clk", true, 100000000),
+	CLOCK_CELL(CLK_ADMA7_1, CLK_ADMA7_1, "adma7_apb_clk", true, 100000000),
+	CLOCK_CELL(CLK_CAN0_0, CLK_CAN0_0, "can0_can_clk", true, 100000000),
+	CLOCK_CELL(CLK_CAN0_1, CLK_CAN0_1, "can0_axi_clk", true, 100000000),
+	CLOCK_CELL(CLK_CAN1_0, CLK_CAN1_0, "can1_can_clk", true, 100000000),
+	CLOCK_CELL(CLK_CAN1_1, CLK_CAN1_1, "can1_axi_clk", true, 100000000),
+	CLOCK_CELL(CLK_CAN2_0, CLK_CAN2_0, "can2_can_clk", true, 100000000),
+	CLOCK_CELL(CLK_CAN2_1, CLK_CAN2_1, "can2_axi_clk", true, 100000000),
+	CLOCK_CELL(CLK_CAN3_0, CLK_CAN3_0, "can3_can_clk", true, 100000000),
+	CLOCK_CELL(CLK_CAN3_1, CLK_CAN3_1, "can3_axi_clk", true, 100000000),
+	CLOCK_CELL(CLK_PS_GPIO_0, CLK_PS_GPIO_0, "ps_gpio_clk", true, 100000000),
+	CLOCK_CELL(CLK_PMC_GPIO_0, CLK_PMC_GPIO_0, "pmc_gpio_clk", true, 100000000),
+	CLOCK_CELL(CLK_SPI0_0, CLK_SPI0_0, "spi0_ref_clk", true, 100000000),
+	CLOCK_CELL(CLK_SPI0_1, CLK_SPI0_1, "spi0_pclk", true, 100000000),
+	CLOCK_CELL(CLK_SPI1_0, CLK_SPI1_0, "spi1_ref_clk", true, 100000000),
+	CLOCK_CELL(CLK_SPI1_1, CLK_SPI1_1, "spi1_pclk", true, 100000000),
+	CLOCK_CELL(CLK_I3C0_0, CLK_I3C0_0, "i3c0_clk", true, 100000000),
+	CLOCK_CELL(CLK_I3C1_0, CLK_I3C1_0, "i3c1_clk", true, 100000000),
+	CLOCK_CELL(CLK_I3C2_0, CLK_I3C2_0, "i3c2_clk", true, 100000000),
+	CLOCK_CELL(CLK_I3C3_0, CLK_I3C3_0, "i3c3_clk", true, 100000000),
+	CLOCK_CELL(CLK_I3C4_0, CLK_I3C4_0, "i3c4_clk", true, 100000000),
+	CLOCK_CELL(CLK_I3C5_0, CLK_I3C5_0, "i3c5_clk", true, 100000000),
+	CLOCK_CELL(CLK_I3C6_0, CLK_I3C6_0, "i3c6_clk", true, 100000000),
+	CLOCK_CELL(CLK_I3C7_0, CLK_I3C7_0, "i3c7_clk", true, 100000000),
+};
+
+/*
+ * struct scmi_reset - Data for the exposed reset controller
+ * @reset_id: Reset identifier in RCC reset driver
+ * @name: Reset string ID exposed to agent
+ */
+struct scmi_reset {
+	unsigned long reset_id;
+	const char *name;
+};
+
+#define RESET_CELL(_scmi_id, _id, _name) \
+	[_scmi_id] = { \
+		.reset_id = (_id), \
+		.name = (_name), \
+	}
+
+static struct scmi_reset scmi0_reset[] = {
+	RESET_CELL(RESET_GEM0_0, RESET_GEM0_0, "gem0"),
+	RESET_CELL(RESET_GEM1_0, RESET_GEM1_0, "gem1"),
+	RESET_CELL(RESET_SERIAL0_0, RESET_SERIAL0_0, "serial0"),
+	RESET_CELL(RESET_SERIAL1_0, RESET_SERIAL1_0, "serial1"),
+	RESET_CELL(RESET_UFS0_0, RESET_UFS0_0, "ufs0"),
+	RESET_CELL(RESET_I2C0_0, RESET_I2C0_0, "i2c0"),
+	RESET_CELL(RESET_I2C1_0, RESET_I2C1_0, "i2c1"),
+	RESET_CELL(RESET_I2C2_0, RESET_I2C2_0, "i2c2"),
+	RESET_CELL(RESET_I2C3_0, RESET_I2C3_0, "i2c3"),
+	RESET_CELL(RESET_I2C4_0, RESET_I2C4_0, "i2c4"),
+	RESET_CELL(RESET_I2C5_0, RESET_I2C5_0, "i2c5"),
+	RESET_CELL(RESET_I2C6_0, RESET_I2C6_0, "i2c6"),
+	RESET_CELL(RESET_I2C7_0, RESET_I2C7_0, "i2c7"),
+	RESET_CELL(RESET_I2C8_0, RESET_I2C8_0, "i2c8"),
+	RESET_CELL(RESET_OSPI0_0, RESET_OSPI0_0, "ospi"),
+	RESET_CELL(RESET_USB0_0, RESET_USB0_0, "usb0_0"),
+	RESET_CELL(RESET_USB0_1, RESET_USB0_1, "usb0_1"),
+	RESET_CELL(RESET_USB0_2, RESET_USB0_2, "usb0_2"),
+	RESET_CELL(RESET_USB1_0, RESET_USB1_0, "usb1_0"),
+	RESET_CELL(RESET_USB1_1, RESET_USB1_1, "usb1_1"),
+	RESET_CELL(RESET_USB1_2, RESET_USB1_2, "usb1_2"),
+	RESET_CELL(RESET_MMC0_0, RESET_MMC0_0, "mmc0"),
+	RESET_CELL(RESET_MMC1_0, RESET_MMC1_0, "mmc1"),
+	RESET_CELL(RESET_SPI0_0, RESET_SPI0_0, "spi0"),
+	RESET_CELL(RESET_SPI1_0, RESET_SPI1_0, "spi1"),
+	RESET_CELL(RESET_QSPI0_0, RESET_QSPI0_0, "qspi"),
+	RESET_CELL(RESET_I3C0_0, RESET_I3C0_0, "i3c0"),
+	RESET_CELL(RESET_I3C1_0, RESET_I3C1_0, "i3c1"),
+	RESET_CELL(RESET_I3C2_0, RESET_I3C2_0, "i3c2"),
+	RESET_CELL(RESET_I3C3_0, RESET_I3C3_0, "i3c3"),
+	RESET_CELL(RESET_I3C4_0, RESET_I3C4_0, "i3c4"),
+	RESET_CELL(RESET_I3C5_0, RESET_I3C5_0, "i3c5"),
+	RESET_CELL(RESET_I3C6_0, RESET_I3C6_0, "i3c6"),
+	RESET_CELL(RESET_I3C7_0, RESET_I3C7_0, "i3c7"),
+	RESET_CELL(RESET_I3C8_0, RESET_I3C8_0, "i3c8"),
+};
+
+struct scmi_resources {
+	struct scmi_clk *clock;
+	size_t clock_count;
+	struct scmi_reset *reset;
+	size_t reset_count;
+
+};
+
+static const struct scmi_resources resources[] = {
+	[0] = {
+		.clock = scmi0_clock,
+		.clock_count = ARRAY_SIZE(scmi0_clock),
+		.reset = scmi0_reset,
+		.reset_count = ARRAY_SIZE(scmi0_reset),
+	},
+};
+
+static const struct scmi_resources *find_resource(unsigned int agent_id)
+{
+	assert(agent_id < ARRAY_SIZE(resources));
+
+	return &resources[agent_id];
+}
+
+static struct scmi_clk *clk_find(unsigned int agent_id, unsigned int scmi_id)
+{
+	const struct scmi_resources *resource = find_resource(agent_id);
+	size_t n = 0U;
+	struct scmi_clk *ret = NULL;
+
+	if (resource != NULL) {
+		for (n = 0U; n < resource->clock_count; n++) {
+			if (n == scmi_id) {
+				ret = &resource->clock[n];
+				break;
+			}
+		}
+	}
+
+	return ret;
+}
+
+size_t plat_scmi_clock_count(unsigned int agent_id)
+{
+	const struct scmi_resources *resource = find_resource(agent_id);
+	size_t ret;
+
+	if (resource == NULL) {
+		ret = 0U;
+	} else {
+		VERBOSE("SCMI: CLK: %d clocks\n", (unsigned int)resource->clock_count);
+
+		ret = resource->clock_count;
+	}
+	return ret;
+}
+
+const char *plat_scmi_clock_get_name(unsigned int agent_id, unsigned int scmi_id)
+{
+	struct scmi_clk *clock = clk_find(agent_id, scmi_id);
+	const char *ret;
+
+	if (clock == NULL) {
+		ret = NULL;
+	} else {
+		VERBOSE("SCMI: CLK: id: %d, get_name: %s\n", scmi_id, clock->name);
+
+		ret = clock->name;
+	}
+	return ret;
+};
+
+/* Called by Linux */
+int32_t plat_scmi_clock_rates_array(unsigned int agent_id, unsigned int scmi_id,
+				    unsigned long *array, size_t *nb_elts,
+				    uint32_t start_idx)
+{
+	struct scmi_clk *clock = clk_find(agent_id, scmi_id);
+
+	if (clock == NULL) {
+		return SCMI_NOT_FOUND;
+	}
+
+	if (start_idx > 0) {
+		return SCMI_OUT_OF_RANGE;
+	}
+
+	if (array == NULL) {
+		*nb_elts = 1U;
+	} else if (*nb_elts == 1U) {
+		*array = clock->rate;
+		VERBOSE("SCMI: CLK: id: %d, clk_name: %s, get_rate %lu\n",
+		     scmi_id, clock->name, *array);
+	} else {
+		return SCMI_GENERIC_ERROR;
+	}
+
+	return SCMI_SUCCESS;
+}
+
+unsigned long plat_scmi_clock_get_rate(unsigned int agent_id, unsigned int scmi_id)
+{
+	struct scmi_clk *clock = clk_find(agent_id, scmi_id);
+	unsigned long ret;
+
+	if ((clock == NULL)) {
+		ret = SCMI_NOT_FOUND;
+	} else {
+		VERBOSE("SCMI: CLK: id: %d, get_rate: %lu\n", scmi_id, clock->rate);
+		ret = clock->rate;
+	}
+	return ret;
+}
+
+int32_t plat_scmi_clock_set_rate(unsigned int agent_id, unsigned int scmi_id,
+				 unsigned long rate)
+{
+	struct scmi_clk *clock = clk_find(agent_id, scmi_id);
+	unsigned long ret = UL(SCMI_SUCCESS);
+
+	if ((clock == NULL)) {
+		ret = SCMI_NOT_FOUND;
+	} else {
+		VERBOSE("SCMI: CLK: id: %d, set_rate: %lu\n", scmi_id, rate);
+		clock->rate = rate;
+	}
+	return ret;
+}
+
+int32_t plat_scmi_clock_get_state(unsigned int agent_id, unsigned int scmi_id)
+{
+	struct scmi_clk *clock = clk_find(agent_id, scmi_id);
+	int32_t ret;
+
+	if ((clock == NULL)) {
+		ret = SCMI_NOT_FOUND;
+	} else {
+		VERBOSE("SCMI: CLK: id: %d, get_state: %d\n", scmi_id, clock->enabled);
+
+		if (clock->enabled) {
+			ret = HIGH;
+		} else {
+			ret = LOW;
+		}
+	}
+	return ret;
+}
+
+int32_t plat_scmi_clock_set_state(unsigned int agent_id, unsigned int scmi_id,
+				  bool enable_not_disable)
+{
+	struct scmi_clk *clock = clk_find(agent_id, scmi_id);
+	int32_t ret;
+
+	if (clock == NULL) {
+		ret = SCMI_NOT_FOUND;
+	} else {
+		if (enable_not_disable) {
+			if (!clock->enabled) {
+				VERBOSE("SCMI: clock: %u enable\n", scmi_id);
+				clock->enabled = true;
+			}
+		} else {
+			if (clock->enabled) {
+				VERBOSE("SCMI: clock: %u disable\n", scmi_id);
+				clock->enabled = false;
+			}
+		}
+
+		VERBOSE("SCMI: CLK: id: %d, set_state: %d\n", scmi_id, clock->enabled);
+
+		ret = SCMI_SUCCESS;
+	}
+
+	return ret;
+}
+
+
+/*
+ * Platform SCMI reset domains
+ */
+static struct scmi_reset *find_reset(unsigned int agent_id,
+					 unsigned int scmi_id)
+{
+	const struct scmi_resources *resource = find_resource(agent_id);
+	size_t n;
+
+	if (resource != NULL) {
+		for (n = 0U; n < resource->reset_count; n++) {
+			if (n == scmi_id) {
+				return &resource->reset[n];
+			}
+		}
+	}
+
+	return NULL;
+}
+
+const char *plat_scmi_rstd_get_name(unsigned int agent_id, unsigned int scmi_id)
+{
+	const struct scmi_reset *reset = find_reset(agent_id, scmi_id);
+
+	if (reset == NULL) {
+		return NULL;
+	}
+
+	return reset->name;
+}
+
+size_t plat_scmi_rstd_count(unsigned int agent_id)
+{
+	const struct scmi_resources *resource = find_resource(agent_id);
+
+	if (resource == NULL) {
+		return 0U;
+	}
+
+	return resource->reset_count;
+}
+
+int32_t plat_scmi_rstd_autonomous(unsigned int agent_id, unsigned int scmi_id,
+				uint32_t state)
+{
+	const struct scmi_reset *reset = find_reset(agent_id, scmi_id);
+
+	if (reset == NULL) {
+		return SCMI_NOT_FOUND;
+	}
+
+	/* Supports only reset with context loss */
+	if (state != 0U) {
+		return SCMI_NOT_SUPPORTED;
+	}
+
+	NOTICE("SCMI reset on ID %lu/%s\n",
+	       reset->reset_id, plat_scmi_rstd_get_name(agent_id, scmi_id));
+
+	return SCMI_SUCCESS;
+}
+
+int32_t plat_scmi_rstd_set_state(unsigned int agent_id, unsigned int scmi_id,
+				 bool assert_not_deassert)
+{
+	const struct scmi_reset *reset = find_reset(agent_id, scmi_id);
+
+	if (reset == NULL) {
+		return SCMI_NOT_FOUND;
+	}
+
+	if (assert_not_deassert) {
+		NOTICE("SCMI reset %lu/%s set\n",
+		       reset->reset_id, plat_scmi_rstd_get_name(agent_id, scmi_id));
+	} else {
+		NOTICE("SCMI reset %lu/%s release\n",
+		       reset->reset_id, plat_scmi_rstd_get_name(agent_id, scmi_id));
+	}
+
+	return SCMI_SUCCESS;
+}
+
+/* Currently only one channel is supported. Expectation is that channel 0 is used by NS SW */
+static struct scmi_msg_channel scmi_channel[] = {
+	[0] = {
+		.shm_addr = SMT_BUFFER_BASE,
+		.shm_size = SMT_BUF_SLOT_SIZE,
+	},
+};
+
+struct scmi_msg_channel *plat_scmi_get_channel(unsigned int agent_id)
+{
+	assert(agent_id < ARRAY_SIZE(scmi_channel));
+
+	VERBOSE("%d: SCMI asking for channel\n", agent_id);
+
+	/* Just in case that code is reused */
+	return &scmi_channel[agent_id];
+}
+
+/* Base protocol implementations */
+const char *plat_scmi_vendor_name(void)
+{
+	return SCMI_VENDOR;
+}
+
+const char *plat_scmi_sub_vendor_name(void)
+{
+	return SCMI_PRODUCT;
+}
+
+/* Currently supporting Clocks and Reset Domains */
+static const uint8_t plat_protocol_list[] = {
+	SCMI_PROTOCOL_ID_BASE,
+	SCMI_PROTOCOL_ID_CLOCK,
+	SCMI_PROTOCOL_ID_RESET_DOMAIN,
+	/*
+	 *SCMI_PROTOCOL_ID_POWER_DOMAIN,
+	 *SCMI_PROTOCOL_ID_SENSOR,
+	 */
+	0U /* Null termination */
+};
+
+size_t plat_scmi_protocol_count(void)
+{
+	const size_t count = ARRAY_SIZE(plat_protocol_list) - 1U;
+
+	VERBOSE("SCMI: Protocol count: %d\n", (int32_t)count);
+
+	return count;
+}
+
+const uint8_t *plat_scmi_protocol_list(unsigned int agent_id __unused)
+{
+	return plat_protocol_list;
+}
+
+void init_scmi_server(void)
+{
+	size_t i;
+	int32_t ret;
+
+	for (i = 0U; i < ARRAY_SIZE(scmi_channel); i++)
+		scmi_smt_init_agent_channel(&scmi_channel[i]);
+
+	INFO("SCMI: Server initialized\n");
+
+	if (platform_id == QEMU) {
+		/* default setting is for QEMU */
+	} else if (platform_id == SPP) {
+		for (i = 0U; i < ARRAY_SIZE(scmi0_clock); i++) {
+
+			/* Keep i2c on 100MHz to calculate rates properly */
+			if (i >= CLK_I2C0_0 && i <= CLK_I2C7_0)
+				continue;
+			/*
+			 * SPP supports multiple versions.
+			 * The cpu_clock value is set to corresponding SPP
+			 * version in early platform setup, resuse the same
+			 * value here.
+			 */
+			ret = plat_scmi_clock_set_rate(0, i, cpu_clock);
+			if (ret < 0) {
+				NOTICE("Failed to set clock rate for SPP scmi_id=%ld\n", i);
+			}
+		}
+	} else {
+		 /* Making MISRA C 2012 15.7 compliant */
+	}
+}
diff --git a/plat/amd/versal2/sip_svc_setup.c b/plat/amd/versal2/sip_svc_setup.c
new file mode 100644
index 0000000..6850030
--- /dev/null
+++ b/plat/amd/versal2/sip_svc_setup.c
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Top level SMC handler for SiP calls. Dispatch PM calls to PM SMC handler. */
+
+#include <errno.h>
+#include <inttypes.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/scmi-msg.h>
+#include <scmi.h>
+#include <tools_share/uuid.h>
+
+#include "ipi_mailbox_svc.h"
+#include "plat_private.h"
+#include "pm_svc_main.h"
+
+/* SMC function IDs for SiP Service queries */
+#define SIP_SVC_UID		(0x8200ff01U)
+#define SIP_SVC_VERSION	(0x8200ff03U)
+
+/* SiP Service Calls version numbers */
+#define SIP_SVC_VERSION_MAJOR		(0U)
+#define SIP_SVC_VERSION_MINOR		(1U)
+
+/* These macros are used to identify PM calls from the SMC function ID */
+#define SIP_FID_MASK	GENMASK(23, 16)
+#define XLNX_FID_MASK	GENMASK(23, 12)
+#define PM_FID_VALUE	0u
+#define IPI_FID_VALUE	0x1000u
+#define is_pm_fid(_fid) (((_fid) & XLNX_FID_MASK) == PM_FID_VALUE)
+#define is_ipi_fid(_fid) (((_fid) & XLNX_FID_MASK) == IPI_FID_VALUE)
+
+/* SiP Service UUID */
+DEFINE_SVC_UUID2(_sip_uuid,
+		0x0499eb70, 0x5ed0, 0x11ee, 0xb3, 0x0a,
+		0x87, 0xd1, 0x1d, 0x4f, 0x8a, 0x9b);
+
+/**
+ * sip_svc_setup() - Setup SiP Service
+ *
+ * Return: 0 on success, negative error code on failure.
+ *
+ */
+static int32_t sip_svc_setup(void)
+{
+	return sip_svc_setup_init();
+}
+
+/*
+ * sip_svc_smc_handler() - Top-level SiP Service SMC handler
+ *
+ * Handler for all SiP SMC calls. Handles standard SIP requests
+ * and calls PM SMC handler if the call is for a PM-API function.
+ */
+static uintptr_t sip_svc_smc_handler(uint32_t smc_fid,
+			     u_register_t x1,
+			     u_register_t x2,
+			     u_register_t x3,
+			     u_register_t x4,
+			     void *cookie,
+			     void *handle,
+			     u_register_t flags)
+{
+	VERBOSE("SMCID: 0x%08x, x1: 0x%016" PRIx64 ", x2: 0x%016" PRIx64 ", x3: 0x%016" PRIx64 ", x4: 0x%016" PRIx64 "\n",
+		smc_fid, x1, x2, x3, x4);
+
+	if ((smc_fid & SIP_FID_MASK) != 0) {
+		WARN("SMC out of SiP assinged range: 0x%x\n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+
+	/* Let PM SMC handler deal with PM-related requests */
+	if (is_pm_fid(smc_fid)) {
+		return smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
+	}
+
+	/* Let IPI SMC handler deal with IPI-related requests if platform */
+	if (is_ipi_fid(smc_fid)) {
+		return ipi_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
+	}
+
+	/* Let PM SMC handler deal with PM-related requests */
+	switch (smc_fid) {
+	case SIP_SVC_UID:
+		SMC_UUID_RET(handle, _sip_uuid);
+
+	case SIP_SVC_VERSION:
+		SMC_RET2(handle, SIP_SVC_VERSION_MAJOR, SIP_SVC_VERSION_MINOR);
+
+	case SIP_SCMI:
+		if (platform_id != EMU) {
+			scmi_smt_fastcall_smc_entry(0);
+			SMC_RET1(handle, 0);
+		}
+		WARN("SCMI is not working on EMU\n");
+		SMC_RET1(handle, SMC_UNK);
+	default:
+		WARN("Unimplemented SiP Service Call: 0x%x\n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
+
+/* Register PM Service Calls as runtime service */
+DECLARE_RT_SVC(
+		sip_svc,
+		OEN_SIP_START,
+		OEN_SIP_END,
+		SMC_TYPE_FAST,
+		sip_svc_setup,
+		sip_svc_smc_handler);
diff --git a/plat/amd/versal2/soc_ipi.c b/plat/amd/versal2/soc_ipi.c
new file mode 100644
index 0000000..85d1bcd
--- /dev/null
+++ b/plat/amd/versal2/soc_ipi.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2024, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * SoC IPI agent registers access management
+ */
+
+#include <lib/utils_def.h>
+#include <plat_ipi.h>
+
+/* versal2 ipi configuration table */
+static const struct ipi_config ipi_table[IPI_ID_MAX] = {
+	/* A78 IPI */
+	[IPI_ID_APU] = {
+		.ipi_bit_mask = IPI0_TRIG_BIT,
+		.ipi_reg_base = IPI0_REG_BASE,
+		.secure_only = 0,
+	},
+
+	/* PMC IPI */
+	[IPI_ID_PMC] = {
+		.ipi_bit_mask = PMC_IPI_TRIG_BIT,
+		.ipi_reg_base = IPI0_REG_BASE,
+		.secure_only = IPI_SECURE_MASK,
+	},
+
+	/* RPU0 IPI */
+	[IPI_ID_RPU0] = {
+		.ipi_bit_mask = IPI1_TRIG_BIT,
+		.ipi_reg_base = IPI1_REG_BASE,
+		.secure_only = 0,
+	},
+
+	/* RPU1 IPI */
+	[IPI_ID_RPU1] = {
+		.ipi_bit_mask = IPI2_TRIG_BIT,
+		.ipi_reg_base = IPI2_REG_BASE,
+		.secure_only = 0,
+	},
+
+	/* IPI3 IPI */
+	[IPI_ID_3] = {
+		.ipi_bit_mask = IPI3_TRIG_BIT,
+		.ipi_reg_base = IPI3_REG_BASE,
+		.secure_only = 0,
+	},
+
+	/* IPI4 IPI */
+	[IPI_ID_4] = {
+		.ipi_bit_mask = IPI4_TRIG_BIT,
+		.ipi_reg_base = IPI4_REG_BASE,
+		.secure_only = 0,
+	},
+
+	/* IPI5 IPI */
+	[IPI_ID_5] = {
+		.ipi_bit_mask = IPI5_TRIG_BIT,
+		.ipi_reg_base = IPI5_REG_BASE,
+		.secure_only = 0,
+	},
+};
+
+/**
+ * soc_ipi_config_table_init() - Initialize versal2 IPI configuration data.
+ */
+void soc_ipi_config_table_init(void)
+{
+	ipi_config_table_init(ipi_table, ARRAY_SIZE(ipi_table));
+}
diff --git a/plat/amd/versal2/tsp/tsp-versal2.mk b/plat/amd/versal2/tsp/tsp-versal2.mk
new file mode 100644
index 0000000..422ed17
--- /dev/null
+++ b/plat/amd/versal2/tsp/tsp-versal2.mk
@@ -0,0 +1,10 @@
+#
+# Copyright (c) 2023-2024, Advanced Micro Devices, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+# TSP source files specific to Versal Gen 2 platform
+
+PLAT_XILINX_COMMON := plat/xilinx/common/
+
+include ${PLAT_XILINX_COMMON}/tsp/tsp.mk