summaryrefslogtreecommitdiffstats
path: root/plat/xilinx/common
diff options
context:
space:
mode:
Diffstat (limited to 'plat/xilinx/common')
-rw-r--r--plat/xilinx/common/include/ipi.h77
-rw-r--r--plat/xilinx/common/include/plat_common.h17
-rw-r--r--plat/xilinx/common/include/plat_console.h27
-rw-r--r--plat/xilinx/common/include/plat_fdt.h12
-rw-r--r--plat/xilinx/common/include/plat_startup.h46
-rw-r--r--plat/xilinx/common/include/pm_api_sys.h103
-rw-r--r--plat/xilinx/common/include/pm_client.h37
-rw-r--r--plat/xilinx/common/include/pm_common.h65
-rw-r--r--plat/xilinx/common/include/pm_defs.h284
-rw-r--r--plat/xilinx/common/include/pm_ipi.h37
-rw-r--r--plat/xilinx/common/include/pm_node.h243
-rw-r--r--plat/xilinx/common/include/pm_svc_main.h39
-rw-r--r--plat/xilinx/common/ipi.c221
-rw-r--r--plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c142
-rw-r--r--plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h39
-rw-r--r--plat/xilinx/common/plat_console.c346
-rw-r--r--plat/xilinx/common/plat_fdt.c98
-rw-r--r--plat/xilinx/common/plat_startup.c300
-rw-r--r--plat/xilinx/common/pm_service/pm_api_sys.c686
-rw-r--r--plat/xilinx/common/pm_service/pm_ipi.c353
-rw-r--r--plat/xilinx/common/pm_service/pm_svc_main.c449
-rw-r--r--plat/xilinx/common/tsp/tsp.mk8
-rw-r--r--plat/xilinx/common/tsp/tsp_plat_setup.c89
-rw-r--r--plat/xilinx/common/versal.c63
24 files changed, 3781 insertions, 0 deletions
diff --git a/plat/xilinx/common/include/ipi.h b/plat/xilinx/common/include/ipi.h
new file mode 100644
index 0000000..1d62f3e
--- /dev/null
+++ b/plat/xilinx/common/include/ipi.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Xilinx IPI management configuration data and macros */
+
+#ifndef IPI_H
+#define IPI_H
+
+#include <stdint.h>
+
+/*********************************************************************
+ * IPI mailbox status macros
+ ********************************************************************/
+#define IPI_MB_STATUS_IDLE (0U)
+#define IPI_MB_STATUS_SEND_PENDING (1U)
+#define IPI_MB_STATUS_RECV_PENDING (2U)
+
+/*********************************************************************
+ * IPI mailbox call is secure or not macros
+ ********************************************************************/
+#define IPI_MB_CALL_NOTSECURE (0U)
+#define IPI_MB_CALL_SECURE (1U)
+
+/*********************************************************************
+ * IPI secure check
+ ********************************************************************/
+#define IPI_SECURE_MASK (0x1U)
+#define IPI_IS_SECURE(I) ((ipi_table[(I)].secure_only & \
+ IPI_SECURE_MASK) ? 1 : 0)
+
+/*********************************************************************
+ * Struct definitions
+ ********************************************************************/
+
+/* structure to maintain IPI configuration information */
+struct ipi_config {
+ unsigned int ipi_bit_mask;
+ unsigned int ipi_reg_base;
+ unsigned char secure_only;
+};
+
+/*********************************************************************
+ * IPI APIs declarations
+ ********************************************************************/
+
+/* Initialize IPI configuration table */
+void ipi_config_table_init(const struct ipi_config *ipi_config_table,
+ uint32_t total_ipi);
+
+/* Validate IPI mailbox access */
+int ipi_mb_validate(uint32_t local, uint32_t remote, unsigned int is_secure);
+
+/* Open the IPI mailbox */
+void ipi_mb_open(uint32_t local, uint32_t remote);
+
+/* Release the IPI mailbox */
+void ipi_mb_release(uint32_t local, uint32_t remote);
+
+/* Enquire IPI mailbox status */
+int ipi_mb_enquire_status(uint32_t local, uint32_t remote);
+
+/* Trigger notification on the IPI mailbox */
+void ipi_mb_notify(uint32_t local, uint32_t remote, uint32_t is_blocking);
+
+/* Ack IPI mailbox notification */
+void ipi_mb_ack(uint32_t local, uint32_t remote);
+
+/* Disable IPI mailbox notification interrupt */
+void ipi_mb_disable_irq(uint32_t local, uint32_t remote);
+
+/* Enable IPI mailbox notification interrupt */
+void ipi_mb_enable_irq(uint32_t local, uint32_t remote);
+
+#endif /* IPI_H */
diff --git a/plat/xilinx/common/include/plat_common.h b/plat/xilinx/common/include/plat_common.h
new file mode 100644
index 0000000..676baa2
--- /dev/null
+++ b/plat/xilinx/common/include/plat_common.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2023, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Header file to contain common macros across different platforms */
+#ifndef PLAT_COMMON_H
+#define PLAT_COMMON_H
+
+#define __bf_shf(x) (__builtin_ffsll(x) - 1U)
+#define FIELD_GET(_mask, _reg) \
+ ({ \
+ (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \
+ })
+
+#endif /* PLAT_COMMON_H */
diff --git a/plat/xilinx/common/include/plat_console.h b/plat/xilinx/common/include/plat_console.h
new file mode 100644
index 0000000..0f8320e
--- /dev/null
+++ b/plat/xilinx/common/include/plat_console.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2023, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_DT_UART_H
+#define PLAT_DT_UART_H
+
+#define DT_UART_DCC_COMPAT "arm,dcc"
+
+#if defined(PLAT_zynqmp)
+#define DT_UART_COMPAT "xlnx,zynqmp-uart"
+#else
+#define DT_UART_COMPAT "arm,pl011"
+#endif
+
+typedef struct dt_uart_info_s {
+ char compatible[30];
+ uintptr_t base;
+ uint32_t baud_rate;
+ int32_t status;
+} dt_uart_info_t;
+
+void setup_console(void);
+
+#endif /* PLAT_DT_UART_H */
diff --git a/plat/xilinx/common/include/plat_fdt.h b/plat/xilinx/common/include/plat_fdt.h
new file mode 100644
index 0000000..a1ee1e1
--- /dev/null
+++ b/plat/xilinx/common/include/plat_fdt.h
@@ -0,0 +1,12 @@
+/*
+ * Copyright (c) 2023, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#ifndef PLAT_FDT_H
+#define PLAT_FDT_H
+
+void prepare_dtb(void);
+
+#endif /* PLAT_FDT_H */
diff --git a/plat/xilinx/common/include/plat_startup.h b/plat/xilinx/common/include/plat_startup.h
new file mode 100644
index 0000000..5270e13
--- /dev/null
+++ b/plat/xilinx/common/include/plat_startup.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_STARTUP_H
+#define PLAT_STARTUP_H
+
+#include <common/bl_common.h>
+
+/* For Xilinx bootloader XBL handover */
+enum xbl_handoff {
+ XBL_HANDOFF_SUCCESS = 0,
+ XBL_HANDOFF_NO_STRUCT,
+ XBL_HANDOFF_INVAL_STRUCT,
+ XBL_HANDOFF_TOO_MANY_PARTS
+};
+
+#define XBL_MAX_PARTITIONS 8U
+
+/* Structure corresponding to each partition entry */
+struct xbl_partition {
+ uint64_t entry_point;
+ uint64_t flags;
+};
+
+/* Structure for handoff parameters to TrustedFirmware-A (TF-A) */
+struct xbl_handoff_params {
+ uint8_t magic[4];
+ uint32_t num_entries;
+ struct xbl_partition partition[XBL_MAX_PARTITIONS];
+};
+
+#define HANDOFF_PARAMS_MAX_SIZE sizeof(struct xbl_handoff_params)
+
+enum xbl_handoff xbl_handover(entry_point_info_t *bl32,
+ entry_point_info_t *bl33,
+ uint64_t handoff_addr);
+
+/* JEDEC Standard Manufacturer's Identification Code and Bank ID JEP106 */
+#define JEDEC_XILINX_MFID U(0x49)
+#define JEDEC_XILINX_BKID U(0)
+
+#endif /* PLAT_STARTUP_H */
diff --git a/plat/xilinx/common/include/pm_api_sys.h b/plat/xilinx/common/include/pm_api_sys.h
new file mode 100644
index 0000000..3fcb62f
--- /dev/null
+++ b/plat/xilinx/common/include/pm_api_sys.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Advanced Micro Devices, 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"
+
+/*********************************************************************
+ * Target module IDs macros
+ ********************************************************************/
+#define LIBPM_MODULE_ID 0x2U
+#define LOADER_MODULE_ID 0x7U
+
+#define MODULE_ID_MASK 0x0000ff00U
+/**********************************************************
+ * PM API function declarations
+ **********************************************************/
+
+enum pm_ret_status pm_handle_eemi_call(uint32_t flag, uint32_t x0, uint32_t x1,
+ uint32_t x2, uint32_t x3, uint32_t x4,
+ uint32_t x5, uint64_t *result);
+enum pm_ret_status pm_self_suspend(uint32_t nid,
+ uint32_t latency,
+ uint32_t state,
+ uintptr_t address, uint32_t flag);
+enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason, uint32_t flag);
+enum pm_ret_status pm_req_suspend(uint32_t target,
+ uint8_t ack,
+ uint32_t latency,
+ uint32_t state, uint32_t flag);
+enum pm_ret_status pm_req_wakeup(uint32_t target, uint32_t set_address,
+ uintptr_t address, uint8_t ack, uint32_t flag);
+enum pm_ret_status pm_set_wakeup_source(uint32_t target, uint32_t device_id,
+ uint8_t enable, uint32_t flag);
+enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag,
+ uint32_t ack);
+void pm_client_set_wakeup_sources(uint32_t node_id);
+enum pm_ret_status pm_pll_set_param(uint32_t clk_id, uint32_t param,
+ uint32_t value, uint32_t flag);
+enum pm_ret_status pm_pll_get_param(uint32_t clk_id, uint32_t param,
+ uint32_t *value, uint32_t flag);
+enum pm_ret_status pm_pll_set_mode(uint32_t clk_id, uint32_t mode,
+ uint32_t flag);
+enum pm_ret_status pm_pll_get_mode(uint32_t clk_id, uint32_t *mode,
+ uint32_t flag);
+enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack,
+ uint32_t flag);
+enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype,
+ uint32_t flag);
+enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id,
+ uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t *value, uint32_t flag);
+enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t *data, uint32_t flag);
+uint32_t pm_get_shutdown_scope(void);
+enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *ret_payload,
+ uint32_t flag);
+enum pm_ret_status pm_load_pdi(uint32_t src, uint32_t address_low,
+ uint32_t address_high, uint32_t flag);
+enum pm_ret_status pm_register_notifier(uint32_t device_id, uint32_t event,
+ uint32_t wake, uint32_t enable,
+ uint32_t flag);
+enum pm_ret_status pm_get_chipid(uint32_t *value);
+
+/*
+ * Assigning of argument values into array elements.
+ */
+#define PM_PACK_PAYLOAD1(pl, mid, flag, arg0) { \
+ pl[0] = (uint32_t)(((uint32_t)(arg0) & 0xFFU) | ((mid) << 8U) | ((flag) << 24U)); \
+}
+
+#define PM_PACK_PAYLOAD2(pl, mid, flag, arg0, arg1) { \
+ pl[1] = (uint32_t)(arg1); \
+ PM_PACK_PAYLOAD1(pl, (mid), (flag), (arg0)); \
+}
+
+#define PM_PACK_PAYLOAD3(pl, mid, flag, arg0, arg1, arg2) { \
+ pl[2] = (uint32_t)(arg2); \
+ PM_PACK_PAYLOAD2(pl, (mid), (flag), (arg0), (arg1)); \
+}
+
+#define PM_PACK_PAYLOAD4(pl, mid, flag, arg0, arg1, arg2, arg3) { \
+ pl[3] = (uint32_t)(arg3); \
+ PM_PACK_PAYLOAD3(pl, (mid), (flag), (arg0), (arg1), (arg2)); \
+}
+
+#define PM_PACK_PAYLOAD5(pl, mid, flag, arg0, arg1, arg2, arg3, arg4) { \
+ pl[4] = (uint32_t)(arg4); \
+ PM_PACK_PAYLOAD4(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3)); \
+}
+
+#define PM_PACK_PAYLOAD6(pl, mid, flag, arg0, arg1, arg2, arg3, arg4, arg5) { \
+ pl[5] = (uint32_t)(arg5); \
+ PM_PACK_PAYLOAD5(pl, (mid), (flag), (arg0), (arg1), (arg2), (arg3), (arg4)); \
+}
+
+#endif /* PM_API_SYS_H */
diff --git a/plat/xilinx/common/include/pm_client.h b/plat/xilinx/common/include/pm_client.h
new file mode 100644
index 0000000..a87923f
--- /dev/null
+++ b/plat/xilinx/common/include/pm_client.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Contains APU specific macros and macros to be defined depending on
+ * the execution environment.
+ */
+
+#ifndef PM_CLIENT_H
+#define PM_CLIENT_H
+
+#include "pm_common.h"
+#include "pm_defs.h"
+
+/* Functions to be implemented by each PU */
+void pm_client_suspend(const struct pm_proc *proc, uint32_t state);
+void pm_client_abort_suspend(void);
+void pm_client_wakeup(const struct pm_proc *proc);
+
+#if !defined(PLAT_zynqmp)
+enum pm_device_node_idx irq_to_pm_node_idx(uint32_t irq);
+#endif
+
+/* Global variables to be set in pm_client.c */
+extern const struct pm_proc *primary_proc;
+
+#if defined(PLAT_zynqmp)
+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 /* PLAT_zynqmp */
+
+#endif /* PM_CLIENT_H */
diff --git a/plat/xilinx/common/include/pm_common.h b/plat/xilinx/common/include/pm_common.h
new file mode 100644
index 0000000..c0308ab
--- /dev/null
+++ b/plat/xilinx/common/include/pm_common.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2013-2018, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Contains definitions of commonly used macros and data types needed
+ * for PU Power Management. This file should be common for all PU's.
+ */
+
+#ifndef PM_COMMON_H
+#define PM_COMMON_H
+
+#include <stdint.h>
+#include <plat_pm_common.h>
+
+#if IPI_CRC_CHECK
+#define PAYLOAD_ARG_CNT 8U
+#define IPI_W0_TO_W6_SIZE 28U
+#define PAYLOAD_CRC_POS 7U
+#define CRC_INIT_VALUE 0x4F4EU
+#define CRC_ORDER 16U
+#define CRC_POLYNOM 0x8005U
+#else
+#define PAYLOAD_ARG_CNT 6U
+#endif
+#define PAYLOAD_ARG_SIZE 4U /* size in bytes */
+
+#define TZ_VERSION_MAJOR 1
+#define TZ_VERSION_MINOR 0
+#define TZ_VERSION ((TZ_VERSION_MAJOR << 16) | \
+ TZ_VERSION_MINOR)
+
+/**
+ * struct pm_ipi - struct for capturing IPI-channel specific info.
+ * @local_ipi_id: Local IPI agent ID.
+ * @remote_ipi_id: Remote IPI Agent ID.
+ * @buffer_base: base address for payload buffer.
+ *
+ */
+struct pm_ipi {
+ const uint32_t local_ipi_id;
+ const uint32_t remote_ipi_id;
+ const uintptr_t buffer_base;
+};
+
+/**
+ * struct pm_proc - struct for capturing processor related info.
+ * @node_id: node-ID of the processor.
+ * @pwrdn_mask: cpu-specific mask to be used for power control register.
+ * @ipi: pointer to IPI channel structure.
+ * (in APU all processors share one IPI channel)
+ *
+ */
+struct pm_proc {
+ const uint32_t node_id;
+ const uint32_t pwrdn_mask;
+ const struct pm_ipi *ipi;
+};
+
+const struct pm_proc *pm_get_proc(uint32_t cpuid);
+
+#endif /* PM_COMMON_H */
diff --git a/plat/xilinx/common/include/pm_defs.h b/plat/xilinx/common/include/pm_defs.h
new file mode 100644
index 0000000..9cdb0ba
--- /dev/null
+++ b/plat/xilinx/common/include/pm_defs.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Advanced Micro Devices, 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((uint32_t)XPM_NODECLASS_DEVICE, \
+ (uint32_t)XPM_NODESUBCL_DEV_PERIPH, \
+ (uint32_t)XPM_NODETYPE_DEV_PERIPH, (IDX))
+
+#define PM_GET_CALLBACK_DATA 0xa01U
+#define PM_GET_TRUSTZONE_VERSION 0xa03U
+#define TF_A_PM_REGISTER_SGI 0xa04U
+
+/* PM API Versions */
+#define PM_API_BASE_VERSION 1U
+#define PM_API_VERSION_2 2U
+
+/* Loader API ids */
+#define PM_LOAD_PDI 0x701U
+#define PM_LOAD_GET_HANDOFF_PARAMS 0x70BU
+
+/* 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
+ ********************************************************************/
+
+/*
+ * ioctl id
+ */
+enum {
+ IOCTL_GET_RPU_OPER_MODE = 0,
+ IOCTL_SET_RPU_OPER_MODE = 1,
+ IOCTL_RPU_BOOT_ADDR_CONFIG = 2,
+ IOCTL_TCM_COMB_CONFIG = 3,
+ IOCTL_SET_TAPDELAY_BYPASS = 4,
+ IOCTL_SD_DLL_RESET = 6,
+ IOCTL_SET_SD_TAPDELAY = 7,
+ /* Ioctl for clock driver */
+ IOCTL_SET_PLL_FRAC_MODE = 8,
+ IOCTL_GET_PLL_FRAC_MODE = 9,
+ IOCTL_SET_PLL_FRAC_DATA = 10,
+ IOCTL_GET_PLL_FRAC_DATA = 11,
+ IOCTL_WRITE_GGS = 12,
+ IOCTL_READ_GGS = 13,
+ IOCTL_WRITE_PGGS = 14,
+ IOCTL_READ_PGGS = 15,
+ /* IOCTL for ULPI reset */
+ IOCTL_ULPI_RESET = 16,
+ /* Set healthy bit value */
+ IOCTL_SET_BOOT_HEALTH_STATUS = 17,
+ IOCTL_AFI = 18,
+ /* Probe counter read/write */
+ IOCTL_PROBE_COUNTER_READ = 19,
+ IOCTL_PROBE_COUNTER_WRITE = 20,
+ IOCTL_OSPI_MUX_SELECT = 21,
+ /* IOCTL for USB power request */
+ IOCTL_USB_SET_STATE = 22,
+ /* IOCTL to get last reset reason */
+ IOCTL_GET_LAST_RESET_REASON = 23,
+ /* AI engine NPI ISR clear */
+ IOCTL_AIE_ISR_CLEAR = 24,
+ /* Register SGI to TF-A */
+ IOCTL_SET_SGI = 25,
+};
+
+/**
+ * enum pm_pll_param - enum represents the parameters for a phase-locked loop.
+ * @PM_PLL_PARAM_DIV2: Enable for divide by 2 function inside the PLL.
+ * @PM_PLL_PARAM_FBDIV: Feedback divisor integer portion for the PLL.
+ * @PM_PLL_PARAM_DATA: Feedback divisor fractional portion for the PLL.
+ * @PM_PLL_PARAM_PRE_SRC: Clock source for PLL input.
+ * @PM_PLL_PARAM_POST_SRC: Clock source for PLL Bypass mode.
+ * @PM_PLL_PARAM_LOCK_DLY: Lock circuit config settings for lock windowsize.
+ * @PM_PLL_PARAM_LOCK_CNT: Lock circuit counter setting.
+ * @PM_PLL_PARAM_LFHF: PLL loop filter high frequency capacitor control.
+ * @PM_PLL_PARAM_CP: PLL charge pump control.
+ * @PM_PLL_PARAM_RES: PLL loop filter resistor control.
+ * @PM_PLL_PARAM_MAX: Represents the maximum parameter value for the PLL
+ */
+enum pm_pll_param {
+ PM_PLL_PARAM_DIV2,
+ PM_PLL_PARAM_FBDIV,
+ PM_PLL_PARAM_DATA,
+ PM_PLL_PARAM_PRE_SRC,
+ PM_PLL_PARAM_POST_SRC,
+ PM_PLL_PARAM_LOCK_DLY,
+ PM_PLL_PARAM_LOCK_CNT,
+ PM_PLL_PARAM_LFHF,
+ PM_PLL_PARAM_CP,
+ PM_PLL_PARAM_RES,
+ PM_PLL_PARAM_MAX,
+};
+
+enum pm_api_id {
+ /* Miscellaneous API functions: */
+ PM_GET_API_VERSION = 1, /* Do not change or move */
+ PM_SET_CONFIGURATION,
+ PM_GET_NODE_STATUS,
+ PM_GET_OP_CHARACTERISTIC,
+ PM_REGISTER_NOTIFIER,
+ /* API for suspending of PUs: */
+ PM_REQ_SUSPEND,
+ PM_SELF_SUSPEND,
+ PM_FORCE_POWERDOWN,
+ PM_ABORT_SUSPEND,
+ PM_REQ_WAKEUP,
+ PM_SET_WAKEUP_SOURCE,
+ PM_SYSTEM_SHUTDOWN,
+ /* API for managing PM slaves: */
+ PM_REQ_NODE,
+ PM_RELEASE_NODE,
+ PM_SET_REQUIREMENT,
+ PM_SET_MAX_LATENCY,
+ /* Direct control API functions: */
+ PM_RESET_ASSERT,
+ PM_RESET_GET_STATUS,
+ PM_MMIO_WRITE,
+ PM_MMIO_READ,
+ PM_INIT_FINALIZE,
+ PM_FPGA_LOAD,
+ PM_FPGA_GET_STATUS,
+ PM_GET_CHIPID,
+ PM_SECURE_RSA_AES,
+ PM_SECURE_SHA,
+ PM_SECURE_RSA,
+ PM_PINCTRL_REQUEST,
+ PM_PINCTRL_RELEASE,
+ PM_PINCTRL_GET_FUNCTION,
+ PM_PINCTRL_SET_FUNCTION,
+ PM_PINCTRL_CONFIG_PARAM_GET,
+ PM_PINCTRL_CONFIG_PARAM_SET,
+ PM_IOCTL,
+ /* API to query information from firmware */
+ PM_QUERY_DATA,
+ /* Clock control API functions */
+ PM_CLOCK_ENABLE,
+ PM_CLOCK_DISABLE,
+ PM_CLOCK_GETSTATE,
+ PM_CLOCK_SETDIVIDER,
+ PM_CLOCK_GETDIVIDER,
+ PM_CLOCK_SETPARENT = 43,
+ PM_CLOCK_GETPARENT,
+ PM_SECURE_IMAGE,
+ /* FPGA PL Readback */
+ PM_FPGA_READ,
+ PM_SECURE_AES,
+ /* PLL control API functions */
+ PM_PLL_SET_PARAMETER,
+ PM_PLL_GET_PARAMETER,
+ PM_PLL_SET_MODE,
+ PM_PLL_GET_MODE,
+ /* PM Register Access API */
+ PM_REGISTER_ACCESS,
+ PM_EFUSE_ACCESS,
+ PM_FPGA_GET_VERSION,
+ PM_FPGA_GET_FEATURE_LIST,
+ PM_FEATURE_CHECK = 63,
+ PM_API_MAX = 74
+};
+
+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;
+
+/* TODO: move pm_ret_status from device specific location to common location */
+/**
+ * enum pm_ret_status - enum represents the return status codes for a PM
+ * operation.
+ * @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_INVALID_CRC: invalid crc in IPI communication.
+ * @PM_RET_ERROR_NOT_ENABLED: feature is not enabled.
+ * @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.
+ * @PM_RET_ERROR_NO_FEATURE: indicates that the requested feature is not
+ * supported.
+ */
+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_INVALID_CRC = 301,
+ PM_RET_ERROR_NOT_ENABLED = 29,
+ 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,
+ PM_RET_ERROR_NO_FEATURE = 2008
+};
+
+/*
+ * Qids
+ */
+enum pm_query_id {
+ XPM_QID_INVALID,
+ XPM_QID_CLOCK_GET_NAME,
+ XPM_QID_CLOCK_GET_TOPOLOGY,
+ XPM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS,
+ XPM_QID_CLOCK_GET_MUXSOURCES,
+ XPM_QID_CLOCK_GET_ATTRIBUTES,
+ XPM_QID_PINCTRL_GET_NUM_PINS,
+ XPM_QID_PINCTRL_GET_NUM_FUNCTIONS,
+ XPM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS,
+ XPM_QID_PINCTRL_GET_FUNCTION_NAME,
+ XPM_QID_PINCTRL_GET_FUNCTION_GROUPS,
+ XPM_QID_PINCTRL_GET_PIN_GROUPS,
+ XPM_QID_CLOCK_GET_NUM_CLOCKS,
+ XPM_QID_CLOCK_GET_MAX_DIVISOR,
+ XPM_QID_PLD_GET_PARENT,
+};
+#endif /* PM_DEFS_H */
diff --git a/plat/xilinx/common/include/pm_ipi.h b/plat/xilinx/common/include/pm_ipi.h
new file mode 100644
index 0000000..976abd6
--- /dev/null
+++ b/plat/xilinx/common/include/pm_ipi.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2013-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PM_IPI_H
+#define PM_IPI_H
+
+#include <stddef.h>
+
+#include <plat_ipi.h>
+#include "pm_common.h"
+
+#define IPI_BLOCKING 1
+#define IPI_NON_BLOCKING 0
+
+void pm_ipi_init(const struct pm_proc *proc);
+
+enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
+ uint32_t payload[PAYLOAD_ARG_CNT]);
+enum pm_ret_status pm_ipi_send_non_blocking(const struct pm_proc *proc,
+ uint32_t payload[PAYLOAD_ARG_CNT]);
+enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
+ uint32_t payload[PAYLOAD_ARG_CNT],
+ uint32_t *value, size_t count);
+enum pm_ret_status pm_ipi_buff_read_callb(uint32_t *value, size_t count);
+void pm_ipi_irq_enable(const struct pm_proc *proc);
+void pm_ipi_irq_clear(const struct pm_proc *proc);
+uint32_t pm_ipi_irq_status(const struct pm_proc *proc);
+#if IPI_CRC_CHECK
+uint32_t calculate_crc(uint32_t payload[PAYLOAD_ARG_CNT], uint32_t buffersize);
+#endif
+
+#endif /* PM_IPI_H */
diff --git a/plat/xilinx/common/include/pm_node.h b/plat/xilinx/common/include/pm_node.h
new file mode 100644
index 0000000..46f6bcf
--- /dev/null
+++ b/plat/xilinx/common/include/pm_node.h
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Advanced Micro Devices, 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 GENMASK_32(5, 0)
+#define NODE_SUBCLASS_MASK_BITS GENMASK_32(5, 0)
+#define NODE_TYPE_MASK_BITS GENMASK_32(5, 0)
+#define NODE_INDEX_MASK_BITS GENMASK_32(13, 0)
+#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 = 0x0,
+
+ /* Processor devices */
+ XPM_NODEIDX_DEV_PMC_PROC = 0x1,
+ XPM_NODEIDX_DEV_PSM_PROC = 0x2,
+ XPM_NODEIDX_DEV_ACPU_0 = 0x3,
+ XPM_NODEIDX_DEV_ACPU_1 = 0x4,
+ XPM_NODEIDX_DEV_RPU0_0 = 0x5,
+ XPM_NODEIDX_DEV_RPU0_1 = 0x6,
+
+ /* Memory devices */
+ XPM_NODEIDX_DEV_OCM_0 = 0x7,
+ XPM_NODEIDX_DEV_OCM_1 = 0x8,
+ XPM_NODEIDX_DEV_OCM_2 = 0x9,
+ XPM_NODEIDX_DEV_OCM_3 = 0xA,
+ XPM_NODEIDX_DEV_TCM_0_A = 0xB,
+ XPM_NODEIDX_DEV_TCM_0_B = 0xC,
+ XPM_NODEIDX_DEV_TCM_1_A = 0xD,
+ XPM_NODEIDX_DEV_TCM_1_B = 0xE,
+ XPM_NODEIDX_DEV_L2_BANK_0 = 0xF,
+ XPM_NODEIDX_DEV_DDR_0 = 0x10,
+ XPM_NODEIDX_DEV_DDR_1 = 0x11,
+ XPM_NODEIDX_DEV_DDR_2 = 0x12,
+ XPM_NODEIDX_DEV_DDR_3 = 0x13,
+ XPM_NODEIDX_DEV_DDR_4 = 0x14,
+ XPM_NODEIDX_DEV_DDR_5 = 0x15,
+ XPM_NODEIDX_DEV_DDR_6 = 0x16,
+ XPM_NODEIDX_DEV_DDR_7 = 0x17,
+
+ /* LPD Peripheral devices */
+ XPM_NODEIDX_DEV_USB_0 = 0x18,
+ XPM_NODEIDX_DEV_GEM_0 = 0x19,
+ XPM_NODEIDX_DEV_GEM_1 = 0x1A,
+ XPM_NODEIDX_DEV_SPI_0 = 0x1B,
+ XPM_NODEIDX_DEV_SPI_1 = 0x1C,
+ XPM_NODEIDX_DEV_I2C_0 = 0x1D,
+ XPM_NODEIDX_DEV_I2C_1 = 0x1E,
+ XPM_NODEIDX_DEV_CAN_FD_0 = 0x1F,
+ XPM_NODEIDX_DEV_CAN_FD_1 = 0x20,
+ XPM_NODEIDX_DEV_UART_0 = 0x21,
+ XPM_NODEIDX_DEV_UART_1 = 0x22,
+ XPM_NODEIDX_DEV_GPIO = 0x23,
+ XPM_NODEIDX_DEV_TTC_0 = 0x24,
+ XPM_NODEIDX_DEV_TTC_1 = 0x25,
+ XPM_NODEIDX_DEV_TTC_2 = 0x26,
+ XPM_NODEIDX_DEV_TTC_3 = 0x27,
+ XPM_NODEIDX_DEV_SWDT_LPD = 0x28,
+
+ /* FPD Peripheral devices */
+ XPM_NODEIDX_DEV_SWDT_FPD = 0x29,
+
+ /* PMC Peripheral devices */
+ XPM_NODEIDX_DEV_OSPI = 0x2A,
+ XPM_NODEIDX_DEV_QSPI = 0x2B,
+ XPM_NODEIDX_DEV_GPIO_PMC = 0x2C,
+ XPM_NODEIDX_DEV_I2C_PMC = 0x2D,
+ XPM_NODEIDX_DEV_SDIO_0 = 0x2E,
+ XPM_NODEIDX_DEV_SDIO_1 = 0x2F,
+
+ XPM_NODEIDX_DEV_PL_0 = 0x30,
+ XPM_NODEIDX_DEV_PL_1 = 0x31,
+ XPM_NODEIDX_DEV_PL_2 = 0x32,
+ XPM_NODEIDX_DEV_PL_3 = 0x33,
+ XPM_NODEIDX_DEV_RTC = 0x34,
+ XPM_NODEIDX_DEV_ADMA_0 = 0x35,
+ XPM_NODEIDX_DEV_ADMA_1 = 0x36,
+ XPM_NODEIDX_DEV_ADMA_2 = 0x37,
+ XPM_NODEIDX_DEV_ADMA_3 = 0x38,
+ XPM_NODEIDX_DEV_ADMA_4 = 0x39,
+ XPM_NODEIDX_DEV_ADMA_5 = 0x3A,
+ XPM_NODEIDX_DEV_ADMA_6 = 0x3B,
+ XPM_NODEIDX_DEV_ADMA_7 = 0x3C,
+ XPM_NODEIDX_DEV_IPI_0 = 0x3D,
+ XPM_NODEIDX_DEV_IPI_1 = 0x3E,
+ XPM_NODEIDX_DEV_IPI_2 = 0x3F,
+ XPM_NODEIDX_DEV_IPI_3 = 0x40,
+ XPM_NODEIDX_DEV_IPI_4 = 0x41,
+ XPM_NODEIDX_DEV_IPI_5 = 0x42,
+ XPM_NODEIDX_DEV_IPI_6 = 0x43,
+
+ /* Entire SoC */
+ XPM_NODEIDX_DEV_SOC = 0x44,
+
+ /* DDR memory controllers */
+ XPM_NODEIDX_DEV_DDRMC_0 = 0x45,
+ XPM_NODEIDX_DEV_DDRMC_1 = 0x46,
+ XPM_NODEIDX_DEV_DDRMC_2 = 0x47,
+ XPM_NODEIDX_DEV_DDRMC_3 = 0x48,
+
+ /* GT devices */
+ XPM_NODEIDX_DEV_GT_0 = 0x49,
+ XPM_NODEIDX_DEV_GT_1 = 0x4A,
+ XPM_NODEIDX_DEV_GT_2 = 0x4B,
+ XPM_NODEIDX_DEV_GT_3 = 0x4C,
+ XPM_NODEIDX_DEV_GT_4 = 0x4D,
+ XPM_NODEIDX_DEV_GT_5 = 0x4E,
+ XPM_NODEIDX_DEV_GT_6 = 0x4F,
+ XPM_NODEIDX_DEV_GT_7 = 0x50,
+ XPM_NODEIDX_DEV_GT_8 = 0x51,
+ XPM_NODEIDX_DEV_GT_9 = 0x52,
+ XPM_NODEIDX_DEV_GT_10 = 0x53,
+
+#if defined(PLAT_versal_net)
+ XPM_NODEIDX_DEV_ACPU_0_0 = 0xAF,
+ XPM_NODEIDX_DEV_ACPU_0_1 = 0xB0,
+ XPM_NODEIDX_DEV_ACPU_0_2 = 0xB1,
+ XPM_NODEIDX_DEV_ACPU_0_3 = 0xB2,
+ XPM_NODEIDX_DEV_ACPU_1_0 = 0xB3,
+ XPM_NODEIDX_DEV_ACPU_1_1 = 0xB4,
+ XPM_NODEIDX_DEV_ACPU_1_2 = 0xB5,
+ XPM_NODEIDX_DEV_ACPU_1_3 = 0xB6,
+ XPM_NODEIDX_DEV_ACPU_2_0 = 0xB7,
+ XPM_NODEIDX_DEV_ACPU_2_1 = 0xB8,
+ XPM_NODEIDX_DEV_ACPU_2_2 = 0xB9,
+ XPM_NODEIDX_DEV_ACPU_2_3 = 0xBA,
+ XPM_NODEIDX_DEV_ACPU_3_0 = 0xBB,
+ XPM_NODEIDX_DEV_ACPU_3_1 = 0xBC,
+ XPM_NODEIDX_DEV_ACPU_3_2 = 0xBD,
+ XPM_NODEIDX_DEV_ACPU_3_3 = 0xBE,
+ XPM_NODEIDX_DEV_RPU_A_0 = 0xBF,
+ XPM_NODEIDX_DEV_RPU_A_1 = 0xC0,
+ XPM_NODEIDX_DEV_RPU_B_0 = 0xC1,
+ XPM_NODEIDX_DEV_RPU_B_1 = 0xC2,
+ XPM_NODEIDX_DEV_OCM_0_0 = 0xC3,
+ XPM_NODEIDX_DEV_OCM_0_1 = 0xC4,
+ XPM_NODEIDX_DEV_OCM_0_2 = 0xC5,
+ XPM_NODEIDX_DEV_OCM_0_3 = 0xC6,
+ XPM_NODEIDX_DEV_OCM_1_0 = 0xC7,
+ XPM_NODEIDX_DEV_OCM_1_1 = 0xC8,
+ XPM_NODEIDX_DEV_OCM_1_2 = 0xC9,
+ XPM_NODEIDX_DEV_OCM_1_3 = 0xCA,
+ XPM_NODEIDX_DEV_TCM_A_0A = 0xCB,
+ XPM_NODEIDX_DEV_TCM_A_0B = 0xCC,
+ XPM_NODEIDX_DEV_TCM_A_0C = 0xCD,
+ XPM_NODEIDX_DEV_TCM_A_1A = 0xCE,
+ XPM_NODEIDX_DEV_TCM_A_1B = 0xCF,
+ XPM_NODEIDX_DEV_TCM_A_1C = 0xD0,
+ XPM_NODEIDX_DEV_TCM_B_0A = 0xD1,
+ XPM_NODEIDX_DEV_TCM_B_0B = 0xD2,
+ XPM_NODEIDX_DEV_TCM_B_0C = 0xD3,
+ XPM_NODEIDX_DEV_TCM_B_1A = 0xD4,
+ XPM_NODEIDX_DEV_TCM_B_1B = 0xD5,
+ XPM_NODEIDX_DEV_TCM_B_1C = 0xD6,
+ XPM_NODEIDX_DEV_USB_1 = 0xD7,
+ XPM_NODEIDX_DEV_PMC_WWDT = 0xD8,
+ XPM_NODEIDX_DEV_LPD_SWDT_0 = 0xD9,
+ XPM_NODEIDX_DEV_LPD_SWDT_1 = 0xDA,
+ XPM_NODEIDX_DEV_FPD_SWDT_0 = 0xDB,
+ XPM_NODEIDX_DEV_FPD_SWDT_1 = 0xDC,
+ XPM_NODEIDX_DEV_FPD_SWDT_2 = 0xDD,
+ XPM_NODEIDX_DEV_FPD_SWDT_3 = 0xDE,
+#endif
+ XPM_NODEIDX_DEV_MAX,
+};
+
+#endif /* PM_NODE_H */
diff --git a/plat/xilinx/common/include/pm_svc_main.h b/plat/xilinx/common/include/pm_svc_main.h
new file mode 100644
index 0000000..4cf7727
--- /dev/null
+++ b/plat/xilinx/common/include/pm_svc_main.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PM_SVC_MAIN_H
+#define PM_SVC_MAIN_H
+
+#include <pm_common.h>
+
+/******************************************************************************/
+/**
+ * SECURE_REDUNDANT_CALL() - Adds redundancy to the function call. This is to
+ * avoid glitches which can skip a function call
+ * and cause altering of the code flow in security
+ * critical functions.
+ * @status: Variable which holds the return value of function executed
+ * @status_tmp: Variable which holds the return value of redundant function
+ * call executed
+ * @function: Function to be executed
+ *
+ * Return: None
+ *
+ ******************************************************************************/
+#define SECURE_REDUNDANT_CALL(status, status_tmp, function, ...) \
+ { \
+ status = function(__VA_ARGS__); \
+ status_tmp = function(__VA_ARGS__); \
+ }
+
+int32_t pm_setup(void);
+uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+ uint64_t x4, const void *cookie, void *handle,
+ uint64_t flags);
+
+int32_t pm_register_sgi(uint32_t sgi_num, uint32_t reset);
+#endif /* PM_SVC_MAIN_H */
diff --git a/plat/xilinx/common/ipi.c b/plat/xilinx/common/ipi.c
new file mode 100644
index 0000000..399d283
--- /dev/null
+++ b/plat/xilinx/common/ipi.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2017-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Xilinx IPI agent registers access management
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <ipi.h>
+#include <plat_private.h>
+
+/*********************************************************************
+ * Macros definitions
+ ********************************************************************/
+
+/* IPI registers offsets macros */
+#define IPI_TRIG_OFFSET 0x00U
+#define IPI_OBR_OFFSET 0x04U
+#define IPI_ISR_OFFSET 0x10U
+#define IPI_IMR_OFFSET 0x14U
+#define IPI_IER_OFFSET 0x18U
+#define IPI_IDR_OFFSET 0x1CU
+
+/* IPI register start offset */
+#define IPI_REG_BASE(I) (ipi_table[(I)].ipi_reg_base)
+
+/* IPI register bit mask */
+#define IPI_BIT_MASK(I) (ipi_table[(I)].ipi_bit_mask)
+
+/* IPI configuration table */
+static const struct ipi_config *ipi_table;
+
+/* Total number of IPI */
+static uint32_t ipi_total;
+
+/**
+ * ipi_config_table_init() - Initialize IPI configuration data.
+ * @ipi_config_table: IPI configuration table.
+ * @total_ipi: Total number of IPI available.
+ *
+ */
+void ipi_config_table_init(const struct ipi_config *ipi_config_table,
+ uint32_t total_ipi)
+{
+ ipi_table = ipi_config_table;
+ ipi_total = total_ipi;
+}
+
+/**
+ * is_ipi_mb_within_range() - verify if IPI mailbox is within range.
+ * @local: local IPI ID.
+ * @remote: remote IPI ID.
+ *
+ * Return: - 1 if within range, 0 if not.
+ *
+ */
+static inline int is_ipi_mb_within_range(uint32_t local, uint32_t remote)
+{
+ int ret = 1;
+
+ if (remote >= ipi_total || local >= ipi_total) {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/**
+ * ipi_mb_validate() - validate IPI mailbox access.
+ * @local: local IPI ID.
+ * @remote: remote IPI ID.
+ * @is_secure: indicate if the requester is from secure software.
+ *
+ * Return: 0 success, negative value for errors.
+ *
+ */
+int ipi_mb_validate(uint32_t local, uint32_t remote, unsigned int is_secure)
+{
+ int ret = 0;
+
+ if (!is_ipi_mb_within_range(local, remote)) {
+ ret = -EINVAL;
+ } else if (IPI_IS_SECURE(local) && !is_secure) {
+ ret = -EPERM;
+ } else if (IPI_IS_SECURE(remote) && !is_secure) {
+ ret = -EPERM;
+ } else {
+ /* To fix the misra 15.7 warning */
+ }
+
+ return ret;
+}
+
+/**
+ * ipi_mb_open() - Open IPI mailbox.
+ * @local: local IPI ID.
+ * @remote: remote IPI ID.
+ *
+ */
+void ipi_mb_open(uint32_t local, uint32_t remote)
+{
+ mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET,
+ IPI_BIT_MASK(remote));
+ mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET,
+ IPI_BIT_MASK(remote));
+}
+
+/**
+ * ipi_mb_release() - Open IPI mailbox.
+ * @local: local IPI ID.
+ * @remote: remote IPI ID.
+ *
+ */
+void ipi_mb_release(uint32_t local, uint32_t remote)
+{
+ mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET,
+ IPI_BIT_MASK(remote));
+}
+
+/**
+ * ipi_mb_enquire_status() - Enquire IPI mailbox status.
+ * @local: local IPI ID.
+ * @remote: remote IPI ID.
+ *
+ * Return: 0 idle, positive value for pending sending or receiving,
+ * negative value for errors.
+ *
+ */
+int ipi_mb_enquire_status(uint32_t local, uint32_t remote)
+{
+ int ret = 0U;
+ uint32_t status;
+
+ status = mmio_read_32(IPI_REG_BASE(local) + IPI_OBR_OFFSET);
+ if (status & IPI_BIT_MASK(remote)) {
+ ret |= IPI_MB_STATUS_SEND_PENDING;
+ }
+ status = mmio_read_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET);
+ if (status & IPI_BIT_MASK(remote)) {
+ ret |= IPI_MB_STATUS_RECV_PENDING;
+ }
+
+ return ret;
+}
+
+/**
+ * ipi_mb_notify() - Trigger IPI mailbox notification.
+ * @local: local IPI ID.
+ * @remote: remote IPI ID.
+ * @is_blocking: if to trigger the notification in blocking mode or not.
+ *
+ * It sets the remote bit in the IPI agent trigger register.
+ *
+ */
+void ipi_mb_notify(uint32_t local, uint32_t remote, uint32_t is_blocking)
+{
+ uint32_t status;
+
+ mmio_write_32(IPI_REG_BASE(local) + IPI_TRIG_OFFSET,
+ IPI_BIT_MASK(remote));
+ if (is_blocking) {
+ do {
+ status = mmio_read_32(IPI_REG_BASE(local) +
+ IPI_OBR_OFFSET);
+ } while (status & IPI_BIT_MASK(remote));
+ }
+}
+
+/**
+ * ipi_mb_ack() - Ack IPI mailbox notification from the other end.
+ * @local: local IPI ID.
+ * @remote: remote IPI ID.
+ *
+ * It will clear the remote bit in the isr register.
+ *
+ */
+void ipi_mb_ack(uint32_t local, uint32_t remote)
+{
+ mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET,
+ IPI_BIT_MASK(remote));
+}
+
+/**
+ * ipi_mb_disable_irq() - Disable IPI mailbox notification interrupt.
+ * @local: local IPI ID.
+ * @remote: remote IPI ID.
+ *
+ * It will mask the remote bit in the idr register.
+ *
+ */
+void ipi_mb_disable_irq(uint32_t local, uint32_t remote)
+{
+ mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET,
+ IPI_BIT_MASK(remote));
+}
+
+/**
+ * ipi_mb_enable_irq() - Enable IPI mailbox notification interrupt.
+ * @local: local IPI ID.
+ * @remote: remote IPI ID.
+ *
+ * It will mask the remote bit in the idr register.
+ *
+ */
+void ipi_mb_enable_irq(uint32_t local, uint32_t remote)
+{
+ mmio_write_32(IPI_REG_BASE(local) + IPI_IER_OFFSET,
+ IPI_BIT_MASK(remote));
+}
diff --git a/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c
new file mode 100644
index 0000000..434cd88
--- /dev/null
+++ b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Top-level SMC handler for ZynqMP IPI Mailbox doorbell functions.
+ */
+
+#include <errno.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+#include <ipi.h>
+#include "ipi_mailbox_svc.h"
+#include <plat_ipi.h>
+#include <plat_private.h>
+
+/*********************************************************************
+ * Macros definitions
+ ********************************************************************/
+
+/* IPI SMC calls macros: */
+#define IPI_SMC_OPEN_IRQ_MASK 0x00000001U /* IRQ enable bit in IPI
+ * open SMC call
+ */
+#define IPI_SMC_NOTIFY_BLOCK_MASK 0x00000001U /* Flag to indicate if
+ * IPI notification needs
+ * to be blocking.
+ */
+#define IPI_SMC_ENQUIRY_DIRQ_MASK 0x00000001U /* Flag to indicate if
+ * notification interrupt
+ * to be disabled.
+ */
+#define IPI_SMC_ACK_EIRQ_MASK 0x00000001U /* Flag to indicate if
+ * notification interrupt
+ * to be enable.
+ */
+
+#define UNSIGNED32_MASK 0xFFFFFFFFU /* 32bit mask */
+
+/**
+ * ipi_smc_handler() - SMC handler for IPI SMC calls.
+ * @smc_fid: Function identifier.
+ * @x1: Arguments.
+ * @x2: Arguments.
+ * @x3: Arguments.
+ * @x4: Arguments.
+ * @cookie: Unused.
+ * @handle: Pointer to caller's context structure.
+ * @flags: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * Return: Unused.
+ *
+ * Determines that smc_fid is valid and supported PM SMC Function ID from the
+ * list of pm_api_ids, otherwise completes the request with
+ * the unknown SMC Function ID.
+ *
+ * The SMC calls for PM service are forwarded from SIP Service SMC handler
+ * function with rt_svc_handle signature.
+ *
+ */
+uint64_t ipi_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
+ uint64_t x3, uint64_t x4, const void *cookie,
+ void *handle, uint64_t flags)
+{
+ int32_t ret;
+ uint32_t ipi_local_id;
+ uint32_t ipi_remote_id;
+ uint32_t is_secure;
+
+ ipi_local_id = x1 & UNSIGNED32_MASK;
+ ipi_remote_id = x2 & UNSIGNED32_MASK;
+
+ /* OEN Number 48 to 63 is for Trusted App and OS
+ * GET_SMC_OEN limits the return value of OEN number to 63 by bitwise
+ * AND operation with 0x3F.
+ * Upper limit check for OEN value is not required.
+ */
+ if (GET_SMC_OEN(smc_fid) >= OEN_TAP_START) {
+ is_secure = 1;
+ } else {
+ is_secure = 0;
+ }
+
+ /* Validate IPI mailbox access */
+ ret = ipi_mb_validate(ipi_local_id, ipi_remote_id, is_secure);
+ if (ret)
+ SMC_RET1(handle, ret);
+
+ switch (GET_SMC_NUM(smc_fid)) {
+ case IPI_MAILBOX_OPEN:
+ ipi_mb_open(ipi_local_id, ipi_remote_id);
+ SMC_RET1(handle, 0);
+ case IPI_MAILBOX_RELEASE:
+ ipi_mb_release(ipi_local_id, ipi_remote_id);
+ SMC_RET1(handle, 0);
+ case IPI_MAILBOX_STATUS_ENQUIRY:
+ {
+ int32_t disable_irq;
+
+ disable_irq = (x3 & IPI_SMC_ENQUIRY_DIRQ_MASK) ? 1 : 0;
+ ret = ipi_mb_enquire_status(ipi_local_id, ipi_remote_id);
+ if ((ret & IPI_MB_STATUS_RECV_PENDING) && disable_irq)
+ ipi_mb_disable_irq(ipi_local_id, ipi_remote_id);
+ SMC_RET1(handle, ret);
+ }
+ case IPI_MAILBOX_NOTIFY:
+ {
+ uint32_t is_blocking;
+
+ is_blocking = (x3 & IPI_SMC_NOTIFY_BLOCK_MASK) ? 1 : 0;
+ ipi_mb_notify(ipi_local_id, ipi_remote_id, is_blocking);
+ SMC_RET1(handle, 0);
+ }
+ case IPI_MAILBOX_ACK:
+ {
+ int32_t enable_irq;
+
+ enable_irq = (x3 & IPI_SMC_ACK_EIRQ_MASK) ? 1 : 0;
+ ipi_mb_ack(ipi_local_id, ipi_remote_id);
+ if (enable_irq)
+ ipi_mb_enable_irq(ipi_local_id, ipi_remote_id);
+ SMC_RET1(handle, 0);
+ }
+ case IPI_MAILBOX_ENABLE_IRQ:
+ ipi_mb_enable_irq(ipi_local_id, ipi_remote_id);
+ SMC_RET1(handle, 0);
+ case IPI_MAILBOX_DISABLE_IRQ:
+ ipi_mb_disable_irq(ipi_local_id, ipi_remote_id);
+ SMC_RET1(handle, 0);
+ default:
+ WARN("Unimplemented IPI service call: 0x%x\n", smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
diff --git a/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h
new file mode 100644
index 0000000..9198a98
--- /dev/null
+++ b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* ZynqMP IPI mailbox doorbell service enums and defines */
+
+#ifndef IPI_MAILBOX_SVC_H
+#define IPI_MAILBOX_SVC_H
+
+#include <stdint.h>
+
+/*********************************************************************
+ * Enum definitions
+ ********************************************************************/
+
+/* IPI SMC function numbers enum definition */
+enum ipi_api_id {
+ /* IPI mailbox operations functions: */
+ IPI_MAILBOX_OPEN = 0x1000,
+ IPI_MAILBOX_RELEASE,
+ IPI_MAILBOX_STATUS_ENQUIRY,
+ IPI_MAILBOX_NOTIFY,
+ IPI_MAILBOX_ACK,
+ IPI_MAILBOX_ENABLE_IRQ,
+ IPI_MAILBOX_DISABLE_IRQ
+};
+
+/*********************************************************************
+ * IPI mailbox service APIs declarations
+ ********************************************************************/
+
+/* IPI SMC handler */
+uint64_t ipi_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2,
+ uint64_t x3, uint64_t x4, const void *cookie, void *handle,
+ uint64_t flags);
+
+#endif /* IPI_MAILBOX_SVC_H */
diff --git a/plat/xilinx/common/plat_console.c b/plat/xilinx/common/plat_console.c
new file mode 100644
index 0000000..0c0e74b
--- /dev/null
+++ b/plat/xilinx/common/plat_console.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2023, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <common/fdt_fixup.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/arm/dcc.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/cadence/cdns_uart.h>
+#include <drivers/console.h>
+#include <libfdt.h>
+#include <plat_console.h>
+
+#include <platform_def.h>
+#include <plat_private.h>
+
+static console_t console;
+
+#if (defined(XILINX_OF_BOARD_DTB_ADDR) && !IS_TFA_IN_OCM(BL31_BASE))
+/**
+ * get_baudrate() - Get the baudrate form DTB.
+ * @dtb: Address of the Device Tree Blob (DTB).
+ *
+ * Return: On success returns the baudrate; on failure returns an error.
+ */
+static int32_t get_baudrate(void *dtb)
+{
+ int node;
+ int32_t ret = 0;
+ const char *prop, *path;
+ char *end;
+ int32_t baud_rate = 0;
+
+ node = fdt_path_offset(dtb, "/secure-chosen");
+ if (node < 0) {
+ node = fdt_path_offset(dtb, "/chosen");
+ if (node < 0) {
+ ret = -FDT_ERR_NOTFOUND;
+ goto error;
+ }
+ }
+
+ prop = fdt_getprop(dtb, node, "stdout-path", NULL);
+ if (prop == NULL) {
+ ret = -FDT_ERR_NOTFOUND;
+ goto error;
+ }
+
+ /* Parse string serial0:115200n8 */
+ path = strchr(prop, ':');
+ if (!path) {
+ ret = -FDT_ERR_NOTFOUND;
+ goto error;
+ } else {
+
+ baud_rate = strtoul(path + 1, &end, 10);
+ if (baud_rate == 0 && end == path) {
+ ERROR("Conversion error occurred: %d\n", baud_rate);
+ ret = -FDT_ERR_NOTFOUND;
+ goto error;
+ }
+ ret = baud_rate;
+ }
+
+error:
+ return ret;
+}
+
+/**
+ * get_node_status() - Get the DTB node status.
+ * @dtb: Address of the Device Tree Blob (DTB).
+ * @node: Node address in the device tree.
+ *
+ * Return: On success, it returns 1; on failure, it returns an 0.
+ */
+static uint32_t get_node_status(void *dtb, int node)
+{
+ const char *status_cell;
+ uint32_t status = 0;
+
+ status_cell = fdt_getprop(dtb, node, "status", NULL);
+ if (!status_cell || strcmp(status_cell, "okay") == 0) {
+ status = 1;
+ } else {
+ status = 0;
+ }
+
+ return status;
+}
+
+/**
+ * fdt_add_uart_info() - Add DTB information to a UART structure.
+ * @info: Pointer to the UART information structure.
+ * @node: Node address in the device tree.
+ * @dtb: Address of the Device Tree Blob(DTB).
+ *
+ * Return: On success, it returns 1; on failure, it returns an 0.
+ */
+static uint32_t fdt_add_uart_info(dt_uart_info_t *info, int node, void *dtb)
+{
+ uintptr_t base_addr;
+ const char *com;
+ uint32_t ret = 0;
+
+ com = fdt_getprop(dtb, node, "compatible", NULL);
+ if (com != NULL) {
+ strlcpy(info->compatible, com, sizeof(info->compatible));
+ } else {
+ ERROR("Compatible property not found in DTB node\n");
+ ret = -FDT_ERR_NOTFOUND;
+ goto error;
+ }
+
+ ret = fdt_get_reg_props_by_index(dtb, node, 0, &base_addr, NULL);
+ if (ret >= 0) {
+ info->base = base_addr;
+ } else {
+ ERROR("Failed to retrieve base address. Error code: %d\n", ret);
+ ret = -FDT_ERR_NOTFOUND;
+ goto error;
+ }
+
+ info->status = get_node_status(dtb, node);
+ info->baud_rate = get_baudrate(dtb);
+
+error:
+ return ret;
+}
+
+/**
+ * fdt_get_uart_info() - Get the uart information form DTB.
+ * @info: Pointer to the UART information structure.
+ *
+ * Return: On success, it returns 0; on failure, it returns an error+reason.
+ */
+static int fdt_get_uart_info(dt_uart_info_t *info)
+{
+ int node, ret = 0;
+ void *dtb = (void *)XILINX_OF_BOARD_DTB_ADDR;
+
+ if (fdt_check_header(dtb) != 0) {
+ ERROR("Can't read DT at %p\n", dtb);
+ ret = -FDT_ERR_NOTFOUND;
+ goto error;
+ }
+
+ ret = fdt_open_into(dtb, dtb, XILINX_OF_BOARD_DTB_MAX_SIZE);
+ if (ret < 0) {
+ ERROR("Invalid Device Tree at %p: error %d\n", dtb, ret);
+ ret = -FDT_ERR_NOTFOUND;
+ goto error;
+ }
+
+ node = fdt_get_stdout_node_offset(dtb);
+ if (node < 0) {
+ ERROR("DT get stdout node failed : %d\n", node);
+ ret = -FDT_ERR_NOTFOUND;
+ goto error;
+ }
+
+ ret = fdt_add_uart_info(info, node, dtb);
+ if (ret < 0) {
+ ERROR("Failed to add DT UART info: %d\n", ret);
+ ret = -FDT_ERR_NOTFOUND;
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/**
+ * check_fdt_uart_info() - Check early uart info with DTB uart info.
+ * @info: Pointer to the UART information structure.
+ *
+ * Return: On success, it returns 0; on failure, it returns an error+reason.
+ */
+static int check_fdt_uart_info(dt_uart_info_t *info)
+{
+ uint32_t ret = 0;
+
+ if (info->status == 0) {
+ ret = -ENODEV;
+ goto error;
+ }
+
+ if ((info->base == console.base) &&
+ (info->baud_rate == UART_BAUDRATE) && !CONSOLE_IS(dcc)) {
+ ret = -ENODEV;
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+/**
+ * console_boot_end() - Unregister the console_t instance form the console list.
+ * @boot_console: Pointer to the console information structure.
+ */
+static void console_boot_end(console_t *boot_console)
+{
+ if (CONSOLE_IS(dcc)) {
+ console_dcc_unregister();
+ } else {
+ console_flush();
+ (void)console_unregister(boot_console);
+ }
+}
+
+/**
+ * setup_runtime_console() - Registers the runtime uart with console list.
+ * @clock: UART clock.
+ * @info: Pointer to the UART information structure.
+ */
+static void setup_runtime_console(uint32_t clock, dt_uart_info_t *info)
+{
+ static console_t bl31_runtime_console;
+ uint32_t rc;
+
+#if defined(PLAT_zynqmp)
+ rc = console_cdns_register(info->base,
+ clock,
+ info->baud_rate,
+ &bl31_runtime_console);
+#else
+ rc = console_pl011_register(info->base,
+ clock,
+ info->baud_rate,
+ &bl31_runtime_console);
+#endif
+ if (rc == 0) {
+ panic();
+ }
+
+ console_set_scope(&bl31_runtime_console,
+ CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME |
+ CONSOLE_FLAG_CRASH);
+}
+
+
+/**
+ * runtime_console_init() - Initializes the run time console information.
+ * @uart_info: Pointer to the UART information structure.
+ * @bl31_boot_console: Pointer to the console information structure.
+ * @clock: UART clock.
+ *
+ * Return: On success, it returns 0; on failure, it returns an error+reason;
+ */
+static int32_t runtime_console_init(dt_uart_info_t *uart_info,
+ console_t *bl31_boot_console,
+ uint32_t clock)
+{
+ int32_t rc = 0;
+
+ /* Parse UART information from Device Tree Blob (DTB) */
+ rc = fdt_get_uart_info(uart_info);
+ if (rc < 0) {
+ rc = -FDT_ERR_NOTFOUND;
+ }
+
+ if (strncmp(uart_info->compatible, DT_UART_COMPAT,
+ strlen(DT_UART_COMPAT)) == 0) {
+
+ if (check_fdt_uart_info(uart_info) == 0) {
+ setup_runtime_console(clock, uart_info);
+ console_boot_end(bl31_boot_console);
+ INFO("Runtime console setup\n");
+ } else {
+ INFO("Early console and DTB console are same\n");
+ }
+ } else if (strncmp(uart_info->compatible, DT_UART_DCC_COMPAT,
+ strlen(DT_UART_DCC_COMPAT)) == 0) {
+ rc = console_dcc_register();
+ if (rc == 0) {
+ panic();
+ }
+ console_boot_end(bl31_boot_console);
+ } else {
+ WARN("BL31: No console device found in DT.\n");
+ }
+
+ return rc;
+}
+#endif
+
+void setup_console(void)
+{
+ uint32_t rc;
+ uint32_t uart_clk = get_uart_clk();
+
+#if defined(PLAT_zynqmp)
+ if (CONSOLE_IS(cadence) || (CONSOLE_IS(cadence1))) {
+ rc = console_cdns_register(UART_BASE,
+ uart_clk,
+ UART_BAUDRATE,
+ &console);
+ if (rc == 0) {
+ panic();
+ }
+
+ console_set_scope(&console, CONSOLE_FLAG_BOOT |
+ CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH);
+ }
+#else
+ if (CONSOLE_IS(pl011) || (CONSOLE_IS(pl011_1))) {
+ /* Initialize the console to provide early debug support */
+ rc = console_pl011_register((uint32_t)UART_BASE,
+ uart_clk,
+ (uint32_t)UART_BAUDRATE,
+ &console);
+ if (rc == 0) {
+ panic();
+ }
+
+ console_set_scope(&console, CONSOLE_FLAG_BOOT |
+ CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH);
+ }
+#endif
+ if (CONSOLE_IS(dcc)) {
+ /* Initialize the dcc console for debug */
+ rc = console_dcc_register();
+ if (rc == 0) {
+ panic();
+ }
+ }
+ INFO("BL31: Early console setup\n");
+
+#if (defined(XILINX_OF_BOARD_DTB_ADDR) && !IS_TFA_IN_OCM(BL31_BASE))
+ static dt_uart_info_t uart_info = {0};
+
+ /* Initialize the runtime console using UART information from the DTB */
+ rc = runtime_console_init(&uart_info, &console, uart_clk);
+ if (rc < 0) {
+ ERROR("Failed to initialize runtime console: %d\n", rc);
+ }
+#endif
+}
diff --git a/plat/xilinx/common/plat_fdt.c b/plat/xilinx/common/plat_fdt.c
new file mode 100644
index 0000000..de5d1a1
--- /dev/null
+++ b/plat/xilinx/common/plat_fdt.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2023, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ */
+#include <common/debug.h>
+#include <common/fdt_fixup.h>
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+#include <plat_fdt.h>
+#include <platform_def.h>
+
+void prepare_dtb(void)
+{
+#if defined(XILINX_OF_BOARD_DTB_ADDR)
+ void *dtb;
+ int map_ret = 0;
+ int ret = 0;
+
+ dtb = (void *)XILINX_OF_BOARD_DTB_ADDR;
+
+ if (!IS_TFA_IN_OCM(BL31_BASE)) {
+
+#if defined(PLAT_XLAT_TABLES_DYNAMIC)
+ map_ret = mmap_add_dynamic_region((unsigned long long)dtb,
+ (uintptr_t)dtb,
+ XILINX_OF_BOARD_DTB_MAX_SIZE,
+ MT_MEMORY | MT_RW | MT_NS);
+ if (map_ret != 0) {
+ WARN("Failed to add dynamic region for dtb: error %d\n",
+ map_ret);
+ }
+#endif
+
+ if (!map_ret) {
+ /* Return if no device tree is detected */
+ if (fdt_check_header(dtb) != 0) {
+ NOTICE("Can't read DT at %p\n", dtb);
+ } else {
+ ret = fdt_open_into(dtb, dtb, XILINX_OF_BOARD_DTB_MAX_SIZE);
+
+ if (ret < 0) {
+ ERROR("Invalid Device Tree at %p: error %d\n",
+ dtb, ret);
+ } else {
+
+ if (dt_add_psci_node(dtb)) {
+ WARN("Failed to add PSCI Device Tree node\n");
+ }
+
+ if (dt_add_psci_cpu_enable_methods(dtb)) {
+ WARN("Failed to add PSCI cpu enable methods in DT\n");
+ }
+
+ /* Reserve memory used by Trusted Firmware. */
+ ret = fdt_add_reserved_memory(dtb,
+ "tf-a",
+ BL31_BASE,
+ BL31_LIMIT
+ -
+ BL31_BASE);
+ if (ret < 0) {
+ WARN("Failed to add reserved memory nodes for BL31 to DT.\n");
+ }
+
+ ret = fdt_pack(dtb);
+ if (ret < 0) {
+ WARN("Failed to pack dtb at %p: error %d\n",
+ dtb, ret);
+ }
+ flush_dcache_range((uintptr_t)dtb,
+ fdt_blob_size(dtb));
+
+ INFO("Changed device tree to advertise PSCI and reserved memories.\n");
+
+ }
+ }
+
+ }
+
+
+#if defined(PLAT_XLAT_TABLES_DYNAMIC)
+ if (!map_ret) {
+ ret = mmap_remove_dynamic_region((uintptr_t)dtb,
+ XILINX_OF_BOARD_DTB_MAX_SIZE);
+ if (ret != 0) {
+ WARN("Failed to remove dynamic region for dtb:error %d\n",
+ ret);
+ }
+ }
+#endif
+ }
+
+#endif
+}
diff --git a/plat/xilinx/common/plat_startup.c b/plat/xilinx/common/plat_startup.c
new file mode 100644
index 0000000..5beb765
--- /dev/null
+++ b/plat/xilinx/common/plat_startup.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2014-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdint.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <plat_startup.h>
+
+
+/*
+ * HandoffParams
+ * Parameter bitfield encoding
+ * -----------------------------------------------------------------------------
+ * Exec State 0 0 -> Aarch64, 1-> Aarch32
+ * endianness 1 0 -> LE, 1 -> BE
+ * secure (TZ) 2 0 -> Non secure, 1 -> secure
+ * EL 3:4 00 -> EL0, 01 -> EL1, 10 -> EL2, 11 -> EL3
+ * CPU# 5:6 00 -> A53_0, 01 -> A53_1, 10 -> A53_2, 11 -> A53_3
+ * Reserved 7:10 Reserved
+ * Cluster# 11:12 00 -> Cluster 0, 01 -> Cluster 1, 10 -> Cluster 2,
+ * 11 -> Cluster (Applicable for Versal NET only).
+ * Reserved 13:16 Reserved
+ */
+
+#define XBL_FLAGS_ESTATE_SHIFT 0U
+#define XBL_FLAGS_ESTATE_MASK (1U << XBL_FLAGS_ESTATE_SHIFT)
+#define XBL_FLAGS_ESTATE_A64 0U
+#define XBL_FLAGS_ESTATE_A32 1U
+
+#define XBL_FLAGS_ENDIAN_SHIFT 1U
+#define XBL_FLAGS_ENDIAN_MASK (1U << XBL_FLAGS_ENDIAN_SHIFT)
+#define XBL_FLAGS_ENDIAN_LE 0U
+#define XBL_FLAGS_ENDIAN_BE 1U
+
+#define XBL_FLAGS_TZ_SHIFT 2U
+#define XBL_FLAGS_TZ_MASK (1U << XBL_FLAGS_TZ_SHIFT)
+#define XBL_FLAGS_NON_SECURE 0U
+#define XBL_FLAGS_SECURE 1U
+
+#define XBL_FLAGS_EL_SHIFT 3U
+#define XBL_FLAGS_EL_MASK (3U << XBL_FLAGS_EL_SHIFT)
+#define XBL_FLAGS_EL0 0U
+#define XBL_FLAGS_EL1 1U
+#define XBL_FLAGS_EL2 2U
+#define XBL_FLAGS_EL3 3U
+
+#define XBL_FLAGS_CPU_SHIFT 5U
+#define XBL_FLAGS_CPU_MASK (3U << XBL_FLAGS_CPU_SHIFT)
+#define XBL_FLAGS_A53_0 0U
+#define XBL_FLAGS_A53_1 1U
+#define XBL_FLAGS_A53_2 2U
+#define XBL_FLAGS_A53_3 3U
+
+#if defined(PLAT_versal_net)
+#define XBL_FLAGS_CLUSTER_SHIFT 11U
+#define XBL_FLAGS_CLUSTER_MASK GENMASK(11, 12)
+
+#define XBL_FLAGS_CLUSTER_0 0U
+#endif /* PLAT_versal_net */
+
+/**
+ * get_xbl_cpu() - Get the target CPU for partition.
+ * @partition: Pointer to partition struct.
+ *
+ * Return: XBL_FLAGS_A53_0, XBL_FLAGS_A53_1, XBL_FLAGS_A53_2 or XBL_FLAGS_A53_3.
+ *
+ */
+static int32_t get_xbl_cpu(const struct xbl_partition *partition)
+{
+ uint64_t flags = partition->flags & XBL_FLAGS_CPU_MASK;
+
+ return flags >> XBL_FLAGS_CPU_SHIFT;
+}
+
+/**
+ * get_xbl_el() - Get the target exception level for partition.
+ * @partition: Pointer to partition struct.
+ *
+ * Return: XBL_FLAGS_EL0, XBL_FLAGS_EL1, XBL_FLAGS_EL2 or XBL_FLAGS_EL3.
+ *
+ */
+static int32_t get_xbl_el(const struct xbl_partition *partition)
+{
+ uint64_t flags = partition->flags & XBL_FLAGS_EL_MASK;
+
+ return flags >> XBL_FLAGS_EL_SHIFT;
+}
+
+/**
+ * get_xbl_ss() - Get the target security state for partition.
+ * @partition: Pointer to partition struct.
+ *
+ * Return: XBL_FLAGS_NON_SECURE or XBL_FLAGS_SECURE.
+ *
+ */
+static int32_t get_xbl_ss(const struct xbl_partition *partition)
+{
+ uint64_t flags = partition->flags & XBL_FLAGS_TZ_MASK;
+
+ return flags >> XBL_FLAGS_TZ_SHIFT;
+}
+
+/**
+ * get_xbl_endian() - Get the target endianness for partition.
+ * @partition: Pointer to partition struct.
+ *
+ * Return: SPSR_E_LITTLE or SPSR_E_BIG.
+ *
+ */
+static int32_t get_xbl_endian(const struct xbl_partition *partition)
+{
+ uint64_t flags = partition->flags & XBL_FLAGS_ENDIAN_MASK;
+
+ flags >>= XBL_FLAGS_ENDIAN_SHIFT;
+
+ if (flags == XBL_FLAGS_ENDIAN_BE) {
+ return SPSR_E_BIG;
+ } else {
+ return SPSR_E_LITTLE;
+ }
+}
+
+/**
+ * get_xbl_estate() - Get the target execution state for partition.
+ * @partition: Pointer to partition struct.
+ *
+ * Return: XBL_FLAGS_ESTATE_A32 or XBL_FLAGS_ESTATE_A64.
+ *
+ */
+static int32_t get_xbl_estate(const struct xbl_partition *partition)
+{
+ uint64_t flags = partition->flags & XBL_FLAGS_ESTATE_MASK;
+
+ return flags >> XBL_FLAGS_ESTATE_SHIFT;
+}
+
+#if defined(PLAT_versal_net)
+/**
+ * get_xbl_cluster - Get the cluster number
+ * @partition: pointer to the partition structure.
+ *
+ * Return: cluster number for the partition.
+ */
+static int32_t get_xbl_cluster(const struct xbl_partition *partition)
+{
+ uint64_t flags = partition->flags & XBL_FLAGS_CLUSTER_MASK;
+
+ return (int32_t)(flags >> XBL_FLAGS_CLUSTER_SHIFT);
+}
+#endif /* PLAT_versal_net */
+
+/**
+ * xbl_handover() - Populates the bl32 and bl33 image info structures.
+ * @bl32: BL32 image info structure.
+ * @bl33: BL33 image info structure.
+ * @handoff_addr: TF-A handoff address.
+ *
+ * Process the handoff parameters from the XBL and populate the BL32 and BL33
+ * image info structures accordingly.
+ *
+ * Return: Return the status of the handoff. The value will be from the
+ * xbl_handoff enum.
+ *
+ */
+enum xbl_handoff xbl_handover(entry_point_info_t *bl32,
+ entry_point_info_t *bl33,
+ uint64_t handoff_addr)
+{
+ const struct xbl_handoff_params *HandoffParams;
+
+ if (!handoff_addr) {
+ WARN("BL31: No handoff structure passed\n");
+ return XBL_HANDOFF_NO_STRUCT;
+ }
+
+ HandoffParams = (struct xbl_handoff_params *)handoff_addr;
+ if ((HandoffParams->magic[0] != 'X') ||
+ (HandoffParams->magic[1] != 'L') ||
+ (HandoffParams->magic[2] != 'N') ||
+ (HandoffParams->magic[3] != 'X')) {
+ ERROR("BL31: invalid handoff structure at %" PRIx64 "\n", handoff_addr);
+ return XBL_HANDOFF_INVAL_STRUCT;
+ }
+
+ VERBOSE("BL31: TF-A handoff params at:0x%" PRIx64 ", entries:%u\n",
+ handoff_addr, HandoffParams->num_entries);
+ if (HandoffParams->num_entries > XBL_MAX_PARTITIONS) {
+ ERROR("BL31: TF-A handoff params: too many partitions (%u/%u)\n",
+ HandoffParams->num_entries, XBL_MAX_PARTITIONS);
+ return XBL_HANDOFF_TOO_MANY_PARTS;
+ }
+
+ /*
+ * we loop over all passed entries but only populate two image structs
+ * (bl32, bl33). I.e. the last applicable images in the handoff
+ * structure will be used for the hand off
+ */
+ for (size_t i = 0; i < HandoffParams->num_entries; i++) {
+ entry_point_info_t *image;
+ int32_t target_estate, target_secure, target_cpu;
+ uint32_t target_endianness, target_el;
+
+ VERBOSE("BL31: %zd: entry:0x%" PRIx64 ", flags:0x%" PRIx64 "\n", i,
+ HandoffParams->partition[i].entry_point,
+ HandoffParams->partition[i].flags);
+
+#if defined(PLAT_versal_net)
+ uint32_t target_cluster;
+
+ target_cluster = get_xbl_cluster(&HandoffParams->partition[i]);
+ if (target_cluster != XBL_FLAGS_CLUSTER_0) {
+ WARN("BL31: invalid target Cluster (%i)\n",
+ target_cluster);
+ continue;
+ }
+#endif /* PLAT_versal_net */
+
+ target_cpu = get_xbl_cpu(&HandoffParams->partition[i]);
+ if (target_cpu != XBL_FLAGS_A53_0) {
+ WARN("BL31: invalid target CPU (%i)\n", target_cpu);
+ continue;
+ }
+
+ target_el = get_xbl_el(&HandoffParams->partition[i]);
+ if ((target_el == XBL_FLAGS_EL3) ||
+ (target_el == XBL_FLAGS_EL0)) {
+ WARN("BL31: invalid target exception level(%i)\n",
+ target_el);
+ continue;
+ }
+
+ target_secure = get_xbl_ss(&HandoffParams->partition[i]);
+ if (target_secure == XBL_FLAGS_SECURE &&
+ target_el == XBL_FLAGS_EL2) {
+ WARN("BL31: invalid security state (%i) for exception level (%i)\n",
+ target_secure, target_el);
+ continue;
+ }
+
+ target_estate = get_xbl_estate(&HandoffParams->partition[i]);
+ target_endianness = get_xbl_endian(&HandoffParams->partition[i]);
+
+ if (target_secure == XBL_FLAGS_SECURE) {
+ image = bl32;
+
+ if (target_estate == XBL_FLAGS_ESTATE_A32) {
+ bl32->spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM,
+ target_endianness,
+ DISABLE_ALL_EXCEPTIONS);
+ } else {
+ bl32->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS);
+ }
+ } else {
+ image = bl33;
+
+ if (target_estate == XBL_FLAGS_ESTATE_A32) {
+ if (target_el == XBL_FLAGS_EL2) {
+ target_el = MODE32_hyp;
+ } else {
+ target_el = MODE32_sys;
+ }
+
+ bl33->spsr = SPSR_MODE32(target_el, SPSR_T_ARM,
+ target_endianness,
+ DISABLE_ALL_EXCEPTIONS);
+ } else {
+ if (target_el == XBL_FLAGS_EL2) {
+ target_el = MODE_EL2;
+ } else {
+ target_el = MODE_EL1;
+ }
+
+ bl33->spsr = SPSR_64(target_el, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS);
+ }
+ }
+
+ VERBOSE("Setting up %s entry point to:%" PRIx64 ", el:%x\n",
+ target_secure == XBL_FLAGS_SECURE ? "BL32" : "BL33",
+ HandoffParams->partition[i].entry_point,
+ target_el);
+ image->pc = HandoffParams->partition[i].entry_point;
+
+ if (target_endianness == SPSR_E_BIG) {
+ EP_SET_EE(image->h.attr, EP_EE_BIG);
+ } else {
+ EP_SET_EE(image->h.attr, EP_EE_LITTLE);
+ }
+ }
+
+ return XBL_HANDOFF_SUCCESS;
+}
diff --git a/plat/xilinx/common/pm_service/pm_api_sys.c b/plat/xilinx/common/pm_service/pm_api_sys.c
new file mode 100644
index 0000000..ffc39bb
--- /dev/null
+++ b/plat/xilinx/common/pm_service/pm_api_sys.c
@@ -0,0 +1,686 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Versal system level PM-API functions and communication with PMC via
+ * IPI interrupts
+ */
+
+#include <drivers/arm/gic_common.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+#include <platform_def.h>
+#include <pm_api_sys.h>
+#include <pm_client.h>
+#include <pm_common.h>
+#include <pm_defs.h>
+#include <pm_ipi.h>
+#include "pm_svc_main.h"
+
+#define NUM_GICD_ISENABLER ((IRQ_MAX >> 5U) + 1U)
+
+/* default shutdown/reboot scope is system(2) */
+static uint32_t pm_shutdown_scope = XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM;
+
+/**
+ * pm_get_shutdown_scope() - Get the currently set shutdown scope.
+ *
+ * Return: Shutdown scope value.
+ *
+ */
+uint32_t pm_get_shutdown_scope(void)
+{
+ return pm_shutdown_scope;
+}
+
+/* PM API functions */
+
+/**
+ * pm_client_set_wakeup_sources - Set all devices with enabled interrupts as
+ * wake sources in the XilPM.
+ * @node_id: Node id of processor.
+ *
+ */
+void pm_client_set_wakeup_sources(uint32_t node_id)
+{
+ uint32_t reg_num, device_id;
+ uint8_t pm_wakeup_nodes_set[XPM_NODEIDX_DEV_MAX] = {0U};
+ uint32_t isenabler1 = PLAT_GICD_BASE_VALUE + GICD_ISENABLER + 4U;
+
+ zeromem(&pm_wakeup_nodes_set, (u_register_t)sizeof(pm_wakeup_nodes_set));
+
+ for (reg_num = 0U; 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 == 0U) {
+ continue;
+ }
+
+ while (reg != 0U) {
+ enum pm_device_node_idx node_idx;
+ uint32_t idx, irq, lowest_set = reg & (-reg);
+ enum pm_ret_status ret;
+
+ idx = (uint32_t)__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) {
+ if (pm_wakeup_nodes_set[node_idx] == 0U) {
+ /* Get device ID from node index */
+ device_id = PERIPH_DEVID((uint32_t)node_idx);
+ ret = pm_set_wakeup_source(node_id,
+ device_id, 1U,
+ SECURE_FLAG);
+ pm_wakeup_nodes_set[node_idx] = (ret == PM_RET_SUCCESS) ?
+ 1U : 0U;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * pm_handle_eemi_call() - PM call for processor to send eemi payload.
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ * @x0: Arguments received per SMC64 standard.
+ * @x1: Arguments received per SMC64 standard.
+ * @x2: Arguments received per SMC64 standard.
+ * @x3: Arguments received per SMC64 standard.
+ * @x4: Arguments received per SMC64 standard.
+ * @x5: Arguments received per SMC64 standard.
+ * @result: Payload received from firmware.
+ *
+ * Return: PM_RET_SUCCESS on success or error code.
+ *
+ */
+enum pm_ret_status pm_handle_eemi_call(uint32_t flag, uint32_t x0, uint32_t x1,
+ uint32_t x2, uint32_t x3, uint32_t x4,
+ uint32_t x5, uint64_t *result)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT] = {0};
+ uint32_t module_id;
+
+ module_id = (x0 & MODULE_ID_MASK) >> 8U;
+
+ //default module id is for LIBPM
+ if (module_id == 0) {
+ module_id = LIBPM_MODULE_ID;
+ }
+
+ PM_PACK_PAYLOAD6(payload, module_id, flag, x0, x1, x2, x3, x4, x5);
+ return pm_ipi_send_sync(primary_proc, payload, (uint32_t *)result, PAYLOAD_ARG_CNT);
+}
+
+/**
+ * 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.
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ *
+ * 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,
+ uint32_t latency,
+ uint32_t state,
+ uintptr_t address, uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ uint32_t cpuid = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpuid);
+
+ if (proc == NULL) {
+ 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, flag, 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.
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ *
+ * 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 flag)
+{
+ 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, flag, PM_ABORT_SUSPEND,
+ reason, primary_proc->node_id);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * 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).
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ *
+ * Return: Returns status, either success or error+reason.
+ *
+ */
+enum pm_ret_status pm_req_suspend(uint32_t target, uint8_t ack,
+ uint32_t latency, uint32_t state,
+ uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, 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.
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ *
+ * 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 flag)
+{
+ 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, flag, PM_REQ_WAKEUP, target,
+ set_address, address, ack);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_get_callbackdata() - Read from IPI response buffer.
+ * @data: array of PAYLOAD_ARG_CNT elements.
+ * @count: Number of values to return.
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ * @ack: 0 - Do not ack IPI after reading payload.
+ * 1 - Ack IPI after reading payload.
+ *
+ * Read value from ipi buffer response buffer.
+ * Return: Returns status, either success or error.
+ *
+ */
+enum pm_ret_status pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag, uint32_t ack)
+{
+ enum pm_ret_status ret = PM_RET_SUCCESS;
+ /* Return if interrupt is not from PMU */
+ if (pm_ipi_irq_status(primary_proc) == 0) {
+ return ret;
+ }
+
+ ret = pm_ipi_buff_read_callb(data, count);
+
+ if (ack != 0U) {
+ pm_ipi_irq_clear(primary_proc);
+ }
+
+ return ret;
+}
+
+/**
+ * pm_pll_set_param() - Set PLL parameter.
+ * @clk_id: PLL clock ID.
+ * @param: PLL parameter ID.
+ * @value: Value to set for PLL parameter.
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ *
+ * This API is deprecated and maintained here for backward compatibility.
+ * New use of this API should be avoided for versal platform.
+ * This API and its use cases will be removed for versal platform.
+ *
+ * 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 flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, 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.
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ *
+ * This API is deprecated and maintained here for backward compatibility.
+ * New use of this API should be avoided for versal platform.
+ * This API and its use cases will be removed for versal platform.
+ *
+ * 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 flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, 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.
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ *
+ * This API is deprecated and maintained here for backward compatibility.
+ * New use of this API should be avoided for versal platform.
+ * This API and its use cases will be removed for versal platform.
+ *
+ * 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 flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, 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.
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ *
+ * This API is deprecated and maintained here for backward compatibility.
+ * New use of this API should be avoided for versal platform.
+ * This API and its use cases will be removed for versal platform.
+ *
+ * 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 flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag, 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
+ * @flag: 0 - Call from secure source
+ * 1 - Call from non-secure source
+ *
+ * Return: Returns status, either success or error+reason.
+ *
+ */
+enum pm_ret_status pm_force_powerdown(uint32_t target, uint8_t ack,
+ uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, flag, 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.
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ *
+ * Return: Returns status, either success or error+reason.
+ *
+ */
+enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype,
+ uint32_t flag)
+{
+ 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, flag, 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.
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ *
+ * This API is deprecated and maintained here for backward compatibility.
+ * New use of this API should be avoided for versal platform.
+ * This API and its use cases will be removed for versal platform.
+ *
+ * Return: 0 if success else non-zero error code of type
+ * enum pm_ret_status.
+ *
+ */
+enum pm_ret_status pm_query_data(uint32_t qid, uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t *data, uint32_t flag)
+{
+ uint32_t ret;
+ uint32_t version[PAYLOAD_ARG_CNT] = {0};
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ uint32_t fw_api_version;
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_QUERY_DATA, qid,
+ arg1, arg2, arg3);
+
+ ret = pm_feature_check((uint32_t)PM_QUERY_DATA, &version[0], flag);
+ if (ret == PM_RET_SUCCESS) {
+ fw_api_version = version[0] & 0xFFFFU;
+ if ((fw_api_version == 2U) &&
+ ((qid == XPM_QID_CLOCK_GET_NAME) ||
+ (qid == XPM_QID_PINCTRL_GET_FUNCTION_NAME))) {
+ ret = pm_ipi_send_sync(primary_proc, payload, data, PAYLOAD_ARG_CNT);
+ if (ret == PM_RET_SUCCESS) {
+ ret = data[0];
+ data[0] = data[1];
+ data[1] = data[2];
+ data[2] = data[3];
+ }
+ } else {
+ ret = pm_ipi_send_sync(primary_proc, payload, data, PAYLOAD_ARG_CNT);
+ }
+ }
+ return ret;
+}
+/**
+ * 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.
+ * @arg3: Argument 3 to requested IOCTL call.
+ * @value: Returned output value.
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ *
+ * This API is deprecated and maintained here for backward compatibility.
+ * New use of this API should be avoided for versal platform.
+ * This API and its use cases will be removed for versal platform.
+ *
+ * This function calls IOCTL to firmware for device control and configuration.
+ *
+ * Return: Returns status, either 0 on success or non-zero error code
+ * of type enum pm_ret_status.
+ *
+ */
+enum pm_ret_status pm_api_ioctl(uint32_t device_id, uint32_t ioctl_id,
+ uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t *value, uint32_t flag)
+{
+ enum pm_ret_status ret;
+
+ switch (ioctl_id) {
+ case IOCTL_SET_PLL_FRAC_MODE:
+ ret = pm_pll_set_mode(arg1, arg2, flag);
+ break;
+ case IOCTL_GET_PLL_FRAC_MODE:
+ ret = pm_pll_get_mode(arg1, value, flag);
+ break;
+ case IOCTL_SET_PLL_FRAC_DATA:
+ ret = pm_pll_set_param(arg1, (uint32_t)PM_PLL_PARAM_DATA, arg2, flag);
+ break;
+ case IOCTL_GET_PLL_FRAC_DATA:
+ ret = pm_pll_get_param(arg1, (uint32_t)PM_PLL_PARAM_DATA, value, flag);
+ break;
+ case IOCTL_SET_SGI:
+ /* Get the sgi number */
+ ret = pm_register_sgi(arg1, arg2);
+ if (ret != 0) {
+ return PM_RET_ERROR_ARGS;
+ }
+ ret = PM_RET_SUCCESS;
+ break;
+ default:
+ return PM_RET_ERROR_NOTSUPPORTED;
+ }
+
+ return ret;
+}
+
+/**
+ * pm_set_wakeup_source() - PM call to specify the wakeup source while
+ * suspended.
+ * @target: Device id of the targeted PU or subsystem
+ * @wkup_device: Device id of the wakeup peripheral
+ * @enable: Enable or disable the specified peripheral as wake source
+ * @flag: 0 - Call from secure source
+ * 1 - Call from non-secure 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 flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, flag, PM_SET_WAKEUP_SOURCE,
+ target, wkup_device, enable);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_feature_check() - Returns the supported API version if supported.
+ * @api_id: API ID to check.
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ * @ret_payload: pointer to array of PAYLOAD_ARG_CNT number of
+ * words Returned supported API version and bitmasks
+ * for IOCTL and QUERY ID
+ *
+ * Return: Returns status, either success or error+reason.
+ *
+ */
+enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *ret_payload,
+ uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ uint32_t module_id;
+
+ /* Return version of API which are implemented in TF-A only */
+ switch (api_id) {
+ case PM_GET_CALLBACK_DATA:
+ case PM_GET_TRUSTZONE_VERSION:
+ ret_payload[0] = PM_API_VERSION_2;
+ return PM_RET_SUCCESS;
+ case TF_A_PM_REGISTER_SGI:
+ ret_payload[0] = PM_API_BASE_VERSION;
+ return PM_RET_SUCCESS;
+ default:
+ break;
+ }
+
+ module_id = (api_id & MODULE_ID_MASK) >> 8U;
+
+ /*
+ * feature check should be done only for LIBPM module
+ * If module_id is 0, then we consider it LIBPM module as default id
+ */
+ if ((module_id > 0) && (module_id != LIBPM_MODULE_ID)) {
+ return PM_RET_SUCCESS;
+ }
+
+ PM_PACK_PAYLOAD2(payload, LIBPM_MODULE_ID, flag,
+ PM_FEATURE_CHECK, api_id);
+ return pm_ipi_send_sync(primary_proc, payload, ret_payload, PAYLOAD_ARG_CNT);
+}
+
+/**
+ * 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.
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ *
+ * 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 flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD4(payload, LOADER_MODULE_ID, flag, PM_LOAD_PDI, src,
+ address_high, address_low);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_register_notifier() - PM call to register a subsystem to be notified
+ * about the device event.
+ * @device_id: Device ID for the Node to which the event is related.
+ * @event: Event in question.
+ * @wake: Wake subsystem upon capturing the event if value 1.
+ * @enable: Enable the registration for value 1, disable for value 0.
+ * @flag: 0 - Call from secure source.
+ * 1 - Call from non-secure source.
+ *
+ * Return: Returns status, either success or error+reason.
+ *
+ */
+enum pm_ret_status pm_register_notifier(uint32_t device_id, uint32_t event,
+ uint32_t wake, uint32_t enable,
+ uint32_t flag)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMC */
+ PM_PACK_PAYLOAD5(payload, LIBPM_MODULE_ID, flag, PM_REGISTER_NOTIFIER,
+ device_id, event, wake, enable);
+
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_get_chipid() - Read silicon ID registers.
+ * @value: Buffer for two 32bit words.
+ *
+ * Return: Returns status, either success or error+reason and,
+ * optionally, @value.
+ */
+enum pm_ret_status pm_get_chipid(uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ PM_PACK_PAYLOAD1(payload, LIBPM_MODULE_ID, SECURE_FLAG, PM_GET_CHIPID);
+
+ return pm_ipi_send_sync(primary_proc, payload, value, 2);
+}
diff --git a/plat/xilinx/common/pm_service/pm_ipi.c b/plat/xilinx/common/pm_service/pm_ipi.c
new file mode 100644
index 0000000..56567dd
--- /dev/null
+++ b/plat/xilinx/common/pm_service/pm_ipi.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2013-2020, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#include <arch_helpers.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <plat/common/platform.h>
+
+#include <ipi.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+#include "pm_defs.h"
+#include "pm_ipi.h"
+
+#define ERROR_CODE_MASK (0xFFFFU)
+#define PM_OFFSET (0U)
+
+/*
+ * ARM v8.2, the cache will turn off automatically when cpu
+ * power down. Therefore, there is no doubt to use the spin_lock here.
+ */
+#if !HW_ASSISTED_COHERENCY
+DEFINE_BAKERY_LOCK(pm_secure_lock);
+static inline void pm_ipi_lock_get(void)
+{
+ bakery_lock_get(&pm_secure_lock);
+}
+
+static inline void pm_ipi_lock_release(void)
+{
+ bakery_lock_release(&pm_secure_lock);
+}
+#else
+spinlock_t pm_secure_lock;
+static inline void pm_ipi_lock_get(void)
+{
+ spin_lock(&pm_secure_lock);
+}
+
+static inline void pm_ipi_lock_release(void)
+{
+ spin_unlock(&pm_secure_lock);
+}
+#endif
+
+/**
+ * pm_ipi_init() - Initialize IPI peripheral for communication with
+ * remote processor.
+ * @proc: Pointer to the processor who is initiating request.
+ *
+ * Return: On success, the initialization function must return 0.
+ * Any other return value will cause the framework to ignore
+ * the service.
+ *
+ * Called from pm_setup initialization function.
+ */
+void pm_ipi_init(const struct pm_proc *proc)
+{
+ ipi_mb_open(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id);
+}
+
+/**
+ * pm_ipi_send_common() - Sends IPI request to the remote processor.
+ * @proc: Pointer to the processor who is initiating request.
+ * @payload: API id and call arguments to be written in IPI buffer.
+ * @is_blocking: if to trigger the notification in blocking mode or not.
+ *
+ * Send an IPI request to the power controller. Caller needs to hold
+ * the 'pm_secure_lock' lock.
+ *
+ * Return: Returns status, either success or error+reason.
+ *
+ */
+static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc,
+ uint32_t payload[PAYLOAD_ARG_CNT],
+ uint32_t is_blocking)
+{
+ uint32_t offset = PM_OFFSET;
+ uintptr_t buffer_base = proc->ipi->buffer_base +
+ IPI_BUFFER_TARGET_REMOTE_OFFSET +
+ IPI_BUFFER_REQ_OFFSET;
+#if IPI_CRC_CHECK
+ payload[PAYLOAD_CRC_POS] = calculate_crc(payload, IPI_W0_TO_W6_SIZE);
+#endif
+
+ /* Write payload into IPI buffer */
+ for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) {
+ mmio_write_32(buffer_base + offset, payload[i]);
+ offset += PAYLOAD_ARG_SIZE;
+ }
+
+ /* Generate IPI to remote processor */
+ ipi_mb_notify(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id,
+ is_blocking);
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_ipi_send_non_blocking() - Sends IPI request to the remote processor
+ * without blocking notification.
+ * @proc: Pointer to the processor who is initiating request.
+ * @payload: API id and call arguments to be written in IPI buffer.
+ *
+ * Send an IPI request to the power controller.
+ *
+ * Return: Returns status, either success or error+reason.
+ *
+ */
+enum pm_ret_status pm_ipi_send_non_blocking(const struct pm_proc *proc,
+ uint32_t payload[PAYLOAD_ARG_CNT])
+{
+ enum pm_ret_status ret;
+
+ pm_ipi_lock_get();
+
+ ret = pm_ipi_send_common(proc, payload, IPI_NON_BLOCKING);
+
+ pm_ipi_lock_release();
+
+ return ret;
+}
+
+/**
+ * pm_ipi_send() - Sends IPI request to the remote processor.
+ * @proc: Pointer to the processor who is initiating request.
+ * @payload: API id and call arguments to be written in IPI buffer.
+ *
+ * Send an IPI request to the power controller.
+ *
+ * Return: Returns status, either success or error+reason.
+ *
+ */
+enum pm_ret_status pm_ipi_send(const struct pm_proc *proc,
+ uint32_t payload[PAYLOAD_ARG_CNT])
+{
+ enum pm_ret_status ret;
+
+ pm_ipi_lock_get();
+
+ ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING);
+
+ pm_ipi_lock_release();
+
+ return ret;
+}
+
+
+/**
+ * pm_ipi_buff_read() - Reads IPI response after remote processor has handled
+ * interrupt.
+ * @proc: Pointer to the processor who is waiting and reading response.
+ * @value: Used to return value from IPI buffer element (optional).
+ * @count: Number of values to return in @value.
+ *
+ * Return: Returns status, either success or error+reason.
+ *
+ */
+static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc,
+ uint32_t *value, size_t count)
+{
+ size_t i;
+ enum pm_ret_status ret;
+#if IPI_CRC_CHECK
+ uint32_t *payload_ptr = value;
+ size_t j;
+ uint32_t response_payload[PAYLOAD_ARG_CNT];
+#endif
+ uintptr_t buffer_base = proc->ipi->buffer_base +
+ IPI_BUFFER_TARGET_REMOTE_OFFSET +
+ IPI_BUFFER_RESP_OFFSET;
+
+ /*
+ * Read response from IPI buffer
+ * buf-0: success or error+reason
+ * buf-1: value
+ * buf-2: unused
+ * buf-3: unused
+ */
+ for (i = 1; i <= count; i++) {
+ *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
+ value++;
+ }
+
+ ret = mmio_read_32(buffer_base);
+#if IPI_CRC_CHECK
+ for (j = 0; j < PAYLOAD_ARG_CNT; j++) {
+ response_payload[j] = mmio_read_32(buffer_base +
+ (j * PAYLOAD_ARG_SIZE));
+ }
+
+ if (response_payload[PAYLOAD_CRC_POS] !=
+ calculate_crc(response_payload, IPI_W0_TO_W6_SIZE)) {
+ NOTICE("ERROR in CRC response payload value:0x%x\n",
+ response_payload[PAYLOAD_CRC_POS]);
+ ret = PM_RET_ERROR_INVALID_CRC;
+ /* Payload data is invalid as CRC validation failed
+ * Clear the payload to avoid leakage of data to upper layers
+ */
+ memset(payload_ptr, 0, count);
+ }
+#endif
+
+ return ret;
+}
+
+/**
+ * pm_ipi_buff_read_callb() - Callback function that reads value from
+ * ipi response buffer.
+ * @value: Used to return value from IPI buffer element.
+ * @count: Number of values to return in @value.
+ *
+ * This callback function fills requested data in @value from ipi response
+ * buffer.
+ *
+ * Return: Returns status, either success or error.
+ *
+ */
+enum pm_ret_status pm_ipi_buff_read_callb(uint32_t *value, size_t count)
+{
+ size_t i;
+#if IPI_CRC_CHECK
+ uint32_t *payload_ptr = value;
+ size_t j;
+ unsigned int response_payload[PAYLOAD_ARG_CNT] = {0};
+#endif
+ uintptr_t buffer_base = IPI_BUFFER_REMOTE_BASE +
+ IPI_BUFFER_TARGET_LOCAL_OFFSET +
+ IPI_BUFFER_REQ_OFFSET;
+ enum pm_ret_status ret = PM_RET_SUCCESS;
+
+ if (count > IPI_BUFFER_MAX_WORDS) {
+ count = IPI_BUFFER_MAX_WORDS;
+ }
+
+ for (i = 0; i <= count; i++) {
+ *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE));
+ value++;
+ }
+#if IPI_CRC_CHECK
+ for (j = 0; j < PAYLOAD_ARG_CNT; j++) {
+ response_payload[j] = mmio_read_32(buffer_base +
+ (j * PAYLOAD_ARG_SIZE));
+ }
+
+ if (response_payload[PAYLOAD_CRC_POS] !=
+ calculate_crc(response_payload, IPI_W0_TO_W6_SIZE)) {
+ NOTICE("ERROR in CRC response payload value:0x%x\n",
+ response_payload[PAYLOAD_CRC_POS]);
+ ret = PM_RET_ERROR_INVALID_CRC;
+ /* Payload data is invalid as CRC validation failed
+ * Clear the payload to avoid leakage of data to upper layers
+ */
+ memset(payload_ptr, 0, count);
+ }
+#endif
+ return ret;
+}
+
+/**
+ * pm_ipi_send_sync() - Sends IPI request to the remote processor.
+ * @proc: Pointer to the processor who is initiating request.
+ * @payload: API id and call arguments to be written in IPI buffer.
+ * @value: Used to return value from IPI buffer element (optional).
+ * @count: Number of values to return in @value.
+ *
+ * Send an IPI request to the power controller and wait for it to be handled.
+ *
+ * Return: Returns status, either success or error+reason and, optionally,
+ * @value.
+ *
+ */
+enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc,
+ uint32_t payload[PAYLOAD_ARG_CNT],
+ uint32_t *value, size_t count)
+{
+ enum pm_ret_status ret;
+
+ pm_ipi_lock_get();
+
+ ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING);
+ if (ret != PM_RET_SUCCESS) {
+ goto unlock;
+ }
+
+ ret = ERROR_CODE_MASK & (pm_ipi_buff_read(proc, value, count));
+
+unlock:
+ pm_ipi_lock_release();
+
+ return ret;
+}
+
+void pm_ipi_irq_enable(const struct pm_proc *proc)
+{
+ ipi_mb_enable_irq(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id);
+}
+
+void pm_ipi_irq_clear(const struct pm_proc *proc)
+{
+ ipi_mb_ack(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id);
+}
+
+uint32_t pm_ipi_irq_status(const struct pm_proc *proc)
+{
+ int32_t ret;
+
+ ret = ipi_mb_enquire_status(proc->ipi->local_ipi_id,
+ proc->ipi->remote_ipi_id);
+ if (ret & IPI_MB_STATUS_RECV_PENDING) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+#if IPI_CRC_CHECK
+uint32_t calculate_crc(uint32_t payload[PAYLOAD_ARG_CNT], uint32_t bufsize)
+{
+ uint32_t crcinit = CRC_INIT_VALUE;
+ uint32_t order = CRC_ORDER;
+ uint32_t polynom = CRC_POLYNOM;
+ uint32_t i, j, c, bit, datain, crcmask, crchighbit;
+ uint32_t crc = crcinit;
+
+ crcmask = ((uint32_t)((1U << (order - 1U)) - 1U) << 1U) | 1U;
+ crchighbit = (uint32_t)(1U << (order - 1U));
+
+ for (i = 0U; i < bufsize; i++) {
+ datain = mmio_read_8((unsigned long)payload + i);
+ c = datain;
+ j = 0x80U;
+ while (j != 0U) {
+ bit = crc & crchighbit;
+ crc <<= 1U;
+ if (0U != (c & j))
+ bit ^= crchighbit;
+ if (bit != 0U)
+ crc ^= polynom;
+ j >>= 1U;
+ }
+ crc &= crcmask;
+ }
+ return crc;
+}
+#endif
diff --git a/plat/xilinx/common/pm_service/pm_svc_main.c b/plat/xilinx/common/pm_service/pm_svc_main.c
new file mode 100644
index 0000000..1e5808c
--- /dev/null
+++ b/plat/xilinx/common/pm_service/pm_svc_main.c
@@ -0,0 +1,449 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022-2023, Advanced Micro Devices, 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 <stdbool.h>
+
+#include "../drivers/arm/gic/v3/gicv3_private.h"
+
+#include <common/runtime_svc.h>
+#include <drivers/arm/gicv3.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_ipi.h"
+#include "pm_svc_main.h"
+
+#define MODE 0x80000000U
+
+#define XSCUGIC_SGIR_EL1_INITID_SHIFT 24U
+#define INVALID_SGI 0xFFU
+#define PM_INIT_SUSPEND_CB (30U)
+#define PM_NOTIFY_CB (32U)
+DEFINE_RENAME_SYSREG_RW_FUNCS(icc_asgi1r_el1, S3_0_C12_C11_6)
+
+/* pm_up = true - UP, pm_up = false - DOWN */
+static bool pm_up;
+static uint32_t sgi = (uint32_t)INVALID_SGI;
+
+static void notify_os(void)
+{
+ int32_t cpu;
+ uint32_t reg;
+
+ cpu = plat_my_core_pos() + 1U;
+
+ reg = (cpu | (sgi << XSCUGIC_SGIR_EL1_INITID_SHIFT));
+ write_icc_asgi1r_el1(reg);
+}
+
+static uint64_t ipi_fiq_handler(uint32_t id, uint32_t flags, void *handle,
+ void *cookie)
+{
+ uint32_t payload[4] = {0};
+ enum pm_ret_status ret;
+
+ VERBOSE("Received IPI FIQ from firmware\n");
+
+ (void)plat_ic_acknowledge_interrupt();
+
+ ret = pm_get_callbackdata(payload, ARRAY_SIZE(payload), 0, 0);
+ if (ret != PM_RET_SUCCESS) {
+ payload[0] = ret;
+ }
+
+ switch (payload[0]) {
+ case PM_INIT_SUSPEND_CB:
+ case PM_NOTIFY_CB:
+ if (sgi != INVALID_SGI) {
+ notify_os();
+ }
+ break;
+ case PM_RET_ERROR_INVALID_CRC:
+ pm_ipi_irq_clear(primary_proc);
+ WARN("Invalid CRC in the payload\n");
+ break;
+
+ default:
+ pm_ipi_irq_clear(primary_proc);
+ WARN("Invalid IPI payload\n");
+ break;
+ }
+
+ /* Clear FIQ */
+ plat_ic_end_of_interrupt(id);
+
+ return 0;
+}
+
+/**
+ * pm_register_sgi() - PM register the IPI interrupt.
+ * @sgi_num: SGI number to be used for communication.
+ * @reset: Reset to invalid SGI when reset=1.
+ *
+ * Return: On success, the initialization function must return 0.
+ * Any other return value will cause the framework to ignore
+ * the service.
+ *
+ * Update the SGI number to be used.
+ *
+ */
+int32_t pm_register_sgi(uint32_t sgi_num, uint32_t reset)
+{
+ if (reset == 1U) {
+ sgi = INVALID_SGI;
+ return 0;
+ }
+
+ if (sgi != INVALID_SGI) {
+ return -EBUSY;
+ }
+
+ if (sgi_num >= GICV3_MAX_SGI_TARGETS) {
+ return -EINVAL;
+ }
+
+ sgi = (uint32_t)sgi_num;
+ return 0;
+}
+
+/**
+ * pm_setup() - PM service setup.
+ *
+ * Return: On success, the initialization function must return 0.
+ * Any other return value will cause the framework to ignore
+ * the service.
+ *
+ * Initialization functions for Versal power management for
+ * communicaton with PMC.
+ *
+ * Called from sip_svc_setup initialization function with the
+ * rt_svc_init signature.
+ *
+ */
+int32_t pm_setup(void)
+{
+ int32_t ret = 0;
+
+ pm_ipi_init(primary_proc);
+ pm_up = true;
+
+ /*
+ * Enable IPI IRQ
+ * assume the rich OS is OK to handle callback IRQs now.
+ * Even if we were wrong, it would not enable the IRQ in
+ * the GIC.
+ */
+ pm_ipi_irq_enable(primary_proc);
+
+ ret = request_intr_type_el3(PLAT_VERSAL_IPI_IRQ, ipi_fiq_handler);
+ if (ret != 0) {
+ WARN("BL31: registering IPI interrupt failed\n");
+ }
+
+ gicd_write_irouter(gicv3_driver_data->gicd_base, PLAT_VERSAL_IPI_IRQ, MODE);
+ return ret;
+}
+
+/**
+ * eemi_for_compatibility() - EEMI calls handler for deprecated calls.
+ * @api_id: identifier for the API being called.
+ * @pm_arg: pointer to the argument data for the API call.
+ * @handle: Pointer to caller's context structure.
+ * @security_flag: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * Return: If EEMI API found then, uintptr_t type address, else 0.
+ *
+ * Some EEMI API's use case needs to be changed in Linux driver, so they
+ * can take advantage of common EEMI handler in TF-A. As of now the old
+ * implementation of these APIs are required to maintain backward compatibility
+ * until their use case in linux driver changes.
+ *
+ */
+static uintptr_t eemi_for_compatibility(uint32_t api_id, uint32_t *pm_arg,
+ void *handle, uint32_t security_flag)
+{
+ enum pm_ret_status ret;
+
+ switch (api_id) {
+
+ case (uint32_t)PM_IOCTL:
+ {
+ uint32_t value = 0U;
+
+ ret = pm_api_ioctl(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], pm_arg[4],
+ &value, security_flag);
+ if (ret == PM_RET_ERROR_NOTSUPPORTED)
+ return (uintptr_t)0;
+
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ case (uint32_t)PM_QUERY_DATA:
+ {
+ uint32_t data[PAYLOAD_ARG_CNT] = { 0 };
+
+ ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], data, security_flag);
+
+ SMC_RET2(handle, (uint64_t)ret | ((uint64_t)data[0] << 32U),
+ (uint64_t)data[1] | ((uint64_t)data[2] << 32U));
+ }
+
+ case (uint32_t)PM_FEATURE_CHECK:
+ {
+ uint32_t result[PAYLOAD_ARG_CNT] = {0U};
+
+ ret = pm_feature_check(pm_arg[0], result, security_flag);
+ SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U),
+ (uint64_t)result[1] | ((uint64_t)result[2] << 32U));
+ }
+
+ case PM_LOAD_PDI:
+ {
+ ret = pm_load_pdi(pm_arg[0], pm_arg[1], pm_arg[2],
+ security_flag);
+ SMC_RET1(handle, (uint64_t)ret);
+ }
+
+ default:
+ return (uintptr_t)0;
+ }
+}
+
+/**
+ * eemi_psci_debugfs_handler() - EEMI API invoked from PSCI.
+ * @api_id: identifier for the API being called.
+ * @pm_arg: pointer to the argument data for the API call.
+ * @handle: Pointer to caller's context structure.
+ * @security_flag: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * These EEMI APIs performs CPU specific power management tasks.
+ * These EEMI APIs are invoked either from PSCI or from debugfs in kernel.
+ * These calls require CPU specific processing before sending IPI request to
+ * Platform Management Controller. For example enable/disable CPU specific
+ * interrupts. This requires separate handler for these calls and may not be
+ * handled using common eemi handler.
+ *
+ * Return: If EEMI API found then, uintptr_t type address, else 0.
+ *
+ */
+static uintptr_t eemi_psci_debugfs_handler(uint32_t api_id, uint32_t *pm_arg,
+ void *handle, uint32_t security_flag)
+{
+ enum pm_ret_status ret;
+
+ switch (api_id) {
+
+ case (uint32_t)PM_SELF_SUSPEND:
+ ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ case (uint32_t)PM_FORCE_POWERDOWN:
+ ret = pm_force_powerdown(pm_arg[0], pm_arg[1], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ case (uint32_t)PM_REQ_SUSPEND:
+ ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ case (uint32_t)PM_ABORT_SUSPEND:
+ ret = pm_abort_suspend(pm_arg[0], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ case (uint32_t)PM_SYSTEM_SHUTDOWN:
+ ret = pm_system_shutdown(pm_arg[0], pm_arg[1], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ default:
+ return (uintptr_t)0;
+ }
+}
+
+/**
+ * TF_A_specific_handler() - SMC handler for TF-A specific functionality.
+ * @api_id: identifier for the API being called.
+ * @pm_arg: pointer to the argument data for the API call.
+ * @handle: Pointer to caller's context structure.
+ * @security_flag: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * These EEMI calls performs functionality that does not require
+ * IPI transaction. The handler ends in TF-A and returns requested data to
+ * kernel from TF-A.
+ *
+ * Return: If TF-A specific API found then, uintptr_t type address, else 0
+ *
+ */
+static uintptr_t TF_A_specific_handler(uint32_t api_id, uint32_t *pm_arg,
+ void *handle, uint32_t security_flag)
+{
+ switch (api_id) {
+
+ case TF_A_PM_REGISTER_SGI:
+ {
+ int32_t ret;
+
+ ret = pm_register_sgi(pm_arg[0], pm_arg[1]);
+ if (ret != 0) {
+ SMC_RET1(handle, (uint32_t)PM_RET_ERROR_ARGS);
+ }
+
+ SMC_RET1(handle, (uint32_t)PM_RET_SUCCESS);
+ }
+
+ case PM_GET_CALLBACK_DATA:
+ {
+ uint32_t result[4] = {0};
+ enum pm_ret_status ret;
+
+ ret = pm_get_callbackdata(result, ARRAY_SIZE(result), security_flag, 1U);
+ if (ret != 0) {
+ result[0] = ret;
+ }
+
+ SMC_RET2(handle,
+ (uint64_t)result[0] | ((uint64_t)result[1] << 32U),
+ (uint64_t)result[2] | ((uint64_t)result[3] << 32U));
+ }
+
+ case PM_GET_TRUSTZONE_VERSION:
+ SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
+ ((uint64_t)TZ_VERSION << 32U));
+
+ default:
+ return (uintptr_t)0;
+ }
+}
+
+/**
+ * eemi_handler() - Prepare EEMI payload and perform IPI transaction.
+ * @api_id: identifier for the API being called.
+ * @pm_arg: pointer to the argument data for the API call.
+ * @handle: Pointer to caller's context structure.
+ * @security_flag: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * EEMI - Embedded Energy Management Interface is Xilinx proprietary protocol
+ * to allow communication between power management controller and different
+ * processing clusters.
+ *
+ * This handler prepares EEMI protocol payload received from kernel and performs
+ * IPI transaction.
+ *
+ * Return: If EEMI API found then, uintptr_t type address, else 0
+ *
+ */
+static uintptr_t eemi_handler(uint32_t api_id, uint32_t *pm_arg,
+ void *handle, uint32_t security_flag)
+{
+ enum pm_ret_status ret;
+ uint32_t buf[PAYLOAD_ARG_CNT] = {0};
+
+ ret = pm_handle_eemi_call(security_flag, api_id, pm_arg[0], pm_arg[1],
+ pm_arg[2], pm_arg[3], pm_arg[4],
+ (uint64_t *)buf);
+ /*
+ * Two IOCTLs, to get clock name and pinctrl name of pm_query_data API
+ * receives 5 words of respoonse from firmware. Currently linux driver can
+ * receive only 4 words from TF-A. So, this needs to be handled separately
+ * than other eemi calls.
+ */
+ if (api_id == (uint32_t)PM_QUERY_DATA) {
+ if ((pm_arg[0] == XPM_QID_CLOCK_GET_NAME ||
+ pm_arg[0] == XPM_QID_PINCTRL_GET_FUNCTION_NAME) &&
+ ret == PM_RET_SUCCESS) {
+ SMC_RET2(handle, (uint64_t)buf[0] | ((uint64_t)buf[1] << 32U),
+ (uint64_t)buf[2] | ((uint64_t)buf[3] << 32U));
+ }
+ }
+
+ SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buf[0] << 32U),
+ (uint64_t)buf[1] | ((uint64_t)buf[2] << 32U));
+}
+
+/**
+ * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
+ * @smc_fid: Function Identifier.
+ * @x1: SMC64 Arguments from kernel.
+ * @x2: SMC64 Arguments from kernel.
+ * @x3: SMC64 Arguments from kernel (upper 32-bits).
+ * @x4: Unused.
+ * @cookie: Unused.
+ * @handle: Pointer to caller's context structure.
+ * @flags: SECURE_FLAG or NON_SECURE_FLAG.
+ *
+ * Return: Unused.
+ *
+ * Determines that smc_fid is valid and supported PM SMC Function ID from the
+ * list of pm_api_ids, otherwise completes the request with
+ * the unknown SMC Function ID.
+ *
+ * The SMC calls for PM service are forwarded from SIP Service SMC handler
+ * function with rt_svc_handle signature.
+ *
+ */
+uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+ uint64_t x4, const void *cookie, void *handle, uint64_t flags)
+{
+ uintptr_t ret;
+ uint32_t pm_arg[PAYLOAD_ARG_CNT] = {0};
+ uint32_t security_flag = NON_SECURE_FLAG;
+ uint32_t api_id;
+ bool status = false, status_tmp = false;
+
+ /* Handle case where PM wasn't initialized properly */
+ if (pm_up == false) {
+ SMC_RET1(handle, SMC_UNK);
+ }
+
+ /*
+ * Mark BIT24 payload (i.e 1st bit of pm_arg[3] ) as secure (0)
+ * if smc called is secure
+ *
+ * Add redundant macro call to immune the code from glitches
+ */
+ SECURE_REDUNDANT_CALL(status, status_tmp, is_caller_secure, flags);
+ if ((status != false) && (status_tmp != false)) {
+ security_flag = SECURE_FLAG;
+ }
+
+ pm_arg[0] = (uint32_t)x1;
+ pm_arg[1] = (uint32_t)(x1 >> 32U);
+ pm_arg[2] = (uint32_t)x2;
+ pm_arg[3] = (uint32_t)(x2 >> 32U);
+ pm_arg[4] = (uint32_t)x3;
+ (void)(x4);
+ api_id = smc_fid & FUNCID_NUM_MASK;
+
+ ret = eemi_for_compatibility(api_id, pm_arg, handle, security_flag);
+ if (ret != (uintptr_t)0) {
+ return ret;
+ }
+
+ ret = eemi_psci_debugfs_handler(api_id, pm_arg, handle, flags);
+ if (ret != (uintptr_t)0) {
+ return ret;
+ }
+
+ ret = TF_A_specific_handler(api_id, pm_arg, handle, security_flag);
+ if (ret != (uintptr_t)0) {
+ return ret;
+ }
+
+ ret = eemi_handler(api_id, pm_arg, handle, security_flag);
+
+ return ret;
+}
diff --git a/plat/xilinx/common/tsp/tsp.mk b/plat/xilinx/common/tsp/tsp.mk
new file mode 100644
index 0000000..b80f531
--- /dev/null
+++ b/plat/xilinx/common/tsp/tsp.mk
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2023, Advanced Micro Devices, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+# TSP source files for AMD-Xilinx platforms
+BL32_SOURCES += plat/common/aarch64/platform_mp_stack.S \
+ plat/xilinx/common/tsp/tsp_plat_setup.c
diff --git a/plat/xilinx/common/tsp/tsp_plat_setup.c b/plat/xilinx/common/tsp/tsp_plat_setup.c
new file mode 100644
index 0000000..21c29c3
--- /dev/null
+++ b/plat/xilinx/common/tsp/tsp_plat_setup.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2014-2019, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2023, Advanced Micro Devices. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <plat/arm/common/plat_arm.h>
+#include <platform_tsp.h>
+
+#include <plat_private.h>
+
+/*******************************************************************************
+ * Initialize the UART
+ ******************************************************************************/
+void tsp_early_platform_setup(void)
+{
+ /*
+ * Register a different console than already in use to display
+ * messages from TSP
+ */
+ static console_t tsp_boot_console;
+ int32_t rc;
+
+#if defined(PLAT_zynqmp)
+ rc = console_cdns_register((uintptr_t)UART_BASE,
+ (uint32_t)get_uart_clk(),
+ (uint32_t)UART_BAUDRATE,
+ &tsp_boot_console);
+#else
+ rc = console_pl011_register((uintptr_t)UART_BASE,
+ (uint32_t)get_uart_clk(),
+ (uint32_t)UART_BAUDRATE,
+ &tsp_boot_console);
+#endif
+
+ if (rc == 0) {
+ panic();
+ }
+
+ console_set_scope(&tsp_boot_console,
+ CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_BOOT);
+}
+
+/*******************************************************************************
+ * Perform platform specific setup placeholder
+ ******************************************************************************/
+void tsp_platform_setup(void)
+{
+/*
+ * For ZynqMP, the GICv2 driver needs to be initialized in S-EL1,
+ * and for other platforms, the GICv3 driver is initialized in EL3.
+ * This is because S-EL1 can use GIC system registers to manage
+ * interrupts and does not need to be initialized again in SEL1.
+ */
+#if defined(PLAT_zynqmp)
+ plat_arm_gic_driver_init();
+ plat_arm_gic_init();
+#endif
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only initializes the MMU
+ ******************************************************************************/
+void tsp_plat_arch_setup(void)
+{
+ const mmap_region_t bl_regions[] = {
+ MAP_REGION_FLAT(BL32_BASE, BL32_END - BL32_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),
+#if defined(PLAT_zynqmp) || defined(PLAT_versal)
+ MAP_REGION_FLAT(BL_COHERENT_RAM_BASE,
+ BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+#endif
+ {0}
+ };
+
+ setup_page_tables(bl_regions, plat_get_mmap());
+ enable_mmu_el1(0);
+}
diff --git a/plat/xilinx/common/versal.c b/plat/xilinx/common/versal.c
new file mode 100644
index 0000000..3ea022c
--- /dev/null
+++ b/plat/xilinx/common/versal.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2023, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/smccc.h>
+#include <services/arm_arch_svc.h>
+
+#include <plat_private.h>
+#include <plat_startup.h>
+#include <pm_api_sys.h>
+
+/**
+ * plat_is_smccc_feature_available() - This function checks whether SMCCC
+ * feature is availabile for platform.
+ * @fid: SMCCC function id.
+ *
+ * Return: SMC_ARCH_CALL_SUCCESS - if SMCCC feature is available.
+ * SMC_ARCH_CALL_NOT_SUPPORTED - Otherwise.
+ *
+ */
+int32_t plat_is_smccc_feature_available(u_register_t fid)
+{
+ switch (fid) {
+ case SMCCC_ARCH_SOC_ID:
+ return SMC_ARCH_CALL_SUCCESS;
+ default:
+ return SMC_ARCH_CALL_NOT_SUPPORTED;
+ }
+}
+
+/**
+ * plat_get_soc_version() - Get the SOC version of the platform.
+ *
+ * Return: SiP defined SoC version in JEP-106.
+ *
+ * This function is called when the SoC_ID_type == 0.
+ * For further details please refer to section 7.4 of SMC Calling Convention.
+ */
+int32_t plat_get_soc_version(void)
+{
+ uint32_t manfid;
+
+ manfid = SOC_ID_SET_JEP_106(JEDEC_XILINX_BKID, JEDEC_XILINX_MFID);
+
+ return (int32_t)(manfid | (platform_version & SOC_ID_IMPL_DEF_MASK));
+}
+
+/**
+ * plat_get_soc_revision() - Get the SOC revision for the platform.
+ *
+ * Return: SiP defined SoC revision.
+ *
+ * This function is called when the SoC_ID_type == 1
+ * For further details please refer to section 7.4 of SMC Calling Convention
+ */
+int32_t plat_get_soc_revision(void)
+{
+ return (platform_id & SOC_ID_REV_MASK);
+}