Merge changes from topic "add-versal-soc-support" into integration

* changes:
  plat: xilinx: Move pm_client.h to common directory
  plat: xilinx: versal: Make silicon default build target
  xilinx: versal: Wire silicon default setup
  versal: Increase OCM memory size for DEBUG builds
  plat: xilinx: versal: Dont set IOU switch clock
  arm64: versal: Adjust cpu clock for versal virtual
  xilinx: versal: Add support for PM_GET_OPERATING_CHARACTERISTIC EEMI call
  plat: versal: Add Get_ChipID API
  plat: xilinx: versal: Add load Pdi API support
  xilinx: versal: Add feature check API
  xilinx: versal: Implement set wakeup source for client
  plat: xilinx: versal: Add GET_CALLBACK_DATA function
  xilinx: versal: Add PSCI APIs for system shutdown & reset
  xilinx: versal: Add PSCI APIs for suspend/resume
  xilinx: versal: Remove no_pmc ops to ON power domain
  xilinx: versal: Add set wakeup source API
  xilinx: versal: Add client wakeup API
  xilinx: versal: Add query data API
  xilinx: versal: Add request wakeup API
  xilinx: versal: Add PM_INIT_FINALIZE API for versal
  xilinx: versal: Add support of PM_GET_TRUSTZONE_VERSION API
  xilinx: versal: enable ipi mailbox service
  xilinx: move ipi mailbox svc to xilinx common
  plat: xilinx: versal: Implement PM IOCTL API
  xilinx: versal: Implement power down/restart related EEMI API
  xilinx: versal: Add SMC handler for EEMI API
  xilinx: versal: Implement PLL related PM APIs
  xilinx: versal: Implement clock related PM APIs
  xilinx: versal: Implement pin control related PM APIs
  xilinx: versal: Implement reset related PM APIs
  xilinx: versal: Implement device related PM APIs
  xilinx: versal: Add support for suspend related APIs
  xilinx: versal: Add get_api_version support
  xilinx: Add support to send PM API to PMC using IPI for versal
  plat: xilinx: versal: Move versal_def.h to include directory
  plat: xilinx: versal: Move versal_private.h to include directory
  plat: xilinx: zynqmp: Use GIC framework for warm restart
diff --git a/docs/plat/xilinx-versal.rst b/docs/plat/xilinx-versal.rst
index 231286e..95c89a8 100644
--- a/docs/plat/xilinx-versal.rst
+++ b/docs/plat/xilinx-versal.rst
@@ -14,7 +14,7 @@
 make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal bl31
 ```
 
-To build ATF for different platform (for now its just versal virtual "versal_virt")
+To build ATF for different platform (supported are "silicon"(default) and "versal_virt")
 ```bash
 make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal VERSAL_PLATFORM=versal_virt bl31
 ```
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.h b/plat/xilinx/common/include/pm_client.h
similarity index 88%
rename from plat/xilinx/zynqmp/pm_service/pm_client.h
rename to plat/xilinx/common/include/pm_client.h
index adbb76f..e91bb8f 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_client.h
+++ b/plat/xilinx/common/include/pm_client.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -19,11 +19,14 @@
 void pm_client_suspend(const struct pm_proc *proc, unsigned int state);
 void pm_client_abort_suspend(void);
 void pm_client_wakeup(const struct pm_proc *proc);
-enum pm_ret_status set_ocm_retention(void);
-enum pm_ret_status pm_set_suspend_mode(uint32_t mode);
-const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid);
 
 /* Global variables to be set in pm_client.c */
 extern const struct pm_proc *primary_proc;
 
+#ifndef VERSAL_PLATFORM
+enum pm_ret_status set_ocm_retention(void);
+enum pm_ret_status pm_set_suspend_mode(uint32_t mode);
+const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid);
+#endif
+
 #endif /* PM_CLIENT_H */
diff --git a/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c
similarity index 97%
rename from plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c
rename to plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c
index c499d78..f531158 100644
--- a/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c
+++ b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h
similarity index 92%
rename from plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h
rename to plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h
index 197c788..10682d8 100644
--- a/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h
+++ b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
diff --git a/plat/xilinx/versal/aarch64/versal_common.c b/plat/xilinx/versal/aarch64/versal_common.c
index 587b797..825421e 100644
--- a/plat/xilinx/versal/aarch64/versal_common.c
+++ b/plat/xilinx/versal/aarch64/versal_common.c
@@ -1,18 +1,18 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <plat_ipi.h>
+#include <versal_def.h>
+#include <plat_private.h>
 #include <common/debug.h>
 #include <drivers/generic_delay_timer.h>
 #include <lib/mmio.h>
 #include <lib/xlat_tables/xlat_tables.h>
 #include <plat/common/platform.h>
 
-#include "../versal_def.h"
-#include "../versal_private.h"
-
 /*
  * Table of regions to map using the MMU.
  * This doesn't include TZRAM as the 'mem_layout' argument passed to
@@ -22,6 +22,8 @@
 	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(CRF_BASE, CRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+	MAP_REGION_FLAT(FPD_MAINCCI_BASE, FPD_MAINCCI_SIZE, MT_DEVICE | MT_RW |
+			MT_SECURE),
 	{ 0 }
 };
 
@@ -39,11 +41,10 @@
 {
 	uint32_t val;
 
-	versal_print_platform_name();
+	/* Configure IPI data for versal */
+	versal_ipi_config_table_init();
 
-	mmio_write_32(VERSAL_CRL_IOU_SWITCH_CTRL,
-		      VERSAL_IOU_SWITCH_CTRL_CLKACT_BIT |
-		      (0x20 << VERSAL_IOU_SWITCH_CTRL_DIVISOR0_SHIFT));
+	versal_print_platform_name();
 
 	/* Global timer init - Program time stamp reference clk */
 	val = mmio_read_32(VERSAL_CRL_TIMESTAMP_REF_CTRL);
diff --git a/plat/xilinx/versal/bl31_versal_setup.c b/plat/xilinx/versal/bl31_versal_setup.c
index d7e07e0..6b56307 100644
--- a/plat/xilinx/versal/bl31_versal_setup.c
+++ b/plat/xilinx/versal/bl31_versal_setup.c
@@ -1,12 +1,13 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
 #include <assert.h>
 #include <errno.h>
-
+#include <plat_arm.h>
+#include <plat_private.h>
 #include <bl31/bl31.h>
 #include <common/bl_common.h>
 #include <common/debug.h>
@@ -15,8 +16,6 @@
 #include <lib/xlat_tables/xlat_tables.h>
 #include <plat/common/platform.h>
 
-#include "versal_private.h"
-
 static entry_point_info_t bl32_image_ep_info;
 static entry_point_info_t bl33_image_ep_info;
 static console_pl011_t versal_runtime_console;
@@ -104,6 +103,9 @@
  */
 void bl31_plat_arch_setup(void)
 {
+	plat_arm_interconnect_init();
+	plat_arm_interconnect_enter_coherency();
+
 	const mmap_region_t bl_regions[] = {
 		MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE,
 			MT_MEMORY | MT_RW | MT_SECURE),
diff --git a/plat/xilinx/versal/include/plat_ipi.h b/plat/xilinx/versal/include/plat_ipi.h
new file mode 100644
index 0000000..6b08f32
--- /dev/null
+++ b/plat/xilinx/versal/include/plat_ipi.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Versal IPI management enums and defines */
+
+#ifndef PLAT_IPI_H
+#define PLAT_IPI_H
+
+#include <ipi.h>
+#include <stdint.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
+
+/*********************************************************************
+ * IPI message buffers
+ ********************************************************************/
+#define IPI_BUFFER_BASEADDR	0xFF3F0000U
+
+#define IPI_BUFFER_APU_BASE	(IPI_BUFFER_BASEADDR + 0x400U)
+#define IPI_BUFFER_PMC_BASE	(IPI_BUFFER_BASEADDR + 0x200U)
+
+#define IPI_BUFFER_TARGET_APU_OFFSET	0x0U
+#define IPI_BUFFER_TARGET_PMC_OFFSET	0x40U
+
+#define IPI_BUFFER_LOCAL_BASE	IPI_BUFFER_APU_BASE
+#define IPI_BUFFER_REMOTE_BASE	IPI_BUFFER_PMC_BASE
+
+#define IPI_BUFFER_TARGET_LOCAL_OFFSET	IPI_BUFFER_TARGET_APU_OFFSET
+#define IPI_BUFFER_TARGET_REMOTE_OFFSET	IPI_BUFFER_TARGET_PMC_OFFSET
+
+#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 for versal */
+void versal_ipi_config_table_init(void);
+
+#endif /* PLAT_IPI_H */
diff --git a/plat/xilinx/versal/include/plat_pm_common.h b/plat/xilinx/versal/include/plat_pm_common.h
new file mode 100644
index 0000000..2d00801
--- /dev/null
+++ b/plat/xilinx/versal/include/plat_pm_common.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2019, Xilinx, 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 <common/debug.h>
+#include <stdint.h>
+#include "pm_defs.h"
+
+#define PAYLOAD_ARG_CNT		6U
+#define PAYLOAD_ARG_SIZE	4U	/* size in bytes */
+
+#define VERSAL_TZ_VERSION_MAJOR		1
+#define VERSAL_TZ_VERSION_MINOR		0
+#define VERSAL_TZ_VERSION		((VERSAL_TZ_VERSION_MAJOR << 16) | \
+					VERSAL_TZ_VERSION_MINOR)
+#endif /* PLAT_PM_COMMON_H */
diff --git a/plat/xilinx/versal/versal_private.h b/plat/xilinx/versal/include/plat_private.h
similarity index 65%
rename from plat/xilinx/versal/versal_private.h
rename to plat/xilinx/versal/include/plat_private.h
index 5d98d08..e302096 100644
--- a/plat/xilinx/versal/versal_private.h
+++ b/plat/xilinx/versal/include/plat_private.h
@@ -1,11 +1,11 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
-#ifndef VERSAL_PRIVATE_H
-#define VERSAL_PRIVATE_H
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
 
 #include <lib/xlat_tables/xlat_tables.h>
 
@@ -18,7 +18,9 @@
 void plat_versal_gic_cpuif_enable(void);
 void plat_versal_gic_cpuif_disable(void);
 void plat_versal_gic_pcpu_init(void);
+void plat_versal_gic_save(void);
+void plat_versal_gic_resume(void);
 
 unsigned int versal_calc_core_pos(u_register_t mpidr);
 
-#endif /* VERSAL_PRIVATE_H */
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/xilinx/versal/include/platform_def.h b/plat/xilinx/versal/include/platform_def.h
index 0c4b954..bcc7a93 100644
--- a/plat/xilinx/versal/include/platform_def.h
+++ b/plat/xilinx/versal/include/platform_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -8,8 +8,7 @@
 #define PLATFORM_DEF_H
 
 #include <arch.h>
-
-#include "../versal_def.h"
+#include "versal_def.h"
 
 /*******************************************************************************
  * Generic platform constants
@@ -32,7 +31,7 @@
  * little space for growth.
  */
 #ifndef VERSAL_ATF_MEM_BASE
-# define BL31_BASE			0xfffea000
+# define BL31_BASE			0xfffe0000
 # define BL31_LIMIT			0xffffffff
 #else
 # define BL31_BASE			(VERSAL_ATF_MEM_BASE)
@@ -76,7 +75,7 @@
  ******************************************************************************/
 #define PLAT_PHY_ADDR_SPACE_SIZE	(1ull << 32)
 #define PLAT_VIRT_ADDR_SPACE_SIZE	(1ull << 32)
-#define MAX_MMAP_REGIONS		7
+#define MAX_MMAP_REGIONS		8
 #define MAX_XLAT_TABLES			5
 
 #define CACHE_WRITEBACK_SHIFT	6
diff --git a/plat/xilinx/versal/versal_def.h b/plat/xilinx/versal/include/versal_def.h
similarity index 72%
rename from plat/xilinx/versal/versal_def.h
rename to plat/xilinx/versal/include/versal_def.h
index 41c65b9..94bd321 100644
--- a/plat/xilinx/versal/versal_def.h
+++ b/plat/xilinx/versal/include/versal_def.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -19,6 +19,7 @@
 
 /* List all supported platforms */
 #define VERSAL_PLATFORM_ID_versal_virt	1
+#define VERSAL_PLATFORM_ID_silicon	4
 
 #define VERSAL_PLATFORM_IS(con)	(VERSAL_PLATFORM_ID_ ## con == VERSAL_PLATFORM)
 
@@ -35,13 +36,10 @@
 
 /* CRL */
 #define VERSAL_CRL				0xFF5E0000
-#define VERSAL_CRL_IOU_SWITCH_CTRL		(VERSAL_CRL + 0x114)
 #define VERSAL_CRL_TIMESTAMP_REF_CTRL		(VERSAL_CRL + 0x14C)
 #define VERSAL_CRL_RST_TIMESTAMP_OFFSET	(VERSAL_CRL + 0x348)
 
 #define VERSAL_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT	(1 << 25)
-#define VERSAL_IOU_SWITCH_CTRL_CLKACT_BIT		(1 << 25)
-#define VERSAL_IOU_SWITCH_CTRL_DIVISOR0_SHIFT		8
 
 /* IOU SCNTRS */
 #define VERSAL_IOU_SCNTRS			 0xFF140000
@@ -56,6 +54,13 @@
 #define VERSAL_IRQ_SEC_PHY_TIMER		29
 
 /*******************************************************************************
+ * CCI-400 related constants
+ ******************************************************************************/
+#define PLAT_ARM_CCI_BASE		0xFD000000
+#define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX	4
+#define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX	5
+
+/*******************************************************************************
  * UART related constants
  ******************************************************************************/
 #define VERSAL_UART0_BASE		0xFF000000
@@ -80,7 +85,12 @@
 # define PLATFORM_NAME		"Versal Virt"
 # define VERSAL_UART_CLOCK	25000000
 # define VERSAL_UART_BAUDRATE	115200
-# define VERSAL_CPU_CLOCK	62500000
+# define VERSAL_CPU_CLOCK	2720000
+#elif VERSAL_PLATFORM_IS(silicon)
+# define PLATFORM_NAME		"Versal Silicon"
+# define VERSAL_UART_CLOCK	100000000
+# define VERSAL_UART_BAUDRATE	115200
+# define VERSAL_CPU_CLOCK	100000000
 #endif
 
 /* Access control register defines */
@@ -97,6 +107,9 @@
 #define CRF_RST_APU_ACPU_RESET		(1 << 0)
 #define CRF_RST_APU_ACPU_PWRON_RESET	(1 << 10)
 
+#define FPD_MAINCCI_BASE	0xFD000000
+#define FPD_MAINCCI_SIZE	0x00100000
+
 /* APU registers and bitfields */
 #define FPD_APU_BASE		0xFD5C0000
 #define FPD_APU_CONFIG_0	(FPD_APU_BASE + 0x20)
@@ -105,5 +118,22 @@
 #define FPD_APU_PWRCTL		(FPD_APU_BASE + 0x90)
 
 #define FPD_APU_CONFIG_0_VINITHI_SHIFT	8
+#define APU_0_PWRCTL_CPUPWRDWNREQ_MASK	1
+#define APU_1_PWRCTL_CPUPWRDWNREQ_MASK	2
+
+/* IPI registers and bitfields */
+#define IPI0_REG_BASE		0xFF330000
+#define IPI0_TRIG_BIT		(1 << 2)
+#define PMC_IPI_TRIG_BIT	(1 << 1)
+#define IPI1_REG_BASE		0xFF340000
+#define IPI1_TRIG_BIT		(1 << 3)
+#define IPI2_REG_BASE		0xFF350000
+#define IPI2_TRIG_BIT		(1 << 4)
+#define IPI3_REG_BASE		0xFF360000
+#define IPI3_TRIG_BIT		(1 << 5)
+#define IPI4_REG_BASE		0xFF370000
+#define IPI4_TRIG_BIT		(1 << 5)
+#define IPI5_REG_BASE		0xFF380000
+#define IPI5_TRIG_BIT		(1 << 6)
 
 #endif /* VERSAL_DEF_H */
diff --git a/plat/xilinx/versal/plat_psci.c b/plat/xilinx/versal/plat_psci.c
index 4a44369..3955085 100644
--- a/plat/xilinx/versal/plat_psci.c
+++ b/plat/xilinx/versal/plat_psci.c
@@ -1,65 +1,111 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <assert.h>
+#include <plat_arm.h>
+#include <plat_private.h>
+#include <pm_common.h>
 #include <common/debug.h>
 #include <lib/mmio.h>
 #include <lib/psci/psci.h>
 #include <plat/common/platform.h>
+#include <plat/arm/common/plat_arm.h>
 
-#include "versal_private.h"
+#include "pm_api_sys.h"
+#include "pm_client.h"
 
 static uintptr_t versal_sec_entry;
 
-static int versal_nopmc_pwr_domain_on(u_register_t mpidr)
+static int versal_pwr_domain_on(u_register_t mpidr)
 {
-	uint32_t r;
 	unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr);
+	const struct pm_proc *proc;
 
 	VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
 
 	if (cpu_id == -1)
 		return PSCI_E_INTERN_FAIL;
 
-	/*
-	 * program RVBAR
-	 */
-	mmio_write_32(FPD_APU_RVBAR_L_0 + (cpu_id << 3), versal_sec_entry);
-	mmio_write_32(FPD_APU_RVBAR_H_0 + (cpu_id << 3), versal_sec_entry >> 32);
+	proc = pm_get_proc(cpu_id);
 
-	/*
-	 * clear VINITHI
-	 */
-	r = mmio_read_32(FPD_APU_CONFIG_0);
-	r &= ~(1 << FPD_APU_CONFIG_0_VINITHI_SHIFT << cpu_id);
-	mmio_write_32(FPD_APU_CONFIG_0, r);
+	/* Send request to PMC to wake up selected ACPU core */
+	pm_req_wakeup(proc->node_id, (versal_sec_entry & 0xFFFFFFFF) | 0x1,
+		      versal_sec_entry >> 32, 0);
 
-	/*
-	 * FIXME: Add power up sequence, By default it works
-	 * now without the need of it as it was powered up by
-	 * default.
-	 */
+	/* Clear power down request */
+	pm_client_wakeup(proc);
 
-	/*
-	 * clear power down request
-	 */
-	r = mmio_read_32(FPD_APU_PWRCTL);
-	r &= ~(1 << cpu_id);
-	mmio_write_32(FPD_APU_PWRCTL, r);
+	return PSCI_E_SUCCESS;
+}
 
-	/*
-	 * release core reset
-	 */
-	r = mmio_read_32(CRF_RST_APU);
-	r &= ~((CRF_RST_APU_ACPU_PWRON_RESET |
-			CRF_RST_APU_ACPU_RESET) << cpu_id);
-	mmio_write_32(CRF_RST_APU, r);
+/**
+ * versal_pwr_domain_suspend() - This function sends request to PMC to suspend
+ * core.
+ *
+ * @target_state	Targated state
+ */
+static void versal_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+	unsigned int state;
+	unsigned int cpu_id = plat_my_core_pos();
+	const struct pm_proc *proc = pm_get_proc(cpu_id);
 
-	return PSCI_E_SUCCESS;
+	for (size_t 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_versal_gic_cpuif_disable();
+
+	plat_versal_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 */
+	pm_self_suspend(proc->node_id, MAX_LATENCY, state, versal_sec_entry);
+
+	/* APU is to be turned off */
+	if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+		/* disable coherency */
+		plat_arm_interconnect_exit_coherency();
+	}
 }
 
+/**
+ * versal_pwr_domain_suspend_finish() - This function performs actions to finish
+ * suspend procedure.
+ *
+ * @target_state	Targated state
+ */
+static void versal_pwr_domain_suspend_finish(
+					const psci_power_state_t *target_state)
+{
+	unsigned int cpu_id = plat_my_core_pos();
+	const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+	for (size_t 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);
+
+	/* enable coherency */
+	plat_arm_interconnect_enter_coherency();
+
+	/* APU was turned off, so restore GIC context */
+	if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+		plat_versal_gic_resume();
+		plat_versal_gic_cpuif_enable();
+	} else {
+		plat_versal_gic_cpuif_enable();
+		plat_versal_gic_pcpu_init();
+	}
+}
+
 void versal_pwr_domain_on_finish(const psci_power_state_t *target_state)
 {
 	/* Enable the gic cpu interface */
@@ -69,9 +115,114 @@
 	plat_versal_gic_cpuif_enable();
 }
 
+/**
+ * versal_system_off() - This function sends the system off request
+ * to firmware.  This function does not return.
+ */
+static void __dead2 versal_system_off(void)
+{
+	/* Send the power down request to the PMC */
+	pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN,
+			  pm_get_shutdown_scope());
+
+	while (1)
+		wfi();
+}
+
+/**
+ * versal_system_reset() - This function sends the reset request
+ * to firmware for the system to reset.  This function does not return.
+ */
+static void __dead2 versal_system_reset(void)
+{
+	/* Send the system reset request to the PMC */
+	pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET,
+			  pm_get_shutdown_scope());
+
+	while (1)
+		wfi();
+}
+
+/**
+ * versal_pwr_domain_off() - This function performs actions to turn off core
+ *
+ * @target_state	Targated state
+ */
+static void versal_pwr_domain_off(const psci_power_state_t *target_state)
+{
+	unsigned int cpu_id = plat_my_core_pos();
+	const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+	for (size_t 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]);
+
+	/* Prevent interrupts from spuriously waking up this cpu */
+	plat_versal_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_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0);
+}
+
+/**
+ * versal_validate_power_state() - This function ensures that the power state
+ * parameter in request is valid.
+ *
+ * @power_state		Power state of core
+ * @req_state		Requested state
+ *
+ * @return	Returns status, either success or reason
+ */
+static int versal_validate_power_state(unsigned int power_state,
+				       psci_power_state_t *req_state)
+{
+	VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
+
+	int pstate = psci_get_pstate_type(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;
+
+	/* We expect the 'state id' to be zero */
+	if (psci_get_pstate_id(power_state))
+		return PSCI_E_INVALID_PARAMS;
+
+	return PSCI_E_SUCCESS;
+}
+
+/**
+ * versal_get_sys_suspend_power_state() -  Get power state for system suspend
+ *
+ * @req_state	Requested state
+ */
+static void versal_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+	req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
+	req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
+}
+
 static const struct plat_psci_ops versal_nopmc_psci_ops = {
-	.pwr_domain_on			= versal_nopmc_pwr_domain_on,
+	.pwr_domain_on			= versal_pwr_domain_on,
+	.pwr_domain_off			= versal_pwr_domain_off,
 	.pwr_domain_on_finish		= versal_pwr_domain_on_finish,
+	.pwr_domain_suspend		= versal_pwr_domain_suspend,
+	.pwr_domain_suspend_finish	= versal_pwr_domain_suspend_finish,
+	.system_off			= versal_system_off,
+	.system_reset			= versal_system_reset,
+	.validate_power_state		= versal_validate_power_state,
+	.get_sys_suspend_power_state	= versal_get_sys_suspend_power_state,
 };
 
 /*******************************************************************************
diff --git a/plat/xilinx/versal/plat_versal.c b/plat/xilinx/versal/plat_versal.c
index 642867d..a080a76 100644
--- a/plat/xilinx/versal/plat_versal.c
+++ b/plat/xilinx/versal/plat_versal.c
@@ -1,13 +1,12 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <plat_private.h>
 #include <plat/common/platform.h>
 
-#include "versal_private.h"
-
 int plat_core_pos_by_mpidr(u_register_t mpidr)
 {
 	if (mpidr & MPIDR_CLUSTER_MASK)
diff --git a/plat/xilinx/versal/platform.mk b/plat/xilinx/versal/platform.mk
index 1c56364..7a8bfa3 100644
--- a/plat/xilinx/versal/platform.mk
+++ b/plat/xilinx/versal/platform.mk
@@ -31,33 +31,48 @@
     $(eval $(call add_define,VERSAL_BL32_MEM_SIZE))
 endif
 
-VERSAL_PLATFORM ?= versal_virt
+VERSAL_PLATFORM ?= silicon
 $(eval $(call add_define_val,VERSAL_PLATFORM,VERSAL_PLATFORM_ID_${VERSAL_PLATFORM}))
 
 VERSAL_CONSOLE	?=	pl011
 $(eval $(call add_define_val,VERSAL_CONSOLE,VERSAL_CONSOLE_ID_${VERSAL_CONSOLE}))
 
-PLAT_INCLUDES		:=	-Iplat/xilinx/versal/include/
+PLAT_INCLUDES		:=	-Iinclude/plat/arm/common/			\
+				-Iplat/xilinx/common/include/			\
+				-Iplat/xilinx/common/ipi_mailbox_service/	\
+				-Iplat/xilinx/versal/include/			\
+				-Iplat/xilinx/versal/pm_service/
 
 PLAT_BL_COMMON_SOURCES	:=	lib/xlat_tables/xlat_tables_common.c		\
 				lib/xlat_tables/aarch64/xlat_tables.c		\
 				drivers/delay_timer/delay_timer.c		\
 				drivers/delay_timer/generic_delay_timer.c	\
 				drivers/arm/gic/common/gic_common.c		\
+				drivers/arm/gic/v3/arm_gicv3_common.c		\
+				drivers/arm/gic/v3/gic500.c			\
 				drivers/arm/gic/v3/gicv3_main.c			\
 				drivers/arm/gic/v3/gicv3_helpers.c		\
 				drivers/arm/pl011/aarch64/pl011_console.S	\
 				plat/common/aarch64/crash_console_helpers.S	\
+				plat/arm/common/arm_cci.c			\
 				plat/common/plat_gicv3.c			\
 				plat/xilinx/versal/aarch64/versal_helpers.S	\
 				plat/xilinx/versal/aarch64/versal_common.c
 
-BL31_SOURCES		+=	lib/cpus/aarch64/cortex_a53.S			\
+BL31_SOURCES		+=	drivers/arm/cci/cci.c				\
+				lib/cpus/aarch64/cortex_a53.S			\
 				lib/cpus/aarch64/cortex_a72.S			\
 				plat/common/plat_psci_common.c			\
+				plat/xilinx/common/ipi.c			\
+				plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c \
+				plat/xilinx/common/pm_service/pm_ipi.c		\
 				plat/xilinx/versal/bl31_versal_setup.c		\
 				plat/xilinx/versal/plat_psci.c			\
 				plat/xilinx/versal/plat_versal.c		\
 				plat/xilinx/versal/plat_topology.c		\
 				plat/xilinx/versal/sip_svc_setup.c		\
-				plat/xilinx/versal/versal_gicv3.c
+				plat/xilinx/versal/versal_gicv3.c		\
+				plat/xilinx/versal/versal_ipi.c			\
+				plat/xilinx/versal/pm_service/pm_svc_main.c	\
+				plat/xilinx/versal/pm_service/pm_api_sys.c	\
+				plat/xilinx/versal/pm_service/pm_client.c
diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.c b/plat/xilinx/versal/pm_service/pm_api_sys.c
new file mode 100644
index 0000000..dbe94e6
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.c
@@ -0,0 +1,885 @@
+/*
+ * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Versal system level PM-API functions and communication with PMC via
+ * IPI interrupts
+ */
+
+#include <pm_common.h>
+#include <pm_ipi.h>
+#include <plat/common/platform.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+
+/*********************************************************************
+ * Target module IDs macros
+ ********************************************************************/
+#define LIBPM_MODULE_ID		0x2
+#define LOADER_MODULE_ID	0x7
+
+/* default shutdown/reboot scope is system(2) */
+static unsigned int pm_shutdown_scope = XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM;
+
+/**
+ * pm_get_shutdown_scope() - Get the currently set shutdown scope
+ *
+ * @return	Shutdown scope value
+ */
+unsigned int pm_get_shutdown_scope(void)
+{
+	return pm_shutdown_scope;
+}
+
+/**
+ * Assigning of argument values into array elements.
+ */
+#define PM_PACK_PAYLOAD1(pl, mid, arg0) {	\
+	pl[0] = (uint32_t)((uint32_t)((arg0) & 0xFF) | (mid << 8)); \
+}
+
+#define PM_PACK_PAYLOAD2(pl, mid, arg0, arg1) {		\
+	pl[1] = (uint32_t)(arg1);			\
+	PM_PACK_PAYLOAD1(pl, mid, arg0);		\
+}
+
+#define PM_PACK_PAYLOAD3(pl, mid, arg0, arg1, arg2) {	\
+	pl[2] = (uint32_t)(arg2);			\
+	PM_PACK_PAYLOAD2(pl, mid, arg0, arg1);		\
+}
+
+#define PM_PACK_PAYLOAD4(pl, mid, arg0, arg1, arg2, arg3) {	\
+	pl[3] = (uint32_t)(arg3);				\
+	PM_PACK_PAYLOAD3(pl, mid, arg0, arg1, arg2);		\
+}
+
+#define PM_PACK_PAYLOAD5(pl, mid, arg0, arg1, arg2, arg3, arg4) {	\
+	pl[4] = (uint32_t)(arg4);					\
+	PM_PACK_PAYLOAD4(pl, mid, arg0, arg1, arg2, arg3);		\
+}
+
+#define PM_PACK_PAYLOAD6(pl, mid, arg0, arg1, arg2, arg3, arg4, arg5) {	\
+	pl[5] = (uint32_t)(arg5);					\
+	PM_PACK_PAYLOAD5(pl, mid, arg0, arg1, arg2, arg3, arg4);	\
+}
+
+/* PM API functions */
+
+/**
+ * pm_get_api_version() - Get version number of PMC PM firmware
+ * @version	Returns 32-bit version number of PMC Power Management Firmware
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_get_api_version(unsigned int *version)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD1(payload, LIBPM_MODULE_ID, PM_GET_API_VERSION);
+	return pm_ipi_send_sync(primary_proc, payload, version, 1);
+}
+
+/**
+ * pm_self_suspend() - PM call for processor to suspend itself
+ * @nid		Node id of the processor or subsystem
+ * @latency	Requested maximum wakeup latency (not supported)
+ * @state	Requested state
+ * @address	Resume address
+ *
+ * This is a blocking call, it will return only once PMU has responded.
+ * On a wakeup, resume address will be automatically set by PMU.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_self_suspend(uint32_t nid,
+				   unsigned int latency,
+				   unsigned int state,
+				   uintptr_t address)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+	unsigned int cpuid = plat_my_core_pos();
+	const struct pm_proc *proc = pm_get_proc(cpuid);
+
+	if (!proc) {
+		WARN("Failed to get proc %d\n", cpuid);
+		return PM_RET_ERROR_INTERNAL;
+	}
+
+	/*
+	 * Do client specific suspend operations
+	 * (e.g. set powerdown request bit)
+	 */
+	pm_client_suspend(proc, state);
+
+	/* Send request to the PLM */
+	PM_PACK_PAYLOAD6(payload, LIBPM_MODULE_ID, PM_SELF_SUSPEND,
+			 proc->node_id, latency, state, address,
+			 (address >> 32));
+	return pm_ipi_send_sync(proc, payload, NULL, 0);
+}
+
+/**
+ * pm_abort_suspend() - PM call to announce that a prior suspend request
+ *			is to be aborted.
+ * @reason	Reason for the abort
+ *
+ * Calling PU expects the PMU to abort the initiated suspend procedure.
+ * This is a non-blocking call without any acknowledge.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/*
+	 * Do client specific abort suspend operations
+	 * (e.g. enable interrupts and clear powerdown request bit)
+	 */
+	pm_client_abort_suspend();
+
+	/* Send request to the PLM */
+	PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_ABORT_SUSPEND, reason,
+			 primary_proc->node_id);
+	return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_req_suspend() - PM call to request for another PU or subsystem to
+ *		      be suspended gracefully.
+ * @target	Node id of the targeted PU or subsystem
+ * @ack		Flag to specify whether acknowledge is requested
+ * @latency	Requested wakeup latency (not supported)
+ * @state	Requested state (not supported)
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_req_suspend(uint32_t target, uint8_t ack,
+				  unsigned int latency, unsigned int state)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_REQ_SUSPEND, target,
+			 latency, state);
+	if (ack == IPI_BLOCKING)
+		return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+	else
+		return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_req_wakeup() - PM call for processor to wake up selected processor
+ *		     or subsystem
+ * @target	Device ID of the processor or subsystem to wake up
+ * @set_address	Resume address presence indicator
+ *		1 - resume address specified, 0 - otherwise
+ * @address	Resume address
+ * @ack		Flag to specify whether acknowledge requested
+ *
+ * This API function is either used to power up another APU core for SMP
+ * (by PSCI) or to power up an entirely different PU or subsystem, such
+ * as RPU0, RPU, or PL_CORE_xx. Resume address for the target PU will be
+ * automatically set by PMC.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address,
+				 uintptr_t address, uint8_t ack)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC to perform the wake of the PU */
+	PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_REQ_WAKEUP, target,
+			 set_address, address, ack);
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_request_device() - Request a device
+ * @device_id		Device ID
+ * @capabilities	Requested capabilities for the device
+ * @qos			Required Quality of Service
+ * @ack			Flag to specify whether acknowledge requested
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_request_device(uint32_t device_id, uint32_t capabilities,
+				     uint32_t qos, uint32_t ack)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_REQUEST_DEVICE,
+			 device_id, capabilities, qos, ack);
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_release_device() - Release a device
+ * @device_id		Device ID
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_release_device(uint32_t device_id)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_RELEASE_DEVICE,
+			 device_id);
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_set_requirement() - Set requirement for the device
+ * @device_id		Device ID
+ * @capabilities	Requested capabilities for the device
+ * @latency		Requested maximum latency
+ * @qos			Required Quality of Service
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_set_requirement(uint32_t device_id, uint32_t capabilities,
+				      uint32_t latency, uint32_t qos)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_SET_REQUIREMENT,
+			 device_id, capabilities, latency, qos);
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_get_device_status() - Get device's status
+ * @device_id		Device ID
+ * @response		Buffer to store device status response
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_get_device_status(uint32_t device_id, uint32_t *response)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_GET_DEVICE_STATUS,
+			 device_id);
+
+	return pm_ipi_send_sync(primary_proc, payload, response, 3);
+}
+
+/**
+ * pm_reset_assert() - Assert/De-assert reset
+ * @reset	Reset ID
+ * @assert	Assert (1) or de-assert (0)
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_reset_assert(uint32_t reset, bool assert)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_RESET_ASSERT, reset,
+			 assert);
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_reset_get_status() - Get current status of a reset line
+ * @reset	Reset ID
+ * @status	Returns current status of selected reset ID
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_reset_get_status(uint32_t reset, uint32_t *status)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_RESET_ASSERT, reset);
+
+	return pm_ipi_send_sync(primary_proc, payload, status, 1);
+}
+
+/**
+ * pm_get_callbackdata() - Read from IPI response buffer
+ * @data - array of PAYLOAD_ARG_CNT elements
+ *
+ * Read value from ipi buffer response buffer.
+ */
+void pm_get_callbackdata(uint32_t *data, size_t count)
+{
+	/* Return if interrupt is not from PMU */
+	if (!pm_ipi_irq_status(primary_proc))
+		return;
+
+	pm_ipi_buff_read_callb(data, count);
+	pm_ipi_irq_clear(primary_proc);
+}
+
+/**
+ * pm_pinctrl_request() - Request a pin
+ * @pin		Pin ID
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_request(uint32_t pin)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PINCTRL_REQUEST, pin);
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pinctrl_release() - Release a pin
+ * @pin		Pin ID
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_release(uint32_t pin)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PINCTRL_RELEASE, pin);
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pinctrl_set_function() - Set pin function
+ * @pin		Pin ID
+ * @function	Function ID
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_set_function(uint32_t pin, uint32_t function)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PINCTRL_SET_FUNCTION, pin,
+			 function)
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pinctrl_get_function() - Get function set on the pin
+ * @pin		Pin ID
+ * @function	Function set on the pin
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_get_function(uint32_t pin, uint32_t *function)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PINCTRL_SET_FUNCTION,
+			 pin);
+
+	return pm_ipi_send_sync(primary_proc, payload, function, 1);
+}
+
+/**
+ * pm_pinctrl_set_pin_param() - Set configuration parameter for the pin
+ * @pin		Pin ID
+ * @param	Parameter ID
+ * @value	Parameter value
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_set_pin_param(uint32_t pin, uint32_t param,
+					    uint32_t value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_PINCTRL_CONFIG_PARAM_SET,
+			 pin, param, value);
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pinctrl_get_pin_param() - Get configuration parameter value for the pin
+ * @pin		Pin ID
+ * @param	Parameter ID
+ * @value	Buffer to store parameter value
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pinctrl_get_pin_param(uint32_t pin, uint32_t param,
+					    uint32_t *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PINCTRL_CONFIG_PARAM_GET,
+			 pin, param);
+
+	return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+/**
+ * pm_clock_enable() - Enable the clock
+ * @clk_id	Clock ID
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_clock_enable(uint32_t clk_id)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_ENABLE, clk_id);
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_clock_disable() - Disable the clock
+ * @clk_id	Clock ID
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_clock_disable(uint32_t clk_id)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_DISABLE, clk_id);
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_clock_get_state() - Get clock status
+ * @clk_id	Clock ID
+ * @state:	Buffer to store clock status (1: Enabled, 0:Disabled)
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_clock_get_state(uint32_t clk_id, uint32_t *state)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_GETSTATE, clk_id);
+
+	return pm_ipi_send_sync(primary_proc, payload, state, 1);
+}
+
+/**
+ * pm_clock_set_divider() - Set divider for the clock
+ * @clk_id	Clock ID
+ * @divider	Divider value
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_clock_set_divider(uint32_t clk_id, uint32_t divider)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_CLOCK_SETDIVIDER, clk_id,
+			 divider);
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_clock_get_divider() - Get divider value for the clock
+ * @clk_id	Clock ID
+ * @divider:	Buffer to store clock divider value
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_clock_get_divider(uint32_t clk_id, uint32_t *divider)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_GETDIVIDER, clk_id);
+
+	return pm_ipi_send_sync(primary_proc, payload, divider, 1);
+}
+
+/**
+ * pm_clock_set_parent() - Set parent for the clock
+ * @clk_id	Clock ID
+ * @parent	Parent ID
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_clock_set_parent(uint32_t clk_id, uint32_t parent)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_CLOCK_SETPARENT, clk_id,
+			 parent);
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_clock_get_parent() - Get parent value for the clock
+ * @clk_id	Clock ID
+ * @parent:	Buffer to store clock parent value
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_clock_get_parent(uint32_t clk_id, uint32_t *parent)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_CLOCK_GETPARENT, clk_id);
+
+	return pm_ipi_send_sync(primary_proc, payload, parent, 1);
+}
+
+/**
+ * pm_pll_set_param() - Set PLL parameter
+ * @clk_id	PLL clock ID
+ * @param	PLL parameter ID
+ * @value	Value to set for PLL parameter
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param,
+				    uint32_t value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_PLL_SET_PARAMETER, clk_id,
+			 param, value);
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pll_get_param() - Get PLL parameter value
+ * @clk_id	PLL clock ID
+ * @param	PLL parameter ID
+ * @value:	Buffer to store PLL parameter value
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param,
+				    uint32_t *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PLL_GET_PARAMETER, clk_id,
+			 param);
+
+	return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+/**
+ * pm_pll_set_mode() - Set PLL mode
+ * @clk_id	PLL clock ID
+ * @mode	PLL mode
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_PLL_SET_MODE, clk_id,
+			 mode);
+
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pll_get_mode() - Get PLL mode
+ * @clk_id	PLL clock ID
+ * @mode:	Buffer to store PLL mode
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_pll_get_mode(uint32_t clk_id, uint32_t *mode)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_PLL_GET_MODE, clk_id);
+
+	return pm_ipi_send_sync(primary_proc, payload, mode, 1);
+}
+
+/**
+ * pm_force_powerdown() - PM call to request for another PU or subsystem to
+ *			  be powered down forcefully
+ * @target	Device ID of the PU node to be forced powered down.
+ * @ack		Flag to specify whether acknowledge is requested
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_FORCE_POWERDOWN, target,
+			 ack);
+
+	if (ack == IPI_BLOCKING)
+		return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+	else
+		return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_system_shutdown() - PM call to request a system shutdown or restart
+ * @type	Shutdown or restart? 0=shutdown, 1=restart, 2=setscope
+ * @subtype	Scope: 0=APU-subsystem, 1=PS, 2=system
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	if (type == XPM_SHUTDOWN_TYPE_SETSCOPE_ONLY) {
+		/* Setting scope for subsequent PSCI reboot or shutdown */
+		pm_shutdown_scope = subtype;
+		return PM_RET_SUCCESS;
+	}
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_SYSTEM_SHUTDOWN, type,
+			 subtype);
+
+	return pm_ipi_send_non_blocking(primary_proc, payload);
+}
+
+/**
+* pm_query_data() -  PM API for querying firmware data
+* @qid	The type of data to query
+* @arg1	Argument 1 to requested query data call
+* @arg2	Argument 2 to requested query data call
+* @arg3	Argument 3 to requested query data call
+* @data	Returned output data
+*
+* This function returns requested data.
+*/
+enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2,
+				 uint32_t arg3, uint32_t *data)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_QUERY_DATA, qid, arg1,
+			 arg2, arg3);
+	return pm_ipi_send_sync(primary_proc, payload, data, 4);
+}
+/**
+ * pm_api_ioctl() -  PM IOCTL API for device control and configs
+ * @device_id	Device ID
+ * @ioctl_id	ID of the requested IOCTL
+ * @arg1	Argument 1 to requested IOCTL call
+ * @arg2	Argument 2 to requested IOCTL call
+ * @value	Returned output value
+ *
+ * This function calls IOCTL to firmware for device control and configuration.
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id,
+				uint32_t arg1, uint32_t arg2, uint32_t *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	switch (ioctl_id) {
+	case IOCTL_SET_PLL_FRAC_MODE:
+		return pm_pll_set_mode(arg1, arg2);
+	case IOCTL_GET_PLL_FRAC_MODE:
+		return pm_pll_get_mode(arg1, value);
+	case IOCTL_SET_PLL_FRAC_DATA:
+		return pm_pll_set_param(arg1, PM_PLL_PARAM_DATA, arg2);
+	case IOCTL_GET_PLL_FRAC_DATA:
+		return pm_pll_get_param(arg1, PM_PLL_PARAM_DATA, value);
+	default:
+		/* Send request to the PMC */
+		PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, PM_IOCTL, device_id,
+				 ioctl_id, arg1, arg2);
+		return pm_ipi_send_sync(primary_proc, payload, value, 1);
+	}
+}
+
+/**
+ * pm_set_wakeup_source() - PM call to specify the wakeup source while suspended
+ * @target	Device id of the targeted PU or subsystem
+ * @wkup_node	Device id of the wakeup peripheral
+ * @enable	Enable or disable the specified peripheral as wake source
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t wkup_device,
+					uint8_t enable)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_SET_WAKEUP_SOURCE, target,
+			 wkup_device, enable);
+	return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_get_chipid() - Read silicon ID registers
+ * @value       Buffer for return values. Must be large enough
+ *		to hold 8 bytes.
+ *
+ * @return      Returns silicon ID registers
+ */
+enum pm_ret_status pm_get_chipid(uint32_t *value)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD1(payload, LIBPM_MODULE_ID, PM_GET_CHIPID);
+
+	return pm_ipi_send_sync(primary_proc, payload, value, 2);
+}
+
+/**
+ * pm_feature_check() - Returns the supported API version if supported
+ * @api_id	API ID to check
+ * @value	Returned supported API version
+ *
+ * @return	Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_feature_check(uint32_t api_id, unsigned int *version)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT], fw_api_version;
+	uint32_t status;
+
+	switch (api_id) {
+	case PM_GET_CALLBACK_DATA:
+	case PM_GET_TRUSTZONE_VERSION:
+	case PM_INIT_FINALIZE:
+		*version = (PM_API_BASE_VERSION << 16);
+		return PM_RET_SUCCESS;
+	case PM_GET_API_VERSION:
+	case PM_GET_DEVICE_STATUS:
+	case PM_GET_OP_CHARACTERISTIC:
+	case PM_REQ_SUSPEND:
+	case PM_SELF_SUSPEND:
+	case PM_FORCE_POWERDOWN:
+	case PM_ABORT_SUSPEND:
+	case PM_REQ_WAKEUP:
+	case PM_SET_WAKEUP_SOURCE:
+	case PM_SYSTEM_SHUTDOWN:
+	case PM_REQUEST_DEVICE:
+	case PM_RELEASE_DEVICE:
+	case PM_SET_REQUIREMENT:
+	case PM_RESET_ASSERT:
+	case PM_RESET_GET_STATUS:
+	case PM_PINCTRL_REQUEST:
+	case PM_PINCTRL_RELEASE:
+	case PM_PINCTRL_GET_FUNCTION:
+	case PM_PINCTRL_SET_FUNCTION:
+	case PM_PINCTRL_CONFIG_PARAM_GET:
+	case PM_PINCTRL_CONFIG_PARAM_SET:
+	case PM_IOCTL:
+	case PM_QUERY_DATA:
+	case PM_CLOCK_ENABLE:
+	case PM_CLOCK_DISABLE:
+	case PM_CLOCK_GETSTATE:
+	case PM_CLOCK_SETDIVIDER:
+	case PM_CLOCK_GETDIVIDER:
+	case PM_CLOCK_SETPARENT:
+	case PM_CLOCK_GETPARENT:
+	case PM_PLL_SET_PARAMETER:
+	case PM_PLL_GET_PARAMETER:
+	case PM_PLL_SET_MODE:
+	case PM_PLL_GET_MODE:
+	case PM_FEATURE_CHECK:
+		*version = (PM_API_BASE_VERSION << 16);
+		break;
+	case PM_LOAD_PDI:
+		*version = (PM_API_BASE_VERSION << 16);
+		return PM_RET_SUCCESS;
+	default:
+		*version = 0U;
+		return PM_RET_ERROR_NOFEATURE;
+	}
+
+	PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, PM_FEATURE_CHECK, api_id);
+
+	status = pm_ipi_send_sync(primary_proc, payload, &fw_api_version, 1);
+	if (status != PM_RET_SUCCESS)
+		return status;
+
+	*version |= fw_api_version;
+
+	return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_load_pdi() - Load the PDI
+ *
+ * This function provides support to load PDI from linux
+ *
+ * src:        Source device of pdi(DDR, OCM, SD etc)
+ * address_low: lower 32-bit Linear memory space address
+ * address_high: higher 32-bit Linear memory space address
+ *
+ * @return      Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_load_pdi(uint32_t src,
+			       uint32_t address_low, uint32_t address_high)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMU */
+	PM_PACK_PAYLOAD4(payload, LOADER_MODULE_ID, PM_LOAD_PDI, src,
+			 address_high, address_low);
+	return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_get_op_characteristic() - PM call to request operating characteristics
+ *                              of a device
+ * @device_id   Device id
+ * @type        Type of the operating characteristic
+ *              (power, temperature and latency)
+ * @result      Returns the operating characteristic for the requested device,
+ *              specified by the type
+ *
+ * @return      Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_get_op_characteristic(uint32_t device_id,
+					    enum pm_opchar_type type,
+					    uint32_t *result)
+{
+	uint32_t payload[PAYLOAD_ARG_CNT];
+
+	/* Send request to the PMC */
+	PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_GET_OP_CHARACTERISTIC,
+			 device_id, type);
+	return pm_ipi_send_sync(primary_proc, payload, result, 1);
+}
diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.h b/plat/xilinx/versal/pm_service/pm_api_sys.h
new file mode 100644
index 0000000..4de592a
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PM_API_SYS_H
+#define PM_API_SYS_H
+
+#include <stdint.h>
+#include "pm_defs.h"
+
+/**********************************************************
+ * PM API function declarations
+ **********************************************************/
+
+enum pm_ret_status pm_get_api_version(unsigned int *version);
+enum pm_ret_status pm_self_suspend(uint32_t nid,
+				   unsigned int latency,
+				   unsigned int state,
+				   uintptr_t address);
+enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason);
+enum pm_ret_status pm_req_suspend(uint32_t target,
+				  uint8_t ack,
+				  unsigned int latency,
+				  unsigned int state);
+enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address,
+				 uintptr_t address, uint8_t ack);
+enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t device_id,
+					uint8_t enable);
+enum pm_ret_status pm_request_device(uint32_t device_id, uint32_t capabilities,
+				     uint32_t qos, uint32_t ack);
+enum pm_ret_status pm_release_device(uint32_t device_id);
+enum pm_ret_status pm_set_requirement(uint32_t device_id, uint32_t capabilities,
+				      uint32_t latency, uint32_t qos);
+enum pm_ret_status pm_get_device_status(uint32_t device_id, uint32_t *response);
+enum pm_ret_status pm_reset_assert(uint32_t reset, bool assert);
+enum pm_ret_status pm_reset_get_status(uint32_t reset, uint32_t *status);
+void pm_get_callbackdata(uint32_t *data, size_t count);
+enum pm_ret_status pm_pinctrl_request(uint32_t pin);
+enum pm_ret_status pm_pinctrl_release(uint32_t pin);
+enum pm_ret_status pm_pinctrl_set_function(uint32_t pin, uint32_t function);
+enum pm_ret_status pm_pinctrl_get_function(uint32_t pin, uint32_t *function);
+enum pm_ret_status pm_pinctrl_set_pin_param(uint32_t pin, uint32_t param,
+					    uint32_t value);
+enum pm_ret_status pm_pinctrl_get_pin_param(uint32_t pin, uint32_t param,
+					    uint32_t *value);
+enum pm_ret_status pm_clock_enable(uint32_t clk_id);
+enum pm_ret_status pm_clock_disable(uint32_t clk_id);
+enum pm_ret_status pm_clock_get_state(uint32_t clk_id, uint32_t *state);
+enum pm_ret_status pm_clock_set_divider(uint32_t clk_id, uint32_t divider);
+enum pm_ret_status pm_clock_get_divider(uint32_t clk_id, uint32_t *divider);
+enum pm_ret_status pm_clock_set_parent(uint32_t clk_id, uint32_t parent);
+enum pm_ret_status pm_clock_get_parent(uint32_t clk_id, uint32_t *parent);
+enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param,
+				    uint32_t value);
+enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param,
+				    uint32_t *value);
+enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode);
+enum pm_ret_status pm_pll_get_mode(uint32_t clk_id, uint32_t *mode);
+enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack);
+enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype);
+enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id,
+				uint32_t arg1, uint32_t arg2, uint32_t *value);
+enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2,
+				 uint32_t arg3, uint32_t *data);
+unsigned int pm_get_shutdown_scope(void);
+enum pm_ret_status pm_get_chipid(uint32_t *value);
+enum pm_ret_status pm_feature_check(uint32_t api_id, unsigned int *version);
+enum pm_ret_status pm_load_pdi(uint32_t src, uint32_t address_low,
+			       uint32_t address_high);
+enum pm_ret_status pm_get_op_characteristic(uint32_t device_id,
+					    enum pm_opchar_type type,
+					    uint32_t *result);
+#endif /* PM_API_SYS_H */
diff --git a/plat/xilinx/versal/pm_service/pm_client.c b/plat/xilinx/versal/pm_service/pm_client.c
new file mode 100644
index 0000000..5b47838
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_client.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2019, Xilinx, 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 <plat_ipi.h>
+#include <platform_def.h>
+#include <versal_def.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/arm/gic_common.h>
+#include <plat/common/platform.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+
+#define UNDEFINED_CPUID		(~0)
+#define IRQ_MAX		142
+#define NUM_GICD_ISENABLER	((IRQ_MAX >> 5) + 1)
+
+DEFINE_BAKERY_LOCK(pm_client_secure_lock);
+
+static const struct pm_ipi apu_ipi = {
+	.local_ipi_id = IPI_ID_APU,
+	.remote_ipi_id = IPI_ID_PMC,
+	.buffer_base = IPI_BUFFER_APU_BASE,
+};
+
+/* Order in pm_procs_all array must match cpu ids */
+static const struct pm_proc pm_procs_all[] = {
+	{
+		.node_id = XPM_DEVID_ACPU_0,
+		.ipi = &apu_ipi,
+		.pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
+	},
+	{
+		.node_id = XPM_DEVID_ACPU_1,
+		.ipi = &apu_ipi,
+		.pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
+	}
+};
+
+const struct pm_proc *primary_proc = &pm_procs_all[0];
+
+/* Interrupt to PM node index map */
+static enum pm_device_node_idx irq_node_map[IRQ_MAX + 1] = {
+	[13] = XPM_NODEIDX_DEV_GPIO,
+	[14] = XPM_NODEIDX_DEV_I2C_0,
+	[15] = XPM_NODEIDX_DEV_I2C_1,
+	[16] = XPM_NODEIDX_DEV_SPI_0,
+	[17] = XPM_NODEIDX_DEV_SPI_1,
+	[18] = XPM_NODEIDX_DEV_UART_0,
+	[19] = XPM_NODEIDX_DEV_UART_1,
+	[20] = XPM_NODEIDX_DEV_CAN_FD_0,
+	[21] = XPM_NODEIDX_DEV_CAN_FD_1,
+	[22] = XPM_NODEIDX_DEV_USB_0,
+	[23] = XPM_NODEIDX_DEV_USB_0,
+	[24] = XPM_NODEIDX_DEV_USB_0,
+	[25] = XPM_NODEIDX_DEV_USB_0,
+	[26] = XPM_NODEIDX_DEV_USB_0,
+	[37] = XPM_NODEIDX_DEV_TTC_0,
+	[38] = XPM_NODEIDX_DEV_TTC_0,
+	[39] = XPM_NODEIDX_DEV_TTC_0,
+	[40] = XPM_NODEIDX_DEV_TTC_1,
+	[41] = XPM_NODEIDX_DEV_TTC_1,
+	[42] = XPM_NODEIDX_DEV_TTC_1,
+	[43] = XPM_NODEIDX_DEV_TTC_2,
+	[44] = XPM_NODEIDX_DEV_TTC_2,
+	[45] = XPM_NODEIDX_DEV_TTC_2,
+	[46] = XPM_NODEIDX_DEV_TTC_3,
+	[47] = XPM_NODEIDX_DEV_TTC_3,
+	[48] = XPM_NODEIDX_DEV_TTC_3,
+	[56] = XPM_NODEIDX_DEV_GEM_0,
+	[57] = XPM_NODEIDX_DEV_GEM_0,
+	[58] = XPM_NODEIDX_DEV_GEM_1,
+	[59] = XPM_NODEIDX_DEV_GEM_1,
+	[60] = XPM_NODEIDX_DEV_ADMA_0,
+	[61] = XPM_NODEIDX_DEV_ADMA_1,
+	[62] = XPM_NODEIDX_DEV_ADMA_2,
+	[63] = XPM_NODEIDX_DEV_ADMA_3,
+	[64] = XPM_NODEIDX_DEV_ADMA_4,
+	[65] = XPM_NODEIDX_DEV_ADMA_5,
+	[66] = XPM_NODEIDX_DEV_ADMA_6,
+	[67] = XPM_NODEIDX_DEV_ADMA_7,
+	[74] = XPM_NODEIDX_DEV_USB_0,
+	[126] = XPM_NODEIDX_DEV_SDIO_0,
+	[127] = XPM_NODEIDX_DEV_SDIO_0,
+	[128] = XPM_NODEIDX_DEV_SDIO_1,
+	[129] = XPM_NODEIDX_DEV_SDIO_1,
+	[142] = XPM_NODEIDX_DEV_RTC,
+};
+
+/**
+ * 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
+ */
+static enum pm_device_node_idx irq_to_pm_node_idx(unsigned int irq)
+{
+	assert(irq <= IRQ_MAX);
+	return irq_node_map[irq];
+}
+
+/**
+ * pm_client_set_wakeup_sources - Set all devices with enabled interrupts as
+ *				  wake sources in the LibPM.
+ */
+static void pm_client_set_wakeup_sources(void)
+{
+	uint32_t reg_num;
+	uint32_t device_id;
+	uint8_t pm_wakeup_nodes_set[XPM_NODEIDX_DEV_MAX];
+	uintptr_t isenabler1 = PLAT_VERSAL_GICD_BASE + GICD_ISENABLER + 4;
+
+	zeromem(&pm_wakeup_nodes_set, sizeof(pm_wakeup_nodes_set));
+
+	for (reg_num = 0; reg_num < NUM_GICD_ISENABLER; reg_num++) {
+		uint32_t base_irq = reg_num << ISENABLER_SHIFT;
+		uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2));
+
+		if (!reg)
+			continue;
+
+		while (reg) {
+			enum pm_device_node_idx node_idx;
+			uint32_t idx, ret, irq, lowest_set = reg & (-reg);
+
+			idx = __builtin_ctz(lowest_set);
+			irq = base_irq + idx;
+
+			if (irq > IRQ_MAX)
+				break;
+
+			node_idx = irq_to_pm_node_idx(irq);
+			reg &= ~lowest_set;
+
+			if ((node_idx != XPM_NODEIDX_DEV_MIN) &&
+			    (!pm_wakeup_nodes_set[node_idx])) {
+				/* Get device ID from node index */
+				device_id = PERIPH_DEVID(node_idx);
+				ret = pm_set_wakeup_source(XPM_DEVID_ACPU_0,
+							   device_id, 1);
+				pm_wakeup_nodes_set[node_idx] = !ret;
+			}
+		}
+	}
+}
+
+/**
+ * pm_client_suspend() - Client-specific suspend actions
+ *
+ * This function should contain any PU-specific actions
+ * required prior to sending suspend request to PMU
+ * Actions taken depend on the state system is suspending to.
+ */
+void pm_client_suspend(const struct pm_proc *proc, unsigned int state)
+{
+	bakery_lock_get(&pm_client_secure_lock);
+
+	if (state == PM_STATE_SUSPEND_TO_RAM)
+		pm_client_set_wakeup_sources();
+
+	/* Set powerdown request */
+	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) |
+		      proc->pwrdn_mask);
+
+	bakery_lock_release(&pm_client_secure_lock);
+}
+
+/**
+ * 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)
+{
+	/* Enable interrupts at processor level (for current cpu) */
+	gicv3_cpuif_enable(plat_my_core_pos());
+
+	bakery_lock_get(&pm_client_secure_lock);
+
+	/* Clear powerdown request */
+	mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) &
+		      ~primary_proc->pwrdn_mask);
+
+	bakery_lock_release(&pm_client_secure_lock);
+}
+
+/**
+ * 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 unsigned int pm_get_cpuid(uint32_t nid)
+{
+	for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
+		if (pm_procs_all[i].node_id == nid)
+			return i;
+	}
+	return UNDEFINED_CPUID;
+}
+
+/**
+ * pm_client_wakeup() - Client-specific wakeup actions
+ *
+ * This function should contain any PU-specific actions
+ * required for waking up another APU core
+ */
+void pm_client_wakeup(const struct pm_proc *proc)
+{
+	unsigned int cpuid = pm_get_cpuid(proc->node_id);
+
+	if (cpuid == UNDEFINED_CPUID)
+		return;
+
+	bakery_lock_get(&pm_client_secure_lock);
+
+	/* clear powerdown bit for affected cpu */
+	uint32_t val = mmio_read_32(FPD_APU_PWRCTL);
+	val &= ~(proc->pwrdn_mask);
+	mmio_write_32(FPD_APU_PWRCTL, val);
+
+	bakery_lock_release(&pm_client_secure_lock);
+}
+
+/**
+ * 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(unsigned int cpuid)
+{
+	if (cpuid < ARRAY_SIZE(pm_procs_all))
+		return &pm_procs_all[cpuid];
+
+	return NULL;
+}
diff --git a/plat/xilinx/versal/pm_service/pm_defs.h b/plat/xilinx/versal/pm_service/pm_defs.h
new file mode 100644
index 0000000..966b00b
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_defs.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Versal power management enums and defines */
+
+#ifndef PM_DEFS_H
+#define PM_DEFS_H
+
+#include "pm_node.h"
+
+/*********************************************************************
+ * Macro definitions
+ ********************************************************************/
+
+/* State arguments of the self suspend */
+#define PM_STATE_CPU_IDLE	0x0U
+#define PM_STATE_SUSPEND_TO_RAM	0xFU
+
+#define MAX_LATENCY		(~0U)
+#define MAX_QOS			100U
+
+/* Processor core device IDs */
+#define APU_DEVID(IDX)	NODEID(XPM_NODECLASS_DEVICE, XPM_NODESUBCL_DEV_CORE, \
+			       XPM_NODETYPE_DEV_CORE_APU, (IDX))
+
+#define XPM_DEVID_ACPU_0	APU_DEVID(XPM_NODEIDX_DEV_ACPU_0)
+#define XPM_DEVID_ACPU_1	APU_DEVID(XPM_NODEIDX_DEV_ACPU_1)
+
+#define PERIPH_DEVID(IDX)	NODEID(XPM_NODECLASS_DEVICE, \
+				       XPM_NODESUBCL_DEV_PERIPH, \
+				       XPM_NODETYPE_DEV_PERIPH, (IDX))
+
+#define PM_GET_CALLBACK_DATA		0xa01
+#define PM_GET_TRUSTZONE_VERSION	0xa03
+
+/* PM API Versions */
+#define PM_API_BASE_VERSION		1U
+
+/* PM API ids */
+#define PM_GET_API_VERSION		1U
+#define PM_GET_DEVICE_STATUS		3U
+#define PM_GET_OP_CHARACTERISTIC	4U
+#define PM_REQ_SUSPEND			6U
+#define PM_SELF_SUSPEND			7U
+#define PM_FORCE_POWERDOWN		8U
+#define PM_ABORT_SUSPEND		9U
+#define PM_REQ_WAKEUP			10U
+#define PM_SET_WAKEUP_SOURCE		11U
+#define PM_SYSTEM_SHUTDOWN		12U
+#define PM_REQUEST_DEVICE		13U
+#define PM_RELEASE_DEVICE		14U
+#define PM_SET_REQUIREMENT		15U
+#define PM_RESET_ASSERT			17U
+#define PM_RESET_GET_STATUS		18U
+#define PM_INIT_FINALIZE		21U
+#define PM_GET_CHIPID			24U
+#define	PM_PINCTRL_REQUEST		28U
+#define	PM_PINCTRL_RELEASE		29U
+#define	PM_PINCTRL_GET_FUNCTION		30U
+#define	PM_PINCTRL_SET_FUNCTION		31U
+#define	PM_PINCTRL_CONFIG_PARAM_GET	32U
+#define	PM_PINCTRL_CONFIG_PARAM_SET	33U
+#define PM_IOCTL			34U
+#define PM_QUERY_DATA			35U
+#define PM_CLOCK_ENABLE			36U
+#define PM_CLOCK_DISABLE		37U
+#define PM_CLOCK_GETSTATE		38U
+#define PM_CLOCK_SETDIVIDER		39U
+#define PM_CLOCK_GETDIVIDER		40U
+#define PM_CLOCK_SETRATE		41U
+#define PM_CLOCK_GETRATE		42U
+#define PM_CLOCK_SETPARENT		43U
+#define PM_CLOCK_GETPARENT		44U
+#define PM_PLL_SET_PARAMETER		48U
+#define PM_PLL_GET_PARAMETER		49U
+#define PM_PLL_SET_MODE			50U
+#define PM_PLL_GET_MODE			51U
+#define PM_FEATURE_CHECK		63U
+
+/* Loader API ids */
+#define PM_LOAD_PDI			0x701U
+
+/* IOCTL IDs for clock driver */
+#define IOCTL_SET_PLL_FRAC_MODE		8
+#define	IOCTL_GET_PLL_FRAC_MODE		9
+#define	IOCTL_SET_PLL_FRAC_DATA		10
+#define	IOCTL_GET_PLL_FRAC_DATA		11
+
+/* Parameter ID for PLL IOCTLs */
+/* Fractional data portion for PLL */
+#define PM_PLL_PARAM_DATA	2
+
+/* System shutdown macros */
+#define	XPM_SHUTDOWN_TYPE_SHUTDOWN	0U
+#define	XPM_SHUTDOWN_TYPE_RESET		1U
+#define	XPM_SHUTDOWN_TYPE_SETSCOPE_ONLY	2U
+
+#define	XPM_SHUTDOWN_SUBTYPE_RST_SUBSYSTEM	0U
+#define	XPM_SHUTDOWN_SUBTYPE_RST_PS_ONLY	1U
+#define	XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM		2U
+
+/*********************************************************************
+ * Enum definitions
+ ********************************************************************/
+
+enum pm_abort_reason {
+	ABORT_REASON_WKUP_EVENT = 100,
+	ABORT_REASON_PU_BUSY,
+	ABORT_REASON_NO_PWRDN,
+	ABORT_REASON_UNKNOWN,
+};
+
+enum pm_opchar_type {
+	PM_OPCHAR_TYPE_POWER = 1,
+	PM_OPCHAR_TYPE_TEMP,
+	PM_OPCHAR_TYPE_LATENCY,
+};
+
+/**
+ * Subsystem IDs
+ */
+typedef enum {
+	XPM_SUBSYSID_PMC,
+	XPM_SUBSYSID_PSM,
+	XPM_SUBSYSID_APU,
+	XPM_SUBSYSID_RPU0_LOCK,
+	XPM_SUBSYSID_RPU0_0,
+	XPM_SUBSYSID_RPU0_1,
+	XPM_SUBSYSID_DDR0,
+	XPM_SUBSYSID_ME,
+	XPM_SUBSYSID_PL,
+	XPM_SUBSYSID_MAX,
+} XPm_SubsystemId;
+
+/**
+ * @PM_RET_SUCCESS:		success
+ * @PM_RET_ERROR_ARGS:		illegal arguments provided (deprecated)
+ * @PM_RET_ERROR_NOTSUPPORTED:	feature not supported  (deprecated)
+ * @PM_RET_ERROR_NOFEATURE:	feature is not available
+ * @PM_RET_ERROR_INTERNAL:	internal error
+ * @PM_RET_ERROR_CONFLICT:	conflict
+ * @PM_RET_ERROR_ACCESS:	access rights violation
+ * @PM_RET_ERROR_INVALID_NODE:	invalid node
+ * @PM_RET_ERROR_DOUBLE_REQ:	duplicate request for same node
+ * @PM_RET_ERROR_ABORT_SUSPEND:	suspend procedure has been aborted
+ * @PM_RET_ERROR_TIMEOUT:	timeout in communication with PMU
+ * @PM_RET_ERROR_NODE_USED:	node is already in use
+ */
+enum pm_ret_status {
+	PM_RET_SUCCESS,
+	PM_RET_ERROR_ARGS = 1,
+	PM_RET_ERROR_NOTSUPPORTED = 4,
+	PM_RET_ERROR_NOFEATURE = 19,
+	PM_RET_ERROR_INTERNAL = 2000,
+	PM_RET_ERROR_CONFLICT = 2001,
+	PM_RET_ERROR_ACCESS = 2002,
+	PM_RET_ERROR_INVALID_NODE = 2003,
+	PM_RET_ERROR_DOUBLE_REQ = 2004,
+	PM_RET_ERROR_ABORT_SUSPEND = 2005,
+	PM_RET_ERROR_TIMEOUT = 2006,
+	PM_RET_ERROR_NODE_USED = 2007
+};
+#endif /* PM_DEFS_H */
diff --git a/plat/xilinx/versal/pm_service/pm_node.h b/plat/xilinx/versal/pm_service/pm_node.h
new file mode 100644
index 0000000..1b82ec7
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_node.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Versal PM nodes enums and defines */
+
+#ifndef PM_NODE_H
+#define PM_NODE_H
+
+/*********************************************************************
+ * Macro definitions
+ ********************************************************************/
+
+#define NODE_CLASS_SHIFT	26U
+#define NODE_SUBCLASS_SHIFT	20U
+#define NODE_TYPE_SHIFT		14U
+#define NODE_INDEX_SHIFT	0U
+#define NODE_CLASS_MASK_BITS    0x3F
+#define NODE_SUBCLASS_MASK_BITS 0x3F
+#define NODE_TYPE_MASK_BITS     0x3F
+#define NODE_INDEX_MASK_BITS    0x3FFF
+#define NODE_CLASS_MASK         (NODE_CLASS_MASK_BITS << NODE_CLASS_SHIFT)
+#define NODE_SUBCLASS_MASK      (NODE_SUBCLASS_MASK_BITS << NODE_SUBCLASS_SHIFT)
+#define NODE_TYPE_MASK          (NODE_TYPE_MASK_BITS << NODE_TYPE_SHIFT)
+#define NODE_INDEX_MASK         (NODE_INDEX_MASK_BITS << NODE_INDEX_SHIFT)
+
+#define NODEID(CLASS, SUBCLASS, TYPE, INDEX)	\
+	     ((((CLASS) & NODE_CLASS_MASK_BITS) << NODE_CLASS_SHIFT) | \
+	     (((SUBCLASS) & NODE_SUBCLASS_MASK_BITS) << NODE_SUBCLASS_SHIFT) | \
+	     (((TYPE) & NODE_TYPE_MASK_BITS) << NODE_TYPE_SHIFT) | \
+	     (((INDEX) & NODE_INDEX_MASK_BITS) << NODE_INDEX_SHIFT))
+
+#define NODECLASS(ID)		(((ID) & NODE_CLASS_MASK) >> NODE_CLASS_SHIFT)
+#define NODESUBCLASS(ID)	(((ID) & NODE_SUBCLASS_MASK) >> \
+				NODE_SUBCLASS_SHIFT)
+#define NODETYPE(ID)		(((ID) & NODE_TYPE_MASK) >> NODE_TYPE_SHIFT)
+#define NODEINDEX(ID)		(((ID) & NODE_INDEX_MASK) >> NODE_INDEX_SHIFT)
+
+/*********************************************************************
+ * Enum definitions
+ ********************************************************************/
+
+/* Node class types */
+enum pm_node_class {
+	XPM_NODECLASS_MIN,
+
+	XPM_NODECLASS_POWER,
+	XPM_NODECLASS_CLOCK,
+	XPM_NODECLASS_RESET,
+	XPM_NODECLASS_MEMIC,
+	XPM_NODECLASS_STMIC,
+	XPM_NODECLASS_DEVICE,
+
+	XPM_NODECLASS_MAX
+};
+
+enum pm_device_node_subclass {
+	/* Device types */
+	XPM_NODESUBCL_DEV_CORE = 1,
+	XPM_NODESUBCL_DEV_PERIPH,
+	XPM_NODESUBCL_DEV_MEM,
+	XPM_NODESUBCL_DEV_SOC,
+	XPM_NODESUBCL_DEV_MEM_CTRLR,
+	XPM_NODESUBCL_DEV_PHY,
+};
+
+enum pm_device_node_type {
+	/* Device types */
+	XPM_NODETYPE_DEV_CORE_PMC = 1,
+	XPM_NODETYPE_DEV_CORE_PSM,
+	XPM_NODETYPE_DEV_CORE_APU,
+	XPM_NODETYPE_DEV_CORE_RPU,
+	XPM_NODETYPE_DEV_OCM,
+	XPM_NODETYPE_DEV_TCM,
+	XPM_NODETYPE_DEV_L2CACHE,
+	XPM_NODETYPE_DEV_DDR,
+	XPM_NODETYPE_DEV_PERIPH,
+	XPM_NODETYPE_DEV_SOC,
+	XPM_NODETYPE_DEV_GT,
+};
+
+/* Device node Indexes */
+enum pm_device_node_idx {
+	/* Device nodes */
+	XPM_NODEIDX_DEV_MIN,
+
+	/* Processor devices */
+	XPM_NODEIDX_DEV_PMC_PROC,
+	XPM_NODEIDX_DEV_PSM_PROC,
+	XPM_NODEIDX_DEV_ACPU_0,
+	XPM_NODEIDX_DEV_ACPU_1,
+	XPM_NODEIDX_DEV_RPU0_0,
+	XPM_NODEIDX_DEV_RPU0_1,
+
+	/* Memory devices */
+	XPM_NODEIDX_DEV_OCM_0,
+	XPM_NODEIDX_DEV_OCM_1,
+	XPM_NODEIDX_DEV_OCM_2,
+	XPM_NODEIDX_DEV_OCM_3,
+	XPM_NODEIDX_DEV_TCM_0_A,
+	XPM_NODEIDX_DEV_TCM_0_B,
+	XPM_NODEIDX_DEV_TCM_1_A,
+	XPM_NODEIDX_DEV_TCM_1_B,
+	XPM_NODEIDX_DEV_L2_BANK_0,
+	XPM_NODEIDX_DEV_DDR_0,
+	XPM_NODEIDX_DEV_DDR_1,
+	XPM_NODEIDX_DEV_DDR_2,
+	XPM_NODEIDX_DEV_DDR_3,
+	XPM_NODEIDX_DEV_DDR_4,
+	XPM_NODEIDX_DEV_DDR_5,
+	XPM_NODEIDX_DEV_DDR_6,
+	XPM_NODEIDX_DEV_DDR_7,
+
+	/* LPD Peripheral devices */
+	XPM_NODEIDX_DEV_USB_0,
+	XPM_NODEIDX_DEV_GEM_0,
+	XPM_NODEIDX_DEV_GEM_1,
+	XPM_NODEIDX_DEV_SPI_0,
+	XPM_NODEIDX_DEV_SPI_1,
+	XPM_NODEIDX_DEV_I2C_0,
+	XPM_NODEIDX_DEV_I2C_1,
+	XPM_NODEIDX_DEV_CAN_FD_0,
+	XPM_NODEIDX_DEV_CAN_FD_1,
+	XPM_NODEIDX_DEV_UART_0,
+	XPM_NODEIDX_DEV_UART_1,
+	XPM_NODEIDX_DEV_GPIO,
+	XPM_NODEIDX_DEV_TTC_0,
+	XPM_NODEIDX_DEV_TTC_1,
+	XPM_NODEIDX_DEV_TTC_2,
+	XPM_NODEIDX_DEV_TTC_3,
+	XPM_NODEIDX_DEV_SWDT_LPD,
+
+	/* FPD Peripheral devices */
+	XPM_NODEIDX_DEV_SWDT_FPD,
+
+	/* PMC Peripheral devices */
+	XPM_NODEIDX_DEV_OSPI,
+	XPM_NODEIDX_DEV_QSPI,
+	XPM_NODEIDX_DEV_GPIO_PMC,
+	XPM_NODEIDX_DEV_I2C_PMC,
+	XPM_NODEIDX_DEV_SDIO_0,
+	XPM_NODEIDX_DEV_SDIO_1,
+
+	XPM_NODEIDX_DEV_PL_0,
+	XPM_NODEIDX_DEV_PL_1,
+	XPM_NODEIDX_DEV_PL_2,
+	XPM_NODEIDX_DEV_PL_3,
+	XPM_NODEIDX_DEV_RTC,
+	XPM_NODEIDX_DEV_ADMA_0,
+	XPM_NODEIDX_DEV_ADMA_1,
+	XPM_NODEIDX_DEV_ADMA_2,
+	XPM_NODEIDX_DEV_ADMA_3,
+	XPM_NODEIDX_DEV_ADMA_4,
+	XPM_NODEIDX_DEV_ADMA_5,
+	XPM_NODEIDX_DEV_ADMA_6,
+	XPM_NODEIDX_DEV_ADMA_7,
+	XPM_NODEIDX_DEV_IPI_0,
+	XPM_NODEIDX_DEV_IPI_1,
+	XPM_NODEIDX_DEV_IPI_2,
+	XPM_NODEIDX_DEV_IPI_3,
+	XPM_NODEIDX_DEV_IPI_4,
+	XPM_NODEIDX_DEV_IPI_5,
+	XPM_NODEIDX_DEV_IPI_6,
+
+	/* Entire SoC */
+	XPM_NODEIDX_DEV_SOC,
+
+	/* DDR memory controllers */
+	XPM_NODEIDX_DEV_DDRMC_0,
+	XPM_NODEIDX_DEV_DDRMC_1,
+	XPM_NODEIDX_DEV_DDRMC_2,
+	XPM_NODEIDX_DEV_DDRMC_3,
+
+	/* GT devices */
+	XPM_NODEIDX_DEV_GT_0,
+	XPM_NODEIDX_DEV_GT_1,
+	XPM_NODEIDX_DEV_GT_2,
+	XPM_NODEIDX_DEV_GT_3,
+	XPM_NODEIDX_DEV_GT_4,
+	XPM_NODEIDX_DEV_GT_5,
+	XPM_NODEIDX_DEV_GT_6,
+	XPM_NODEIDX_DEV_GT_7,
+	XPM_NODEIDX_DEV_GT_8,
+	XPM_NODEIDX_DEV_GT_9,
+	XPM_NODEIDX_DEV_GT_10,
+
+	XPM_NODEIDX_DEV_MAX
+};
+
+#endif /* PM_NODE_H */
diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.c b/plat/xilinx/versal/pm_service/pm_svc_main.c
new file mode 100644
index 0000000..a3a9f43
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_svc_main.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Top-level SMC handler for Versal power management calls and
+ * IPI setup functions for communication with PMC.
+ */
+
+#include <errno.h>
+#include <plat_private.h>
+#include <stdbool.h>
+#include <common/runtime_svc.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_ipi.h"
+
+/* pm_up = true - UP, pm_up = false - DOWN */
+static bool pm_up;
+
+/**
+ * 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.
+ */
+int pm_setup(void)
+{
+	int status, ret = 0;
+
+	status = pm_ipi_init(primary_proc);
+
+	if (status < 0) {
+		INFO("BL31: PM Service Init Failed, Error Code %d!\n", status);
+		ret = status;
+	} else {
+		pm_up = true;
+	}
+
+	return ret;
+}
+
+/**
+ * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
+ * @smc_fid - Function Identifier
+ * @x1 - x4 - Arguments
+ * @cookie  - Unused
+ * @handler - Pointer to caller's context structure
+ *
+ * @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, void *cookie, void *handle, uint64_t flags)
+{
+	enum pm_ret_status ret;
+
+	uint32_t pm_arg[4];
+
+	/* Handle case where PM wasn't initialized properly */
+	if (!pm_up)
+		SMC_RET1(handle, SMC_UNK);
+
+	pm_arg[0] = (uint32_t)x1;
+	pm_arg[1] = (uint32_t)(x1 >> 32);
+	pm_arg[2] = (uint32_t)x2;
+	pm_arg[3] = (uint32_t)(x2 >> 32);
+
+	switch (smc_fid & FUNCID_NUM_MASK) {
+	/* PM API Functions */
+	case PM_SELF_SUSPEND:
+		ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
+				      pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_FORCE_POWERDOWN:
+		ret = pm_force_powerdown(pm_arg[0], pm_arg[1]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_REQ_SUSPEND:
+		ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
+				     pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_ABORT_SUSPEND:
+		ret = pm_abort_suspend(pm_arg[0]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_SYSTEM_SHUTDOWN:
+		ret = pm_system_shutdown(pm_arg[0], pm_arg[1]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_REQ_WAKEUP:
+		ret = pm_req_wakeup(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_SET_WAKEUP_SOURCE:
+		ret = pm_set_wakeup_source(pm_arg[0], pm_arg[1], pm_arg[2]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_REQUEST_DEVICE:
+		ret = pm_request_device(pm_arg[0], pm_arg[1], pm_arg[2],
+					pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_RELEASE_DEVICE:
+		ret = pm_release_device(pm_arg[0]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_SET_REQUIREMENT:
+		ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2],
+					 pm_arg[3]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_GET_API_VERSION:
+	{
+		uint32_t api_version;
+
+		ret = pm_get_api_version(&api_version);
+		SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
+				 ((uint64_t)api_version << 32));
+	}
+
+	case PM_GET_DEVICE_STATUS:
+	{
+		uint32_t buff[3];
+
+		ret = pm_get_device_status(pm_arg[0], buff);
+		SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buff[0] << 32),
+			 (uint64_t)buff[1] | ((uint64_t)buff[2] << 32));
+	}
+
+	case PM_RESET_ASSERT:
+		ret = pm_reset_assert(pm_arg[0], pm_arg[1]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_RESET_GET_STATUS:
+	{
+		uint32_t reset_status;
+
+		ret = pm_reset_get_status(pm_arg[0], &reset_status);
+		SMC_RET1(handle, (uint64_t)ret |
+			 ((uint64_t)reset_status << 32));
+	}
+
+	case PM_INIT_FINALIZE:
+		SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS);
+
+	case PM_GET_CALLBACK_DATA:
+	{
+		uint32_t result[4] = {0};
+
+		pm_get_callbackdata(result, sizeof(result));
+		SMC_RET2(handle,
+			 (uint64_t)result[0] | ((uint64_t)result[1] << 32),
+			 (uint64_t)result[2] | ((uint64_t)result[3] << 32));
+	}
+
+	case PM_PINCTRL_REQUEST:
+		ret = pm_pinctrl_request(pm_arg[0]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_PINCTRL_RELEASE:
+		ret = pm_pinctrl_release(pm_arg[0]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_PINCTRL_GET_FUNCTION:
+	{
+		uint32_t value = 0;
+
+		ret = pm_pinctrl_get_function(pm_arg[0], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_PINCTRL_SET_FUNCTION:
+		ret = pm_pinctrl_set_function(pm_arg[0], pm_arg[1]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_PINCTRL_CONFIG_PARAM_GET:
+	{
+		uint32_t value;
+
+		ret = pm_pinctrl_get_pin_param(pm_arg[0], pm_arg[1], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_PINCTRL_CONFIG_PARAM_SET:
+		ret = pm_pinctrl_set_pin_param(pm_arg[0], pm_arg[1], pm_arg[2]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_IOCTL:
+	{
+		uint32_t value;
+
+		ret = pm_api_ioctl(pm_arg[0], pm_arg[1], pm_arg[2],
+				   pm_arg[3], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_QUERY_DATA:
+	{
+		uint32_t data[4] = { 0 };
+
+		ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2],
+			      pm_arg[3], data);
+		SMC_RET2(handle, (uint64_t)ret  | ((uint64_t)data[0] << 32),
+			 (uint64_t)data[1] | ((uint64_t)data[2] << 32));
+	}
+
+	case PM_CLOCK_ENABLE:
+		ret = pm_clock_enable(pm_arg[0]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_CLOCK_DISABLE:
+		ret = pm_clock_disable(pm_arg[0]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_CLOCK_GETSTATE:
+	{
+		uint32_t value;
+
+		ret = pm_clock_get_state(pm_arg[0], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_CLOCK_SETDIVIDER:
+		ret = pm_clock_set_divider(pm_arg[0], pm_arg[1]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_CLOCK_GETDIVIDER:
+	{
+		uint32_t value;
+
+		ret = pm_clock_get_divider(pm_arg[0], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_CLOCK_SETPARENT:
+		ret = pm_clock_set_parent(pm_arg[0], pm_arg[1]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_CLOCK_GETPARENT:
+	{
+		uint32_t value;
+
+		ret = pm_clock_get_parent(pm_arg[0], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+	}
+
+	case PM_PLL_SET_PARAMETER:
+		ret = pm_pll_set_param(pm_arg[0], pm_arg[1], pm_arg[2]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_PLL_GET_PARAMETER:
+	{
+		uint32_t value;
+
+		ret = pm_pll_get_param(pm_arg[0], pm_arg[1], &value);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value << 32));
+	}
+
+	case PM_PLL_SET_MODE:
+		ret = pm_pll_set_mode(pm_arg[0], pm_arg[1]);
+		SMC_RET1(handle, (uint64_t)ret);
+
+	case PM_PLL_GET_MODE:
+	{
+		uint32_t mode;
+
+		ret = pm_pll_get_mode(pm_arg[0], &mode);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)mode << 32));
+	}
+
+	case PM_GET_TRUSTZONE_VERSION:
+		SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
+			 ((uint64_t)VERSAL_TZ_VERSION << 32));
+
+	case PM_GET_CHIPID:
+	{
+		uint32_t result[2];
+
+		ret = pm_get_chipid(result);
+		SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32),
+			 result[1]);
+	}
+
+	case PM_FEATURE_CHECK:
+	{
+		uint32_t version;
+
+		ret = pm_feature_check(pm_arg[0], &version);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)version << 32));
+	}
+
+	case PM_LOAD_PDI:
+	{
+		ret = pm_load_pdi(pm_arg[0], pm_arg[1], pm_arg[2]);
+		SMC_RET1(handle, (uint64_t)ret);
+	}
+
+	case PM_GET_OP_CHARACTERISTIC:
+	{
+		uint32_t result;
+
+		ret = pm_get_op_characteristic(pm_arg[0], pm_arg[1], &result);
+		SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result << 32));
+	}
+
+	default:
+		WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
+		SMC_RET1(handle, SMC_UNK);
+	}
+}
diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.h b/plat/xilinx/versal/pm_service/pm_svc_main.h
new file mode 100644
index 0000000..71329ca
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_svc_main.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PM_SVC_MAIN_H
+#define PM_SVC_MAIN_H
+
+#include <pm_common.h>
+
+int pm_setup(void);
+uint64_t pm_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);
+
+#endif /* PM_SVC_MAIN_H */
diff --git a/plat/xilinx/versal/sip_svc_setup.c b/plat/xilinx/versal/sip_svc_setup.c
index 8f2180b..bc7d8b7 100644
--- a/plat/xilinx/versal/sip_svc_setup.c
+++ b/plat/xilinx/versal/sip_svc_setup.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -10,6 +10,9 @@
 #include <common/runtime_svc.h>
 #include <tools_share/uuid.h>
 
+#include "ipi_mailbox_svc.h"
+#include "pm_svc_main.h"
+
 /* SMC function IDs for SiP Service queries */
 #define VERSAL_SIP_SVC_CALL_COUNT	0x8200ff00
 #define VERSAL_SIP_SVC_UID		0x8200ff01
@@ -22,7 +25,9 @@
 /* These macros are used to identify PM calls from the SMC function ID */
 #define PM_FID_MASK	0xf000u
 #define PM_FID_VALUE	0u
+#define IPI_FID_VALUE	0x1000u
 #define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE)
+#define is_ipi_fid(_fid) (((_fid) & PM_FID_MASK) == IPI_FID_VALUE)
 
 /* SiP Service UUID */
 DEFINE_SVC_UUID2(versal_sip_uuid,
@@ -36,6 +41,9 @@
  */
 static int32_t sip_svc_setup(void)
 {
+	/* PM implementation as SiP Service */
+	pm_setup();
+
 	return 0;
 }
 
@@ -55,6 +63,18 @@
 			     u_register_t flags)
 {
 	/* Let PM SMC handler deal with PM-related requests */
+	if (is_pm_fid(smc_fid)) {
+		return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+				      flags);
+	}
+
+	/* Let IPI SMC handler deal with IPI-related requests */
+	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 VERSAL_SIP_SVC_CALL_COUNT:
 		/* PM functions + default functions */
diff --git a/plat/xilinx/versal/versal_gicv3.c b/plat/xilinx/versal/versal_gicv3.c
index dcf23b4..08e7cf9 100644
--- a/plat/xilinx/versal/versal_gicv3.c
+++ b/plat/xilinx/versal/versal_gicv3.c
@@ -1,9 +1,10 @@
 /*
- * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
 
+#include <plat_private.h>
 #include <platform_def.h>
 
 #include <common/interrupt_props.h>
@@ -11,8 +12,6 @@
 #include <lib/utils.h>
 #include <plat/common/platform.h>
 
-#include "versal_private.h"
-
 /******************************************************************************
  * The following functions are defined as weak to allow a platform to override
  * the way the GICv3 driver is initialised and used.
diff --git a/plat/xilinx/versal/versal_ipi.c b/plat/xilinx/versal/versal_ipi.c
new file mode 100644
index 0000000..27541ff
--- /dev/null
+++ b/plat/xilinx/versal/versal_ipi.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Versal IPI agent registers access management
+ */
+
+#include <errno.h>
+#include <ipi.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+#include <string.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+/* versal ipi configuration table */
+const static struct ipi_config versal_ipi_table[] = {
+	/* A72 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 = 0,
+	},
+
+	/* 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,
+	},
+};
+
+/* versal_ipi_config_table_init() - Initialize versal IPI configuration data
+ *
+ * @ipi_config_table  - IPI configuration table
+ * @ipi_total - Total number of IPI available
+ *
+ */
+void versal_ipi_config_table_init(void)
+{
+	ipi_config_table_init(versal_ipi_table, ARRAY_SIZE(versal_ipi_table));
+}
diff --git a/plat/xilinx/zynqmp/plat_psci.c b/plat/xilinx/zynqmp/plat_psci.c
index a32e089..f579f79 100644
--- a/plat/xilinx/zynqmp/plat_psci.c
+++ b/plat/xilinx/zynqmp/plat_psci.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
  */
@@ -100,9 +100,8 @@
 	for (size_t 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_arm_gic_pcpu_init();
 	gicv2_cpuif_enable();
-	gicv2_pcpu_distif_init();
 }
 
 static void zynqmp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk
index 1039e27..de4bf3a 100644
--- a/plat/xilinx/zynqmp/platform.mk
+++ b/plat/xilinx/zynqmp/platform.mk
@@ -11,6 +11,8 @@
 ZYNQMP_WDT_RESTART := 0
 ZYNQMP_IPI_CRC_CHECK := 0
 override RESET_TO_BL31 := 1
+override GICV2_G0_FOR_EL3 := 1
+override WARMBOOT_ENABLE_DCACHE_EARLY := 1
 
 # Do not enable SVE
 ENABLE_SVE_FOR_NS	:= 0
@@ -53,9 +55,9 @@
 PLAT_INCLUDES		:=	-Iinclude/plat/arm/common/			\
 				-Iinclude/plat/arm/common/aarch64/		\
 				-Iplat/xilinx/common/include/			\
+				-Iplat/xilinx/common/ipi_mailbox_service/	\
 				-Iplat/xilinx/zynqmp/include/			\
 				-Iplat/xilinx/zynqmp/pm_service/		\
-				-Iplat/xilinx/zynqmp/ipi_mailbox_service/
 
 PLAT_BL_COMMON_SOURCES	:=	lib/xlat_tables/xlat_tables_common.c		\
 				lib/xlat_tables/aarch64/xlat_tables.c		\
@@ -78,6 +80,7 @@
 				lib/cpus/aarch64/aem_generic.S			\
 				lib/cpus/aarch64/cortex_a53.S			\
 				plat/common/plat_psci_common.c			\
+				plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c \
 				plat/xilinx/common/pm_service/pm_ipi.c		\
 				plat/xilinx/zynqmp/bl31_zynqmp_setup.c		\
 				plat/xilinx/zynqmp/plat_psci.c			\
@@ -90,5 +93,8 @@
 				plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c	\
 				plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c	\
 				plat/xilinx/zynqmp/pm_service/pm_api_clock.c	\
-				plat/xilinx/zynqmp/pm_service/pm_client.c	\
-				plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c
+				plat/xilinx/zynqmp/pm_service/pm_client.c
+
+ifneq (${RESET_TO_BL31},1)
+  $(error "Using BL31 as the reset vector is only one option supported on ZynqMP. Please set RESET_TO_BL31 to 1.")
+endif
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
index 5a320f1..98dbe7d 100644
--- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
@@ -77,8 +77,12 @@
 
 	INFO("Active Cores: %d\n", active_cores);
 
-	/* trigger SGI to active cores */
-	gicv2_raise_sgi(ARM_IRQ_SEC_SGI_7, target_cpu_list);
+	for (i = PLATFORM_CORE_COUNT - 1; i >= 0; i--) {
+		if (target_cpu_list & (1 << i)) {
+			/* trigger SGI to active cores */
+			plat_ic_raise_el3_sgi(ARM_IRQ_SEC_SGI_7, i);
+		}
+	}
 }
 
 /**
@@ -106,6 +110,8 @@
 {
 	INFO("BL31: Got TTC FIQ\n");
 
+	plat_ic_end_of_interrupt(id);
+
 	/* Clear TTC interrupt by reading interrupt register */
 	mmio_read_32(TTC3_INTR_REGISTER_1);