summaryrefslogtreecommitdiffstats
path: root/plat/xilinx
diff options
context:
space:
mode:
Diffstat (limited to 'plat/xilinx')
-rw-r--r--plat/xilinx/common/include/ipi.h77
-rw-r--r--plat/xilinx/common/include/plat_startup.h41
-rw-r--r--plat/xilinx/common/include/pm_client.h33
-rw-r--r--plat/xilinx/common/include/pm_common.h62
-rw-r--r--plat/xilinx/common/include/pm_ipi.h36
-rw-r--r--plat/xilinx/common/ipi.c222
-rw-r--r--plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c133
-rw-r--r--plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.h39
-rw-r--r--plat/xilinx/common/plat_startup.c260
-rw-r--r--plat/xilinx/common/pm_service/pm_ipi.c300
-rw-r--r--plat/xilinx/versal/aarch64/versal_common.c54
-rw-r--r--plat/xilinx/versal/aarch64/versal_helpers.S73
-rw-r--r--plat/xilinx/versal/bl31_versal_setup.c236
-rw-r--r--plat/xilinx/versal/include/plat_ipi.h55
-rw-r--r--plat/xilinx/versal/include/plat_macros.S110
-rw-r--r--plat/xilinx/versal/include/plat_pm_common.h22
-rw-r--r--plat/xilinx/versal/include/plat_private.h39
-rw-r--r--plat/xilinx/versal/include/platform_def.h104
-rw-r--r--plat/xilinx/versal/include/versal_def.h146
-rw-r--r--plat/xilinx/versal/plat_psci.c249
-rw-r--r--plat/xilinx/versal/plat_topology.c14
-rw-r--r--plat/xilinx/versal/plat_versal.c21
-rw-r--r--plat/xilinx/versal/platform.mk98
-rw-r--r--plat/xilinx/versal/pm_service/pm_api_sys.c589
-rw-r--r--plat/xilinx/versal/pm_service/pm_api_sys.h101
-rw-r--r--plat/xilinx/versal/pm_service/pm_client.c261
-rw-r--r--plat/xilinx/versal/pm_service/pm_defs.h167
-rw-r--r--plat/xilinx/versal/pm_service/pm_node.h192
-rw-r--r--plat/xilinx/versal/pm_service/pm_svc_main.c395
-rw-r--r--plat/xilinx/versal/pm_service/pm_svc_main.h18
-rw-r--r--plat/xilinx/versal/sip_svc_setup.c102
-rw-r--r--plat/xilinx/versal/versal_gicv3.c186
-rw-r--r--plat/xilinx/versal/versal_ipi.c82
-rw-r--r--plat/xilinx/versal_net/aarch64/versal_net_common.c127
-rw-r--r--plat/xilinx/versal_net/aarch64/versal_net_helpers.S110
-rw-r--r--plat/xilinx/versal_net/bl31_versal_net_setup.c223
-rw-r--r--plat/xilinx/versal_net/include/plat_ipi.h58
-rw-r--r--plat/xilinx/versal_net/include/plat_macros.S118
-rw-r--r--plat/xilinx/versal_net/include/plat_pm_common.h25
-rw-r--r--plat/xilinx/versal_net/include/plat_private.h49
-rw-r--r--plat/xilinx/versal_net/include/platform_def.h114
-rw-r--r--plat/xilinx/versal_net/include/versal_net_def.h171
-rw-r--r--plat/xilinx/versal_net/plat_psci.c220
-rw-r--r--plat/xilinx/versal_net/plat_psci_pm.c264
-rw-r--r--plat/xilinx/versal_net/plat_topology.c63
-rw-r--r--plat/xilinx/versal_net/platform.mk102
-rw-r--r--plat/xilinx/versal_net/pm_service/pm_client.c240
-rw-r--r--plat/xilinx/versal_net/sip_svc_setup.c101
-rw-r--r--plat/xilinx/versal_net/versal_net_gicv3.c222
-rw-r--r--plat/xilinx/versal_net/versal_net_ipi.c85
-rw-r--r--plat/xilinx/zynqmp/aarch64/zynqmp_common.c391
-rw-r--r--plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S86
-rw-r--r--plat/xilinx/zynqmp/bl31_zynqmp_setup.c268
-rw-r--r--plat/xilinx/zynqmp/include/plat_ipi.h56
-rw-r--r--plat/xilinx/zynqmp/include/plat_macros.S28
-rw-r--r--plat/xilinx/zynqmp/include/plat_pm_common.h24
-rw-r--r--plat/xilinx/zynqmp/include/plat_private.h33
-rw-r--r--plat/xilinx/zynqmp/include/platform_def.h161
-rw-r--r--plat/xilinx/zynqmp/include/zynqmp_def.h365
-rw-r--r--plat/xilinx/zynqmp/plat_psci.c230
-rw-r--r--plat/xilinx/zynqmp/plat_topology.c13
-rw-r--r--plat/xilinx/zynqmp/plat_zynqmp.c21
-rw-r--r--plat/xilinx/zynqmp/platform.mk143
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_clock.c3048
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_clock.h333
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c767
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h96
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c2112
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h723
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_sys.c1836
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_api_sys.h197
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_client.c354
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_defs.h363
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_svc_main.c621
-rw-r--r--plat/xilinx/zynqmp/pm_service/pm_svc_main.h20
-rw-r--r--plat/xilinx/zynqmp/sip_svc_setup.c105
-rw-r--r--plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk8
-rw-r--r--plat/xilinx/zynqmp/tsp/tsp_plat_setup.c65
-rw-r--r--plat/xilinx/zynqmp/zynqmp_ehf.c24
-rw-r--r--plat/xilinx/zynqmp/zynqmp_ipi.c100
-rw-r--r--plat/xilinx/zynqmp/zynqmp_sdei.c37
81 files changed, 19437 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_startup.h b/plat/xilinx/common/include/plat_startup.h
new file mode 100644
index 0000000..1733930
--- /dev/null
+++ b/plat/xilinx/common/include/plat_startup.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_STARTUP_H
+#define PLAT_STARTUP_H
+
+#include <common/bl_common.h>
+
+/* For FSBL handover */
+enum fsbl_handoff {
+ FSBL_HANDOFF_SUCCESS = 0,
+ FSBL_HANDOFF_NO_STRUCT,
+ FSBL_HANDOFF_INVAL_STRUCT,
+ FSBL_HANDOFF_TOO_MANY_PARTS
+};
+
+#define FSBL_MAX_PARTITIONS 8U
+
+/* Structure corresponding to each partition entry */
+struct xfsbl_partition {
+ uint64_t entry_point;
+ uint64_t flags;
+};
+
+/* Structure for handoff parameters to ARM Trusted Firmware (ATF) */
+struct xfsbl_atf_handoff_params {
+ uint8_t magic[4];
+ uint32_t num_entries;
+ struct xfsbl_partition partition[FSBL_MAX_PARTITIONS];
+};
+
+#define ATF_HANDOFF_PARAMS_MAX_SIZE sizeof(struct xfsbl_atf_handoff_params)
+
+enum fsbl_handoff fsbl_atf_handover(entry_point_info_t *bl32,
+ entry_point_info_t *bl33,
+ uint64_t atf_handoff_addr);
+
+#endif /* PLAT_STARTUP_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..eae1d98
--- /dev/null
+++ b/plat/xilinx/common/include/pm_client.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2013-2019, 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
+ */
+
+/*
+ * 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);
+
+/* 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..89626e5
--- /dev/null
+++ b/plat/xilinx/common/include/pm_common.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. 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)
+
+/**
+ * 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;
+};
+
+/**
+ * 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_ipi.h b/plat/xilinx/common/include/pm_ipi.h
new file mode 100644
index 0000000..52dfc47
--- /dev/null
+++ b/plat/xilinx/common/include/pm_ipi.h
@@ -0,0 +1,36 @@
+/*
+ * 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 <plat_ipi.h>
+#include <stddef.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);
+void 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/ipi.c b/plat/xilinx/common/ipi.c
new file mode 100644
index 0000000..6438896
--- /dev/null
+++ b/plat/xilinx/common/ipi.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2020-2022, Xilinx, 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 */
+const static struct ipi_config *ipi_table;
+
+/* Total number of IPI */
+static uint32_t ipi_total;
+
+/**
+ * ipi_config_init() - Initialize IPI configuration data
+ *
+ * @ipi_config_table - IPI configuration table
+ * @ipi_total - 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..cb6aaa5
--- /dev/null
+++ b/plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. 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 <plat_ipi.h>
+#include <plat_private.h>
+
+#include "ipi_mailbox_svc.h"
+#include "../../../services/spd/trusty/smcall.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 - x4 - Arguments
+ * @cookie - Unused
+ * @handler - Pointer to caller's context structure
+ *
+ * @return - Unused
+ *
+ * Determines that smc_fid is valid and supported PM SMC Function ID from the
+ * list of pm_api_ids, otherwise completes the request with
+ * the unknown SMC Function ID
+ *
+ * The SMC calls for PM service are forwarded from SIP Service SMC handler
+ * function with rt_svc_handle signature
+ */
+uint64_t 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;
+
+ if (SMC_ENTITY(smc_fid) >= SMC_ENTITY_TRUSTED_APP)
+ 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 (SMC_FUNCTION(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..af13db9
--- /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_startup.c b/plat/xilinx/common/plat_startup.c
new file mode 100644
index 0000000..de9cf4d
--- /dev/null
+++ b/plat/xilinx/common/plat_startup.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. 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>
+
+
+/*
+ * ATFHandoffParams
+ * 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
+ */
+
+#define FSBL_FLAGS_ESTATE_SHIFT 0U
+#define FSBL_FLAGS_ESTATE_MASK (1U << FSBL_FLAGS_ESTATE_SHIFT)
+#define FSBL_FLAGS_ESTATE_A64 0U
+#define FSBL_FLAGS_ESTATE_A32 1U
+
+#define FSBL_FLAGS_ENDIAN_SHIFT 1U
+#define FSBL_FLAGS_ENDIAN_MASK (1U << FSBL_FLAGS_ENDIAN_SHIFT)
+#define FSBL_FLAGS_ENDIAN_LE 0U
+#define FSBL_FLAGS_ENDIAN_BE 1U
+
+#define FSBL_FLAGS_TZ_SHIFT 2U
+#define FSBL_FLAGS_TZ_MASK (1U << FSBL_FLAGS_TZ_SHIFT)
+#define FSBL_FLAGS_NON_SECURE 0U
+#define FSBL_FLAGS_SECURE 1U
+
+#define FSBL_FLAGS_EL_SHIFT 3U
+#define FSBL_FLAGS_EL_MASK (3U << FSBL_FLAGS_EL_SHIFT)
+#define FSBL_FLAGS_EL0 0U
+#define FSBL_FLAGS_EL1 1U
+#define FSBL_FLAGS_EL2 2U
+#define FSBL_FLAGS_EL3 3U
+
+#define FSBL_FLAGS_CPU_SHIFT 5U
+#define FSBL_FLAGS_CPU_MASK (3U << FSBL_FLAGS_CPU_SHIFT)
+#define FSBL_FLAGS_A53_0 0U
+#define FSBL_FLAGS_A53_1 1U
+#define FSBL_FLAGS_A53_2 2U
+#define FSBL_FLAGS_A53_3 3U
+
+/**
+ * @partition: Pointer to partition struct
+ *
+ * Get the target CPU for @partition.
+ *
+ * Return: FSBL_FLAGS_A53_0, FSBL_FLAGS_A53_1, FSBL_FLAGS_A53_2 or FSBL_FLAGS_A53_3
+ */
+static int32_t get_fsbl_cpu(const struct xfsbl_partition *partition)
+{
+ uint64_t flags = partition->flags & FSBL_FLAGS_CPU_MASK;
+
+ return flags >> FSBL_FLAGS_CPU_SHIFT;
+}
+
+/**
+ * @partition: Pointer to partition struct
+ *
+ * Get the target exception level for @partition.
+ *
+ * Return: FSBL_FLAGS_EL0, FSBL_FLAGS_EL1, FSBL_FLAGS_EL2 or FSBL_FLAGS_EL3
+ */
+static int32_t get_fsbl_el(const struct xfsbl_partition *partition)
+{
+ uint64_t flags = partition->flags & FSBL_FLAGS_EL_MASK;
+
+ return flags >> FSBL_FLAGS_EL_SHIFT;
+}
+
+/**
+ * @partition: Pointer to partition struct
+ *
+ * Get the target security state for @partition.
+ *
+ * Return: FSBL_FLAGS_NON_SECURE or FSBL_FLAGS_SECURE
+ */
+static int32_t get_fsbl_ss(const struct xfsbl_partition *partition)
+{
+ uint64_t flags = partition->flags & FSBL_FLAGS_TZ_MASK;
+
+ return flags >> FSBL_FLAGS_TZ_SHIFT;
+}
+
+/**
+ * @partition: Pointer to partition struct
+ *
+ * Get the target endianness for @partition.
+ *
+ * Return: SPSR_E_LITTLE or SPSR_E_BIG
+ */
+static int32_t get_fsbl_endian(const struct xfsbl_partition *partition)
+{
+ uint64_t flags = partition->flags & FSBL_FLAGS_ENDIAN_MASK;
+
+ flags >>= FSBL_FLAGS_ENDIAN_SHIFT;
+
+ if (flags == FSBL_FLAGS_ENDIAN_BE) {
+ return SPSR_E_BIG;
+ } else {
+ return SPSR_E_LITTLE;
+ }
+}
+
+/**
+ * @partition: Pointer to partition struct
+ *
+ * Get the target execution state for @partition.
+ *
+ * Return: FSBL_FLAGS_ESTATE_A32 or FSBL_FLAGS_ESTATE_A64
+ */
+static int32_t get_fsbl_estate(const struct xfsbl_partition *partition)
+{
+ uint64_t flags = partition->flags & FSBL_FLAGS_ESTATE_MASK;
+
+ return flags >> FSBL_FLAGS_ESTATE_SHIFT;
+}
+
+/**
+ * Populates the bl32 and bl33 image info structures
+ * @bl32: BL32 image info structure
+ * @bl33: BL33 image info structure
+ * atf_handoff_addr: ATF handoff address
+ *
+ * Process the handoff paramters from the FSBL and populate the BL32 and BL33
+ * image info structures accordingly.
+ *
+ * Return: Return the status of the handoff. The value will be from the
+ * fsbl_handoff enum.
+ */
+enum fsbl_handoff fsbl_atf_handover(entry_point_info_t *bl32,
+ entry_point_info_t *bl33,
+ uint64_t atf_handoff_addr)
+{
+ const struct xfsbl_atf_handoff_params *ATFHandoffParams;
+ if (!atf_handoff_addr) {
+ WARN("BL31: No ATF handoff structure passed\n");
+ return FSBL_HANDOFF_NO_STRUCT;
+ }
+
+ ATFHandoffParams = (struct xfsbl_atf_handoff_params *)atf_handoff_addr;
+ if ((ATFHandoffParams->magic[0] != 'X') ||
+ (ATFHandoffParams->magic[1] != 'L') ||
+ (ATFHandoffParams->magic[2] != 'N') ||
+ (ATFHandoffParams->magic[3] != 'X')) {
+ ERROR("BL31: invalid ATF handoff structure at %" PRIx64 "\n",
+ atf_handoff_addr);
+ return FSBL_HANDOFF_INVAL_STRUCT;
+ }
+
+ VERBOSE("BL31: ATF handoff params at:0x%" PRIx64 ", entries:%u\n",
+ atf_handoff_addr, ATFHandoffParams->num_entries);
+ if (ATFHandoffParams->num_entries > FSBL_MAX_PARTITIONS) {
+ ERROR("BL31: ATF handoff params: too many partitions (%u/%u)\n",
+ ATFHandoffParams->num_entries, FSBL_MAX_PARTITIONS);
+ return FSBL_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 < ATFHandoffParams->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,
+ ATFHandoffParams->partition[i].entry_point,
+ ATFHandoffParams->partition[i].flags);
+
+ target_cpu = get_fsbl_cpu(&ATFHandoffParams->partition[i]);
+ if (target_cpu != FSBL_FLAGS_A53_0) {
+ WARN("BL31: invalid target CPU (%i)\n", target_cpu);
+ continue;
+ }
+
+ target_el = get_fsbl_el(&ATFHandoffParams->partition[i]);
+ if ((target_el == FSBL_FLAGS_EL3) ||
+ (target_el == FSBL_FLAGS_EL0)) {
+ WARN("BL31: invalid exception level (%i)\n", target_el);
+ continue;
+ }
+
+ target_secure = get_fsbl_ss(&ATFHandoffParams->partition[i]);
+ if (target_secure == FSBL_FLAGS_SECURE &&
+ target_el == FSBL_FLAGS_EL2) {
+ WARN("BL31: invalid security state (%i) for exception level (%i)\n",
+ target_secure, target_el);
+ continue;
+ }
+
+ target_estate = get_fsbl_estate(&ATFHandoffParams->partition[i]);
+ target_endianness = get_fsbl_endian(&ATFHandoffParams->partition[i]);
+
+ if (target_secure == FSBL_FLAGS_SECURE) {
+ image = bl32;
+
+ if (target_estate == FSBL_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 == FSBL_FLAGS_ESTATE_A32) {
+ if (target_el == FSBL_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 == FSBL_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 == FSBL_FLAGS_SECURE ? "BL32" : "BL33",
+ ATFHandoffParams->partition[i].entry_point,
+ target_el);
+ image->pc = ATFHandoffParams->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 FSBL_HANDOFF_SUCCESS;
+}
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..513d6be
--- /dev/null
+++ b/plat/xilinx/common/pm_service/pm_ipi.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, 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 <ipi.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+#include "pm_defs.h"
+#include "pm_ipi.h"
+
+#define ERROR_CODE_MASK (0xFFFFU)
+#define PM_OFFSET (0U)
+
+DEFINE_BAKERY_LOCK(pm_secure_lock);
+
+/**
+ * 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)
+{
+ bakery_lock_init(&pm_secure_lock);
+ 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
+ *
+ * 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;
+
+ bakery_lock_get(&pm_secure_lock);
+
+ ret = pm_ipi_send_common(proc, payload, IPI_NON_BLOCKING);
+
+ bakery_lock_release(&pm_secure_lock);
+
+ 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;
+
+ bakery_lock_get(&pm_secure_lock);
+
+ ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING);
+
+ bakery_lock_release(&pm_secure_lock);
+
+ 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;
+#if IPI_CRC_CHECK
+ 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++;
+ }
+#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]);
+ }
+#endif
+
+ return mmio_read_32(buffer_base);
+}
+
+/**
+ * pm_ipi_buff_read_callb() - Reads IPI response after remote processor has
+ * handled interrupt
+ * @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
+ */
+void pm_ipi_buff_read_callb(uint32_t *value, size_t count)
+{
+ size_t i;
+#if IPI_CRC_CHECK
+ 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;
+
+ 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]);
+ }
+#endif
+}
+
+/**
+ * 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;
+
+ bakery_lock_get(&pm_secure_lock);
+
+ 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:
+ bakery_lock_release(&pm_secure_lock);
+
+ 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/versal/aarch64/versal_common.c b/plat/xilinx/versal/aarch64/versal_common.c
new file mode 100644
index 0000000..f55cde9
--- /dev/null
+++ b/plat/xilinx/versal/aarch64/versal_common.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_ipi.h>
+#include <versal_def.h>
+#include <plat_private.h>
+#include <common/debug.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+
+/*
+ * Table of regions to map using the MMU.
+ * This doesn't include TZRAM as the 'mem_layout' argument passed to
+ * configure_mmu_elx() will give the available subset of that,
+ */
+const mmap_region_t plat_versal_mmap[] = {
+ MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(CRF_BASE, CRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(FPD_MAINCCI_BASE, FPD_MAINCCI_SIZE, MT_DEVICE | MT_RW |
+ MT_SECURE),
+ { 0 }
+};
+
+const mmap_region_t *plat_versal_get_mmap(void)
+{
+ return plat_versal_mmap;
+}
+
+static void versal_print_platform_name(void)
+{
+ NOTICE("ATF running on Xilinx %s\n", PLATFORM_NAME);
+}
+
+void versal_config_setup(void)
+{
+ /* Configure IPI data for versal */
+ versal_ipi_config_table_init();
+
+ versal_print_platform_name();
+
+ generic_delay_timer_init();
+}
+
+uint32_t plat_get_syscnt_freq2(void)
+{
+ return VERSAL_CPU_CLOCK;
+}
+
diff --git a/plat/xilinx/versal/aarch64/versal_helpers.S b/plat/xilinx/versal/aarch64/versal_helpers.S
new file mode 100644
index 0000000..26eb052
--- /dev/null
+++ b/plat/xilinx/versal/aarch64/versal_helpers.S
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/gicv3.h>
+#include <platform_def.h>
+
+ .globl plat_secondary_cold_boot_setup
+ .globl plat_is_my_cpu_primary
+ .globl versal_calc_core_pos
+ .globl platform_mem_init
+ .globl plat_my_core_pos
+
+ /* -----------------------------------------------------
+ * void plat_secondary_cold_boot_setup (void);
+ *
+ * This function performs any platform specific actions
+ * needed for a secondary cpu after a cold reset e.g
+ * mark the cpu's presence, mechanism to place it in a
+ * holding pen etc.
+ * TODO: Should we read the PSYS register to make sure
+ * that the request has gone through.
+ * -----------------------------------------------------
+ */
+func plat_secondary_cold_boot_setup
+ mrs x0, mpidr_el1
+
+ /*
+ * There is no sane reason to come out of this wfi. This
+ * cpu will be powered on and reset by the cpu_on pm api
+ */
+ dsb sy
+ bl plat_panic_handler
+endfunc plat_secondary_cold_boot_setup
+
+func plat_is_my_cpu_primary
+ mov x9, x30
+ bl plat_my_core_pos
+ cmp x0, #VERSAL_PRIMARY_CPU
+ cset x0, eq
+ ret x9
+endfunc plat_is_my_cpu_primary
+
+ /* -----------------------------------------------------
+ * unsigned int plat_my_core_pos(void)
+ * This function uses the versal_calc_core_pos()
+ * definition to get the index of the calling CPU.
+ * -----------------------------------------------------
+ */
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b versal_calc_core_pos
+endfunc plat_my_core_pos
+
+func versal_calc_core_pos
+ and x1, x0, #MPIDR_CPU_MASK
+ and x0, x0, #MPIDR_CLUSTER_MASK
+ add x0, x1, x0, LSR #6
+ ret
+endfunc versal_calc_core_pos
+
+ /* ---------------------------------------------------------------------
+ * We don't need to carry out any memory initialization on VERSAL
+ * platform. The Secure RAM is accessible straight away.
+ * ---------------------------------------------------------------------
+ */
+func platform_mem_init
+ ret
+endfunc platform_mem_init
diff --git a/plat/xilinx/versal/bl31_versal_setup.c b/plat/xilinx/versal/bl31_versal_setup.c
new file mode 100644
index 0000000..9b36208
--- /dev/null
+++ b/plat/xilinx/versal/bl31_versal_setup.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <plat_arm.h>
+#include <plat_private.h>
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/dcc.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat/common/platform.h>
+#include <versal_def.h>
+#include <plat_private.h>
+#include <plat_startup.h>
+#include <pm_ipi.h>
+#include "pm_client.h"
+#include "pm_api_sys.h"
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/*
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ */
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+ assert(sec_state_is_valid(type));
+
+ if (type == NON_SECURE) {
+ return &bl33_image_ep_info;
+ }
+
+ return &bl32_image_ep_info;
+}
+
+/*
+ * Set the build time defaults,if we can't find any config data.
+ */
+static inline void bl31_set_default_config(void)
+{
+ bl32_image_ep_info.pc = (uintptr_t)BL32_BASE;
+ bl32_image_ep_info.spsr = (uint32_t)arm_get_spsr_for_bl32_entry();
+ bl33_image_ep_info.pc = (uintptr_t)plat_get_ns_image_entrypoint();
+ bl33_image_ep_info.spsr = (uint32_t)SPSR_64(MODE_EL2, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS);
+}
+
+/*
+ * Perform any BL31 specific platform actions. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they
+ * are lost (potentially). This needs to be done before the MMU is initialized
+ * so that the memory layout can be used while creating page tables.
+ */
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ uint64_t atf_handoff_addr;
+ uint32_t payload[PAYLOAD_ARG_CNT], max_size = ATF_HANDOFF_PARAMS_MAX_SIZE;
+ enum pm_ret_status ret_status;
+ uint64_t addr[ATF_HANDOFF_PARAMS_MAX_SIZE];
+
+ if (VERSAL_CONSOLE_IS(pl011) || (VERSAL_CONSOLE_IS(pl011_1))) {
+ static console_t versal_runtime_console;
+ /* Initialize the console to provide early debug support */
+ int32_t rc = console_pl011_register((uintptr_t)VERSAL_UART_BASE,
+ (uint32_t)VERSAL_UART_CLOCK,
+ (uint32_t)VERSAL_UART_BAUDRATE,
+ &versal_runtime_console);
+ if (rc == 0) {
+ panic();
+ }
+
+ console_set_scope(&versal_runtime_console, (uint32_t)(CONSOLE_FLAG_BOOT |
+ CONSOLE_FLAG_RUNTIME));
+ } else if (VERSAL_CONSOLE_IS(dcc)) {
+ /* Initialize the dcc console for debug */
+ int32_t rc = console_dcc_register();
+ if (rc == 0) {
+ panic();
+ }
+ } else {
+ NOTICE("BL31: Did not register for any console.\n");
+ }
+
+ /* Initialize the platform config for future decision making */
+ versal_config_setup();
+ /* There are no parameters from BL2 if BL31 is a reset vector */
+ assert(arg0 == 0U);
+ assert(arg1 == 0U);
+
+ /*
+ * Do initial security configuration to allow DRAM/device access. On
+ * Base VERSAL only DRAM security is programmable (via TrustZone), but
+ * other platforms might have more programmable security devices
+ * present.
+ */
+
+ /* Populate common information for BL32 and BL33 */
+ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
+ SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+ SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0);
+ SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+ PM_PACK_PAYLOAD4(payload, LOADER_MODULE_ID, 1, PM_LOAD_GET_HANDOFF_PARAMS,
+ (uintptr_t)addr >> 32U, (uintptr_t)addr, max_size);
+ ret_status = pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+ if (ret_status == PM_RET_SUCCESS) {
+ INFO("BL31: GET_HANDOFF_PARAMS call success=%d\n", ret_status);
+ atf_handoff_addr = (uintptr_t)&addr;
+ } else {
+ ERROR("BL31: GET_HANDOFF_PARAMS Failed, read atf_handoff_addr from reg\n");
+ atf_handoff_addr = mmio_read_32(PMC_GLOBAL_GLOB_GEN_STORAGE4);
+ }
+
+ enum fsbl_handoff ret = fsbl_atf_handover(&bl32_image_ep_info,
+ &bl33_image_ep_info,
+ atf_handoff_addr);
+ if (ret == FSBL_HANDOFF_NO_STRUCT || ret == FSBL_HANDOFF_INVAL_STRUCT) {
+ bl31_set_default_config();
+ } else if (ret == FSBL_HANDOFF_TOO_MANY_PARTS) {
+ ERROR("BL31: Error too many partitions %u\n", ret);
+ } else if (ret != FSBL_HANDOFF_SUCCESS) {
+ panic();
+ } else {
+ INFO("BL31: fsbl-atf handover success %u\n", ret);
+ }
+
+ NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc);
+ NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc);
+}
+
+static versal_intr_info_type_el3_t type_el3_interrupt_table[MAX_INTR_EL3];
+
+int request_intr_type_el3(uint32_t id, interrupt_type_handler_t handler)
+{
+ static uint32_t index;
+ uint32_t i;
+
+ /* Validate 'handler' and 'id' parameters */
+ if (handler == NULL || index >= MAX_INTR_EL3) {
+ return -EINVAL;
+ }
+
+ /* Check if a handler has already been registered */
+ for (i = 0; i < index; i++) {
+ if (id == type_el3_interrupt_table[i].id) {
+ return -EALREADY;
+ }
+ }
+
+ type_el3_interrupt_table[index].id = id;
+ type_el3_interrupt_table[index].handler = handler;
+
+ index++;
+
+ return 0;
+}
+
+static uint64_t rdo_el3_interrupt_handler(uint32_t id, uint32_t flags,
+ void *handle, void *cookie)
+{
+ uint32_t intr_id;
+ uint32_t i;
+ interrupt_type_handler_t handler = NULL;
+
+ intr_id = plat_ic_get_pending_interrupt_id();
+
+ for (i = 0; i < MAX_INTR_EL3; i++) {
+ if (intr_id == type_el3_interrupt_table[i].id) {
+ handler = type_el3_interrupt_table[i].handler;
+ }
+ }
+
+ if (handler != NULL) {
+ return handler(intr_id, flags, handle, cookie);
+ }
+
+ return 0;
+}
+void bl31_platform_setup(void)
+{
+ /* Initialize the gic cpu and distributor interfaces */
+ plat_versal_gic_driver_init();
+ plat_versal_gic_init();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+ uint64_t flags = 0;
+ int32_t rc;
+
+ set_interrupt_rm_flag(flags, NON_SECURE);
+ rc = register_interrupt_type_handler(INTR_TYPE_EL3,
+ rdo_el3_interrupt_handler, flags);
+ if (rc != 0) {
+ panic();
+ }
+}
+
+/*
+ * Perform the very early platform specific architectural setup here.
+ */
+void bl31_plat_arch_setup(void)
+{
+ plat_arm_interconnect_init();
+ plat_arm_interconnect_enter_coherency();
+
+ const mmap_region_t bl_regions[] = {
+ MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE,
+ MT_MEMORY | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE,
+ MT_CODE | MT_SECURE),
+ MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE,
+ MT_RO_DATA | MT_SECURE),
+ MAP_REGION_FLAT(BL_COHERENT_RAM_BASE,
+ BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ {0}
+ };
+
+ setup_page_tables(bl_regions, plat_versal_get_mmap());
+ enable_mmu_el3(0);
+}
diff --git a/plat/xilinx/versal/include/plat_ipi.h b/plat/xilinx/versal/include/plat_ipi.h
new file mode 100644
index 0000000..36a4380
--- /dev/null
+++ b/plat/xilinx/versal/include/plat_ipi.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Versal IPI management enums and defines */
+
+#ifndef PLAT_IPI_H
+#define PLAT_IPI_H
+
+#include <ipi.h>
+#include <stdint.h>
+
+/*********************************************************************
+ * IPI agent IDs macros
+ ********************************************************************/
+#define IPI_ID_PMC 1U
+#define IPI_ID_APU 2U
+#define IPI_ID_RPU0 3U
+#define IPI_ID_RPU1 4U
+#define IPI_ID_3 5U
+#define IPI_ID_4 6U
+#define IPI_ID_5 7U
+
+/*********************************************************************
+ * IPI message buffers
+ ********************************************************************/
+#define IPI_BUFFER_BASEADDR 0xFF3F0000U
+
+#define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U)
+#define IPI_BUFFER_PMC_BASE (IPI_BUFFER_BASEADDR + 0x200U)
+
+#define IPI_BUFFER_TARGET_APU_OFFSET 0x80U
+#define IPI_BUFFER_TARGET_PMC_OFFSET 0x40U
+
+#define IPI_BUFFER_LOCAL_BASE IPI_BUFFER_APU_BASE
+#define IPI_BUFFER_REMOTE_BASE IPI_BUFFER_PMC_BASE
+
+#define IPI_BUFFER_TARGET_LOCAL_OFFSET IPI_BUFFER_TARGET_APU_OFFSET
+#define IPI_BUFFER_TARGET_REMOTE_OFFSET IPI_BUFFER_TARGET_PMC_OFFSET
+
+#define IPI_BUFFER_MAX_WORDS 8
+
+#define IPI_BUFFER_REQ_OFFSET 0x0U
+#define IPI_BUFFER_RESP_OFFSET 0x20U
+
+/*********************************************************************
+ * Platform specific IPI API declarations
+ ********************************************************************/
+
+/* Configure IPI table for versal */
+void versal_ipi_config_table_init(void);
+
+#endif /* PLAT_IPI_H */
diff --git a/plat/xilinx/versal/include/plat_macros.S b/plat/xilinx/versal/include/plat_macros.S
new file mode 100644
index 0000000..3a52212
--- /dev/null
+++ b/plat/xilinx/versal/include/plat_macros.S
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+
+#include "../include/platform_def.h"
+
+.section .rodata.gic_reg_name, "aS"
+/* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */
+gicc_regs:
+ .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+
+/* Applicable only to GICv3 with SRE enabled */
+icc_regs:
+ .asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", ""
+
+/* Registers common to both GICv2 and GICv3 */
+gicd_pend_reg:
+ .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n"
+newline:
+ .asciz "\n"
+spacer:
+ .asciz ":\t\t0x"
+
+ /* ---------------------------------------------
+ * The below utility macro prints out relevant GIC
+ * registers whenever an unhandled exception is
+ * taken in BL31 on Versal platform.
+ * Expects: GICD base in x16, GICC base in x17
+ * Clobbers: x0 - x10, sp
+ * ---------------------------------------------
+ */
+ .macro versal_print_gic_regs
+ /* Check for GICv3 system register access */
+ mrs x7, id_aa64pfr0_el1
+ ubfx x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
+ cmp x7, #1
+ b.ne print_gicv2
+
+ /* Check for SRE enable */
+ mrs x8, ICC_SRE_EL3
+ tst x8, #ICC_SRE_SRE_BIT
+ b.eq print_gicv2
+
+ /* Load the icc reg list to x6 */
+ adr x6, icc_regs
+ /* Load the icc regs to gp regs used by str_in_crash_buf_print */
+ mrs x8, ICC_HPPIR0_EL1
+ mrs x9, ICC_HPPIR1_EL1
+ mrs x10, ICC_CTLR_EL3
+ /* Store to the crash buf and print to console */
+ bl str_in_crash_buf_print
+ b print_gic_common
+
+print_gicv2:
+ /* Load the gicc reg list to x6 */
+ adr x6, gicc_regs
+ /* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+ ldr w8, [x17, #GICC_HPPIR]
+ ldr w9, [x17, #GICC_AHPPIR]
+ ldr w10, [x17, #GICC_CTLR]
+ /* Store to the crash buf and print to console */
+ bl str_in_crash_buf_print
+
+print_gic_common:
+ /* Print the GICD_ISPENDR regs */
+ add x7, x16, #GICD_ISPENDR
+ adr x4, gicd_pend_reg
+ bl asm_print_str
+gicd_ispendr_loop:
+ sub x4, x7, x16
+ cmp x4, #0x280
+ b.eq exit_print_gic_regs
+ bl asm_print_hex
+
+ adr x4, spacer
+ bl asm_print_str
+
+ ldr x4, [x7], #8
+ bl asm_print_hex
+
+ adr x4, newline
+ bl asm_print_str
+ b gicd_ispendr_loop
+exit_print_gic_regs:
+ .endm
+
+ /* ---------------------------------------------
+ * The below required platform porting macro
+ * prints out relevant GIC and CCI registers
+ * whenever an unhandled exception is taken in
+ * BL31.
+ * Clobbers: x0 - x10, x16, x17, sp
+ * ---------------------------------------------
+ */
+ .macro plat_crash_print_regs
+ mov_imm x17, PLAT_VERSAL_GICD_BASE
+ mov_imm x16, PLAT_VERSAL_GICR_BASE
+ versal_print_gic_regs
+ .endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/xilinx/versal/include/plat_pm_common.h b/plat/xilinx/versal/include/plat_pm_common.h
new file mode 100644
index 0000000..4c057b8
--- /dev/null
+++ b/plat/xilinx/versal/include/plat_pm_common.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Contains platform specific definitions of commonly used macros data types
+ * for PU Power Management. This file should be common for all PU's.
+ */
+
+#ifndef PLAT_PM_COMMON_H
+#define PLAT_PM_COMMON_H
+
+#include <common/debug.h>
+#include <stdint.h>
+#include "pm_defs.h"
+
+#define NON_SECURE_FLAG 1U
+#define SECURE_FLAG 0U
+
+#endif /* PLAT_PM_COMMON_H */
diff --git a/plat/xilinx/versal/include/plat_private.h b/plat/xilinx/versal/include/plat_private.h
new file mode 100644
index 0000000..818797d
--- /dev/null
+++ b/plat/xilinx/versal/include/plat_private.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
+
+#include <lib/xlat_tables/xlat_tables.h>
+#include <bl31/interrupt_mgmt.h>
+
+typedef struct versal_intr_info_type_el3 {
+ uint32_t id;
+ interrupt_type_handler_t handler;
+} versal_intr_info_type_el3_t;
+
+void versal_config_setup(void);
+
+const mmap_region_t *plat_versal_get_mmap(void);
+
+void plat_versal_gic_driver_init(void);
+void plat_versal_gic_init(void);
+void plat_versal_gic_cpuif_enable(void);
+void plat_versal_gic_cpuif_disable(void);
+void plat_versal_gic_pcpu_init(void);
+void plat_versal_gic_save(void);
+void plat_versal_gic_resume(void);
+
+uint32_t versal_calc_core_pos(u_register_t mpidr);
+/*
+ * Register handler to specific GIC entrance
+ * for INTR_TYPE_EL3 type of interrupt
+ */
+int32_t request_intr_type_el3(uint32_t irq, interrupt_type_handler_t fiq_handler);
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/xilinx/versal/include/platform_def.h b/plat/xilinx/versal/include/platform_def.h
new file mode 100644
index 0000000..6d95fdc
--- /dev/null
+++ b/plat/xilinx/versal/include/platform_def.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include "versal_def.h"
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE U(0x440)
+
+#define PLATFORM_CORE_COUNT U(2)
+#define PLAT_MAX_PWR_LVL U(1)
+#define PLAT_MAX_RET_STATE U(1)
+#define PLAT_MAX_OFF_STATE U(2)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL31 at the top of the Trusted SRAM (just below the shared memory, if
+ * present). BL31_BASE is calculated using the current BL31 debug size plus a
+ * little space for growth.
+ */
+#ifndef VERSAL_ATF_MEM_BASE
+# define BL31_BASE U(0xfffe0000)
+# define BL31_LIMIT U(0xffffffff)
+#else
+# define BL31_BASE (VERSAL_ATF_MEM_BASE)
+# define BL31_LIMIT (VERSAL_ATF_MEM_BASE + VERSAL_ATF_MEM_SIZE - 1)
+# ifdef VERSAL_ATF_MEM_PROGBITS_SIZE
+# define BL31_PROGBITS_LIMIT (VERSAL_ATF_MEM_BASE + VERSAL_ATF_MEM_PROGBITS_SIZE - 1)
+# endif
+#endif
+
+/*******************************************************************************
+ * BL32 specific defines.
+ ******************************************************************************/
+#ifndef VERSAL_BL32_MEM_BASE
+# define BL32_BASE U(0x60000000)
+# define BL32_LIMIT U(0x7fffffff)
+#else
+# define BL32_BASE (VERSAL_BL32_MEM_BASE)
+# define BL32_LIMIT (VERSAL_BL32_MEM_BASE + VERSAL_BL32_MEM_SIZE - 1)
+#endif
+
+/*******************************************************************************
+ * BL33 specific defines.
+ ******************************************************************************/
+#ifndef PRELOADED_BL33_BASE
+# define PLAT_ARM_NS_IMAGE_BASE U(0x8000000)
+#else
+# define PLAT_ARM_NS_IMAGE_BASE PRELOADED_BL33_BASE
+#endif
+
+/*******************************************************************************
+ * TSP specific defines.
+ ******************************************************************************/
+#define TSP_SEC_MEM_BASE BL32_BASE
+#define TSP_SEC_MEM_SIZE (BL32_LIMIT - BL32_BASE + 1)
+
+/* ID of the secure physical generic timer interrupt used by the TSP */
+#define TSP_IRQ_SEC_PHY_TIMER ARM_IRQ_SEC_PHY_TIMER
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32)
+#define MAX_MMAP_REGIONS 8
+#define MAX_XLAT_TABLES 5
+
+#define CACHE_WRITEBACK_SHIFT 6
+#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+
+#define PLAT_VERSAL_GICD_BASE U(0xF9000000)
+#define PLAT_VERSAL_GICR_BASE U(0xF9080000)
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLAT_VERSAL_G1S_IRQS VERSAL_IRQ_SEC_PHY_TIMER
+#define PLAT_VERSAL_G0_IRQS VERSAL_IRQ_SEC_PHY_TIMER
+#define PLAT_VERSAL_IPI_IRQ U(62)
+
+#define PLAT_VERSAL_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(VERSAL_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+
+#define PLAT_VERSAL_G0_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(PLAT_VERSAL_IPI_IRQ, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/xilinx/versal/include/versal_def.h b/plat/xilinx/versal/include/versal_def.h
new file mode 100644
index 0000000..60431a5
--- /dev/null
+++ b/plat/xilinx/versal/include/versal_def.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef VERSAL_DEF_H
+#define VERSAL_DEF_H
+
+#include <plat/arm/common/smccc_def.h>
+#include <plat/common/common_def.h>
+
+/* number of interrupt handlers. increase as required */
+#define MAX_INTR_EL3 2
+/* List all consoles */
+#define VERSAL_CONSOLE_ID_pl011 1
+#define VERSAL_CONSOLE_ID_pl011_0 1
+#define VERSAL_CONSOLE_ID_pl011_1 2
+#define VERSAL_CONSOLE_ID_dcc 3
+
+#define VERSAL_CONSOLE_IS(con) (VERSAL_CONSOLE_ID_ ## con == VERSAL_CONSOLE)
+
+/* List all supported platforms */
+#define VERSAL_PLATFORM_ID_versal_virt 1
+#define VERSAL_PLATFORM_ID_spp_itr6 2
+#define VERSAL_PLATFORM_ID_emu_itr6 3
+#define VERSAL_PLATFORM_ID_silicon 4
+
+#define VERSAL_PLATFORM_IS(con) (VERSAL_PLATFORM_ID_ ## con == VERSAL_PLATFORM)
+
+/* Firmware Image Package */
+#define VERSAL_PRIMARY_CPU 0
+
+/*******************************************************************************
+ * memory map related constants
+ ******************************************************************************/
+#define DEVICE0_BASE 0xFF000000
+#define DEVICE0_SIZE 0x00E00000
+#define DEVICE1_BASE 0xF9000000
+#define DEVICE1_SIZE 0x00800000
+
+/*******************************************************************************
+ * IRQ constants
+ ******************************************************************************/
+#define VERSAL_IRQ_SEC_PHY_TIMER U(29)
+
+/*******************************************************************************
+ * CCI-400 related constants
+ ******************************************************************************/
+#define PLAT_ARM_CCI_BASE 0xFD000000
+#define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX 4
+#define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX 5
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define VERSAL_UART0_BASE 0xFF000000
+#define VERSAL_UART1_BASE 0xFF010000
+
+#if VERSAL_CONSOLE_IS(pl011) || VERSAL_CONSOLE_IS(dcc)
+# define VERSAL_UART_BASE VERSAL_UART0_BASE
+#elif VERSAL_CONSOLE_IS(pl011_1)
+# define VERSAL_UART_BASE VERSAL_UART1_BASE
+#else
+# error "invalid VERSAL_CONSOLE"
+#endif
+
+#define PLAT_VERSAL_CRASH_UART_BASE VERSAL_UART_BASE
+#define PLAT_VERSAL_CRASH_UART_CLK_IN_HZ VERSAL_UART_CLOCK
+#define VERSAL_CONSOLE_BAUDRATE VERSAL_UART_BAUDRATE
+
+/*******************************************************************************
+ * Platform related constants
+ ******************************************************************************/
+#if VERSAL_PLATFORM_IS(versal_virt)
+# define PLATFORM_NAME "Versal Virt"
+# define VERSAL_UART_CLOCK 25000000
+# define VERSAL_UART_BAUDRATE 115200
+# define VERSAL_CPU_CLOCK 2720000
+#elif VERSAL_PLATFORM_IS(silicon)
+# define PLATFORM_NAME "Versal Silicon"
+# define VERSAL_UART_CLOCK 100000000
+# define VERSAL_UART_BAUDRATE 115200
+# define VERSAL_CPU_CLOCK 100000000
+#elif VERSAL_PLATFORM_IS(spp_itr6)
+# define PLATFORM_NAME "SPP ITR6"
+# define VERSAL_UART_CLOCK 25000000
+# define VERSAL_UART_BAUDRATE 115200
+# define VERSAL_CPU_CLOCK 2720000
+#elif VERSAL_PLATFORM_IS(emu_itr6)
+# define PLATFORM_NAME "EMU ITR6"
+# define VERSAL_UART_CLOCK 212000
+# define VERSAL_UART_BAUDRATE 9600
+# define VERSAL_CPU_CLOCK 212000
+#endif
+
+/* Access control register defines */
+#define ACTLR_EL3_L2ACTLR_BIT (1 << 6)
+#define ACTLR_EL3_CPUACTLR_BIT (1 << 0)
+
+/* For cpu reset APU space here too 0xFE5F1000 CRF_APB*/
+#define CRF_BASE 0xFD1A0000
+#define CRF_SIZE 0x00600000
+
+/* CRF registers and bitfields */
+#define CRF_RST_APU (CRF_BASE + 0X00000300)
+
+#define CRF_RST_APU_ACPU_RESET (1 << 0)
+#define CRF_RST_APU_ACPU_PWRON_RESET (1 << 10)
+
+#define FPD_MAINCCI_BASE 0xFD000000
+#define FPD_MAINCCI_SIZE 0x00100000
+
+/* APU registers and bitfields */
+#define FPD_APU_BASE 0xFD5C0000U
+#define FPD_APU_CONFIG_0 (FPD_APU_BASE + 0x20U)
+#define FPD_APU_RVBAR_L_0 (FPD_APU_BASE + 0x40U)
+#define FPD_APU_RVBAR_H_0 (FPD_APU_BASE + 0x44U)
+#define FPD_APU_PWRCTL (FPD_APU_BASE + 0x90U)
+
+#define FPD_APU_CONFIG_0_VINITHI_SHIFT 8U
+#define APU_0_PWRCTL_CPUPWRDWNREQ_MASK 1U
+#define APU_1_PWRCTL_CPUPWRDWNREQ_MASK 2U
+
+/* PMC registers and bitfields */
+#define PMC_GLOBAL_BASE 0xF1110000U
+#define PMC_GLOBAL_GLOB_GEN_STORAGE4 (PMC_GLOBAL_BASE + 0x40U)
+
+/* IPI registers and bitfields */
+#define IPI0_REG_BASE U(0xFF330000)
+#define IPI0_TRIG_BIT (1U << 2U)
+#define PMC_IPI_TRIG_BIT (1U << 1U)
+#define IPI1_REG_BASE U(0xFF340000)
+#define IPI1_TRIG_BIT (1U << 3U)
+#define IPI2_REG_BASE U(0xFF350000)
+#define IPI2_TRIG_BIT (1U << 4U)
+#define IPI3_REG_BASE U(0xFF360000)
+#define IPI3_TRIG_BIT (1U << 5U)
+#define IPI4_REG_BASE U(0xFF370000)
+#define IPI4_TRIG_BIT (1U << 5U)
+#define IPI5_REG_BASE U(0xFF380000)
+#define IPI5_TRIG_BIT (1U << 6U)
+
+#endif /* VERSAL_DEF_H */
diff --git a/plat/xilinx/versal/plat_psci.c b/plat/xilinx/versal/plat_psci.c
new file mode 100644
index 0000000..6787f31
--- /dev/null
+++ b/plat/xilinx/versal/plat_psci.c
@@ -0,0 +1,249 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <plat_arm.h>
+#include <plat_private.h>
+#include <pm_common.h>
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/common/platform.h>
+#include <plat/arm/common/plat_arm.h>
+
+#include "pm_api_sys.h"
+#include "pm_client.h"
+
+static uintptr_t versal_sec_entry;
+
+static int32_t versal_pwr_domain_on(u_register_t mpidr)
+{
+ int32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
+ const struct pm_proc *proc;
+
+ VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
+
+ if (cpu_id == -1) {
+ return PSCI_E_INTERN_FAIL;
+ }
+
+ proc = pm_get_proc((uint32_t)cpu_id);
+
+ /* Send request to PMC to wake up selected ACPU core */
+ (void)pm_req_wakeup(proc->node_id, (versal_sec_entry & 0xFFFFFFFFU) | 0x1U,
+ versal_sec_entry >> 32, 0, SECURE_FLAG);
+
+ /* Clear power down request */
+ pm_client_wakeup(proc);
+
+ return PSCI_E_SUCCESS;
+}
+
+/**
+ * versal_pwr_domain_suspend() - This function sends request to PMC to suspend
+ * core.
+ *
+ * @target_state Targated state
+ */
+static void versal_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+ uint32_t state;
+ uint32_t cpu_id = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+ for (size_t i = 0U; i <= PLAT_MAX_PWR_LVL; i++) {
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+ }
+
+ plat_versal_gic_cpuif_disable();
+
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ plat_versal_gic_save();
+ }
+
+ state = target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE ?
+ PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE;
+
+ /* Send request to PMC to suspend this core */
+ (void)pm_self_suspend(proc->node_id, MAX_LATENCY, state, versal_sec_entry,
+ SECURE_FLAG);
+
+ /* APU is to be turned off */
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ /* disable coherency */
+ plat_arm_interconnect_exit_coherency();
+ }
+}
+
+/**
+ * versal_pwr_domain_suspend_finish() - This function performs actions to finish
+ * suspend procedure.
+ *
+ * @target_state Targated state
+ */
+static void versal_pwr_domain_suspend_finish(
+ const psci_power_state_t *target_state)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+ for (size_t i = 0U; i <= PLAT_MAX_PWR_LVL; i++) {
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+ }
+
+ /* Clear the APU power control register for this cpu */
+ pm_client_wakeup(proc);
+
+ /* enable coherency */
+ plat_arm_interconnect_enter_coherency();
+
+ /* APU was turned off, so restore GIC context */
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ plat_versal_gic_resume();
+ }
+
+ plat_versal_gic_cpuif_enable();
+}
+
+void versal_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ /* Enable the gic cpu interface */
+ plat_versal_gic_pcpu_init();
+
+ /* Program the gic per-cpu distributor or re-distributor interface */
+ plat_versal_gic_cpuif_enable();
+}
+
+/**
+ * versal_system_off() - This function sends the system off request
+ * to firmware. This function does not return.
+ */
+static void __dead2 versal_system_off(void)
+{
+ /* Send the power down request to the PMC */
+ (void)pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN,
+ pm_get_shutdown_scope(), SECURE_FLAG);
+
+ while (1) {
+ wfi();
+ }
+}
+
+/**
+ * versal_system_reset() - This function sends the reset request
+ * to firmware for the system to reset. This function does not return.
+ */
+static void __dead2 versal_system_reset(void)
+{
+ /* Send the system reset request to the PMC */
+ (void)pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET,
+ pm_get_shutdown_scope(), SECURE_FLAG);
+
+ while (1) {
+ wfi();
+ }
+}
+
+/**
+ * versal_pwr_domain_off() - This function performs actions to turn off core
+ *
+ * @target_state Targated state
+ */
+static void versal_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+ for (size_t i = 0U; i <= PLAT_MAX_PWR_LVL; i++) {
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+ }
+
+ /* Prevent interrupts from spuriously waking up this cpu */
+ plat_versal_gic_cpuif_disable();
+
+ /*
+ * Send request to PMC to power down the appropriate APU CPU
+ * core.
+ * According to PSCI specification, CPU_off function does not
+ * have resume address and CPU core can only be woken up
+ * invoking CPU_on function, during which resume address will
+ * be set.
+ */
+ (void)pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0,
+ SECURE_FLAG);
+}
+
+/**
+ * versal_validate_power_state() - This function ensures that the power state
+ * parameter in request is valid.
+ *
+ * @power_state Power state of core
+ * @req_state Requested state
+ *
+ * @return Returns status, either success or reason
+ */
+static int32_t versal_validate_power_state(uint32_t power_state,
+ psci_power_state_t *req_state)
+{
+ VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
+
+ uint32_t pstate = psci_get_pstate_type(power_state);
+
+ assert(req_state);
+
+ /* Sanity check the requested state */
+ if (pstate == PSTATE_TYPE_STANDBY) {
+ req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
+ } else {
+ req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
+ }
+
+ /* We expect the 'state id' to be zero */
+ if (psci_get_pstate_id(power_state) != 0U) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
+/**
+ * versal_get_sys_suspend_power_state() - Get power state for system suspend
+ *
+ * @req_state Requested state
+ */
+static void versal_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+ req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
+ req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
+}
+
+static const struct plat_psci_ops versal_nopmc_psci_ops = {
+ .pwr_domain_on = versal_pwr_domain_on,
+ .pwr_domain_off = versal_pwr_domain_off,
+ .pwr_domain_on_finish = versal_pwr_domain_on_finish,
+ .pwr_domain_suspend = versal_pwr_domain_suspend,
+ .pwr_domain_suspend_finish = versal_pwr_domain_suspend_finish,
+ .system_off = versal_system_off,
+ .system_reset = versal_system_reset,
+ .validate_power_state = versal_validate_power_state,
+ .get_sys_suspend_power_state = versal_get_sys_suspend_power_state,
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops.
+ ******************************************************************************/
+int32_t plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const struct plat_psci_ops **psci_ops)
+{
+ versal_sec_entry = sec_entrypoint;
+
+ *psci_ops = &versal_nopmc_psci_ops;
+
+ return 0;
+}
diff --git a/plat/xilinx/versal/plat_topology.c b/plat/xilinx/versal/plat_topology.c
new file mode 100644
index 0000000..6a94544
--- /dev/null
+++ b/plat/xilinx/versal/plat_topology.c
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+static const uint8_t plat_power_domain_tree_desc[] = {1, PLATFORM_CORE_COUNT};
+
+const uint8_t *plat_get_power_domain_tree_desc(void)
+{
+ return plat_power_domain_tree_desc;
+}
diff --git a/plat/xilinx/versal/plat_versal.c b/plat/xilinx/versal/plat_versal.c
new file mode 100644
index 0000000..132c7b7
--- /dev/null
+++ b/plat/xilinx/versal/plat_versal.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+int32_t plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+ if ((mpidr & MPIDR_CLUSTER_MASK) != 0U) {
+ return -1;
+ }
+
+ if ((mpidr & MPIDR_CPU_MASK) >= PLATFORM_CORE_COUNT) {
+ return -1;
+ }
+
+ return (int32_t)versal_calc_core_pos(mpidr);
+}
diff --git a/plat/xilinx/versal/platform.mk b/plat/xilinx/versal/platform.mk
new file mode 100644
index 0000000..8087297
--- /dev/null
+++ b/plat/xilinx/versal/platform.mk
@@ -0,0 +1,98 @@
+# Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+override PROGRAMMABLE_RESET_ADDRESS := 1
+PSCI_EXTENDED_STATE_ID := 1
+A53_DISABLE_NON_TEMPORAL_HINT := 0
+SEPARATE_CODE_AND_RODATA := 1
+override RESET_TO_BL31 := 1
+PL011_GENERIC_UART := 1
+IPI_CRC_CHECK := 0
+HARDEN_SLS_ALL := 0
+
+# A72 Erratum for SoC
+ERRATA_A72_859971 := 1
+ERRATA_A72_1319367 := 1
+
+ifdef VERSAL_ATF_MEM_BASE
+ $(eval $(call add_define,VERSAL_ATF_MEM_BASE))
+
+ ifndef VERSAL_ATF_MEM_SIZE
+ $(error "VERSAL_ATF_BASE defined without VERSAL_ATF_SIZE")
+ endif
+ $(eval $(call add_define,VERSAL_ATF_MEM_SIZE))
+
+ ifdef VERSAL_ATF_MEM_PROGBITS_SIZE
+ $(eval $(call add_define,VERSAL_ATF_MEM_PROGBITS_SIZE))
+ endif
+endif
+
+ifdef VERSAL_BL32_MEM_BASE
+ $(eval $(call add_define,VERSAL_BL32_MEM_BASE))
+
+ ifndef VERSAL_BL32_MEM_SIZE
+ $(error "VERSAL_BL32_BASE defined without VERSAL_BL32_SIZE")
+ endif
+ $(eval $(call add_define,VERSAL_BL32_MEM_SIZE))
+endif
+
+ifdef IPI_CRC_CHECK
+ $(eval $(call add_define,IPI_CRC_CHECK))
+endif
+
+VERSAL_PLATFORM ?= silicon
+$(eval $(call add_define_val,VERSAL_PLATFORM,VERSAL_PLATFORM_ID_${VERSAL_PLATFORM}))
+
+PLAT_INCLUDES := -Iinclude/plat/arm/common/ \
+ -Iplat/xilinx/common/include/ \
+ -Iplat/xilinx/common/ipi_mailbox_service/ \
+ -Iplat/xilinx/versal/include/ \
+ -Iplat/xilinx/versal/pm_service/
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+
+PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \
+ lib/xlat_tables/aarch64/xlat_tables.c \
+ drivers/arm/dcc/dcc_console.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ ${GICV3_SOURCES} \
+ drivers/arm/pl011/aarch64/pl011_console.S \
+ plat/common/aarch64/crash_console_helpers.S \
+ plat/arm/common/arm_cci.c \
+ plat/arm/common/arm_common.c \
+ plat/common/plat_gicv3.c \
+ plat/xilinx/versal/aarch64/versal_helpers.S \
+ plat/xilinx/versal/aarch64/versal_common.c
+
+VERSAL_CONSOLE ?= pl011
+ifeq (${VERSAL_CONSOLE}, $(filter ${VERSAL_CONSOLE},pl011 pl011_0 pl011_1 dcc))
+else
+ $(error "Please define VERSAL_CONSOLE")
+endif
+
+$(eval $(call add_define_val,VERSAL_CONSOLE,VERSAL_CONSOLE_ID_${VERSAL_CONSOLE}))
+
+BL31_SOURCES += drivers/arm/cci/cci.c \
+ lib/cpus/aarch64/cortex_a72.S \
+ plat/common/plat_psci_common.c \
+ plat/xilinx/common/ipi.c \
+ plat/xilinx/common/plat_startup.c \
+ plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c \
+ plat/xilinx/common/pm_service/pm_ipi.c \
+ plat/xilinx/versal/bl31_versal_setup.c \
+ plat/xilinx/versal/plat_psci.c \
+ plat/xilinx/versal/plat_versal.c \
+ plat/xilinx/versal/plat_topology.c \
+ plat/xilinx/versal/sip_svc_setup.c \
+ plat/xilinx/versal/versal_gicv3.c \
+ plat/xilinx/versal/versal_ipi.c \
+ plat/xilinx/versal/pm_service/pm_svc_main.c \
+ plat/xilinx/versal/pm_service/pm_api_sys.c \
+ plat/xilinx/versal/pm_service/pm_client.c
+
+ifeq ($(HARDEN_SLS_ALL), 1)
+TF_CFLAGS_aarch64 += -mharden-sls=all
+endif
diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.c b/plat/xilinx/versal/pm_service/pm_api_sys.c
new file mode 100644
index 0000000..db9fae4
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.c
@@ -0,0 +1,589 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, 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 <pm_common.h>
+#include <pm_ipi.h>
+#include <plat/common/platform.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_defs.h"
+#include "pm_svc_main.h"
+
+/* 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_handle_eemi_call() - PM call for processor to send eemi payload
+ * @flag 0 - Call from secure source
+ * 1 - Call from non-secure source
+ * @x0 to 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
+ * @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.
+ */
+void pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag, uint32_t ack)
+{
+ /* Return if interrupt is not from PMU */
+ if (pm_ipi_irq_status(primary_proc) == 0) {
+ return;
+ }
+
+ pm_ipi_buff_read_callb(data, count);
+
+ if (ack != 0U) {
+ pm_ipi_irq_clear(primary_proc);
+ }
+}
+
+/**
+ * pm_pll_set_param() - Set PLL parameter
+ *
+ * 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.
+ *
+ * @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
+ *
+ * @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
+ *
+ * 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.
+ *
+ * @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
+ *
+ * @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
+ *
+ * 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.
+ *
+ * @clk_id PLL clock ID
+ * @mode PLL mode
+ * @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_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
+ *
+ * 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.
+ *
+ * @clk_id PLL clock ID
+ * @mode: Buffer to store PLL mode
+ * @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_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
+ *
+ * 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.
+ *
+ * @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
+ *
+ * @retur - 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(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
+ *
+ * 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.
+ *
+ * @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 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, PM_PLL_PARAM_DATA, arg2, flag);
+ break;
+ case IOCTL_GET_PLL_FRAC_DATA:
+ ret = pm_pll_get_param(arg1, 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_node 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 ATF 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);
+}
diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.h b/plat/xilinx/versal/pm_service/pm_api_sys.h
new file mode 100644
index 0000000..c539aa7
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, 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);
+void pm_get_callbackdata(uint32_t *data, size_t count, uint32_t flag,
+ uint32_t ack);
+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);
+
+/**
+ * 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/versal/pm_service/pm_client.c b/plat/xilinx/versal/pm_service/pm_client.c
new file mode 100644
index 0000000..ce5e533
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_client.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * APU specific definition of processors in the subsystem as well as functions
+ * for getting information about and changing state of the APU.
+ */
+
+#include <assert.h>
+#include <plat_ipi.h>
+#include <platform_def.h>
+#include <versal_def.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <drivers/arm/gicv3.h>
+#include <drivers/arm/gic_common.h>
+#include <plat/common/platform.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_defs.h"
+
+#define UNDEFINED_CPUID (~0)
+#define IRQ_MAX 142U
+#define NUM_GICD_ISENABLER ((IRQ_MAX >> 5U) + 1U)
+
+DEFINE_BAKERY_LOCK(pm_client_secure_lock);
+
+static const struct pm_ipi apu_ipi = {
+ .local_ipi_id = IPI_ID_APU,
+ .remote_ipi_id = IPI_ID_PMC,
+ .buffer_base = IPI_BUFFER_APU_BASE,
+};
+
+/* Order in pm_procs_all array must match cpu ids */
+static const struct pm_proc pm_procs_all[] = {
+ {
+ .node_id = XPM_DEVID_ACPU_0,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
+ },
+ {
+ .node_id = XPM_DEVID_ACPU_1,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
+ }
+};
+
+const struct pm_proc *primary_proc = &pm_procs_all[0];
+
+/* Interrupt to PM node index map */
+static enum pm_device_node_idx irq_node_map[IRQ_MAX + 1] = {
+ [13] = XPM_NODEIDX_DEV_GPIO,
+ [14] = XPM_NODEIDX_DEV_I2C_0,
+ [15] = XPM_NODEIDX_DEV_I2C_1,
+ [16] = XPM_NODEIDX_DEV_SPI_0,
+ [17] = XPM_NODEIDX_DEV_SPI_1,
+ [18] = XPM_NODEIDX_DEV_UART_0,
+ [19] = XPM_NODEIDX_DEV_UART_1,
+ [20] = XPM_NODEIDX_DEV_CAN_FD_0,
+ [21] = XPM_NODEIDX_DEV_CAN_FD_1,
+ [22] = XPM_NODEIDX_DEV_USB_0,
+ [23] = XPM_NODEIDX_DEV_USB_0,
+ [24] = XPM_NODEIDX_DEV_USB_0,
+ [25] = XPM_NODEIDX_DEV_USB_0,
+ [26] = XPM_NODEIDX_DEV_USB_0,
+ [37] = XPM_NODEIDX_DEV_TTC_0,
+ [38] = XPM_NODEIDX_DEV_TTC_0,
+ [39] = XPM_NODEIDX_DEV_TTC_0,
+ [40] = XPM_NODEIDX_DEV_TTC_1,
+ [41] = XPM_NODEIDX_DEV_TTC_1,
+ [42] = XPM_NODEIDX_DEV_TTC_1,
+ [43] = XPM_NODEIDX_DEV_TTC_2,
+ [44] = XPM_NODEIDX_DEV_TTC_2,
+ [45] = XPM_NODEIDX_DEV_TTC_2,
+ [46] = XPM_NODEIDX_DEV_TTC_3,
+ [47] = XPM_NODEIDX_DEV_TTC_3,
+ [48] = XPM_NODEIDX_DEV_TTC_3,
+ [56] = XPM_NODEIDX_DEV_GEM_0,
+ [57] = XPM_NODEIDX_DEV_GEM_0,
+ [58] = XPM_NODEIDX_DEV_GEM_1,
+ [59] = XPM_NODEIDX_DEV_GEM_1,
+ [60] = XPM_NODEIDX_DEV_ADMA_0,
+ [61] = XPM_NODEIDX_DEV_ADMA_1,
+ [62] = XPM_NODEIDX_DEV_ADMA_2,
+ [63] = XPM_NODEIDX_DEV_ADMA_3,
+ [64] = XPM_NODEIDX_DEV_ADMA_4,
+ [65] = XPM_NODEIDX_DEV_ADMA_5,
+ [66] = XPM_NODEIDX_DEV_ADMA_6,
+ [67] = XPM_NODEIDX_DEV_ADMA_7,
+ [74] = XPM_NODEIDX_DEV_USB_0,
+ [126] = XPM_NODEIDX_DEV_SDIO_0,
+ [127] = XPM_NODEIDX_DEV_SDIO_0,
+ [128] = XPM_NODEIDX_DEV_SDIO_1,
+ [129] = XPM_NODEIDX_DEV_SDIO_1,
+ [142] = XPM_NODEIDX_DEV_RTC,
+};
+
+/**
+ * irq_to_pm_node_idx - Get PM node index corresponding to the interrupt number
+ * @irq: Interrupt number
+ *
+ * Return: PM node index corresponding to the specified interrupt
+ */
+static enum pm_device_node_idx irq_to_pm_node_idx(uint32_t irq)
+{
+ assert(irq <= IRQ_MAX);
+ return irq_node_map[irq];
+}
+
+/**
+ * pm_client_set_wakeup_sources - Set all devices with enabled interrupts as
+ * wake sources in the LibPM.
+ * @node_id: Node id of processor
+ */
+static void pm_client_set_wakeup_sources(uint32_t node_id)
+{
+ uint32_t reg_num;
+ uint32_t device_id;
+ uint8_t pm_wakeup_nodes_set[XPM_NODEIDX_DEV_MAX];
+ uintptr_t isenabler1 = PLAT_VERSAL_GICD_BASE + GICD_ISENABLER + 4;
+
+ zeromem(&pm_wakeup_nodes_set, (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 = __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 && node_idx < XPM_NODEIDX_DEV_MAX) {
+ if (pm_wakeup_nodes_set[node_idx] == 0U) {
+ /* Get device ID from node index */
+ device_id = PERIPH_DEVID(node_idx);
+ ret = pm_set_wakeup_source(node_id,
+ device_id, 1,
+ SECURE_FLAG);
+ pm_wakeup_nodes_set[node_idx] = (ret == PM_RET_SUCCESS) ?
+ 1 : 0;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * pm_client_suspend() - Client-specific suspend actions
+ *
+ * This function should contain any PU-specific actions
+ * required prior to sending suspend request to PMU
+ * Actions taken depend on the state system is suspending to.
+ */
+void pm_client_suspend(const struct pm_proc *proc, uint32_t state)
+{
+ bakery_lock_get(&pm_client_secure_lock);
+
+ if (state == PM_STATE_SUSPEND_TO_RAM) {
+ pm_client_set_wakeup_sources((uint32_t)proc->node_id);
+ }
+
+ /* Set powerdown request */
+ mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) |
+ (uint32_t)proc->pwrdn_mask);
+
+ bakery_lock_release(&pm_client_secure_lock);
+}
+
+/**
+ * pm_client_abort_suspend() - Client-specific abort-suspend actions
+ *
+ * This function should contain any PU-specific actions
+ * required for aborting a prior suspend request
+ */
+void pm_client_abort_suspend(void)
+{
+ /* Enable interrupts at processor level (for current cpu) */
+ gicv3_cpuif_enable(plat_my_core_pos());
+
+ bakery_lock_get(&pm_client_secure_lock);
+
+ /* Clear powerdown request */
+ mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) &
+ ~((uint32_t)primary_proc->pwrdn_mask));
+
+ bakery_lock_release(&pm_client_secure_lock);
+}
+
+/**
+ * pm_get_cpuid() - get the local cpu ID for a global node ID
+ * @nid: node id of the processor
+ *
+ * Return: the cpu ID (starting from 0) for the subsystem
+ */
+static uint32_t pm_get_cpuid(uint32_t nid)
+{
+ for (size_t i = 0U; i < ARRAY_SIZE(pm_procs_all); i++) {
+ if (pm_procs_all[i].node_id == nid) {
+ return i;
+ }
+ }
+ return UNDEFINED_CPUID;
+}
+
+/**
+ * pm_client_wakeup() - Client-specific wakeup actions
+ *
+ * This function should contain any PU-specific actions
+ * required for waking up another APU core
+ */
+void pm_client_wakeup(const struct pm_proc *proc)
+{
+ uint32_t cpuid = pm_get_cpuid(proc->node_id);
+
+ if (cpuid == UNDEFINED_CPUID) {
+ return;
+ }
+
+ bakery_lock_get(&pm_client_secure_lock);
+
+ /* clear powerdown bit for affected cpu */
+ uint32_t val = mmio_read_32(FPD_APU_PWRCTL);
+ val &= ~(proc->pwrdn_mask);
+ mmio_write_32(FPD_APU_PWRCTL, val);
+
+ bakery_lock_release(&pm_client_secure_lock);
+}
+
+/**
+ * pm_get_proc() - returns pointer to the proc structure
+ * @cpuid: id of the cpu whose proc struct pointer should be returned
+ *
+ * Return: pointer to a proc structure if proc is found, otherwise NULL
+ */
+const struct pm_proc *pm_get_proc(uint32_t cpuid)
+{
+ if (cpuid < ARRAY_SIZE(pm_procs_all)) {
+ return &pm_procs_all[cpuid];
+ }
+
+ return NULL;
+}
diff --git a/plat/xilinx/versal/pm_service/pm_defs.h b/plat/xilinx/versal/pm_service/pm_defs.h
new file mode 100644
index 0000000..2922b5d
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_defs.h
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Versal power management enums and defines */
+
+#ifndef PM_DEFS_H
+#define PM_DEFS_H
+
+#include "pm_node.h"
+
+/*********************************************************************
+ * Macro definitions
+ ********************************************************************/
+
+/* State arguments of the self suspend */
+#define PM_STATE_CPU_IDLE 0x0U
+#define PM_STATE_SUSPEND_TO_RAM 0xFU
+
+#define MAX_LATENCY (~0U)
+#define MAX_QOS 100U
+
+/* Processor core device IDs */
+#define APU_DEVID(IDX) NODEID(XPM_NODECLASS_DEVICE, XPM_NODESUBCL_DEV_CORE, \
+ XPM_NODETYPE_DEV_CORE_APU, (IDX))
+
+#define XPM_DEVID_ACPU_0 APU_DEVID(XPM_NODEIDX_DEV_ACPU_0)
+#define XPM_DEVID_ACPU_1 APU_DEVID(XPM_NODEIDX_DEV_ACPU_1)
+
+#define PERIPH_DEVID(IDX) NODEID(XPM_NODECLASS_DEVICE, \
+ XPM_NODESUBCL_DEV_PERIPH, \
+ XPM_NODETYPE_DEV_PERIPH, (IDX))
+
+#define PM_GET_CALLBACK_DATA 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
+
+/* PM API ids */
+#define PM_REGISTER_NOTIFIER 5U
+#define PM_REQ_SUSPEND 6U
+#define PM_SELF_SUSPEND 7U
+#define PM_FORCE_POWERDOWN 8U
+#define PM_ABORT_SUSPEND 9U
+#define PM_REQ_WAKEUP 10U
+#define PM_SET_WAKEUP_SOURCE 11U
+#define PM_SYSTEM_SHUTDOWN 12U
+#define PM_IOCTL 34U
+#define PM_QUERY_DATA 35U
+#define PM_PLL_SET_PARAMETER 48U
+#define PM_PLL_GET_PARAMETER 49U
+#define PM_PLL_SET_MODE 50U
+#define PM_PLL_GET_MODE 51U
+#define PM_FEATURE_CHECK 63U
+
+/* Loader API ids */
+#define PM_LOAD_PDI 0x701U
+#define PM_LOAD_GET_HANDOFF_PARAMS 0x70BU
+
+/* IOCTL IDs for clock driver */
+#define IOCTL_SET_PLL_FRAC_MODE 8U
+#define IOCTL_GET_PLL_FRAC_MODE 9U
+#define IOCTL_SET_PLL_FRAC_DATA 10U
+#define IOCTL_GET_PLL_FRAC_DATA 11U
+#define IOCTL_SET_SGI 25U
+
+/* Parameter ID for PLL IOCTLs */
+/* Fractional data portion for PLL */
+#define PM_PLL_PARAM_DATA 2
+
+/* System shutdown macros */
+#define XPM_SHUTDOWN_TYPE_SHUTDOWN 0U
+#define XPM_SHUTDOWN_TYPE_RESET 1U
+#define XPM_SHUTDOWN_TYPE_SETSCOPE_ONLY 2U
+
+#define XPM_SHUTDOWN_SUBTYPE_RST_SUBSYSTEM 0U
+#define XPM_SHUTDOWN_SUBTYPE_RST_PS_ONLY 1U
+#define XPM_SHUTDOWN_SUBTYPE_RST_SYSTEM 2U
+
+/*********************************************************************
+ * Enum definitions
+ ********************************************************************/
+
+enum pm_abort_reason {
+ ABORT_REASON_WKUP_EVENT = 100,
+ ABORT_REASON_PU_BUSY,
+ ABORT_REASON_NO_PWRDN,
+ ABORT_REASON_UNKNOWN,
+};
+
+enum pm_opchar_type {
+ PM_OPCHAR_TYPE_POWER = 1,
+ PM_OPCHAR_TYPE_TEMP,
+ PM_OPCHAR_TYPE_LATENCY,
+};
+
+/**
+ * Subsystem IDs
+ */
+typedef enum {
+ XPM_SUBSYSID_PMC,
+ XPM_SUBSYSID_PSM,
+ XPM_SUBSYSID_APU,
+ XPM_SUBSYSID_RPU0_LOCK,
+ XPM_SUBSYSID_RPU0_0,
+ XPM_SUBSYSID_RPU0_1,
+ XPM_SUBSYSID_DDR0,
+ XPM_SUBSYSID_ME,
+ XPM_SUBSYSID_PL,
+ XPM_SUBSYSID_MAX,
+} XPm_SubsystemId;
+
+/**
+ * @PM_RET_SUCCESS: success
+ * @PM_RET_ERROR_ARGS: illegal arguments provided (deprecated)
+ * @PM_RET_ERROR_NOTSUPPORTED: feature not supported (deprecated)
+ * @PM_RET_ERROR_NOFEATURE: feature is not available
+ * @PM_RET_ERROR_INTERNAL: internal error
+ * @PM_RET_ERROR_CONFLICT: conflict
+ * @PM_RET_ERROR_ACCESS: access rights violation
+ * @PM_RET_ERROR_INVALID_NODE: invalid node
+ * @PM_RET_ERROR_DOUBLE_REQ: duplicate request for same node
+ * @PM_RET_ERROR_ABORT_SUSPEND: suspend procedure has been aborted
+ * @PM_RET_ERROR_TIMEOUT: timeout in communication with PMU
+ * @PM_RET_ERROR_NODE_USED: node is already in use
+ */
+enum pm_ret_status {
+ PM_RET_SUCCESS,
+ PM_RET_ERROR_ARGS = 1,
+ PM_RET_ERROR_NOTSUPPORTED = 4,
+ PM_RET_ERROR_NOFEATURE = 19,
+ PM_RET_ERROR_INTERNAL = 2000,
+ PM_RET_ERROR_CONFLICT = 2001,
+ PM_RET_ERROR_ACCESS = 2002,
+ PM_RET_ERROR_INVALID_NODE = 2003,
+ PM_RET_ERROR_DOUBLE_REQ = 2004,
+ PM_RET_ERROR_ABORT_SUSPEND = 2005,
+ PM_RET_ERROR_TIMEOUT = 2006,
+ PM_RET_ERROR_NODE_USED = 2007
+};
+
+/**
+ * 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/versal/pm_service/pm_node.h b/plat/xilinx/versal/pm_service/pm_node.h
new file mode 100644
index 0000000..1b82ec7
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_node.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2019, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Versal PM nodes enums and defines */
+
+#ifndef PM_NODE_H
+#define PM_NODE_H
+
+/*********************************************************************
+ * Macro definitions
+ ********************************************************************/
+
+#define NODE_CLASS_SHIFT 26U
+#define NODE_SUBCLASS_SHIFT 20U
+#define NODE_TYPE_SHIFT 14U
+#define NODE_INDEX_SHIFT 0U
+#define NODE_CLASS_MASK_BITS 0x3F
+#define NODE_SUBCLASS_MASK_BITS 0x3F
+#define NODE_TYPE_MASK_BITS 0x3F
+#define NODE_INDEX_MASK_BITS 0x3FFF
+#define NODE_CLASS_MASK (NODE_CLASS_MASK_BITS << NODE_CLASS_SHIFT)
+#define NODE_SUBCLASS_MASK (NODE_SUBCLASS_MASK_BITS << NODE_SUBCLASS_SHIFT)
+#define NODE_TYPE_MASK (NODE_TYPE_MASK_BITS << NODE_TYPE_SHIFT)
+#define NODE_INDEX_MASK (NODE_INDEX_MASK_BITS << NODE_INDEX_SHIFT)
+
+#define NODEID(CLASS, SUBCLASS, TYPE, INDEX) \
+ ((((CLASS) & NODE_CLASS_MASK_BITS) << NODE_CLASS_SHIFT) | \
+ (((SUBCLASS) & NODE_SUBCLASS_MASK_BITS) << NODE_SUBCLASS_SHIFT) | \
+ (((TYPE) & NODE_TYPE_MASK_BITS) << NODE_TYPE_SHIFT) | \
+ (((INDEX) & NODE_INDEX_MASK_BITS) << NODE_INDEX_SHIFT))
+
+#define NODECLASS(ID) (((ID) & NODE_CLASS_MASK) >> NODE_CLASS_SHIFT)
+#define NODESUBCLASS(ID) (((ID) & NODE_SUBCLASS_MASK) >> \
+ NODE_SUBCLASS_SHIFT)
+#define NODETYPE(ID) (((ID) & NODE_TYPE_MASK) >> NODE_TYPE_SHIFT)
+#define NODEINDEX(ID) (((ID) & NODE_INDEX_MASK) >> NODE_INDEX_SHIFT)
+
+/*********************************************************************
+ * Enum definitions
+ ********************************************************************/
+
+/* Node class types */
+enum pm_node_class {
+ XPM_NODECLASS_MIN,
+
+ XPM_NODECLASS_POWER,
+ XPM_NODECLASS_CLOCK,
+ XPM_NODECLASS_RESET,
+ XPM_NODECLASS_MEMIC,
+ XPM_NODECLASS_STMIC,
+ XPM_NODECLASS_DEVICE,
+
+ XPM_NODECLASS_MAX
+};
+
+enum pm_device_node_subclass {
+ /* Device types */
+ XPM_NODESUBCL_DEV_CORE = 1,
+ XPM_NODESUBCL_DEV_PERIPH,
+ XPM_NODESUBCL_DEV_MEM,
+ XPM_NODESUBCL_DEV_SOC,
+ XPM_NODESUBCL_DEV_MEM_CTRLR,
+ XPM_NODESUBCL_DEV_PHY,
+};
+
+enum pm_device_node_type {
+ /* Device types */
+ XPM_NODETYPE_DEV_CORE_PMC = 1,
+ XPM_NODETYPE_DEV_CORE_PSM,
+ XPM_NODETYPE_DEV_CORE_APU,
+ XPM_NODETYPE_DEV_CORE_RPU,
+ XPM_NODETYPE_DEV_OCM,
+ XPM_NODETYPE_DEV_TCM,
+ XPM_NODETYPE_DEV_L2CACHE,
+ XPM_NODETYPE_DEV_DDR,
+ XPM_NODETYPE_DEV_PERIPH,
+ XPM_NODETYPE_DEV_SOC,
+ XPM_NODETYPE_DEV_GT,
+};
+
+/* Device node Indexes */
+enum pm_device_node_idx {
+ /* Device nodes */
+ XPM_NODEIDX_DEV_MIN,
+
+ /* Processor devices */
+ XPM_NODEIDX_DEV_PMC_PROC,
+ XPM_NODEIDX_DEV_PSM_PROC,
+ XPM_NODEIDX_DEV_ACPU_0,
+ XPM_NODEIDX_DEV_ACPU_1,
+ XPM_NODEIDX_DEV_RPU0_0,
+ XPM_NODEIDX_DEV_RPU0_1,
+
+ /* Memory devices */
+ XPM_NODEIDX_DEV_OCM_0,
+ XPM_NODEIDX_DEV_OCM_1,
+ XPM_NODEIDX_DEV_OCM_2,
+ XPM_NODEIDX_DEV_OCM_3,
+ XPM_NODEIDX_DEV_TCM_0_A,
+ XPM_NODEIDX_DEV_TCM_0_B,
+ XPM_NODEIDX_DEV_TCM_1_A,
+ XPM_NODEIDX_DEV_TCM_1_B,
+ XPM_NODEIDX_DEV_L2_BANK_0,
+ XPM_NODEIDX_DEV_DDR_0,
+ XPM_NODEIDX_DEV_DDR_1,
+ XPM_NODEIDX_DEV_DDR_2,
+ XPM_NODEIDX_DEV_DDR_3,
+ XPM_NODEIDX_DEV_DDR_4,
+ XPM_NODEIDX_DEV_DDR_5,
+ XPM_NODEIDX_DEV_DDR_6,
+ XPM_NODEIDX_DEV_DDR_7,
+
+ /* LPD Peripheral devices */
+ XPM_NODEIDX_DEV_USB_0,
+ XPM_NODEIDX_DEV_GEM_0,
+ XPM_NODEIDX_DEV_GEM_1,
+ XPM_NODEIDX_DEV_SPI_0,
+ XPM_NODEIDX_DEV_SPI_1,
+ XPM_NODEIDX_DEV_I2C_0,
+ XPM_NODEIDX_DEV_I2C_1,
+ XPM_NODEIDX_DEV_CAN_FD_0,
+ XPM_NODEIDX_DEV_CAN_FD_1,
+ XPM_NODEIDX_DEV_UART_0,
+ XPM_NODEIDX_DEV_UART_1,
+ XPM_NODEIDX_DEV_GPIO,
+ XPM_NODEIDX_DEV_TTC_0,
+ XPM_NODEIDX_DEV_TTC_1,
+ XPM_NODEIDX_DEV_TTC_2,
+ XPM_NODEIDX_DEV_TTC_3,
+ XPM_NODEIDX_DEV_SWDT_LPD,
+
+ /* FPD Peripheral devices */
+ XPM_NODEIDX_DEV_SWDT_FPD,
+
+ /* PMC Peripheral devices */
+ XPM_NODEIDX_DEV_OSPI,
+ XPM_NODEIDX_DEV_QSPI,
+ XPM_NODEIDX_DEV_GPIO_PMC,
+ XPM_NODEIDX_DEV_I2C_PMC,
+ XPM_NODEIDX_DEV_SDIO_0,
+ XPM_NODEIDX_DEV_SDIO_1,
+
+ XPM_NODEIDX_DEV_PL_0,
+ XPM_NODEIDX_DEV_PL_1,
+ XPM_NODEIDX_DEV_PL_2,
+ XPM_NODEIDX_DEV_PL_3,
+ XPM_NODEIDX_DEV_RTC,
+ XPM_NODEIDX_DEV_ADMA_0,
+ XPM_NODEIDX_DEV_ADMA_1,
+ XPM_NODEIDX_DEV_ADMA_2,
+ XPM_NODEIDX_DEV_ADMA_3,
+ XPM_NODEIDX_DEV_ADMA_4,
+ XPM_NODEIDX_DEV_ADMA_5,
+ XPM_NODEIDX_DEV_ADMA_6,
+ XPM_NODEIDX_DEV_ADMA_7,
+ XPM_NODEIDX_DEV_IPI_0,
+ XPM_NODEIDX_DEV_IPI_1,
+ XPM_NODEIDX_DEV_IPI_2,
+ XPM_NODEIDX_DEV_IPI_3,
+ XPM_NODEIDX_DEV_IPI_4,
+ XPM_NODEIDX_DEV_IPI_5,
+ XPM_NODEIDX_DEV_IPI_6,
+
+ /* Entire SoC */
+ XPM_NODEIDX_DEV_SOC,
+
+ /* DDR memory controllers */
+ XPM_NODEIDX_DEV_DDRMC_0,
+ XPM_NODEIDX_DEV_DDRMC_1,
+ XPM_NODEIDX_DEV_DDRMC_2,
+ XPM_NODEIDX_DEV_DDRMC_3,
+
+ /* GT devices */
+ XPM_NODEIDX_DEV_GT_0,
+ XPM_NODEIDX_DEV_GT_1,
+ XPM_NODEIDX_DEV_GT_2,
+ XPM_NODEIDX_DEV_GT_3,
+ XPM_NODEIDX_DEV_GT_4,
+ XPM_NODEIDX_DEV_GT_5,
+ XPM_NODEIDX_DEV_GT_6,
+ XPM_NODEIDX_DEV_GT_7,
+ XPM_NODEIDX_DEV_GT_8,
+ XPM_NODEIDX_DEV_GT_9,
+ XPM_NODEIDX_DEV_GT_10,
+
+ XPM_NODEIDX_DEV_MAX
+};
+
+#endif /* PM_NODE_H */
diff --git a/plat/xilinx/versal/pm_service/pm_svc_main.c b/plat/xilinx/versal/pm_service/pm_svc_main.c
new file mode 100644
index 0000000..9eb426a
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_svc_main.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (c) 2022, 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 <plat_private.h>
+#include <stdbool.h>
+#include <common/runtime_svc.h>
+#include <plat/common/platform.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_ipi.h"
+#include <drivers/arm/gicv3.h>
+#include "../drivers/arm/gic/v3/gicv3_private.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};
+
+ VERBOSE("Received IPI FIQ from firmware\n");
+
+ (void)plat_ic_acknowledge_interrupt();
+
+ pm_get_callbackdata(payload, ARRAY_SIZE(payload), 0, 0);
+ switch (payload[0]) {
+ case PM_INIT_SUSPEND_CB:
+ case PM_NOTIFY_CB:
+ if (sgi != INVALID_SGI) {
+ notify_os();
+ }
+ 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 - 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
+ *
+ * @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 PM_IOCTL:
+ {
+ uint32_t value;
+
+ 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 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 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
+ *
+ * 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
+ */
+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 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 PM_FORCE_POWERDOWN:
+ ret = pm_force_powerdown(pm_arg[0], pm_arg[1], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ case 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 PM_ABORT_SUSPEND:
+ ret = pm_abort_suspend(pm_arg[0], security_flag);
+ SMC_RET1(handle, (u_register_t)ret);
+
+ case 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
+ *
+ * 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.
+ */
+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};
+
+ pm_get_callbackdata(result, ARRAY_SIZE(result), security_flag, 1U);
+ 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
+ *
+ * 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.
+ */
+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 == 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 - x4 - SMC64 Arguments from kernel
+ * x3 (upper 32-bits) and x4 are Unused
+ * @cookie - Unused
+ * @handler - Pointer to caller's context structure
+ *
+ * @return - Unused
+ *
+ * Determines that smc_fid is valid and supported PM SMC Function ID from the
+ * list of pm_api_ids, otherwise completes the request with
+ * the unknown SMC Function ID
+ *
+ * The SMC calls for PM service are forwarded from SIP Service SMC handler
+ * function with rt_svc_handle signature
+ */
+uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+ uint64_t x4, const void *cookie, void *handle, uint64_t flags)
+{
+ uintptr_t ret;
+ uint32_t pm_arg[PAYLOAD_ARG_CNT] = {0};
+ uint32_t security_flag = SECURE_FLAG;
+ uint32_t api_id;
+
+ /* 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 non-secure (1)
+ * if smc called is non secure
+ */
+ if (is_caller_non_secure(flags) != 0) {
+ security_flag = NON_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/versal/pm_service/pm_svc_main.h b/plat/xilinx/versal/pm_service/pm_svc_main.h
new file mode 100644
index 0000000..b6e764f
--- /dev/null
+++ b/plat/xilinx/versal/pm_service/pm_svc_main.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (c) 2019-2022, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PM_SVC_MAIN_H
+#define PM_SVC_MAIN_H
+
+#include <pm_common.h>
+
+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/versal/sip_svc_setup.c b/plat/xilinx/versal/sip_svc_setup.c
new file mode 100644
index 0000000..6f2ff94
--- /dev/null
+++ b/plat/xilinx/versal/sip_svc_setup.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Top level SMC handler for SiP calls. Dispatch PM calls to PM SMC handler. */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <tools_share/uuid.h>
+
+#include "ipi_mailbox_svc.h"
+#include "pm_svc_main.h"
+
+/* SMC function IDs for SiP Service queries */
+#define VERSAL_SIP_SVC_CALL_COUNT U(0x8200ff00)
+#define VERSAL_SIP_SVC_UID U(0x8200ff01)
+#define VERSAL_SIP_SVC_VERSION U(0x8200ff03)
+
+/* SiP Service Calls version numbers */
+#define SIP_SVC_VERSION_MAJOR U(0)
+#define SIP_SVC_VERSION_MINOR U(1)
+
+/* These macros are used to identify PM calls from the SMC function ID */
+#define PM_FID_MASK 0xf000u
+#define PM_FID_VALUE 0u
+#define IPI_FID_VALUE 0x1000u
+#define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE)
+#define is_ipi_fid(_fid) (((_fid) & PM_FID_MASK) == IPI_FID_VALUE)
+
+/* SiP Service UUID */
+DEFINE_SVC_UUID2(versal_sip_uuid,
+ 0x2ab9e4ecU, 0x93b9U, 0x11e7U, 0xa0U, 0x19U,
+ 0xdfU, 0xe0U, 0xdbU, 0xadU, 0x0aU, 0xe0U);
+
+/**
+ * sip_svc_setup() - Setup SiP Service
+ *
+ * Invokes PM setup
+ */
+static int32_t sip_svc_setup(void)
+{
+ /* PM implementation as SiP Service */
+ (void)pm_setup();
+
+ return 0;
+}
+
+/**
+ * sip_svc_smc_handler() - Top-level SiP Service SMC handler
+ *
+ * Handler for all SiP SMC calls. Handles standard SIP requests
+ * and calls PM SMC handler if the call is for a PM-API function.
+ */
+uintptr_t sip_svc_smc_handler(uint32_t smc_fid,
+ u_register_t x1,
+ u_register_t x2,
+ u_register_t x3,
+ u_register_t x4,
+ void *cookie,
+ void *handle,
+ u_register_t flags)
+{
+ /* Let PM SMC handler deal with PM-related requests */
+ if (is_pm_fid(smc_fid)) {
+ return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+ flags);
+ }
+
+ /* Let IPI SMC handler deal with IPI-related requests */
+ if (is_ipi_fid(smc_fid)) {
+ return ipi_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+ flags);
+ }
+
+ /* Let PM SMC handler deal with PM-related requests */
+ switch (smc_fid) {
+ case VERSAL_SIP_SVC_CALL_COUNT:
+ /* PM functions + default functions */
+ SMC_RET1(handle, 2);
+
+ case VERSAL_SIP_SVC_UID:
+ SMC_UUID_RET(handle, versal_sip_uuid);
+
+ case VERSAL_SIP_SVC_VERSION:
+ SMC_RET2(handle, SIP_SVC_VERSION_MAJOR, SIP_SVC_VERSION_MINOR);
+
+ default:
+ WARN("Unimplemented SiP Service Call: 0x%x\n", smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
+
+/* Register PM Service Calls as runtime service */
+DECLARE_RT_SVC(
+ sip_svc,
+ OEN_SIP_START,
+ OEN_SIP_END,
+ SMC_TYPE_FAST,
+ sip_svc_setup,
+ sip_svc_smc_handler);
diff --git a/plat/xilinx/versal/versal_gicv3.c b/plat/xilinx/versal/versal_gicv3.c
new file mode 100644
index 0000000..d410906
--- /dev/null
+++ b/plat/xilinx/versal/versal_gicv3.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_private.h>
+#include <platform_def.h>
+
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+/******************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way the GICv3 driver is initialised and used.
+ *****************************************************************************/
+#pragma weak plat_versal_gic_driver_init
+#pragma weak plat_versal_gic_init
+#pragma weak plat_versal_gic_cpuif_enable
+#pragma weak plat_versal_gic_cpuif_disable
+#pragma weak plat_versal_gic_pcpu_init
+#pragma weak plat_versal_gic_redistif_on
+#pragma weak plat_versal_gic_redistif_off
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const interrupt_prop_t versal_interrupt_props[] = {
+ PLAT_VERSAL_G1S_IRQ_PROPS(INTR_GROUP1S),
+ PLAT_VERSAL_G0_IRQ_PROPS(INTR_GROUP0)
+};
+
+/*
+ * We save and restore the GICv3 context on system suspend. Allocate the
+ * data in the designated EL3 Secure carve-out memory.
+ */
+static gicv3_redist_ctx_t rdist_ctx __section("versal_el3_tzc_dram");
+static gicv3_dist_ctx_t dist_ctx __section("versal_el3_tzc_dram");
+
+/*
+ * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register
+ * to core position.
+ *
+ * Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity
+ * values read from GICR_TYPER don't have an MT field. To reuse the same
+ * translation used for CPUs, we insert MT bit read from the PE's MPIDR into
+ * that read from GICR_TYPER.
+ *
+ * Assumptions:
+ *
+ * - All CPUs implemented in the system have MPIDR_EL1.MT bit set;
+ * - No CPUs implemented in the system use affinity level 3.
+ */
+static uint32_t versal_gicv3_mpidr_hash(u_register_t mpidr)
+{
+ mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
+ return versal_calc_core_pos(mpidr);
+}
+
+static const gicv3_driver_data_t versal_gic_data __unused = {
+ .gicd_base = PLAT_VERSAL_GICD_BASE,
+ .gicr_base = PLAT_VERSAL_GICR_BASE,
+ .interrupt_props = versal_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(versal_interrupt_props),
+ .rdistif_num = PLATFORM_CORE_COUNT,
+ .rdistif_base_addrs = rdistif_base_addrs,
+ .mpidr_to_core_pos = versal_gicv3_mpidr_hash
+};
+
+void __init plat_versal_gic_driver_init(void)
+{
+ /*
+ * The GICv3 driver is initialized in EL3 and does not need
+ * to be initialized again in SEL1. This is because the S-EL1
+ * can use GIC system registers to manage interrupts and does
+ * not need GIC interface base addresses to be configured.
+ */
+#if IMAGE_BL31
+ gicv3_driver_init(&versal_gic_data);
+#endif
+}
+
+/******************************************************************************
+ * Versal common helper to initialize the GIC. Only invoked by BL31
+ *****************************************************************************/
+void __init plat_versal_gic_init(void)
+{
+ gicv3_distif_init();
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal common helper to enable the GIC CPU interface
+ *****************************************************************************/
+void plat_versal_gic_cpuif_enable(void)
+{
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal common helper to disable the GIC CPU interface
+ *****************************************************************************/
+void plat_versal_gic_cpuif_disable(void)
+{
+ gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal common helper to initialize the per-cpu redistributor interface in
+ * GICv3
+ *****************************************************************************/
+void plat_versal_gic_pcpu_init(void)
+{
+ gicv3_rdistif_init(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal common helpers to power GIC redistributor interface
+ *****************************************************************************/
+void plat_versal_gic_redistif_on(void)
+{
+ gicv3_rdistif_on(plat_my_core_pos());
+}
+
+void plat_versal_gic_redistif_off(void)
+{
+ gicv3_rdistif_off(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal common helper to save & restore the GICv3 on resume from system
+ * suspend
+ *****************************************************************************/
+void plat_versal_gic_save(void)
+{
+ /*
+ * If an ITS is available, save its context before
+ * the Redistributor using:
+ * gicv3_its_save_disable(gits_base, &its_ctx[i])
+ * Additionnaly, an implementation-defined sequence may
+ * be required to save the whole ITS state.
+ */
+
+ /*
+ * Save the GIC Redistributors and ITS contexts before the
+ * Distributor context. As we only handle SYSTEM SUSPEND API,
+ * we only need to save the context of the CPU that is issuing
+ * the SYSTEM SUSPEND call, i.e. the current CPU.
+ */
+ gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx);
+
+ /* Save the GIC Distributor context */
+ gicv3_distif_save(&dist_ctx);
+
+ /*
+ * From here, all the components of the GIC can be safely powered down
+ * as long as there is an alternate way to handle wakeup interrupt
+ * sources.
+ */
+}
+
+void plat_versal_gic_resume(void)
+{
+ /* Restore the GIC Distributor context */
+ gicv3_distif_init_restore(&dist_ctx);
+
+ /*
+ * Restore the GIC Redistributor and ITS contexts after the
+ * Distributor context. As we only handle SYSTEM SUSPEND API,
+ * we only need to restore the context of the CPU that issued
+ * the SYSTEM SUSPEND call.
+ */
+ gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx);
+
+ /*
+ * If an ITS is available, restore its context after
+ * the Redistributor using:
+ * gicv3_its_restore(gits_base, &its_ctx[i])
+ * An implementation-defined sequence may be required to
+ * restore the whole ITS state. The ITS must also be
+ * re-enabled after this sequence has been executed.
+ */
+}
diff --git a/plat/xilinx/versal/versal_ipi.c b/plat/xilinx/versal/versal_ipi.c
new file mode 100644
index 0000000..f99af82
--- /dev/null
+++ b/plat/xilinx/versal/versal_ipi.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2019-2021, Xilinx, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Versal IPI agent registers access management
+ */
+
+#include <errno.h>
+#include <ipi.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+#include <string.h>
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+
+/* versal ipi configuration table */
+const static struct ipi_config versal_ipi_table[] = {
+ /* A72 IPI */
+ [IPI_ID_APU] = {
+ .ipi_bit_mask = IPI0_TRIG_BIT,
+ .ipi_reg_base = IPI0_REG_BASE,
+ .secure_only = 0U,
+ },
+
+ /* PMC IPI */
+ [IPI_ID_PMC] = {
+ .ipi_bit_mask = PMC_IPI_TRIG_BIT,
+ .ipi_reg_base = IPI0_REG_BASE,
+ .secure_only = 0U,
+ },
+
+ /* RPU0 IPI */
+ [IPI_ID_RPU0] = {
+ .ipi_bit_mask = IPI1_TRIG_BIT,
+ .ipi_reg_base = IPI1_REG_BASE,
+ .secure_only = 0U,
+ },
+
+ /* RPU1 IPI */
+ [IPI_ID_RPU1] = {
+ .ipi_bit_mask = IPI2_TRIG_BIT,
+ .ipi_reg_base = IPI2_REG_BASE,
+ .secure_only = 0U,
+ },
+
+ /* IPI3 IPI */
+ [IPI_ID_3] = {
+ .ipi_bit_mask = IPI3_TRIG_BIT,
+ .ipi_reg_base = IPI3_REG_BASE,
+ .secure_only = 0U,
+ },
+
+ /* IPI4 IPI */
+ [IPI_ID_4] = {
+ .ipi_bit_mask = IPI4_TRIG_BIT,
+ .ipi_reg_base = IPI4_REG_BASE,
+ .secure_only = 0U,
+ },
+
+ /* IPI5 IPI */
+ [IPI_ID_5] = {
+ .ipi_bit_mask = IPI5_TRIG_BIT,
+ .ipi_reg_base = IPI5_REG_BASE,
+ .secure_only = 0U,
+ },
+};
+
+/* versal_ipi_config_table_init() - Initialize versal IPI configuration data
+ *
+ * @ipi_config_table - IPI configuration table
+ * @ipi_total - Total number of IPI available
+ *
+ */
+void versal_ipi_config_table_init(void)
+{
+ ipi_config_table_init(versal_ipi_table, ARRAY_SIZE(versal_ipi_table));
+}
diff --git a/plat/xilinx/versal_net/aarch64/versal_net_common.c b/plat/xilinx/versal_net/aarch64/versal_net_common.c
new file mode 100644
index 0000000..c78b5d0
--- /dev/null
+++ b/plat/xilinx/versal_net/aarch64/versal_net_common.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2021-2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <plat/common/platform.h>
+#include <plat_ipi.h>
+
+#include <plat_private.h>
+#include <versal_net_def.h>
+
+uint32_t platform_id, platform_version;
+
+/*
+ * Table of regions to map using the MMU.
+ * This doesn't include TZRAM as the 'mem_layout' argument passed to
+ * configure_mmu_elx() will give the available subset of that,
+ */
+const mmap_region_t plat_versal_net_mmap[] = {
+ MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(DEVICE2_BASE, DEVICE2_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(CRF_BASE, CRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(IPI_BASE, IPI_SIZE, MT_DEVICE | MT_RW | MT_SECURE),
+ { 0 }
+};
+
+const mmap_region_t *plat_versal_net_get_mmap(void)
+{
+ return plat_versal_net_mmap;
+}
+
+/* For saving cpu clock for certain platform */
+uint32_t cpu_clock;
+
+char *board_name_decode(void)
+{
+ switch (platform_id) {
+ case VERSAL_NET_SPP:
+ return "IPP";
+ case VERSAL_NET_EMU:
+ return "EMU";
+ case VERSAL_NET_SILICON:
+ return "Silicon";
+ case VERSAL_NET_QEMU:
+ return "QEMU";
+ default:
+ return "Unknown";
+ }
+}
+
+void board_detection(void)
+{
+ uint32_t version;
+
+ version = mmio_read_32(PMC_TAP_VERSION);
+ platform_id = FIELD_GET(PLATFORM_MASK, version);
+ platform_version = FIELD_GET(PLATFORM_VERSION_MASK, version);
+
+ if (platform_id == VERSAL_NET_QEMU_COSIM) {
+ platform_id = VERSAL_NET_QEMU;
+ }
+
+ if ((platform_id == VERSAL_NET_SPP) ||
+ (platform_id == VERSAL_NET_EMU) ||
+ (platform_id == VERSAL_NET_QEMU)) {
+ /*
+ * 9 is diff for
+ * 0 means 0.9 version
+ * 1 means 1.0 version
+ * 2 means 1.1 version
+ * etc,
+ */
+ platform_version += 9U;
+ }
+
+ /* Make sure that console is setup to see this message */
+ VERBOSE("Platform id: %d version: %d.%d\n", platform_id,
+ platform_version / 10U, platform_version % 10U);
+}
+
+void versal_net_config_setup(void)
+{
+ uint32_t val;
+ uintptr_t crl_base, iou_scntrs_base, psx_base;
+
+ crl_base = VERSAL_NET_CRL;
+ iou_scntrs_base = VERSAL_NET_IOU_SCNTRS;
+ psx_base = PSX_CRF;
+
+ /* Reset for system timestamp generator in FPX */
+ mmio_write_32(psx_base + PSX_CRF_RST_TIMESTAMP_OFFSET, 0);
+
+ /* Global timer init - Program time stamp reference clk */
+ val = mmio_read_32(crl_base + VERSAL_NET_CRL_TIMESTAMP_REF_CTRL_OFFSET);
+ val |= VERSAL_NET_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT;
+ mmio_write_32(crl_base + VERSAL_NET_CRL_TIMESTAMP_REF_CTRL_OFFSET, val);
+
+ /* Clear reset of timestamp reg */
+ mmio_write_32(crl_base + VERSAL_NET_CRL_RST_TIMESTAMP_OFFSET, 0);
+
+ /* Program freq register in System counter and enable system counter. */
+ mmio_write_32(iou_scntrs_base + VERSAL_NET_IOU_SCNTRS_BASE_FREQ_OFFSET,
+ cpu_clock);
+ mmio_write_32(iou_scntrs_base + VERSAL_NET_IOU_SCNTRS_COUNTER_CONTROL_REG_OFFSET,
+ VERSAL_NET_IOU_SCNTRS_CONTROL_EN);
+
+ generic_delay_timer_init();
+
+#if (TFA_NO_PM == 0)
+ /* Configure IPI data for versal_net */
+ versal_net_ipi_config_table_init();
+#endif
+}
+
+uint32_t plat_get_syscnt_freq2(void)
+{
+ return cpu_clock;
+}
diff --git a/plat/xilinx/versal_net/aarch64/versal_net_helpers.S b/plat/xilinx/versal_net/aarch64/versal_net_helpers.S
new file mode 100644
index 0000000..48082a6
--- /dev/null
+++ b/plat/xilinx/versal_net/aarch64/versal_net_helpers.S
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <arch.h>
+#include <asm_macros.S>
+#include <drivers/arm/gicv3.h>
+#include <platform_def.h>
+
+ .globl plat_secondary_cold_boot_setup
+ .globl plat_is_my_cpu_primary
+ .globl platform_mem_init
+ .globl plat_my_core_pos
+ .globl plat_crash_console_init
+ .globl plat_crash_console_putc
+ .globl plat_crash_console_flush
+
+ /* -----------------------------------------------------
+ * void plat_secondary_cold_boot_setup (void);
+ *
+ * This function performs any platform specific actions
+ * needed for a secondary cpu after a cold reset e.g
+ * mark the cpu's presence, mechanism to place it in a
+ * holding pen etc.
+ * TODO: Should we read the PSYS register to make sure
+ * that the request has gone through.
+ * -----------------------------------------------------
+ */
+func plat_secondary_cold_boot_setup
+ mrs x0, mpidr_el1
+
+ /*
+ * There is no sane reason to come out of this wfi. This
+ * cpu will be powered on and reset by the cpu_on pm api
+ */
+ dsb sy
+ bl plat_panic_handler
+endfunc plat_secondary_cold_boot_setup
+
+func plat_is_my_cpu_primary
+ mov x9, x30
+ bl plat_my_core_pos
+ cmp x0, #VERSAL_NET_PRIMARY_CPU
+ cset x0, eq
+ ret x9
+endfunc plat_is_my_cpu_primary
+
+ /* -----------------------------------------------------
+ * unsigned int plat_my_core_pos(void)
+ * This function uses the plat_core_pos_by_mpidr()
+ * definition to get the index of the calling CPU.
+ * -----------------------------------------------------
+ */
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b plat_core_pos_by_mpidr
+endfunc plat_my_core_pos
+
+ /* ---------------------------------------------------------------------
+ * We don't need to carry out any memory initialization on Versal NET
+ * platform. The Secure RAM is accessible straight away.
+ * ---------------------------------------------------------------------
+ */
+func platform_mem_init
+ ret
+endfunc platform_mem_init
+
+
+ /* ---------------------------------------------
+ * int plat_crash_console_init(void)
+ * Function to initialize the crash console
+ * without a C Runtime to print crash report.
+ * Clobber list : x0, x1, x2
+ * ---------------------------------------------
+ */
+func plat_crash_console_init
+/* mov_imm x0, PLAT_VERSAL_NET_CRASH_UART_BASE
+ mov_imm x1, PLAT_VERSAL_NET_CRASH_UART_CLK_IN_HZ
+ mov_imm x2, VERSAL_NET_CONSOLE_BAUDRATE
+ b console_pl011_core_init */
+endfunc plat_crash_console_init
+
+ /* ---------------------------------------------
+ * int plat_crash_console_putc(int c)
+ * Function to print a character on the crash
+ * console without a C Runtime.
+ * Clobber list : x1, x2
+ * ---------------------------------------------
+ */
+func plat_crash_console_putc
+ mov_imm x1, PLAT_VERSAL_NET_CRASH_UART_BASE
+ b console_pl011_core_putc
+endfunc plat_crash_console_putc
+
+ /* ---------------------------------------------
+ * void plat_crash_console_flush()
+ * Function to force a write of all buffered
+ * data that hasn't been output.
+ * Out : void.
+ * Clobber list : x0, x1
+ * ---------------------------------------------
+ */
+func plat_crash_console_flush
+ mov_imm x0, PLAT_VERSAL_NET_CRASH_UART_BASE
+ b console_pl011_core_flush
+endfunc plat_crash_console_flush
diff --git a/plat/xilinx/versal_net/bl31_versal_net_setup.c b/plat/xilinx/versal_net/bl31_versal_net_setup.c
new file mode 100644
index 0000000..c9942d6
--- /dev/null
+++ b/plat/xilinx/versal_net/bl31_versal_net_setup.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <common/fdt_fixup.h>
+#include <common/fdt_wrappers.h>
+#include <drivers/arm/pl011.h>
+#include <drivers/console.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+#include <libfdt.h>
+#include <plat/common/platform.h>
+#include <plat_arm.h>
+
+#include <plat_private.h>
+#include <plat_startup.h>
+#include <versal_net_def.h>
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+static console_t versal_net_runtime_console;
+
+/*
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ */
+entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+ assert(sec_state_is_valid(type));
+
+ if (type == NON_SECURE) {
+ return &bl33_image_ep_info;
+ }
+
+ return &bl32_image_ep_info;
+}
+
+/*
+ * Set the build time defaults,if we can't find any config data.
+ */
+static inline void bl31_set_default_config(void)
+{
+ bl32_image_ep_info.pc = BL32_BASE;
+ bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry();
+ bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+ bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS);
+}
+
+/*
+ * Perform any BL31 specific platform actions. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they
+ * are lost (potentially). This needs to be done before the MMU is initialized
+ * so that the memory layout can be used while creating page tables.
+ */
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ uint32_t uart_clock;
+ int32_t rc;
+
+ board_detection();
+
+ switch (platform_id) {
+ case VERSAL_NET_SPP:
+ cpu_clock = 1000000;
+ uart_clock = 1000000;
+ break;
+ case VERSAL_NET_EMU:
+ cpu_clock = 3660000;
+ uart_clock = 25000000;
+ break;
+ case VERSAL_NET_QEMU:
+ /* Random values now */
+ cpu_clock = 100000000;
+ uart_clock = 25000000;
+ break;
+ case VERSAL_NET_SILICON:
+ cpu_clock = 100000000;
+ uart_clock = 100000000;
+ break;
+ default:
+ panic();
+ }
+
+ /* Initialize the console to provide early debug support */
+ rc = console_pl011_register(VERSAL_NET_UART_BASE, uart_clock,
+ VERSAL_NET_UART_BAUDRATE,
+ &versal_net_runtime_console);
+ if (rc == 0) {
+ panic();
+ }
+
+ console_set_scope(&versal_net_runtime_console, CONSOLE_FLAG_BOOT |
+ CONSOLE_FLAG_RUNTIME);
+
+ NOTICE("TF-A running on Xilinx %s %d.%d\n", board_name_decode(),
+ platform_version / 10U, platform_version % 10U);
+
+ /* Initialize the platform config for future decision making */
+ versal_net_config_setup();
+ /* There are no parameters from BL2 if BL31 is a reset vector */
+ assert(arg0 == 0U);
+ assert(arg1 == 0U);
+
+ /*
+ * Do initial security configuration to allow DRAM/device access. On
+ * Base VERSAL_NET only DRAM security is programmable (via TrustZone), but
+ * other platforms might have more programmable security devices
+ * present.
+ */
+
+ /* Populate common information for BL32 and BL33 */
+ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
+ SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+ SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0);
+ SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+ bl31_set_default_config();
+
+ NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc);
+ NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc);
+}
+
+static versal_intr_info_type_el3_t type_el3_interrupt_table[MAX_INTR_EL3];
+
+int request_intr_type_el3(uint32_t id, interrupt_type_handler_t handler)
+{
+ static uint32_t index;
+ uint32_t i;
+
+ /* Validate 'handler' and 'id' parameters */
+ if (handler == NULL || index >= MAX_INTR_EL3) {
+ return -EINVAL;
+ }
+
+ /* Check if a handler has already been registered */
+ for (i = 0; i < index; i++) {
+ if (id == type_el3_interrupt_table[i].id) {
+ return -EALREADY;
+ }
+ }
+
+ type_el3_interrupt_table[index].id = id;
+ type_el3_interrupt_table[index].handler = handler;
+
+ index++;
+
+ return 0;
+}
+
+static uint64_t rdo_el3_interrupt_handler(uint32_t id, uint32_t flags,
+ void *handle, void *cookie)
+{
+ uint32_t intr_id;
+ uint32_t i;
+ interrupt_type_handler_t handler = NULL;
+
+ intr_id = plat_ic_get_pending_interrupt_id();
+
+ for (i = 0; i < MAX_INTR_EL3; i++) {
+ if (intr_id == type_el3_interrupt_table[i].id) {
+ handler = type_el3_interrupt_table[i].handler;
+ }
+ }
+
+ if (handler != NULL) {
+ handler(intr_id, flags, handle, cookie);
+ }
+
+ return 0;
+}
+
+void bl31_platform_setup(void)
+{
+ /* Initialize the gic cpu and distributor interfaces */
+ plat_versal_net_gic_driver_init();
+ plat_versal_net_gic_init();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+ uint64_t flags = 0;
+ int32_t rc;
+
+ set_interrupt_rm_flag(flags, NON_SECURE);
+ rc = register_interrupt_type_handler(INTR_TYPE_EL3,
+ rdo_el3_interrupt_handler, flags);
+ if (rc != 0) {
+ panic();
+ }
+}
+
+/*
+ * Perform the very early platform specific architectural setup here.
+ */
+void bl31_plat_arch_setup(void)
+{
+ const mmap_region_t bl_regions[] = {
+ MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE,
+ MT_MEMORY | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE,
+ MT_CODE | MT_SECURE),
+ MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE,
+ MT_RO_DATA | MT_SECURE),
+ {0}
+ };
+
+ setup_page_tables(bl_regions, plat_versal_net_get_mmap());
+ enable_mmu(0);
+}
diff --git a/plat/xilinx/versal_net/include/plat_ipi.h b/plat/xilinx/versal_net/include/plat_ipi.h
new file mode 100644
index 0000000..5255f8f
--- /dev/null
+++ b/plat/xilinx/versal_net/include/plat_ipi.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Versal IPI management enums and defines */
+
+#ifndef PLAT_IPI_H
+#define PLAT_IPI_H
+
+#include <stdint.h>
+
+#include <ipi.h>
+
+/*********************************************************************
+ * IPI agent IDs macros
+ ********************************************************************/
+#define IPI_ID_PMC 1U
+#define IPI_ID_APU 2U
+#define IPI_ID_RPU0 3U
+#define IPI_ID_RPU1 4U
+#define IPI_ID_3 5U
+#define IPI_ID_4 6U
+#define IPI_ID_5 7U
+#define IPI_ID_MAX 8U
+
+/*********************************************************************
+ * IPI message buffers
+ ********************************************************************/
+#define IPI_BUFFER_BASEADDR (0xEB3F0000U)
+
+#define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U)
+#define IPI_BUFFER_PMC_BASE (IPI_BUFFER_BASEADDR + 0x200U)
+
+#define IPI_BUFFER_TARGET_APU_OFFSET 0x80U
+#define IPI_BUFFER_TARGET_PMC_OFFSET 0x40U
+
+#define IPI_BUFFER_LOCAL_BASE IPI_BUFFER_APU_BASE
+#define IPI_BUFFER_REMOTE_BASE IPI_BUFFER_PMC_BASE
+
+#define IPI_BUFFER_TARGET_LOCAL_OFFSET IPI_BUFFER_TARGET_APU_OFFSET
+#define IPI_BUFFER_TARGET_REMOTE_OFFSET IPI_BUFFER_TARGET_PMC_OFFSET
+
+#define IPI_BUFFER_MAX_WORDS 8
+
+#define IPI_BUFFER_REQ_OFFSET 0x0U
+#define IPI_BUFFER_RESP_OFFSET 0x20U
+
+/*********************************************************************
+ * Platform specific IPI API declarations
+ ********************************************************************/
+
+/* Configure IPI table for versal_net */
+void versal_net_ipi_config_table_init(void);
+
+#endif /* PLAT_IPI_H */
diff --git a/plat/xilinx/versal_net/include/plat_macros.S b/plat/xilinx/versal_net/include/plat_macros.S
new file mode 100644
index 0000000..fb108b6
--- /dev/null
+++ b/plat/xilinx/versal_net/include/plat_macros.S
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <drivers/arm/gicv3.h>
+
+#include "../include/platform_def.h"
+
+.section .rodata.gic_reg_name, "aS"
+/* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */
+gicc_regs:
+ .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+
+/* Applicable only to GICv3 with SRE enabled */
+icc_regs:
+ .asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", ""
+
+/* Registers common to both GICv2 and GICv3 */
+gicd_pend_reg:
+ .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n"
+newline:
+ .asciz "\n"
+spacer:
+ .asciz ":\t\t0x"
+
+ /* ---------------------------------------------
+ * The below utility macro prints out relevant GIC
+ * registers whenever an unhandled exception is
+ * taken in BL31 on Versal NET platform.
+ * Expects: GICD base in x16, GICC base in x17
+ * Clobbers: x0 - x10, sp
+ * ---------------------------------------------
+ */
+ .macro versal_net_print_gic_regs
+ /* Check for GICv3 system register access */
+ mrs x7, id_aa64pfr0_el1
+ ubfx x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
+ cmp x7, #1
+ b.ne print_gicv2
+
+ /* Check for SRE enable */
+ mrs x8, ICC_SRE_EL3
+ tst x8, #ICC_SRE_SRE_BIT
+ b.eq print_gicv2
+
+ /* Load the icc reg list to x6 */
+ adr x6, icc_regs
+ /* Load the icc regs to gp regs used by str_in_crash_buf_print */
+ mrs x8, ICC_HPPIR0_EL1
+ mrs x9, ICC_HPPIR1_EL1
+ mrs x10, ICC_CTLR_EL3
+ /* Store to the crash buf and print to console */
+ bl str_in_crash_buf_print
+ b print_gic_common
+
+print_gicv2:
+ /* Load the gicc reg list to x6 */
+ adr x6, gicc_regs
+ /* Load the gicc regs to gp regs used by str_in_crash_buf_print */
+ ldr w8, [x17, #GICC_HPPIR]
+ ldr w9, [x17, #GICC_AHPPIR]
+ ldr w10, [x17, #GICC_CTLR]
+ /* Store to the crash buf and print to console */
+ bl str_in_crash_buf_print
+
+print_gic_common:
+ /* Print the GICD_ISPENDR regs */
+ add x7, x16, #GICD_ISPENDR
+ adr x4, gicd_pend_reg
+ bl asm_print_str
+gicd_ispendr_loop:
+ sub x4, x7, x16
+ cmp x4, #0x280
+ b.eq exit_print_gic_regs
+ bl asm_print_hex
+
+ adr x4, spacer
+ bl asm_print_str
+
+ ldr x4, [x7], #8
+ bl asm_print_hex
+
+ adr x4, newline
+ bl asm_print_str
+ b gicd_ispendr_loop
+exit_print_gic_regs:
+ .endm
+
+ /* ---------------------------------------------
+ * The below required platform porting macro
+ * prints out relevant GIC and CCI registers
+ * whenever an unhandled exception is taken in
+ * BL31.
+ * Clobbers: x0 - x10, x16, x17, sp
+ * ---------------------------------------------
+ */
+ .macro plat_crash_print_regs
+ /*
+ * Empty for now to handle more platforms variant.
+ * Uncomment it when versions are stable
+ */
+ /*
+ mov_imm x17, PLAT_VERSAL_NET_GICD_BASE
+ mov_imm x16, PLAT_VERSAL_NET_GICR_BASE
+ versal_net_print_gic_regs
+ */
+ .endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/xilinx/versal_net/include/plat_pm_common.h b/plat/xilinx/versal_net/include/plat_pm_common.h
new file mode 100644
index 0000000..ad7b40f
--- /dev/null
+++ b/plat/xilinx/versal_net/include/plat_pm_common.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Contains platform specific definitions of commonly used macros data types
+ * for PU Power Management. This file should be common for all PU's.
+ */
+
+#ifndef PLAT_PM_COMMON_H
+#define PLAT_PM_COMMON_H
+
+#include <stdint.h>
+
+#include <common/debug.h>
+
+#include "pm_defs.h"
+
+#define NON_SECURE_FLAG 1U
+#define SECURE_FLAG 0U
+
+#endif /* PLAT_PM_COMMON_H */
diff --git a/plat/xilinx/versal_net/include/plat_private.h b/plat/xilinx/versal_net/include/plat_private.h
new file mode 100644
index 0000000..6a3bc19
--- /dev/null
+++ b/plat/xilinx/versal_net/include/plat_private.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
+
+#include <bl31/interrupt_mgmt.h>
+#include <lib/xlat_tables/xlat_tables_v2.h>
+
+typedef struct versal_intr_info_type_el3 {
+ uint32_t id;
+ interrupt_type_handler_t handler;
+} versal_intr_info_type_el3_t;
+
+void versal_net_config_setup(void);
+
+const mmap_region_t *plat_versal_net_get_mmap(void);
+
+void plat_versal_net_gic_driver_init(void);
+void plat_versal_net_gic_init(void);
+void plat_versal_net_gic_cpuif_enable(void);
+void plat_versal_net_gic_cpuif_disable(void);
+void plat_versal_net_gic_pcpu_init(void);
+void plat_versal_net_gic_save(void);
+void plat_versal_net_gic_resume(void);
+void plat_versal_net_gic_redistif_on(void);
+void plat_versal_net_gic_redistif_off(void);
+
+extern uint32_t cpu_clock, platform_id, platform_version;
+void board_detection(void);
+char *board_name_decode(void);
+uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+ uint64_t x4, void *cookie, void *handle, uint64_t flags);
+int32_t sip_svc_setup_init(void);
+/*
+ * Register handler to specific GIC entrance
+ * for INTR_TYPE_EL3 type of interrupt
+ */
+int request_intr_type_el3(uint32_t irq, interrupt_type_handler_t fiq_handler);
+
+#define PM_GET_CHIPID (24U)
+#define IOCTL_OSPI_MUX_SELECT (21U)
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/xilinx/versal_net/include/platform_def.h b/plat/xilinx/versal_net/include/platform_def.h
new file mode 100644
index 0000000..696771f
--- /dev/null
+++ b/plat/xilinx/versal_net/include/platform_def.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include "versal_net_def.h"
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE U(0x440)
+
+#define PLATFORM_CLUSTER_COUNT U(4)
+#define PLATFORM_CORE_COUNT_PER_CLUSTER U(4) /* 4 CPUs per cluster */
+
+#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * PLATFORM_CORE_COUNT_PER_CLUSTER)
+
+#define PLAT_MAX_PWR_LVL U(2)
+#define PLAT_MAX_RET_STATE U(1)
+#define PLAT_MAX_OFF_STATE U(2)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL31 at the top of the Trusted SRAM (just below the shared memory, if
+ * present). BL31_BASE is calculated using the current BL31 debug size plus a
+ * little space for growth.
+ */
+#ifndef VERSAL_NET_ATF_MEM_BASE
+# define BL31_BASE U(0xBBF00000)
+# define BL31_LIMIT U(0xBBFFFFFF)
+#else
+# define BL31_BASE U(VERSAL_NET_ATF_MEM_BASE)
+# define BL31_LIMIT U(VERSAL_NET_ATF_MEM_BASE + VERSAL_NET_ATF_MEM_SIZE - 1)
+# ifdef VERSAL_NET_ATF_MEM_PROGBITS_SIZE
+# define BL31_PROGBITS_LIMIT U(VERSAL_NET_ATF_MEM_BASE + \
+ VERSAL_NET_ATF_MEM_PROGBITS_SIZE - 1)
+# endif
+#endif
+
+/*******************************************************************************
+ * BL32 specific defines.
+ ******************************************************************************/
+#ifndef VERSAL_NET_BL32_MEM_BASE
+# define BL32_BASE U(0x60000000)
+# define BL32_LIMIT U(0x7FFFFFFF)
+#else
+# define BL32_BASE U(VERSAL_NET_BL32_MEM_BASE)
+# define BL32_LIMIT U(VERSAL_NET_BL32_MEM_BASE + VERSAL_NET_BL32_MEM_SIZE - 1)
+#endif
+
+/*******************************************************************************
+ * BL33 specific defines.
+ ******************************************************************************/
+#ifndef PRELOADED_BL33_BASE
+# define PLAT_ARM_NS_IMAGE_BASE U(0x8000000)
+#else
+# define PLAT_ARM_NS_IMAGE_BASE U(PRELOADED_BL33_BASE)
+#endif
+
+/*******************************************************************************
+ * TSP specific defines.
+ ******************************************************************************/
+#define TSP_SEC_MEM_BASE BL32_BASE
+#define TSP_SEC_MEM_SIZE (BL32_LIMIT - BL32_BASE + 1U)
+
+/* ID of the secure physical generic timer interrupt used by the TSP */
+#define TSP_IRQ_SEC_PHY_TIMER ARM_IRQ_SEC_PHY_TIMER
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define PLAT_DDR_LOWMEM_MAX U(0x80000000)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32U)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32U)
+#if (BL31_LIMIT < PLAT_DDR_LOWMEM_MAX)
+#define MAX_MMAP_REGIONS U(10)
+#else
+#define MAX_MMAP_REGIONS U(9)
+#endif
+
+#define MAX_XLAT_TABLES U(8)
+
+#define CACHE_WRITEBACK_SHIFT U(6)
+#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+
+#define PLAT_VERSAL_NET_GICD_BASE U(0xE2000000)
+#define PLAT_VERSAL_NET_GICR_BASE U(0xE2060000)
+
+/*
+ * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#define PLAT_VERSAL_IPI_IRQ 62
+
+#define PLAT_VERSAL_NET_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(VERSAL_NET_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL)
+
+#define PLAT_VERSAL_NET_G0_IRQ_PROPS(grp)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/xilinx/versal_net/include/versal_net_def.h b/plat/xilinx/versal_net/include/versal_net_def.h
new file mode 100644
index 0000000..8cb5bf3
--- /dev/null
+++ b/plat/xilinx/versal_net/include/versal_net_def.h
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2022, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef VERSAL_NET_DEF_H
+#define VERSAL_NET_DEF_H
+
+#include <plat/arm/common/smccc_def.h>
+#include <plat/common/common_def.h>
+
+#define MAX_INTR_EL3 2
+/* This part is taken from U-Boot project under GPL that's why dual license above */
+#define __bf_shf(x) (__builtin_ffsll(x) - 1U)
+#define FIELD_GET(_mask, _reg) \
+ ({ \
+ (typeof(_mask))(((_reg) & (_mask)) >> __bf_shf(_mask)); \
+ })
+
+/* List all consoles */
+#define VERSAL_NET_CONSOLE_ID_pl011 U(1)
+#define VERSAL_NET_CONSOLE_ID_pl011_0 U(1)
+#define VERSAL_NET_CONSOLE_ID_pl011_1 U(2)
+
+#define VERSAL_NET_CONSOLE_IS(con) (VERSAL_NET_CONSOLE_ID_ ## con == VERSAL_NET_CONSOLE)
+
+/* List all platforms */
+#define VERSAL_NET_SILICON U(0)
+#define VERSAL_NET_SPP U(1)
+#define VERSAL_NET_EMU U(2)
+#define VERSAL_NET_QEMU U(3)
+#define VERSAL_NET_QEMU_COSIM U(7)
+
+/* For platform detection */
+#define PMC_TAP U(0xF11A0000)
+#define PMC_TAP_VERSION (PMC_TAP + 0x4U)
+# define PLATFORM_MASK GENMASK(27U, 24U)
+# define PLATFORM_VERSION_MASK GENMASK(31U, 28U)
+
+/* Global timer reset */
+#define PSX_CRF U(0xEC200000)
+#define ACPU0_CLK_CTRL U(0x10C)
+#define ACPU_CLK_CTRL_CLKACT BIT(25)
+
+#define RST_APU0_OFFSET U(0x300)
+#define RST_APU_COLD_RESET BIT(0)
+#define RST_APU_WARN_RESET BIT(4)
+#define RST_APU_CLUSTER_COLD_RESET BIT(8)
+#define RST_APU_CLUSTER_WARM_RESET BIT(9)
+
+#define PSX_CRF_RST_TIMESTAMP_OFFSET U(0x33C)
+
+#define APU_PCLI U(0xECB10000)
+#define APU_PCLI_CPU_STEP U(0x30)
+#define APU_PCLI_CLUSTER_CPU_STEP (4U * APU_PCLI_CPU_STEP)
+#define APU_PCLI_CLUSTER_OFFSET U(0x8000)
+#define APU_PCLI_CLUSTER_STEP U(0x1000)
+#define PCLI_PREQ_OFFSET U(0x4)
+#define PREQ_CHANGE_REQUEST BIT(0)
+#define PCLI_PSTATE_OFFSET U(0x8)
+#define PCLI_PSTATE_VAL_SET U(0x48)
+#define PCLI_PSTATE_VAL_CLEAR U(0x38)
+
+/* Firmware Image Package */
+#define VERSAL_NET_PRIMARY_CPU U(0)
+
+#define CORE_0_IEN_POWER_OFFSET (0x00000018U)
+#define APU_PCIL_CORE_X_IEN_POWER_REG(cpu_id) (APU_PCLI + (CORE_0_IEN_POWER_OFFSET + \
+ (0x30 * cpu_id)))
+#define APU_PCIL_CORE_X_IEN_POWER_MASK (0x00000001U)
+#define CORE_0_IDS_POWER_OFFSET (0x0000001CU)
+#define APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id) (APU_PCLI + (CORE_0_IDS_POWER_OFFSET + \
+ (0x30 * cpu_id)))
+#define APU_PCIL_CORE_X_IDS_POWER_MASK (0x00000001U)
+#define CORE_PWRDN_EN_BIT_MASK (0x1U)
+
+/*******************************************************************************
+ * memory map related constants
+ ******************************************************************************/
+/* IPP 1.2/SPP 0.9 mapping */
+#define DEVICE0_BASE U(0xE8000000) /* psx, crl, iou */
+#define DEVICE0_SIZE U(0x08000000)
+#define DEVICE1_BASE U(0xE2000000) /* gic */
+#define DEVICE1_SIZE U(0x00800000)
+#define DEVICE2_BASE U(0xF1000000) /* uart, pmc_tap */
+#define DEVICE2_SIZE U(0x01000000)
+#define CRF_BASE U(0xFD1A0000)
+#define CRF_SIZE U(0x00600000)
+#define IPI_BASE U(0xEB300000)
+#define IPI_SIZE U(0x00100000)
+
+/* CRL */
+#define VERSAL_NET_CRL U(0xEB5E0000)
+#define VERSAL_NET_CRL_TIMESTAMP_REF_CTRL_OFFSET U(0x14C)
+#define VERSAL_NET_CRL_RST_TIMESTAMP_OFFSET U(0x348)
+
+#define VERSAL_NET_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT (1U << 25U)
+
+/* IOU SCNTRS */
+#define VERSAL_NET_IOU_SCNTRS U(0xEC920000)
+#define VERSAL_NET_IOU_SCNTRS_COUNTER_CONTROL_REG_OFFSET U(0)
+#define VERSAL_NET_IOU_SCNTRS_BASE_FREQ_OFFSET U(0x20)
+
+#define VERSAL_NET_IOU_SCNTRS_CONTROL_EN U(1)
+
+#define APU_CLUSTER0 U(0xECC00000)
+#define APU_RVBAR_L_0 U(0x40)
+#define APU_RVBAR_H_0 U(0x44)
+#define APU_CLUSTER_STEP U(0x100000)
+
+#define SLCR_OSPI_QSPI_IOU_AXI_MUX_SEL U(0xF1060504)
+
+/*******************************************************************************
+ * IRQ constants
+ ******************************************************************************/
+#define VERSAL_NET_IRQ_SEC_PHY_TIMER U(29)
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define VERSAL_NET_UART0_BASE U(0xF1920000)
+#define VERSAL_NET_UART_BAUDRATE 115200
+
+#define VERSAL_NET_UART_BASE VERSAL_NET_UART0_BASE
+
+#define PLAT_VERSAL_NET_CRASH_UART_BASE VERSAL_NET_UART_BASE
+#define PLAT_VERSAL_NET_CRASH_UART_CLK_IN_HZ VERSAL_NET_UART_CLOCK
+#define VERSAL_NET_CONSOLE_BAUDRATE VERSAL_NET_UART_BAUDRATE
+
+/*******************************************************************************
+ * IPI registers and bitfields
+ ******************************************************************************/
+#define IPI0_REG_BASE (0xEB330000U)
+#define IPI0_TRIG_BIT (1 << 2)
+#define PMC_IPI_TRIG_BIT (1 << 1)
+#define IPI1_REG_BASE (0xEB340000U)
+#define IPI1_TRIG_BIT (1 << 3)
+#define IPI2_REG_BASE (0xEB350000U)
+#define IPI2_TRIG_BIT (1 << 4)
+#define IPI3_REG_BASE (0xEB360000U)
+#define IPI3_TRIG_BIT (1 << 5)
+#define IPI4_REG_BASE (0xEB370000U)
+#define IPI4_TRIG_BIT (1 << 6)
+#define IPI5_REG_BASE (0xEB380000U)
+#define IPI5_TRIG_BIT (1 << 7)
+
+/* Processor core device IDs */
+#define PM_DEV_CLUSTER0_ACPU_0 (0x1810C0AFU)
+#define PM_DEV_CLUSTER0_ACPU_1 (0x1810C0B0U)
+#define PM_DEV_CLUSTER0_ACPU_2 (0x1810C0B1U)
+#define PM_DEV_CLUSTER0_ACPU_3 (0x1810C0B2U)
+
+#define PM_DEV_CLUSTER1_ACPU_0 (0x1810C0B3U)
+#define PM_DEV_CLUSTER1_ACPU_1 (0x1810C0B4U)
+#define PM_DEV_CLUSTER1_ACPU_2 (0x1810C0B5U)
+#define PM_DEV_CLUSTER1_ACPU_3 (0x1810C0B6U)
+
+#define PM_DEV_CLUSTER2_ACPU_0 (0x1810C0B7U)
+#define PM_DEV_CLUSTER2_ACPU_1 (0x1810C0B8U)
+#define PM_DEV_CLUSTER2_ACPU_2 (0x1810C0B9U)
+#define PM_DEV_CLUSTER2_ACPU_3 (0x1810C0BAU)
+
+#define PM_DEV_CLUSTER3_ACPU_0 (0x1810C0BBU)
+#define PM_DEV_CLUSTER3_ACPU_1 (0x1810C0BCU)
+#define PM_DEV_CLUSTER3_ACPU_2 (0x1810C0BDU)
+#define PM_DEV_CLUSTER3_ACPU_3 (0x1810C0BEU)
+
+#endif /* VERSAL_NET_DEF_H */
diff --git a/plat/xilinx/versal_net/plat_psci.c b/plat/xilinx/versal_net/plat_psci.c
new file mode 100644
index 0000000..c5833a9
--- /dev/null
+++ b/plat/xilinx/versal_net/plat_psci.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <plat_arm.h>
+
+#include <plat_private.h>
+
+#define PM_RET_ERROR_NOFEATURE U(19)
+
+#define PM_IOCTL 34U
+
+static uintptr_t versal_net_sec_entry;
+
+static void zynqmp_cpu_standby(plat_local_state_t cpu_state)
+{
+ dsb();
+ wfi();
+}
+
+static int32_t zynqmp_nopmu_pwr_domain_on(u_register_t mpidr)
+{
+ uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
+ uint32_t cpu = cpu_id % PLATFORM_CORE_COUNT_PER_CLUSTER;
+ uint32_t cluster = cpu_id / PLATFORM_CORE_COUNT_PER_CLUSTER;
+ uintptr_t apu_cluster_base = 0, apu_pcli_base, apu_pcli_cluster = 0;
+ uintptr_t rst_apu_cluster = PSX_CRF + RST_APU0_OFFSET + (cluster * 0x4);
+
+ VERBOSE("%s: mpidr: 0x%lx, cpuid: %x, cpu: %x, cluster: %x\n",
+ __func__, mpidr, cpu_id, cpu, cluster);
+
+ if (cpu_id == -1) {
+ return PSCI_E_INTERN_FAIL;
+ }
+
+ if (platform_id == VERSAL_NET_SPP && cluster > 1) {
+ panic();
+ }
+
+ if (cluster > 3) {
+ panic();
+ }
+
+ apu_pcli_cluster = APU_PCLI + APU_PCLI_CLUSTER_OFFSET + (cluster * APU_PCLI_CLUSTER_STEP);
+ apu_cluster_base = APU_CLUSTER0 + (cluster * APU_CLUSTER_STEP);
+
+ /* Enable clock */
+ mmio_setbits_32(PSX_CRF + ACPU0_CLK_CTRL + (cluster * 0x4), ACPU_CLK_CTRL_CLKACT);
+
+ /* Enable cluster states */
+ mmio_setbits_32(apu_pcli_cluster + PCLI_PSTATE_OFFSET, PCLI_PSTATE_VAL_SET);
+ mmio_setbits_32(apu_pcli_cluster + PCLI_PREQ_OFFSET, PREQ_CHANGE_REQUEST);
+
+ /* assert core reset */
+ mmio_setbits_32(rst_apu_cluster, ((RST_APU_COLD_RESET|RST_APU_WARN_RESET) << cpu));
+
+ /* program RVBAR */
+ mmio_write_32(apu_cluster_base + APU_RVBAR_L_0 + (cpu << 3),
+ (uint32_t)versal_net_sec_entry);
+ mmio_write_32(apu_cluster_base + APU_RVBAR_H_0 + (cpu << 3),
+ versal_net_sec_entry >> 32);
+
+ /* de-assert core reset */
+ mmio_clrbits_32(rst_apu_cluster, ((RST_APU_COLD_RESET|RST_APU_WARN_RESET) << cpu));
+
+ /* clear cluster resets */
+ mmio_clrbits_32(rst_apu_cluster, RST_APU_CLUSTER_WARM_RESET);
+ mmio_clrbits_32(rst_apu_cluster, RST_APU_CLUSTER_COLD_RESET);
+
+ apu_pcli_base = APU_PCLI + (APU_PCLI_CPU_STEP * cpu) +
+ (APU_PCLI_CLUSTER_CPU_STEP * cluster);
+
+ mmio_write_32(apu_pcli_base + PCLI_PSTATE_OFFSET, PCLI_PSTATE_VAL_CLEAR);
+ mmio_write_32(apu_pcli_base + PCLI_PREQ_OFFSET, PREQ_CHANGE_REQUEST);
+
+ return PSCI_E_SUCCESS;
+}
+
+static void zynqmp_nopmu_pwr_domain_off(const psci_power_state_t *target_state)
+{
+}
+
+static void __dead2 zynqmp_nopmu_system_reset(void)
+{
+ while (1)
+ wfi();
+}
+
+static int32_t zynqmp_validate_ns_entrypoint(uint64_t ns_entrypoint)
+{
+ return PSCI_E_SUCCESS;
+}
+
+static void zynqmp_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+}
+
+static void zynqmp_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ plat_versal_net_gic_pcpu_init();
+ plat_versal_net_gic_cpuif_enable();
+}
+
+static void zynqmp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+}
+
+static void __dead2 zynqmp_system_off(void)
+{
+ while (1)
+ wfi();
+}
+
+static int32_t zynqmp_validate_power_state(uint32_t power_state, psci_power_state_t *req_state)
+{
+ return PSCI_E_SUCCESS;
+}
+
+static void zynqmp_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+ req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
+ req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
+}
+
+static const struct plat_psci_ops versal_net_nopmc_psci_ops = {
+ .cpu_standby = zynqmp_cpu_standby,
+ .pwr_domain_on = zynqmp_nopmu_pwr_domain_on,
+ .pwr_domain_off = zynqmp_nopmu_pwr_domain_off,
+ .system_reset = zynqmp_nopmu_system_reset,
+ .validate_ns_entrypoint = zynqmp_validate_ns_entrypoint,
+ .pwr_domain_suspend = zynqmp_pwr_domain_suspend,
+ .pwr_domain_on_finish = zynqmp_pwr_domain_on_finish,
+ .pwr_domain_suspend_finish = zynqmp_pwr_domain_suspend_finish,
+ .system_off = zynqmp_system_off,
+ .validate_power_state = zynqmp_validate_power_state,
+ .get_sys_suspend_power_state = zynqmp_get_sys_suspend_power_state,
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops.
+ ******************************************************************************/
+int32_t plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const struct plat_psci_ops **psci_ops)
+{
+ versal_net_sec_entry = sec_entrypoint;
+
+ VERBOSE("Setting up entry point %lx\n", versal_net_sec_entry);
+
+ *psci_ops = &versal_net_nopmc_psci_ops;
+
+ return 0;
+}
+
+int sip_svc_setup_init(void)
+{
+ return 0;
+}
+
+static int32_t no_pm_ioctl(uint32_t device_id, uint32_t ioctl_id,
+ uint32_t arg1, uint32_t arg2)
+{
+ VERBOSE("%s: ioctl_id: %x, arg1: %x\n", __func__, ioctl_id, arg1);
+ if (ioctl_id == IOCTL_OSPI_MUX_SELECT) {
+ mmio_write_32(SLCR_OSPI_QSPI_IOU_AXI_MUX_SEL, arg1);
+ return 0;
+ }
+ return PM_RET_ERROR_NOFEATURE;
+}
+
+static uint64_t no_pm_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+ uint64_t x4, void *cookie, void *handle, uint64_t flags)
+{
+ int32_t ret;
+ uint32_t arg[4], api_id;
+
+ arg[0] = (uint32_t)x1;
+ arg[1] = (uint32_t)(x1 >> 32);
+ arg[2] = (uint32_t)x2;
+ arg[3] = (uint32_t)(x2 >> 32);
+
+ api_id = smc_fid & FUNCID_NUM_MASK;
+ VERBOSE("%s: smc_fid: %x, api_id=0x%x\n", __func__, smc_fid, api_id);
+
+ switch (api_id) {
+ case PM_IOCTL:
+ {
+ ret = no_pm_ioctl(arg[0], arg[1], arg[2], arg[3]);
+ SMC_RET1(handle, (uint64_t)ret);
+ }
+ case PM_GET_CHIPID:
+ {
+ uint32_t idcode, version;
+
+ idcode = mmio_read_32(PMC_TAP);
+ version = mmio_read_32(PMC_TAP_VERSION);
+ SMC_RET2(handle, ((uint64_t)idcode << 32), version);
+ }
+ default:
+ WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
+
+uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
+ void *cookie, void *handle, uint64_t flags)
+{
+ return no_pm_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
+}
diff --git a/plat/xilinx/versal_net/plat_psci_pm.c b/plat/xilinx/versal_net/plat_psci_pm.c
new file mode 100644
index 0000000..8beaa9a
--- /dev/null
+++ b/plat/xilinx/versal_net/plat_psci_pm.c
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+
+#include <common/debug.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <plat_arm.h>
+
+#include <plat_private.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include <pm_common.h>
+#include "pm_svc_main.h"
+#include "versal_net_def.h"
+
+static uintptr_t versal_net_sec_entry;
+
+static int32_t versal_net_pwr_domain_on(u_register_t mpidr)
+{
+ uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
+ const struct pm_proc *proc;
+
+ VERBOSE("%s: mpidr: 0x%lx, cpuid: %x\n",
+ __func__, mpidr, cpu_id);
+
+ if (cpu_id == -1) {
+ return PSCI_E_INTERN_FAIL;
+ }
+
+ proc = pm_get_proc(cpu_id);
+ if (!proc) {
+ return PSCI_E_INTERN_FAIL;
+ }
+
+ pm_req_wakeup(proc->node_id, (versal_net_sec_entry & 0xFFFFFFFFU) | 0x1U,
+ versal_net_sec_entry >> 32, 0, 0);
+
+ /* Clear power down request */
+ pm_client_wakeup(proc);
+
+ return PSCI_E_SUCCESS;
+}
+
+/**
+ * versal_net_pwr_domain_off() - This function performs actions to turn off core
+ *
+ * @param target_state Targeted state
+ */
+static void versal_net_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+ for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+ }
+
+ /* Prevent interrupts from spuriously waking up this cpu */
+ plat_versal_net_gic_cpuif_disable();
+
+ /*
+ * Send request to PMC to power down the appropriate APU CPU
+ * core.
+ * According to PSCI specification, CPU_off function does not
+ * have resume address and CPU core can only be woken up
+ * invoking CPU_on function, during which resume address will
+ * be set.
+ */
+ pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0,
+ SECURE_FLAG);
+}
+
+/**
+ * versal_net_system_reset() - This function sends the reset request
+ * to firmware for the system to reset. This function does not return.
+ */
+static void __dead2 versal_net_system_reset(void)
+{
+ /* Send the system reset request to the PMC */
+ pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET,
+ pm_get_shutdown_scope(), SECURE_FLAG);
+
+ while (1) {
+ wfi();
+ }
+}
+
+/**
+ * versal_net_pwr_domain_suspend() - This function sends request to PMC to suspend
+ * core.
+ *
+ * @param target_state Targeted state
+ */
+static void versal_net_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+ uint32_t state;
+ uint32_t cpu_id = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+ for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+ }
+
+ plat_versal_net_gic_cpuif_disable();
+
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ plat_versal_net_gic_save();
+ }
+
+ state = target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE ?
+ PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE;
+
+ /* Send request to PMC to suspend this core */
+ pm_self_suspend(proc->node_id, MAX_LATENCY, state, versal_net_sec_entry,
+ SECURE_FLAG);
+
+ /* TODO: disable coherency */
+}
+
+static void versal_net_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ (void)target_state;
+
+ /* Enable the gic cpu interface */
+ plat_versal_net_gic_pcpu_init();
+
+ /* Program the gic per-cpu distributor or re-distributor interface */
+ plat_versal_net_gic_cpuif_enable();
+}
+
+/**
+ * versal_net_pwr_domain_suspend_finish() - This function performs actions to finish
+ * suspend procedure.
+ *
+ * @param target_state Targeted state
+ */
+static void versal_net_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+ for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+
+ /* Clear the APU power control register for this cpu */
+ pm_client_wakeup(proc);
+
+ /* TODO: enable coherency */
+
+ /* APU was turned off, so restore GIC context */
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ plat_versal_net_gic_resume();
+ }
+
+ plat_versal_net_gic_cpuif_enable();
+}
+
+/**
+ * versal_net_system_off() - This function sends the system off request
+ * to firmware. This function does not return.
+ */
+static void __dead2 versal_net_system_off(void)
+{
+ /* Send the power down request to the PMC */
+ pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN,
+ pm_get_shutdown_scope(), SECURE_FLAG);
+
+ while (1) {
+ wfi();
+ }
+}
+
+/**
+ * versal_net_validate_power_state() - This function ensures that the power state
+ * parameter in request is valid.
+ *
+ * @param power_state Power state of core
+ * @param req_state Requested state
+ *
+ * @return Returns status, either PSCI_E_SUCCESS or reason
+ */
+static int32_t versal_net_validate_power_state(unsigned int power_state,
+ psci_power_state_t *req_state)
+{
+ VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
+
+ int32_t pstate = psci_get_pstate_type(power_state);
+
+ assert(req_state);
+
+ /* Sanity check the requested state */
+ if (pstate == PSTATE_TYPE_STANDBY) {
+ req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
+ } else {
+ req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
+ }
+
+ /* We expect the 'state id' to be zero */
+ if (psci_get_pstate_id(power_state)) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
+/**
+ * versal_net_get_sys_suspend_power_state() - Get power state for system suspend
+ *
+ * @param req_state Requested state
+ */
+static void versal_net_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+ req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
+ req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
+}
+
+static const struct plat_psci_ops versal_net_nopmc_psci_ops = {
+ .pwr_domain_on = versal_net_pwr_domain_on,
+ .pwr_domain_off = versal_net_pwr_domain_off,
+ .pwr_domain_on_finish = versal_net_pwr_domain_on_finish,
+ .pwr_domain_suspend = versal_net_pwr_domain_suspend,
+ .pwr_domain_suspend_finish = versal_net_pwr_domain_suspend_finish,
+ .system_off = versal_net_system_off,
+ .system_reset = versal_net_system_reset,
+ .validate_power_state = versal_net_validate_power_state,
+ .get_sys_suspend_power_state = versal_net_get_sys_suspend_power_state,
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops.
+ ******************************************************************************/
+int32_t plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const struct plat_psci_ops **psci_ops)
+{
+ versal_net_sec_entry = sec_entrypoint;
+
+ VERBOSE("Setting up entry point %lx\n", versal_net_sec_entry);
+
+ *psci_ops = &versal_net_nopmc_psci_ops;
+
+ return 0;
+}
+
+int32_t sip_svc_setup_init(void)
+{
+ return pm_setup();
+}
+
+uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4,
+ void *cookie, void *handle, uint64_t flags)
+{
+ return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
+}
diff --git a/plat/xilinx/versal_net/plat_topology.c b/plat/xilinx/versal_net/plat_topology.c
new file mode 100644
index 0000000..7f985b0
--- /dev/null
+++ b/plat/xilinx/versal_net/plat_topology.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include <platform_def.h>
+
+static const uint8_t plat_power_domain_tree_desc[] = {
+ /* Number of root nodes */
+ 1,
+ /* Number of clusters */
+ PLATFORM_CLUSTER_COUNT,
+ /* Number of children for the first cluster node */
+ PLATFORM_CORE_COUNT_PER_CLUSTER,
+ /* Number of children for the second cluster node */
+ PLATFORM_CORE_COUNT_PER_CLUSTER,
+ /* Number of children for the third cluster node */
+ PLATFORM_CORE_COUNT_PER_CLUSTER,
+ /* Number of children for the fourth cluster node */
+ PLATFORM_CORE_COUNT_PER_CLUSTER,
+};
+
+const uint8_t *plat_get_power_domain_tree_desc(void)
+{
+ return plat_power_domain_tree_desc;
+}
+
+/*******************************************************************************
+ * This function implements a part of the critical interface between the psci
+ * generic layer and the platform that allows the former to query the platform
+ * to convert an MPIDR to a unique linear index. An error code (-1) is returned
+ * in case the MPIDR is invalid.
+ ******************************************************************************/
+int32_t plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+ uint32_t cluster_id, cpu_id;
+
+ mpidr &= MPIDR_AFFINITY_MASK;
+
+ cluster_id = MPIDR_AFFLVL2_VAL(mpidr);
+ cpu_id = MPIDR_AFFLVL1_VAL(mpidr);
+
+ if (cluster_id >= PLATFORM_CLUSTER_COUNT) {
+ return -3;
+ }
+
+ /*
+ * Validate cpu_id by checking whether it represents a CPU in
+ * one of the two clusters present on the platform.
+ */
+ if (cpu_id >= PLATFORM_CORE_COUNT_PER_CLUSTER) {
+ return -1;
+ }
+
+ return (cpu_id + (cluster_id * PLATFORM_CORE_COUNT_PER_CLUSTER));
+}
diff --git a/plat/xilinx/versal_net/platform.mk b/plat/xilinx/versal_net/platform.mk
new file mode 100644
index 0000000..b3d56bc
--- /dev/null
+++ b/plat/xilinx/versal_net/platform.mk
@@ -0,0 +1,102 @@
+# Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+# Copyright (c) 2021-2022, Xilinx, Inc. All rights reserved.
+# Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+PLAT_PATH := plat/xilinx/versal_net
+
+# A78 Erratum for SoC
+ERRATA_A78_AE_1941500 := 1
+ERRATA_A78_AE_1951502 := 1
+ERRATA_A78_AE_2376748 := 1
+ERRATA_A78_AE_2395408 := 1
+
+override PROGRAMMABLE_RESET_ADDRESS := 1
+PSCI_EXTENDED_STATE_ID := 1
+SEPARATE_CODE_AND_RODATA := 1
+override RESET_TO_BL31 := 1
+PL011_GENERIC_UART := 1
+GIC_ENABLE_V4_EXTN := 0
+GICV3_SUPPORT_GIC600 := 1
+TFA_NO_PM := 0
+
+override CTX_INCLUDE_AARCH32_REGS := 0
+
+ifdef TFA_NO_PM
+ $(eval $(call add_define,TFA_NO_PM))
+endif
+
+ifdef VERSAL_NET_ATF_MEM_BASE
+ $(eval $(call add_define,VERSAL_NET_ATF_MEM_BASE))
+
+ ifndef VERSAL_NET_ATF_MEM_SIZE
+ $(error "VERSAL_NET_ATF_BASE defined without VERSAL_NET_ATF_SIZE")
+ endif
+ $(eval $(call add_define,VERSAL_NET_ATF_MEM_SIZE))
+
+ ifdef VERSAL_NET_ATF_MEM_PROGBITS_SIZE
+ $(eval $(call add_define,VERSAL_NET_ATF_MEM_PROGBITS_SIZE))
+ endif
+endif
+
+ifdef VERSAL_NET_BL32_MEM_BASE
+ $(eval $(call add_define,VERSAL_NET_BL32_MEM_BASE))
+
+ ifndef VERSAL_NET_BL32_MEM_SIZE
+ $(error "VERSAL_NET_BL32_BASE defined without VERSAL_NET_BL32_SIZE")
+ endif
+ $(eval $(call add_define,VERSAL_NET_BL32_MEM_SIZE))
+endif
+
+USE_COHERENT_MEM := 0
+HW_ASSISTED_COHERENCY := 1
+
+VERSAL_NET_CONSOLE ?= pl011
+$(eval $(call add_define_val,VERSAL_NET_CONSOLE,VERSAL_NET_CONSOLE_ID_${VERSAL_NET_CONSOLE}))
+
+PLAT_INCLUDES := -Iinclude/plat/arm/common/ \
+ -Iplat/xilinx/common/include/ \
+ -Iplat/xilinx/common/ipi_mailbox_service/ \
+ -I${PLAT_PATH}/include/ \
+ -Iplat/xilinx/versal/pm_service/
+
+# Include GICv3 driver files
+include drivers/arm/gic/v3/gicv3.mk
+include lib/xlat_tables_v2/xlat_tables.mk
+include lib/libfdt/libfdt.mk
+
+PLAT_BL_COMMON_SOURCES := \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ ${GICV3_SOURCES} \
+ drivers/arm/pl011/aarch64/pl011_console.S \
+ plat/arm/common/arm_common.c \
+ plat/common/plat_gicv3.c \
+ ${PLAT_PATH}/aarch64/versal_net_helpers.S \
+ ${PLAT_PATH}/aarch64/versal_net_common.c
+
+BL31_SOURCES += drivers/arm/cci/cci.c \
+ lib/cpus/aarch64/cortex_a78_ae.S \
+ lib/cpus/aarch64/cortex_a78.S \
+ plat/common/plat_psci_common.c
+ifeq ($(TFA_NO_PM), 0)
+BL31_SOURCES += plat/xilinx/versal/pm_service/pm_api_sys.c \
+ plat/xilinx/common/pm_service/pm_ipi.c \
+ ${PLAT_PATH}/plat_psci_pm.c \
+ plat/xilinx/versal/pm_service/pm_svc_main.c \
+ ${PLAT_PATH}/pm_service/pm_client.c \
+ ${PLAT_PATH}/versal_net_ipi.c
+else
+BL31_SOURCES += ${PLAT_PATH}/plat_psci.c
+endif
+BL31_SOURCES += plat/xilinx/common/plat_startup.c \
+ plat/xilinx/common/ipi.c \
+ plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c \
+ ${PLAT_PATH}/bl31_versal_net_setup.c \
+ ${PLAT_PATH}/plat_topology.c \
+ common/fdt_fixup.c \
+ ${LIBFDT_SRCS} \
+ ${PLAT_PATH}/sip_svc_setup.c \
+ ${PLAT_PATH}/versal_net_gicv3.c \
+ ${XLAT_TABLES_LIB_SRCS}
diff --git a/plat/xilinx/versal_net/pm_service/pm_client.c b/plat/xilinx/versal_net/pm_service/pm_client.c
new file mode 100644
index 0000000..6487324
--- /dev/null
+++ b/plat/xilinx/versal_net/pm_service/pm_client.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * APU specific definition of processors in the subsystem as well as functions
+ * for getting information about and changing state of the APU.
+ */
+
+#include <assert.h>
+
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include <plat_ipi.h>
+#include <platform_def.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include <versal_net_def.h>
+
+#define UNDEFINED_CPUID (~0)
+
+DEFINE_RENAME_SYSREG_RW_FUNCS(cpu_pwrctrl_val, S3_0_C15_C2_7)
+DEFINE_BAKERY_LOCK(pm_client_secure_lock);
+
+static const struct pm_ipi apu_ipi = {
+ .local_ipi_id = IPI_ID_APU,
+ .remote_ipi_id = IPI_ID_PMC,
+ .buffer_base = IPI_BUFFER_APU_BASE,
+};
+
+/* Order in pm_procs_all array must match cpu ids */
+static const struct pm_proc pm_procs_all[] = {
+ {
+ .node_id = PM_DEV_CLUSTER0_ACPU_0,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER0_ACPU_1,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER0_ACPU_2,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER0_ACPU_3,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER1_ACPU_0,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER1_ACPU_1,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER1_ACPU_2,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER1_ACPU_3,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER2_ACPU_0,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER2_ACPU_1,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER2_ACPU_2,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER2_ACPU_3,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER3_ACPU_0,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER3_ACPU_1,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER3_ACPU_2,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ },
+ {
+ .node_id = PM_DEV_CLUSTER3_ACPU_3,
+ .ipi = &apu_ipi,
+ .pwrdn_mask = 0,
+ }
+};
+
+const struct pm_proc *primary_proc = &pm_procs_all[0];
+
+/**
+ * pm_get_proc() - returns pointer to the proc structure
+ * @param cpuid id of the cpu whose proc struct pointer should be returned
+ *
+ * @return pointer to a proc structure if proc is found, otherwise NULL
+ */
+const struct pm_proc *pm_get_proc(uint32_t cpuid)
+{
+ if (cpuid < ARRAY_SIZE(pm_procs_all)) {
+ return &pm_procs_all[cpuid];
+ }
+
+ NOTICE("ERROR: cpuid: %d proc NULL\n", cpuid);
+ return NULL;
+}
+
+/**
+ * pm_client_suspend() - Client-specific suspend actions
+ *
+ * This function should contain any PU-specific actions
+ * required prior to sending suspend request to PMU
+ * Actions taken depend on the state system is suspending to.
+ *
+ * @param proc processor which need to suspend
+ * @param state desired suspend state
+ */
+void pm_client_suspend(const struct pm_proc *proc, uint32_t state)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+ uintptr_t val;
+
+ bakery_lock_get(&pm_client_secure_lock);
+
+ /* TODO: Set wakeup source */
+
+ val = read_cpu_pwrctrl_val();
+ val |= CORE_PWRDN_EN_BIT_MASK;
+ write_cpu_pwrctrl_val(val);
+
+ isb();
+
+ mmio_write_32(APU_PCIL_CORE_X_IEN_POWER_REG(cpu_id),
+ APU_PCIL_CORE_X_IEN_POWER_MASK);
+
+ bakery_lock_release(&pm_client_secure_lock);
+}
+
+/**
+ * pm_get_cpuid() - get the local cpu ID for a global node ID
+ * @param nid node id of the processor
+ *
+ * @return the cpu ID (starting from 0) for the subsystem
+ */
+static uint32_t pm_get_cpuid(uint32_t nid)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
+ if (pm_procs_all[i].node_id == nid) {
+ return i;
+ }
+ }
+ return UNDEFINED_CPUID;
+}
+
+/**
+ * pm_client_wakeup() - Client-specific wakeup actions
+ *
+ * This function should contain any PU-specific actions
+ * required for waking up another APU core
+ *
+ * @param proc Processor which need to wakeup
+ */
+void pm_client_wakeup(const struct pm_proc *proc)
+{
+ uint32_t cpuid = pm_get_cpuid(proc->node_id);
+
+ if (cpuid == UNDEFINED_CPUID) {
+ return;
+ }
+
+ bakery_lock_get(&pm_client_secure_lock);
+
+ /* TODO: clear powerdown bit for affected cpu */
+
+ bakery_lock_release(&pm_client_secure_lock);
+}
+
+/**
+ * pm_client_abort_suspend() - Client-specific abort-suspend actions
+ *
+ * This function should contain any PU-specific actions
+ * required for aborting a prior suspend request
+ */
+void pm_client_abort_suspend(void)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+ uintptr_t val;
+
+ /* Enable interrupts at processor level (for current cpu) */
+ gicv3_cpuif_enable(plat_my_core_pos());
+
+ bakery_lock_get(&pm_client_secure_lock);
+
+ /* Clear powerdown request */
+ val = read_cpu_pwrctrl_val();
+ val &= ~CORE_PWRDN_EN_BIT_MASK;
+ write_cpu_pwrctrl_val(val);
+
+ isb();
+
+ /* Disabled power down interrupt */
+ mmio_write_32(APU_PCIL_CORE_X_IDS_POWER_REG(cpu_id),
+ APU_PCIL_CORE_X_IDS_POWER_MASK);
+
+ bakery_lock_release(&pm_client_secure_lock);
+}
diff --git a/plat/xilinx/versal_net/sip_svc_setup.c b/plat/xilinx/versal_net/sip_svc_setup.c
new file mode 100644
index 0000000..0e3940f
--- /dev/null
+++ b/plat/xilinx/versal_net/sip_svc_setup.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Top level SMC handler for SiP calls. Dispatch PM calls to PM SMC handler. */
+
+#include <errno.h>
+
+#include <common/debug.h>
+#include <common/runtime_svc.h>
+#include <tools_share/uuid.h>
+
+#include "ipi_mailbox_svc.h"
+#include "plat_private.h"
+#include "pm_svc_main.h"
+
+/* SMC function IDs for SiP Service queries */
+#define VERSAL_NET_SIP_SVC_CALL_COUNT (0x8200ff00U)
+#define VERSAL_NET_SIP_SVC_UID (0x8200ff01U)
+#define VERSAL_NET_SIP_SVC_VERSION (0x8200ff03U)
+
+/* SiP Service Calls version numbers */
+#define SIP_SVC_VERSION_MAJOR (0U)
+#define SIP_SVC_VERSION_MINOR (1U)
+
+/* These macros are used to identify PM calls from the SMC function ID */
+#define PM_FID_MASK 0xf000u
+#define PM_FID_VALUE 0u
+#define IPI_FID_VALUE 0x1000u
+#define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE)
+#define is_ipi_fid(_fid) (((_fid) & PM_FID_MASK) == IPI_FID_VALUE)
+
+/* SiP Service UUID */
+DEFINE_SVC_UUID2(versal_net_sip_uuid,
+ 0x80d4c25a, 0xebaf, 0x11eb, 0x94, 0x68,
+ 0x0b, 0x4e, 0x3b, 0x8f, 0xc3, 0x60);
+
+/**
+ * sip_svc_setup() - Setup SiP Service
+ */
+static int32_t sip_svc_setup(void)
+{
+ return sip_svc_setup_init();
+}
+
+/*
+ * sip_svc_smc_handler() - Top-level SiP Service SMC handler
+ *
+ * Handler for all SiP SMC calls. Handles standard SIP requests
+ * and calls PM SMC handler if the call is for a PM-API function.
+ */
+static uintptr_t sip_svc_smc_handler(uint32_t smc_fid,
+ u_register_t x1,
+ u_register_t x2,
+ u_register_t x3,
+ u_register_t x4,
+ void *cookie,
+ void *handle,
+ u_register_t flags)
+{
+ /* Let PM SMC handler deal with PM-related requests */
+ if (is_pm_fid(smc_fid)) {
+ return smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+ flags);
+ }
+
+ /* Let IPI SMC handler deal with IPI-related requests if platform */
+ if (is_ipi_fid(smc_fid)) {
+ return ipi_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
+ }
+
+ /* Let PM SMC handler deal with PM-related requests */
+ switch (smc_fid) {
+ case VERSAL_NET_SIP_SVC_CALL_COUNT:
+ /* PM functions + default functions */
+ SMC_RET1(handle, 2);
+
+ case VERSAL_NET_SIP_SVC_UID:
+ SMC_UUID_RET(handle, versal_net_sip_uuid);
+
+ case VERSAL_NET_SIP_SVC_VERSION:
+ SMC_RET2(handle, SIP_SVC_VERSION_MAJOR, SIP_SVC_VERSION_MINOR);
+
+ default:
+ WARN("Unimplemented SiP Service Call: 0x%x\n", smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
+
+/* Register PM Service Calls as runtime service */
+DECLARE_RT_SVC(
+ sip_svc,
+ OEN_SIP_START,
+ OEN_SIP_END,
+ SMC_TYPE_FAST,
+ sip_svc_setup,
+ sip_svc_smc_handler);
diff --git a/plat/xilinx/versal_net/versal_net_gicv3.c b/plat/xilinx/versal_net/versal_net_gicv3.c
new file mode 100644
index 0000000..b7ac6ab
--- /dev/null
+++ b/plat/xilinx/versal_net/versal_net_gicv3.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2018-2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/debug.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gicv3.h>
+#include <lib/utils.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include <platform_def.h>
+
+/******************************************************************************
+ * The following functions are defined as weak to allow a platform to override
+ * the way the GICv3 driver is initialised and used.
+ *****************************************************************************/
+#pragma weak plat_versal_net_gic_driver_init
+#pragma weak plat_versal_net_gic_init
+#pragma weak plat_versal_net_gic_cpuif_enable
+#pragma weak plat_versal_net_gic_cpuif_disable
+#pragma weak plat_versal_net_gic_pcpu_init
+#pragma weak plat_versal_net_gic_redistif_on
+#pragma weak plat_versal_net_gic_redistif_off
+
+/* The GICv3 driver only needs to be initialized in EL3 */
+static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
+
+static const uintptr_t gicr_base_addrs[2] = {
+ PLAT_VERSAL_NET_GICR_BASE, /* GICR Base address of the primary CPU */
+ 0U /* Zero Termination */
+};
+
+/* List of zero terminated GICR frame addresses which CPUs will probe */
+static const uintptr_t *gicr_frames;
+
+static const interrupt_prop_t versal_net_interrupt_props[] = {
+ PLAT_VERSAL_NET_G1S_IRQ_PROPS(INTR_GROUP1S),
+ PLAT_VERSAL_NET_G0_IRQ_PROPS(INTR_GROUP0)
+};
+
+/*
+ * We save and restore the GICv3 context on system suspend. Allocate the
+ * data in the designated EL3 Secure carve-out memory.
+ */
+static gicv3_redist_ctx_t rdist_ctx __section("versal_net_el3_tzc_dram");
+static gicv3_dist_ctx_t dist_ctx __section("versal_net_el3_tzc_dram");
+
+/*
+ * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register
+ * to core position.
+ *
+ * Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity
+ * values read from GICR_TYPER don't have an MT field. To reuse the same
+ * translation used for CPUs, we insert MT bit read from the PE's MPIDR into
+ * that read from GICR_TYPER.
+ *
+ * Assumptions:
+ *
+ * - All CPUs implemented in the system have MPIDR_EL1.MT bit set;
+ * - No CPUs implemented in the system use affinity level 3.
+ */
+static uint32_t versal_net_gicv3_mpidr_hash(u_register_t mpidr)
+{
+ mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK);
+ return plat_core_pos_by_mpidr(mpidr);
+}
+
+static const gicv3_driver_data_t versal_net_gic_data __unused = {
+ .gicd_base = PLAT_VERSAL_NET_GICD_BASE,
+ .gicr_base = 0U,
+ .interrupt_props = versal_net_interrupt_props,
+ .interrupt_props_num = ARRAY_SIZE(versal_net_interrupt_props),
+ .rdistif_num = PLATFORM_CORE_COUNT,
+ .rdistif_base_addrs = rdistif_base_addrs,
+ .mpidr_to_core_pos = versal_net_gicv3_mpidr_hash
+};
+
+void __init plat_versal_net_gic_driver_init(void)
+{
+ /*
+ * The GICv3 driver is initialized in EL3 and does not need
+ * to be initialized again in SEL1. This is because the S-EL1
+ * can use GIC system registers to manage interrupts and does
+ * not need GIC interface base addresses to be configured.
+ */
+#if IMAGE_BL31
+ gicv3_driver_init(&versal_net_gic_data);
+ gicr_frames = gicr_base_addrs;
+
+ if (gicv3_rdistif_probe(gicr_frames[0]) == -1) {
+ ERROR("No GICR base frame found for Primary CPU\n");
+ panic();
+ }
+#endif
+}
+
+/******************************************************************************
+ * Versal NET common helper to initialize the GIC. Only invoked by BL31
+ *****************************************************************************/
+void __init plat_versal_net_gic_init(void)
+{
+ gicv3_distif_init();
+ gicv3_rdistif_init(plat_my_core_pos());
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal NET common helper to enable the GIC CPU interface
+ *****************************************************************************/
+void plat_versal_net_gic_cpuif_enable(void)
+{
+ gicv3_cpuif_enable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal NET common helper to disable the GIC CPU interface
+ *****************************************************************************/
+void plat_versal_net_gic_cpuif_disable(void)
+{
+ gicv3_cpuif_disable(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal NET common helper to initialize the per-cpu redistributor interface in
+ * GICv3
+ *****************************************************************************/
+void plat_versal_net_gic_pcpu_init(void)
+{
+ int32_t result;
+ const uintptr_t *plat_gicr_frames = gicr_frames;
+
+ do {
+ result = gicv3_rdistif_probe(*plat_gicr_frames);
+
+ /* If the probe is successful, no need to proceed further */
+ if (result == 0) {
+ break;
+ }
+
+ plat_gicr_frames++;
+ } while (*plat_gicr_frames != 0U);
+
+ if (result == -1) {
+ ERROR("No GICR base frame found for CPU 0x%lx\n", read_mpidr());
+ panic();
+ }
+
+ gicv3_rdistif_init(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal NET common helpers to power GIC redistributor interface
+ *****************************************************************************/
+void plat_versal_net_gic_redistif_on(void)
+{
+ gicv3_rdistif_on(plat_my_core_pos());
+}
+
+void plat_versal_net_gic_redistif_off(void)
+{
+ gicv3_rdistif_off(plat_my_core_pos());
+}
+
+/******************************************************************************
+ * Versal NET common helper to save & restore the GICv3 on resume from system
+ * suspend
+ *****************************************************************************/
+void plat_versal_net_gic_save(void)
+{
+ /*
+ * If an ITS is available, save its context before
+ * the Redistributor using:
+ * gicv3_its_save_disable(gits_base, &its_ctx[i])
+ * Additionnaly, an implementation-defined sequence may
+ * be required to save the whole ITS state.
+ */
+
+ /*
+ * Save the GIC Redistributors and ITS contexts before the
+ * Distributor context. As we only handle SYSTEM SUSPEND API,
+ * we only need to save the context of the CPU that is issuing
+ * the SYSTEM SUSPEND call, i.e. the current CPU.
+ */
+ gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx);
+
+ /* Save the GIC Distributor context */
+ gicv3_distif_save(&dist_ctx);
+
+ /*
+ * From here, all the components of the GIC can be safely powered down
+ * as long as there is an alternate way to handle wakeup interrupt
+ * sources.
+ */
+}
+
+void plat_versal_net_gic_resume(void)
+{
+ /* Restore the GIC Distributor context */
+ gicv3_distif_init_restore(&dist_ctx);
+
+ /*
+ * Restore the GIC Redistributor and ITS contexts after the
+ * Distributor context. As we only handle SYSTEM SUSPEND API,
+ * we only need to restore the context of the CPU that issued
+ * the SYSTEM SUSPEND call.
+ */
+ gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx);
+
+ /*
+ * If an ITS is available, restore its context after
+ * the Redistributor using:
+ * gicv3_its_restore(gits_base, &its_ctx[i])
+ * An implementation-defined sequence may be required to
+ * restore the whole ITS state. The ITS must also be
+ * re-enabled after this sequence has been executed.
+ */
+}
diff --git a/plat/xilinx/versal_net/versal_net_ipi.c b/plat/xilinx/versal_net/versal_net_ipi.c
new file mode 100644
index 0000000..26ded89
--- /dev/null
+++ b/plat/xilinx/versal_net/versal_net_ipi.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2022, Xilinx, Inc. All rights reserved.
+ * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Versal NET 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_ipi.h>
+#include <plat_private.h>
+
+/* versal_net ipi configuration table */
+static const struct ipi_config versal_net_ipi_table[IPI_ID_MAX] = {
+ /* A72 IPI */
+ [IPI_ID_APU] = {
+ .ipi_bit_mask = IPI0_TRIG_BIT,
+ .ipi_reg_base = IPI0_REG_BASE,
+ .secure_only = 0,
+ },
+
+ /* PMC IPI */
+ [IPI_ID_PMC] = {
+ .ipi_bit_mask = PMC_IPI_TRIG_BIT,
+ .ipi_reg_base = IPI0_REG_BASE,
+ .secure_only = 0,
+ },
+
+ /* RPU0 IPI */
+ [IPI_ID_RPU0] = {
+ .ipi_bit_mask = IPI1_TRIG_BIT,
+ .ipi_reg_base = IPI1_REG_BASE,
+ .secure_only = 0,
+ },
+
+ /* RPU1 IPI */
+ [IPI_ID_RPU1] = {
+ .ipi_bit_mask = IPI2_TRIG_BIT,
+ .ipi_reg_base = IPI2_REG_BASE,
+ .secure_only = 0,
+ },
+
+ /* IPI3 IPI */
+ [IPI_ID_3] = {
+ .ipi_bit_mask = IPI3_TRIG_BIT,
+ .ipi_reg_base = IPI3_REG_BASE,
+ .secure_only = 0,
+ },
+
+ /* IPI4 IPI */
+ [IPI_ID_4] = {
+ .ipi_bit_mask = IPI4_TRIG_BIT,
+ .ipi_reg_base = IPI4_REG_BASE,
+ .secure_only = 0,
+ },
+
+ /* IPI5 IPI */
+ [IPI_ID_5] = {
+ .ipi_bit_mask = IPI5_TRIG_BIT,
+ .ipi_reg_base = IPI5_REG_BASE,
+ .secure_only = 0,
+ },
+};
+
+/* versal_net_ipi_config_table_init() - Initialize versal_net IPI configuration data
+ *
+ * @ipi_config_table - IPI configuration table
+ * @ipi_total - Total number of IPI available
+ *
+ */
+void versal_net_ipi_config_table_init(void)
+{
+ ipi_config_table_init(versal_net_ipi_table, ARRAY_SIZE(versal_net_ipi_table));
+}
diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_common.c b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
new file mode 100644
index 0000000..3946e9b
--- /dev/null
+++ b/plat/xilinx/zynqmp/aarch64/zynqmp_common.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <common/debug.h>
+#include <drivers/generic_delay_timer.h>
+#include <lib/mmio.h>
+#include <lib/xlat_tables/xlat_tables.h>
+#include <plat_ipi.h>
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+#include "pm_api_sys.h"
+
+/*
+ * Table of regions to map using the MMU.
+ * This doesn't include TZRAM as the 'mem_layout' argument passed to
+ * configure_mmu_elx() will give the available subset of that,
+ */
+const mmap_region_t plat_arm_mmap[] = {
+ { DEVICE0_BASE, DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
+ { DEVICE1_BASE, DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
+ { CRF_APB_BASE, CRF_APB_BASE, CRF_APB_SIZE, MT_DEVICE | MT_RW | MT_SECURE },
+ {0}
+};
+
+static uint32_t zynqmp_get_silicon_ver(void)
+{
+ static unsigned int ver;
+
+ if (!ver) {
+ ver = mmio_read_32(ZYNQMP_CSU_BASEADDR +
+ ZYNQMP_CSU_VERSION_OFFSET);
+ ver &= ZYNQMP_SILICON_VER_MASK;
+ ver >>= ZYNQMP_SILICON_VER_SHIFT;
+ }
+
+ return ver;
+}
+
+uint32_t zynqmp_get_uart_clk(void)
+{
+ unsigned int ver = zynqmp_get_silicon_ver();
+
+ if (ver == ZYNQMP_CSU_VERSION_QEMU) {
+ return 133000000;
+ } else {
+ return 100000000;
+ }
+}
+
+#if LOG_LEVEL >= LOG_LEVEL_NOTICE
+static const struct {
+ uint32_t id;
+ uint32_t ver;
+ char *name;
+ bool evexists;
+} zynqmp_devices[] = {
+ {
+ .id = 0x10,
+ .name = "XCZU3EG",
+ },
+ {
+ .id = 0x10,
+ .ver = 0x2c,
+ .name = "XCZU3CG",
+ },
+ {
+ .id = 0x11,
+ .name = "XCZU2EG",
+ },
+ {
+ .id = 0x11,
+ .ver = 0x2c,
+ .name = "XCZU2CG",
+ },
+ {
+ .id = 0x20,
+ .name = "XCZU5EV",
+ .evexists = true,
+ },
+ {
+ .id = 0x20,
+ .ver = 0x100,
+ .name = "XCZU5EG",
+ .evexists = true,
+ },
+ {
+ .id = 0x20,
+ .ver = 0x12c,
+ .name = "XCZU5CG",
+ },
+ {
+ .id = 0x21,
+ .name = "XCZU4EV",
+ .evexists = true,
+ },
+ {
+ .id = 0x21,
+ .ver = 0x100,
+ .name = "XCZU4EG",
+ .evexists = true,
+ },
+ {
+ .id = 0x21,
+ .ver = 0x12c,
+ .name = "XCZU4CG",
+ },
+ {
+ .id = 0x30,
+ .name = "XCZU7EV",
+ .evexists = true,
+ },
+ {
+ .id = 0x30,
+ .ver = 0x100,
+ .name = "XCZU7EG",
+ .evexists = true,
+ },
+ {
+ .id = 0x30,
+ .ver = 0x12c,
+ .name = "XCZU7CG",
+ },
+ {
+ .id = 0x38,
+ .name = "XCZU9EG",
+ },
+ {
+ .id = 0x38,
+ .ver = 0x2c,
+ .name = "XCZU9CG",
+ },
+ {
+ .id = 0x39,
+ .name = "XCZU6EG",
+ },
+ {
+ .id = 0x39,
+ .ver = 0x2c,
+ .name = "XCZU6CG",
+ },
+ {
+ .id = 0x40,
+ .name = "XCZU11EG",
+ },
+ {
+ .id = 0x50,
+ .name = "XCZU15EG",
+ },
+ {
+ .id = 0x58,
+ .name = "XCZU19EG",
+ },
+ {
+ .id = 0x59,
+ .name = "XCZU17EG",
+ },
+ {
+ .id = 0x60,
+ .name = "XCZU28DR",
+ },
+ {
+ .id = 0x61,
+ .name = "XCZU21DR",
+ },
+ {
+ .id = 0x62,
+ .name = "XCZU29DR",
+ },
+ {
+ .id = 0x63,
+ .name = "XCZU23DR",
+ },
+ {
+ .id = 0x64,
+ .name = "XCZU27DR",
+ },
+ {
+ .id = 0x65,
+ .name = "XCZU25DR",
+ },
+ {
+ .id = 0x66,
+ .name = "XCZU39DR",
+ },
+ {
+ .id = 0x7d,
+ .name = "XCZU43DR",
+ },
+ {
+ .id = 0x78,
+ .name = "XCZU46DR",
+ },
+ {
+ .id = 0x7f,
+ .name = "XCZU47DR",
+ },
+ {
+ .id = 0x7b,
+ .name = "XCZU48DR",
+ },
+ {
+ .id = 0x7e,
+ .name = "XCZU49DR",
+ },
+};
+
+#define ZYNQMP_PL_STATUS_BIT 9
+#define ZYNQMP_PL_STATUS_MASK BIT(ZYNQMP_PL_STATUS_BIT)
+#define ZYNQMP_CSU_VERSION_MASK ~(ZYNQMP_PL_STATUS_MASK)
+
+#define SILICON_ID_XCK24 0x4714093U
+#define SILICON_ID_XCK26 0x4724093U
+
+static char *zynqmp_get_silicon_idcode_name(void)
+{
+ uint32_t id, ver, chipid[2];
+ size_t i, j, len;
+ const char *name = "EG/EV";
+
+#ifdef IMAGE_BL32
+ /*
+ * For BL32, get the chip id info directly by reading corresponding
+ * registers instead of making pm call. This has limitation
+ * that these registers should be configured to have access
+ * from APU which is default case.
+ */
+ chipid[0] = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
+ chipid[1] = mmio_read_32(EFUSE_BASEADDR + EFUSE_IPDISABLE_OFFSET);
+#else
+ if (pm_get_chipid(chipid) != PM_RET_SUCCESS) {
+ return "XCZUUNKN";
+ }
+#endif
+
+ id = chipid[0] & (ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK |
+ ZYNQMP_CSU_IDCODE_SVD_MASK);
+ id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT;
+ ver = chipid[1] >> ZYNQMP_EFUSE_IPDISABLE_SHIFT;
+
+ for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) {
+ if (zynqmp_devices[i].id == id &&
+ zynqmp_devices[i].ver == (ver & ZYNQMP_CSU_VERSION_MASK)) {
+ break;
+ }
+ }
+
+ if (i >= ARRAY_SIZE(zynqmp_devices)) {
+ switch (chipid[0]) {
+ case SILICON_ID_XCK24:
+ return "XCK24";
+ case SILICON_ID_XCK26:
+ return "XCK26";
+ default:
+ return "XCZUUNKN";
+ }
+ }
+
+ if (!zynqmp_devices[i].evexists) {
+ return zynqmp_devices[i].name;
+ }
+
+ if ((ver & ZYNQMP_PL_STATUS_MASK) != 0U) {
+ return zynqmp_devices[i].name;
+ }
+
+ len = strlen(zynqmp_devices[i].name) - 2;
+ for (j = 0; j < strlen(name); j++) {
+ zynqmp_devices[i].name[len] = name[j];
+ len++;
+ }
+ zynqmp_devices[i].name[len] = '\0';
+
+ return zynqmp_devices[i].name;
+}
+
+static unsigned int zynqmp_get_rtl_ver(void)
+{
+ uint32_t ver;
+
+ ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
+ ver &= ZYNQMP_RTL_VER_MASK;
+ ver >>= ZYNQMP_RTL_VER_SHIFT;
+
+ return ver;
+}
+
+static char *zynqmp_print_silicon_idcode(void)
+{
+ uint32_t id, maskid, tmp;
+
+ id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET);
+
+ tmp = id;
+ tmp &= ZYNQMP_CSU_IDCODE_XILINX_ID_MASK |
+ ZYNQMP_CSU_IDCODE_FAMILY_MASK;
+ maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT |
+ ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT;
+ if (tmp != maskid) {
+ ERROR("Incorrect XILINX IDCODE 0x%x, maskid 0x%x\n", id, maskid);
+ return "UNKN";
+ }
+ VERBOSE("Xilinx IDCODE 0x%x\n", id);
+ return zynqmp_get_silicon_idcode_name();
+}
+
+static uint32_t zynqmp_get_ps_ver(void)
+{
+ uint32_t ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET);
+
+ ver &= ZYNQMP_PS_VER_MASK;
+ ver >>= ZYNQMP_PS_VER_SHIFT;
+
+ return ver + 1U;
+}
+
+static void zynqmp_print_platform_name(void)
+{
+ uint32_t ver = zynqmp_get_silicon_ver();
+ uint32_t rtl = zynqmp_get_rtl_ver();
+ char *label = "Unknown";
+
+ switch (ver) {
+ case ZYNQMP_CSU_VERSION_QEMU:
+ label = "QEMU";
+ break;
+ case ZYNQMP_CSU_VERSION_SILICON:
+ label = "silicon";
+ break;
+ default:
+ /* Do nothing in default case */
+ break;
+ }
+
+ VERBOSE("TF-A running on %s/%s at 0x%x\n",
+ zynqmp_print_silicon_idcode(), label, BL31_BASE);
+ VERBOSE("TF-A running on v%d/RTL%d.%d\n",
+ zynqmp_get_ps_ver(), (rtl & 0xf0) >> 4, rtl & 0xf);
+}
+#else
+static inline void zynqmp_print_platform_name(void) { }
+#endif
+
+uint32_t zynqmp_get_bootmode(void)
+{
+ uint32_t r;
+ unsigned int ret;
+
+ ret = pm_mmio_read(CRL_APB_BOOT_MODE_USER, &r);
+
+ if (ret != PM_RET_SUCCESS) {
+ r = mmio_read_32(CRL_APB_BOOT_MODE_USER);
+ }
+
+ return r & CRL_APB_BOOT_MODE_MASK;
+}
+
+void zynqmp_config_setup(void)
+{
+ uint64_t counter_freq;
+
+ /* Configure IPI data for ZynqMP */
+ zynqmp_ipi_config_table_init();
+
+ zynqmp_print_platform_name();
+
+ /* Configure counter frequency */
+ counter_freq = read_cntfrq_el0();
+ if (counter_freq == ZYNQMP_DEFAULT_COUNTER_FREQ) {
+ write_cntfrq_el0(plat_get_syscnt_freq2());
+ }
+
+ generic_delay_timer_init();
+}
+
+uint32_t plat_get_syscnt_freq2(void)
+{
+ uint32_t ver = zynqmp_get_silicon_ver();
+
+ if (ver == ZYNQMP_CSU_VERSION_QEMU) {
+ return 65000000;
+ } else {
+ return mmio_read_32(IOU_SCNTRS_BASEFREQ);
+ }
+}
diff --git a/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S b/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S
new file mode 100644
index 0000000..d8439f7
--- /dev/null
+++ b/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <asm_macros.S>
+#include <drivers/arm/gicv2.h>
+#include <platform_def.h>
+
+ .globl plat_secondary_cold_boot_setup
+ .globl plat_is_my_cpu_primary
+ .globl zynqmp_calc_core_pos
+ .globl plat_my_core_pos
+ .globl platform_mem_init
+
+ /* -----------------------------------------------------
+ * void plat_secondary_cold_boot_setup (void);
+ *
+ * This function performs any platform specific actions
+ * needed for a secondary cpu after a cold reset e.g
+ * mark the cpu's presence, mechanism to place it in a
+ * holding pen etc.
+ * TODO: Should we read the PSYS register to make sure
+ * that the request has gone through.
+ * -----------------------------------------------------
+ */
+func plat_secondary_cold_boot_setup
+ mrs x0, mpidr_el1
+
+ /* Deactivate the gic cpu interface */
+ ldr x1, =BASE_GICC_BASE
+ mov w0, #(IRQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP1)
+ orr w0, w0, #(IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP0)
+ str w0, [x1, #GICC_CTLR]
+
+ /*
+ * There is no sane reason to come out of this wfi. This
+ * cpu will be powered on and reset by the cpu_on pm api
+ */
+ dsb sy
+1:
+ no_ret plat_panic_handler
+endfunc plat_secondary_cold_boot_setup
+
+func plat_is_my_cpu_primary
+ mov x9, x30
+ bl plat_my_core_pos
+ cmp x0, #ZYNQMP_PRIMARY_CPU
+ cset x0, eq
+ ret x9
+endfunc plat_is_my_cpu_primary
+
+ /* -----------------------------------------------------
+ * unsigned int plat_my_core_pos(void)
+ * This function uses the zynqmp_calc_core_pos()
+ * definition to get the index of the calling CPU.
+ * -----------------------------------------------------
+ */
+func plat_my_core_pos
+ mrs x0, mpidr_el1
+ b zynqmp_calc_core_pos
+endfunc plat_my_core_pos
+
+ /* -----------------------------------------------------
+ * unsigned int zynqmp_calc_core_pos(u_register_t mpidr)
+ * Helper function to calculate the core position.
+ * With this function: CorePos = (ClusterId * 4) +
+ * CoreId
+ * -----------------------------------------------------
+ */
+func zynqmp_calc_core_pos
+ and x1, x0, #MPIDR_CPU_MASK
+ and x0, x0, #MPIDR_CLUSTER_MASK
+ add x0, x1, x0, LSR #6
+ ret
+endfunc zynqmp_calc_core_pos
+
+ /* ---------------------------------------------------------------------
+ * We don't need to carry out any memory initialization on ARM
+ * platforms. The Secure RAM is accessible straight away.
+ * ---------------------------------------------------------------------
+ */
+func platform_mem_init
+ ret
+endfunc platform_mem_init
diff --git a/plat/xilinx/zynqmp/bl31_zynqmp_setup.c b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
new file mode 100644
index 0000000..1d59537
--- /dev/null
+++ b/plat/xilinx/zynqmp/bl31_zynqmp_setup.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <bl31/bl31.h>
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/arm/dcc.h>
+#include <drivers/console.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+#include <lib/mmio.h>
+
+#include <plat_startup.h>
+#include <plat_private.h>
+#include <zynqmp_def.h>
+
+#include <common/fdt_fixup.h>
+#include <common/fdt_wrappers.h>
+#include <libfdt.h>
+
+static entry_point_info_t bl32_image_ep_info;
+static entry_point_info_t bl33_image_ep_info;
+
+/*
+ * Return a pointer to the 'entry_point_info' structure of the next image for
+ * the security state specified. BL33 corresponds to the non-secure image type
+ * while BL32 corresponds to the secure image type. A NULL pointer is returned
+ * if the image does not exist.
+ */
+struct entry_point_info *bl31_plat_get_next_image_ep_info(uint32_t type)
+{
+ entry_point_info_t *next_image_info;
+
+ assert(sec_state_is_valid(type));
+ if (type == NON_SECURE) {
+ next_image_info = &bl33_image_ep_info;
+ } else {
+ next_image_info = &bl32_image_ep_info;
+ }
+
+ return next_image_info;
+}
+
+/*
+ * Set the build time defaults. We want to do this when doing a JTAG boot
+ * or if we can't find any other config data.
+ */
+static inline void bl31_set_default_config(void)
+{
+ bl32_image_ep_info.pc = BL32_BASE;
+ bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry();
+ bl33_image_ep_info.pc = plat_get_ns_image_entrypoint();
+ bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX,
+ DISABLE_ALL_EXCEPTIONS);
+}
+
+/*
+ * Perform any BL31 specific platform actions. Here is an opportunity to copy
+ * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before they
+ * are lost (potentially). This needs to be done before the MMU is initialized
+ * so that the memory layout can be used while creating page tables.
+ */
+void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
+ u_register_t arg2, u_register_t arg3)
+{
+ uint64_t atf_handoff_addr;
+
+ if (ZYNQMP_CONSOLE_IS(cadence) || (ZYNQMP_CONSOLE_IS(cadence1))) {
+ /* Register the console to provide early debug support */
+ static console_t bl31_boot_console;
+ (void)console_cdns_register(ZYNQMP_UART_BASE,
+ zynqmp_get_uart_clk(),
+ ZYNQMP_UART_BAUDRATE,
+ &bl31_boot_console);
+ console_set_scope(&bl31_boot_console,
+ CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_BOOT);
+ } else if (ZYNQMP_CONSOLE_IS(dcc)) {
+ /* Initialize the dcc console for debug */
+ int32_t rc = console_dcc_register();
+ if (rc == 0) {
+ panic();
+ }
+ } else {
+ ERROR("BL31: No console device found.\n");
+ }
+ /* Initialize the platform config for future decision making */
+ zynqmp_config_setup();
+
+ /* There are no parameters from BL2 if BL31 is a reset vector */
+ assert(arg0 == 0U);
+ assert(arg1 == 0U);
+
+ /*
+ * Do initial security configuration to allow DRAM/device access. On
+ * Base ZYNQMP only DRAM security is programmable (via TrustZone), but
+ * other platforms might have more programmable security devices
+ * present.
+ */
+
+ /* Populate common information for BL32 and BL33 */
+ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0);
+ SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE);
+ SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0);
+ SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE);
+
+ atf_handoff_addr = mmio_read_32(PMU_GLOBAL_GEN_STORAGE6);
+
+ if (zynqmp_get_bootmode() == ZYNQMP_BOOTMODE_JTAG) {
+ bl31_set_default_config();
+ } else {
+ /* use parameters from FSBL */
+ enum fsbl_handoff ret = fsbl_atf_handover(&bl32_image_ep_info,
+ &bl33_image_ep_info,
+ atf_handoff_addr);
+ if (ret == FSBL_HANDOFF_NO_STRUCT) {
+ bl31_set_default_config();
+ } else if (ret != FSBL_HANDOFF_SUCCESS) {
+ panic();
+ }
+ }
+ if (bl32_image_ep_info.pc != 0) {
+ VERBOSE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc);
+ }
+ if (bl33_image_ep_info.pc != 0) {
+ VERBOSE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc);
+ }
+}
+
+#if ZYNQMP_WDT_RESTART
+static interrupt_type_handler_t type_el3_interrupt_table[MAX_INTR_EL3];
+
+int request_intr_type_el3(uint32_t id, interrupt_type_handler_t handler)
+{
+ /* Validate 'handler' and 'id' parameters */
+ if (!handler || id >= MAX_INTR_EL3) {
+ return -EINVAL;
+ }
+
+ /* Check if a handler has already been registered */
+ if (type_el3_interrupt_table[id]) {
+ return -EALREADY;
+ }
+
+ type_el3_interrupt_table[id] = handler;
+
+ return 0;
+}
+
+static uint64_t rdo_el3_interrupt_handler(uint32_t id, uint32_t flags,
+ void *handle, void *cookie)
+{
+ uint32_t intr_id;
+ interrupt_type_handler_t handler;
+
+ intr_id = plat_ic_get_pending_interrupt_id();
+ handler = type_el3_interrupt_table[intr_id];
+ if (handler != NULL) {
+ handler(intr_id, flags, handle, cookie);
+ }
+
+ return 0;
+}
+#endif
+
+#if (BL31_LIMIT < PLAT_DDR_LOWMEM_MAX)
+static void prepare_dtb(void)
+{
+ void *dtb = (void *)XILINX_OF_BOARD_DTB_ADDR;
+ int ret;
+
+ /* Return if no device tree is detected */
+ if (fdt_check_header(dtb) != 0) {
+ NOTICE("Can't read DT at %p\n", dtb);
+ return;
+ }
+
+ 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);
+ return;
+ }
+
+ if (dt_add_psci_node(dtb)) {
+ ERROR("Failed to add PSCI Device Tree node\n");
+ return;
+ }
+
+ if (dt_add_psci_cpu_enable_methods(dtb)) {
+ ERROR("Failed to add PSCI cpu enable methods in Device Tree\n");
+ return;
+ }
+
+ /* Reserve memory used by Trusted Firmware. */
+ if (fdt_add_reserved_memory(dtb, "tf-a", BL31_BASE, BL31_LIMIT - BL31_BASE)) {
+ WARN("Failed to add reserved memory nodes to DT.\n");
+ }
+
+ ret = fdt_pack(dtb);
+ if (ret < 0) {
+ ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, ret);
+ }
+
+ clean_dcache_range((uintptr_t)dtb, fdt_blob_size(dtb));
+ INFO("Changed device tree to advertise PSCI and reserved memories.\n");
+}
+#endif
+
+void bl31_platform_setup(void)
+{
+#if (BL31_LIMIT < PLAT_DDR_LOWMEM_MAX)
+ prepare_dtb();
+#endif
+
+ /* Initialize the gic cpu and distributor interfaces */
+ plat_arm_gic_driver_init();
+ plat_arm_gic_init();
+}
+
+void bl31_plat_runtime_setup(void)
+{
+#if ZYNQMP_WDT_RESTART
+ uint64_t flags = 0;
+ uint64_t rc;
+
+ set_interrupt_rm_flag(flags, NON_SECURE);
+ rc = register_interrupt_type_handler(INTR_TYPE_EL3,
+ rdo_el3_interrupt_handler, flags);
+ if (rc) {
+ panic();
+ }
+#endif
+}
+
+/*
+ * Perform the very early platform specific architectural setup here.
+ */
+void bl31_plat_arch_setup(void)
+{
+ plat_arm_interconnect_init();
+ plat_arm_interconnect_enter_coherency();
+
+
+ const mmap_region_t bl_regions[] = {
+#if (BL31_LIMIT < PLAT_DDR_LOWMEM_MAX)
+ MAP_REGION_FLAT(XILINX_OF_BOARD_DTB_ADDR, XILINX_OF_BOARD_DTB_MAX_SIZE,
+ MT_MEMORY | MT_RW | MT_NS),
+#endif
+ MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE,
+ MT_MEMORY | MT_RW | MT_SECURE),
+ MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE,
+ MT_CODE | MT_SECURE),
+ MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE,
+ MT_RO_DATA | MT_SECURE),
+ MAP_REGION_FLAT(BL_COHERENT_RAM_BASE,
+ BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ {0}
+ };
+
+ setup_page_tables(bl_regions, plat_arm_get_mmap());
+ enable_mmu_el3(0);
+}
diff --git a/plat/xilinx/zynqmp/include/plat_ipi.h b/plat/xilinx/zynqmp/include/plat_ipi.h
new file mode 100644
index 0000000..a78f93a
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/plat_ipi.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* ZynqMP IPI management enums and defines */
+
+#ifndef PLAT_IPI_H
+#define PLAT_IPI_H
+
+#include <stdint.h>
+#include <ipi.h>
+
+/*********************************************************************
+ * IPI agent IDs macros
+ ********************************************************************/
+#define IPI_ID_APU 0U
+#define IPI_ID_RPU0 1U
+#define IPI_ID_RPU1 2U
+#define IPI_ID_PMU0 3U
+#define IPI_ID_PMU1 4U
+#define IPI_ID_PMU2 5U
+#define IPI_ID_PMU3 6U
+#define IPI_ID_PL0 7U
+#define IPI_ID_PL1 8U
+#define IPI_ID_PL2 9U
+#define IPI_ID_PL3 10U
+
+/*********************************************************************
+ * IPI message buffers
+ ********************************************************************/
+#define IPI_BUFFER_BASEADDR 0xFF990000U
+
+#define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U)
+#define IPI_BUFFER_PMU_BASE (IPI_BUFFER_BASEADDR + 0xE00U)
+
+#define IPI_BUFFER_LOCAL_BASE IPI_BUFFER_APU_BASE
+#define IPI_BUFFER_REMOTE_BASE IPI_BUFFER_PMU_BASE
+
+#define IPI_BUFFER_TARGET_LOCAL_OFFSET 0x80U
+#define IPI_BUFFER_TARGET_REMOTE_OFFSET 0x1C0U
+
+#define IPI_BUFFER_MAX_WORDS 8U
+
+#define IPI_BUFFER_REQ_OFFSET 0x0U
+#define IPI_BUFFER_RESP_OFFSET 0x20U
+
+/*********************************************************************
+ * Platform specific IPI API declarations
+ ********************************************************************/
+
+/* Configure IPI table for zynqmp */
+void zynqmp_ipi_config_table_init(void);
+
+#endif /* PLAT_IPI_H */
diff --git a/plat/xilinx/zynqmp/include/plat_macros.S b/plat/xilinx/zynqmp/include/plat_macros.S
new file mode 100644
index 0000000..bf1ff82
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/plat_macros.S
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef PLAT_MACROS_S
+#define PLAT_MACROS_S
+
+#include <arm_macros.S>
+#include <cci_macros.S>
+#include "zynqmp_def.h"
+
+ /* ---------------------------------------------
+ * The below required platform porting macro
+ * prints out relevant GIC and CCI registers
+ * whenever an unhandled exception is taken in
+ * BL31.
+ * Clobbers: x0 - x10, x16, x17, sp
+ * ---------------------------------------------
+ */
+ .macro plat_crash_print_regs
+ mov_imm x17, BASE_GICC_BASE
+ mov_imm x16, BASE_GICD_BASE
+ arm_print_gic_regs
+ print_cci_regs
+ .endm
+
+#endif /* PLAT_MACROS_S */
diff --git a/plat/xilinx/zynqmp/include/plat_pm_common.h b/plat/xilinx/zynqmp/include/plat_pm_common.h
new file mode 100644
index 0000000..a57aebe
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/plat_pm_common.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Contains platform specific definitions of commonly used macros data types
+ * for PU Power Management. This file should be common for all PU's.
+ */
+
+#ifndef PLAT_PM_COMMON_H
+#define PLAT_PM_COMMON_H
+
+#include <stdint.h>
+#include <common/debug.h>
+#include "pm_defs.h"
+
+
+#define ZYNQMP_TZ_VERSION_MAJOR 1
+#define ZYNQMP_TZ_VERSION_MINOR 0
+#define ZYNQMP_TZ_VERSION ((ZYNQMP_TZ_VERSION_MAJOR << 16) | \
+ ZYNQMP_TZ_VERSION_MINOR)
+#endif /* _PLAT_PM_COMMON_H_ */
diff --git a/plat/xilinx/zynqmp/include/plat_private.h b/plat/xilinx/zynqmp/include/plat_private.h
new file mode 100644
index 0000000..534777b
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/plat_private.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLAT_PRIVATE_H
+#define PLAT_PRIVATE_H
+
+#include <stdint.h>
+
+#include <bl31/interrupt_mgmt.h>
+#include <common/bl_common.h>
+#include <drivers/cadence/cdns_uart.h>
+
+void zynqmp_config_setup(void);
+
+uint32_t zynqmp_calc_core_pos(u_register_t mpidr);
+
+/* ZynqMP specific functions */
+uint32_t zynqmp_get_uart_clk(void);
+uint32_t zynqmp_get_bootmode(void);
+
+
+#if ZYNQMP_WDT_RESTART
+/*
+ * Register handler to specific GIC entrance
+ * for INTR_TYPE_EL3 type of interrupt
+ */
+int request_intr_type_el3(uint32_t, interrupt_type_handler_t);
+#endif
+
+#endif /* PLAT_PRIVATE_H */
diff --git a/plat/xilinx/zynqmp/include/platform_def.h b/plat/xilinx/zynqmp/include/platform_def.h
new file mode 100644
index 0000000..c2d22c2
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/platform_def.h
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2014-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PLATFORM_DEF_H
+#define PLATFORM_DEF_H
+
+#include <arch.h>
+#include <common/interrupt_props.h>
+#include <drivers/arm/gic_common.h>
+#include <lib/utils_def.h>
+
+#include "zynqmp_def.h"
+
+/*******************************************************************************
+ * Generic platform constants
+ ******************************************************************************/
+
+/* Size of cacheable stacks */
+#define PLATFORM_STACK_SIZE 0x440
+
+#define PLATFORM_CORE_COUNT U(4)
+#define PLAT_NUM_POWER_DOMAINS U(5)
+#define PLAT_MAX_PWR_LVL U(1)
+#define PLAT_MAX_RET_STATE U(1)
+#define PLAT_MAX_OFF_STATE U(2)
+
+/*******************************************************************************
+ * BL31 specific defines.
+ ******************************************************************************/
+/*
+ * Put BL31 at the top of the Trusted SRAM (just below the shared memory, if
+ * present). BL31_BASE is calculated using the current BL31 debug size plus a
+ * little space for growth.
+ */
+#ifndef ZYNQMP_ATF_MEM_BASE
+#if !DEBUG && defined(SPD_none) && !SDEI_SUPPORT
+# define BL31_BASE U(0xfffea000)
+# define BL31_LIMIT U(0x100000000)
+#else
+# define BL31_BASE U(0xfffe5000)
+# define BL31_LIMIT U(0x100000000)
+#endif
+#else
+# define BL31_BASE (ZYNQMP_ATF_MEM_BASE)
+# define BL31_LIMIT (ZYNQMP_ATF_MEM_BASE + ZYNQMP_ATF_MEM_SIZE - 1)
+# ifdef ZYNQMP_ATF_MEM_PROGBITS_SIZE
+# define BL31_PROGBITS_LIMIT (ZYNQMP_ATF_MEM_BASE + ZYNQMP_ATF_MEM_PROGBITS_SIZE - 1)
+# endif
+#endif
+
+/*******************************************************************************
+ * BL32 specific defines.
+ ******************************************************************************/
+#ifndef ZYNQMP_BL32_MEM_BASE
+# define BL32_BASE U(0x60000000)
+# define BL32_LIMIT U(0x7fffffff)
+#else
+# define BL32_BASE (ZYNQMP_BL32_MEM_BASE)
+# define BL32_LIMIT (ZYNQMP_BL32_MEM_BASE + ZYNQMP_BL32_MEM_SIZE - 1)
+#endif
+
+/*******************************************************************************
+ * BL33 specific defines.
+ ******************************************************************************/
+#ifndef PRELOADED_BL33_BASE
+# define PLAT_ARM_NS_IMAGE_BASE U(0x8000000)
+#else
+# define PLAT_ARM_NS_IMAGE_BASE PRELOADED_BL33_BASE
+#endif
+
+/*******************************************************************************
+ * TSP specific defines.
+ ******************************************************************************/
+#define TSP_SEC_MEM_BASE BL32_BASE
+#define TSP_SEC_MEM_SIZE (BL32_LIMIT - BL32_BASE + 1)
+
+/* ID of the secure physical generic timer interrupt used by the TSP */
+#define TSP_IRQ_SEC_PHY_TIMER ARM_IRQ_SEC_PHY_TIMER
+
+/*******************************************************************************
+ * Platform specific page table and MMU setup constants
+ ******************************************************************************/
+#define XILINX_OF_BOARD_DTB_ADDR U(0x100000)
+#define XILINX_OF_BOARD_DTB_MAX_SIZE U(0x200000)
+#define PLAT_DDR_LOWMEM_MAX U(0x80000000)
+
+#define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32)
+#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
+#if (BL31_LIMIT < PLAT_DDR_LOWMEM_MAX)
+#define MAX_MMAP_REGIONS 8
+#define MAX_XLAT_TABLES 6
+#else
+#define MAX_MMAP_REGIONS 7
+#define MAX_XLAT_TABLES 5
+#endif
+
+#define CACHE_WRITEBACK_SHIFT 6
+#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT)
+
+#define ZYNQMP_SDEI_SGI_PRIVATE U(8)
+
+/* Platform macros to support exception handling framework */
+#define PLAT_PRI_BITS U(3)
+#define PLAT_SDEI_CRITICAL_PRI 0x10
+#define PLAT_SDEI_NORMAL_PRI 0x20
+
+#define PLAT_ARM_GICD_BASE BASE_GICD_BASE
+#define PLAT_ARM_GICC_BASE BASE_GICC_BASE
+/*
+ * Define properties of Group 1 Secure and Group 0 interrupts as per GICv3
+ * terminology. On a GICv2 system or mode, the lists will be merged and treated
+ * as Group 0 interrupts.
+ */
+#if !ZYNQMP_WDT_RESTART
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE)
+#else
+#define PLAT_ARM_G1S_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_LEVEL), \
+ INTR_PROP_DESC(IRQ_TTC3_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE), \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \
+ GIC_INTR_CFG_EDGE)
+#endif
+
+#define PLAT_ARM_G0_IRQ_PROPS(grp) \
+ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, PLAT_SDEI_NORMAL_PRI, grp, \
+ GIC_INTR_CFG_EDGE)
+
+#endif /* PLATFORM_DEF_H */
diff --git a/plat/xilinx/zynqmp/include/zynqmp_def.h b/plat/xilinx/zynqmp/include/zynqmp_def.h
new file mode 100644
index 0000000..428bed5
--- /dev/null
+++ b/plat/xilinx/zynqmp/include/zynqmp_def.h
@@ -0,0 +1,365 @@
+/*
+ * Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ZYNQMP_DEF_H
+#define ZYNQMP_DEF_H
+
+#include <plat/arm/common/smccc_def.h>
+#include <plat/common/common_def.h>
+
+#define ZYNQMP_CONSOLE_ID_cadence 1
+#define ZYNQMP_CONSOLE_ID_cadence0 1
+#define ZYNQMP_CONSOLE_ID_cadence1 2
+#define ZYNQMP_CONSOLE_ID_dcc 3
+
+#define ZYNQMP_CONSOLE_IS(con) (ZYNQMP_CONSOLE_ID_ ## con == ZYNQMP_CONSOLE)
+
+/* Default counter frequency */
+#define ZYNQMP_DEFAULT_COUNTER_FREQ 0U
+
+/* Firmware Image Package */
+#define ZYNQMP_PRIMARY_CPU 0
+
+/* Memory location options for Shared data and TSP in ZYNQMP */
+#define ZYNQMP_IN_TRUSTED_SRAM 0
+#define ZYNQMP_IN_TRUSTED_DRAM 1
+
+/*******************************************************************************
+ * ZYNQMP memory map related constants
+ ******************************************************************************/
+/* Aggregate of all devices in the first GB */
+#define DEVICE0_BASE U(0xFF000000)
+#define DEVICE0_SIZE U(0x00E00000)
+#define DEVICE1_BASE U(0xF9000000)
+#define DEVICE1_SIZE U(0x00800000)
+
+/* For cpu reset APU space here too 0xFE5F1000 CRF_APB*/
+#define CRF_APB_BASE U(0xFD1A0000)
+#define CRF_APB_SIZE U(0x00600000)
+#define CRF_APB_CLK_BASE U(0xFD1A0020)
+
+/* CRF registers and bitfields */
+#define CRF_APB_RST_FPD_APU (CRF_APB_BASE + 0X00000104)
+
+#define CRF_APB_RST_FPD_APU_ACPU_RESET (U(1) << 0)
+#define CRF_APB_RST_FPD_APU_ACPU_PWRON_RESET (U(1) << 10)
+
+/* CRL registers and bitfields */
+#define CRL_APB_BASE U(0xFF5E0000)
+#define CRL_APB_BOOT_MODE_USER (CRL_APB_BASE + 0x200)
+#define CRL_APB_RESET_CTRL (CRL_APB_BASE + 0x218)
+#define CRL_APB_RST_LPD_TOP (CRL_APB_BASE + 0x23C)
+#define CRL_APB_BOOT_PIN_CTRL (CRL_APB_BASE + U(0x250))
+#define CRL_APB_CLK_BASE U(0xFF5E0020)
+
+#define CRL_APB_RPU_AMBA_RESET (U(1) << 2)
+#define CRL_APB_RPLL_CTRL_BYPASS (U(1) << 3)
+
+#define CRL_APB_RESET_CTRL_SOFT_RESET (U(1) << 4)
+
+#define CRL_APB_BOOT_MODE_MASK (U(0xf) << 0)
+#define CRL_APB_BOOT_PIN_MASK (U(0xf0f) << 0)
+#define CRL_APB_BOOT_DRIVE_PIN_1_SHIFT U(9)
+#define CRL_APB_BOOT_ENABLE_PIN_1_SHIFT U(1)
+#define CRL_APB_BOOT_ENABLE_PIN_1 (U(0x1) << \
+ CRL_APB_BOOT_ENABLE_PIN_1_SHIFT)
+#define CRL_APB_BOOT_DRIVE_PIN_1 (U(0x1) << \
+ CRL_APB_BOOT_DRIVE_PIN_1_SHIFT)
+#define ZYNQMP_BOOTMODE_JTAG U(0)
+#define ZYNQMP_ULPI_RESET_VAL_HIGH (CRL_APB_BOOT_ENABLE_PIN_1 | \
+ CRL_APB_BOOT_DRIVE_PIN_1)
+#define ZYNQMP_ULPI_RESET_VAL_LOW CRL_APB_BOOT_ENABLE_PIN_1
+
+/* system counter registers and bitfields */
+#define IOU_SCNTRS_BASE U(0xFF260000)
+#define IOU_SCNTRS_BASEFREQ (IOU_SCNTRS_BASE + 0x20)
+
+/* APU registers and bitfields */
+#define APU_BASE U(0xFD5C0000)
+#define APU_CONFIG_0 (APU_BASE + 0x20)
+#define APU_RVBAR_L_0 (APU_BASE + 0x40)
+#define APU_RVBAR_H_0 (APU_BASE + 0x44)
+#define APU_PWRCTL (APU_BASE + 0x90)
+
+#define APU_CONFIG_0_VINITHI_SHIFT 8
+#define APU_0_PWRCTL_CPUPWRDWNREQ_MASK 1
+#define APU_1_PWRCTL_CPUPWRDWNREQ_MASK 2
+#define APU_2_PWRCTL_CPUPWRDWNREQ_MASK 4
+#define APU_3_PWRCTL_CPUPWRDWNREQ_MASK 8
+
+/* PMU registers and bitfields */
+#define PMU_GLOBAL_BASE U(0xFFD80000)
+#define PMU_GLOBAL_CNTRL (PMU_GLOBAL_BASE + 0)
+#define PMU_GLOBAL_GEN_STORAGE6 (PMU_GLOBAL_BASE + 0x48)
+#define PMU_GLOBAL_REQ_PWRUP_STATUS (PMU_GLOBAL_BASE + 0x110)
+#define PMU_GLOBAL_REQ_PWRUP_EN (PMU_GLOBAL_BASE + 0x118)
+#define PMU_GLOBAL_REQ_PWRUP_DIS (PMU_GLOBAL_BASE + 0x11c)
+#define PMU_GLOBAL_REQ_PWRUP_TRIG (PMU_GLOBAL_BASE + 0x120)
+
+#define PMU_GLOBAL_CNTRL_FW_IS_PRESENT (1 << 4)
+
+/*******************************************************************************
+ * CCI-400 related constants
+ ******************************************************************************/
+#define PLAT_ARM_CCI_BASE U(0xFD6E0000)
+#define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX 3
+#define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX 4
+
+/*******************************************************************************
+ * GIC-400 & interrupt handling related constants
+ ******************************************************************************/
+#define BASE_GICD_BASE U(0xF9010000)
+#define BASE_GICC_BASE U(0xF9020000)
+#define BASE_GICH_BASE U(0xF9040000)
+#define BASE_GICV_BASE U(0xF9060000)
+
+#if ZYNQMP_WDT_RESTART
+#define IRQ_SEC_IPI_APU 67
+#define IRQ_TTC3_1 77
+#define TTC3_BASE_ADDR U(0xFF140000)
+#define TTC3_INTR_REGISTER_1 (TTC3_BASE_ADDR + 0x54)
+#define TTC3_INTR_ENABLE_1 (TTC3_BASE_ADDR + 0x60)
+#endif
+
+#define ARM_IRQ_SEC_PHY_TIMER 29
+
+#define ARM_IRQ_SEC_SGI_0 8
+#define ARM_IRQ_SEC_SGI_1 9
+#define ARM_IRQ_SEC_SGI_2 10
+#define ARM_IRQ_SEC_SGI_3 11
+#define ARM_IRQ_SEC_SGI_4 12
+#define ARM_IRQ_SEC_SGI_5 13
+#define ARM_IRQ_SEC_SGI_6 14
+#define ARM_IRQ_SEC_SGI_7 15
+
+#define MAX_INTR_EL3 128
+
+/*******************************************************************************
+ * UART related constants
+ ******************************************************************************/
+#define ZYNQMP_UART0_BASE U(0xFF000000)
+#define ZYNQMP_UART1_BASE U(0xFF010000)
+
+#if ZYNQMP_CONSOLE_IS(cadence) || ZYNQMP_CONSOLE_IS(dcc)
+# define ZYNQMP_UART_BASE ZYNQMP_UART0_BASE
+#elif ZYNQMP_CONSOLE_IS(cadence1)
+# define ZYNQMP_UART_BASE ZYNQMP_UART1_BASE
+#else
+# error "invalid ZYNQMP_CONSOLE"
+#endif
+
+#define ZYNQMP_CRASH_UART_BASE ZYNQMP_UART_BASE
+/* impossible to call C routine how it is done now - hardcode any value */
+#define ZYNQMP_CRASH_UART_CLK_IN_HZ 100000000 /* FIXME */
+/* Must be non zero */
+#define ZYNQMP_UART_BAUDRATE 115200
+
+/* Silicon version detection */
+#define ZYNQMP_SILICON_VER_MASK 0xF000
+#define ZYNQMP_SILICON_VER_SHIFT 12
+#define ZYNQMP_CSU_VERSION_SILICON 0
+#define ZYNQMP_CSU_VERSION_QEMU 3
+
+#define ZYNQMP_RTL_VER_MASK 0xFF0U
+#define ZYNQMP_RTL_VER_SHIFT 4
+
+#define ZYNQMP_PS_VER_MASK 0xFU
+#define ZYNQMP_PS_VER_SHIFT 0
+
+#define ZYNQMP_CSU_BASEADDR U(0xFFCA0000)
+#define ZYNQMP_CSU_IDCODE_OFFSET 0x40U
+
+#define ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT 0U
+#define ZYNQMP_CSU_IDCODE_XILINX_ID_MASK (0xFFFU << \
+ ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT)
+#define ZYNQMP_CSU_IDCODE_XILINX_ID 0x093
+
+#define ZYNQMP_CSU_IDCODE_SVD_SHIFT 12U
+#define ZYNQMP_CSU_IDCODE_SVD_MASK (0x7U << \
+ ZYNQMP_CSU_IDCODE_SVD_SHIFT)
+#define ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT 15U
+#define ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK (0xFU << \
+ ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT)
+#define ZYNQMP_CSU_IDCODE_SUB_FAMILY_SHIFT 19U
+#define ZYNQMP_CSU_IDCODE_SUB_FAMILY_MASK (0x3U << \
+ ZYNQMP_CSU_IDCODE_SUB_FAMILY_SHIFT)
+#define ZYNQMP_CSU_IDCODE_FAMILY_SHIFT 21U
+#define ZYNQMP_CSU_IDCODE_FAMILY_MASK (0x7FU << \
+ ZYNQMP_CSU_IDCODE_FAMILY_SHIFT)
+#define ZYNQMP_CSU_IDCODE_FAMILY 0x23
+
+#define ZYNQMP_CSU_IDCODE_REVISION_SHIFT 28U
+#define ZYNQMP_CSU_IDCODE_REVISION_MASK (0xFU << \
+ ZYNQMP_CSU_IDCODE_REVISION_SHIFT)
+#define ZYNQMP_CSU_IDCODE_REVISION 0U
+
+#define ZYNQMP_CSU_VERSION_OFFSET 0x44U
+
+/* Efuse */
+#define EFUSE_BASEADDR U(0xFFCC0000)
+#define EFUSE_IPDISABLE_OFFSET 0x1018
+#define EFUSE_IPDISABLE_VERSION 0x1FFU
+#define ZYNQMP_EFUSE_IPDISABLE_SHIFT 20
+
+/* Access control register defines */
+#define ACTLR_EL3_L2ACTLR_BIT (1 << 6)
+#define ACTLR_EL3_CPUACTLR_BIT (1 << 0)
+
+#define FPD_SLCR_BASEADDR U(0xFD610000)
+#define IOU_SLCR_BASEADDR U(0xFF180000)
+
+#define ZYNQMP_RPU_GLBL_CNTL U(0xFF9A0000)
+#define ZYNQMP_RPU0_CFG U(0xFF9A0100)
+#define ZYNQMP_RPU1_CFG U(0xFF9A0200)
+#define ZYNQMP_SLSPLIT_MASK U(0x08)
+#define ZYNQMP_TCM_COMB_MASK U(0x40)
+#define ZYNQMP_SLCLAMP_MASK U(0x10)
+#define ZYNQMP_VINITHI_MASK U(0x04)
+
+/* Tap delay bypass */
+#define IOU_TAPDLY_BYPASS U(0XFF180390)
+#define TAP_DELAY_MASK U(0x7)
+
+/* SGMII mode */
+#define IOU_GEM_CTRL U(0xFF180360)
+#define IOU_GEM_CLK_CTRL U(0xFF180308)
+#define SGMII_SD_MASK U(0x3)
+#define SGMII_SD_OFFSET U(2)
+#define SGMII_PCS_SD_0 U(0x0)
+#define SGMII_PCS_SD_1 U(0x1)
+#define SGMII_PCS_SD_PHY U(0x2)
+#define GEM_SGMII_MASK U(0x4)
+#define GEM_CLK_CTRL_MASK U(0xF)
+#define GEM_CLK_CTRL_OFFSET U(5)
+#define GEM_RX_SRC_SEL_GTR U(0x1)
+#define GEM_SGMII_MODE U(0x4)
+
+/* SD DLL reset */
+#define ZYNQMP_SD_DLL_CTRL U(0xFF180358)
+#define ZYNQMP_SD0_DLL_RST_MASK U(0x00000004)
+#define ZYNQMP_SD0_DLL_RST U(0x00000004)
+#define ZYNQMP_SD1_DLL_RST_MASK U(0x00040000)
+#define ZYNQMP_SD1_DLL_RST U(0x00040000)
+
+/* SD tap delay */
+#define ZYNQMP_SD_DLL_CTRL U(0xFF180358)
+#define ZYNQMP_SD_ITAP_DLY U(0xFF180314)
+#define ZYNQMP_SD_OTAP_DLY U(0xFF180318)
+#define ZYNQMP_SD_TAP_OFFSET U(16)
+#define ZYNQMP_SD_ITAPCHGWIN_MASK U(0x200)
+#define ZYNQMP_SD_ITAPCHGWIN U(0x200)
+#define ZYNQMP_SD_ITAPDLYENA_MASK U(0x100)
+#define ZYNQMP_SD_ITAPDLYENA U(0x100)
+#define ZYNQMP_SD_ITAPDLYSEL_MASK U(0xFF)
+#define ZYNQMP_SD_OTAPDLYSEL_MASK U(0x3F)
+#define ZYNQMP_SD_OTAPDLYENA_MASK U(0x40)
+#define ZYNQMP_SD_OTAPDLYENA U(0x40)
+
+/* Clock control registers */
+/* Full power domain clocks */
+#define CRF_APB_APLL_CTRL (CRF_APB_CLK_BASE + 0x00)
+#define CRF_APB_DPLL_CTRL (CRF_APB_CLK_BASE + 0x0c)
+#define CRF_APB_VPLL_CTRL (CRF_APB_CLK_BASE + 0x18)
+#define CRF_APB_PLL_STATUS (CRF_APB_CLK_BASE + 0x24)
+#define CRF_APB_APLL_TO_LPD_CTRL (CRF_APB_CLK_BASE + 0x28)
+#define CRF_APB_DPLL_TO_LPD_CTRL (CRF_APB_CLK_BASE + 0x2c)
+#define CRF_APB_VPLL_TO_LPD_CTRL (CRF_APB_CLK_BASE + 0x30)
+/* Peripheral clocks */
+#define CRF_APB_ACPU_CTRL (CRF_APB_CLK_BASE + 0x40)
+#define CRF_APB_DBG_TRACE_CTRL (CRF_APB_CLK_BASE + 0x44)
+#define CRF_APB_DBG_FPD_CTRL (CRF_APB_CLK_BASE + 0x48)
+#define CRF_APB_DP_VIDEO_REF_CTRL (CRF_APB_CLK_BASE + 0x50)
+#define CRF_APB_DP_AUDIO_REF_CTRL (CRF_APB_CLK_BASE + 0x54)
+#define CRF_APB_DP_STC_REF_CTRL (CRF_APB_CLK_BASE + 0x5c)
+#define CRF_APB_DDR_CTRL (CRF_APB_CLK_BASE + 0x60)
+#define CRF_APB_GPU_REF_CTRL (CRF_APB_CLK_BASE + 0x64)
+#define CRF_APB_SATA_REF_CTRL (CRF_APB_CLK_BASE + 0x80)
+#define CRF_APB_PCIE_REF_CTRL (CRF_APB_CLK_BASE + 0x94)
+#define CRF_APB_GDMA_REF_CTRL (CRF_APB_CLK_BASE + 0x98)
+#define CRF_APB_DPDMA_REF_CTRL (CRF_APB_CLK_BASE + 0x9c)
+#define CRF_APB_TOPSW_MAIN_CTRL (CRF_APB_CLK_BASE + 0xa0)
+#define CRF_APB_TOPSW_LSBUS_CTRL (CRF_APB_CLK_BASE + 0xa4)
+#define CRF_APB_GTGREF0_REF_CTRL (CRF_APB_CLK_BASE + 0xa8)
+#define CRF_APB_DBG_TSTMP_CTRL (CRF_APB_CLK_BASE + 0xd8)
+
+/* Low power domain clocks */
+#define CRL_APB_IOPLL_CTRL (CRL_APB_CLK_BASE + 0x00)
+#define CRL_APB_RPLL_CTRL (CRL_APB_CLK_BASE + 0x10)
+#define CRL_APB_PLL_STATUS (CRL_APB_CLK_BASE + 0x20)
+#define CRL_APB_IOPLL_TO_FPD_CTRL (CRL_APB_CLK_BASE + 0x24)
+#define CRL_APB_RPLL_TO_FPD_CTRL (CRL_APB_CLK_BASE + 0x28)
+/* Peripheral clocks */
+#define CRL_APB_USB3_DUAL_REF_CTRL (CRL_APB_CLK_BASE + 0x2c)
+#define CRL_APB_GEM0_REF_CTRL (CRL_APB_CLK_BASE + 0x30)
+#define CRL_APB_GEM1_REF_CTRL (CRL_APB_CLK_BASE + 0x34)
+#define CRL_APB_GEM2_REF_CTRL (CRL_APB_CLK_BASE + 0x38)
+#define CRL_APB_GEM3_REF_CTRL (CRL_APB_CLK_BASE + 0x3c)
+#define CRL_APB_USB0_BUS_REF_CTRL (CRL_APB_CLK_BASE + 0x40)
+#define CRL_APB_USB1_BUS_REF_CTRL (CRL_APB_CLK_BASE + 0x44)
+#define CRL_APB_QSPI_REF_CTRL (CRL_APB_CLK_BASE + 0x48)
+#define CRL_APB_SDIO0_REF_CTRL (CRL_APB_CLK_BASE + 0x4c)
+#define CRL_APB_SDIO1_REF_CTRL (CRL_APB_CLK_BASE + 0x50)
+#define CRL_APB_UART0_REF_CTRL (CRL_APB_CLK_BASE + 0x54)
+#define CRL_APB_UART1_REF_CTRL (CRL_APB_CLK_BASE + 0x58)
+#define CRL_APB_SPI0_REF_CTRL (CRL_APB_CLK_BASE + 0x5c)
+#define CRL_APB_SPI1_REF_CTRL (CRL_APB_CLK_BASE + 0x60)
+#define CRL_APB_CAN0_REF_CTRL (CRL_APB_CLK_BASE + 0x64)
+#define CRL_APB_CAN1_REF_CTRL (CRL_APB_CLK_BASE + 0x68)
+#define CRL_APB_CPU_R5_CTRL (CRL_APB_CLK_BASE + 0x70)
+#define CRL_APB_IOU_SWITCH_CTRL (CRL_APB_CLK_BASE + 0x7c)
+#define CRL_APB_CSU_PLL_CTRL (CRL_APB_CLK_BASE + 0x80)
+#define CRL_APB_PCAP_CTRL (CRL_APB_CLK_BASE + 0x84)
+#define CRL_APB_LPD_SWITCH_CTRL (CRL_APB_CLK_BASE + 0x88)
+#define CRL_APB_LPD_LSBUS_CTRL (CRL_APB_CLK_BASE + 0x8c)
+#define CRL_APB_DBG_LPD_CTRL (CRL_APB_CLK_BASE + 0x90)
+#define CRL_APB_NAND_REF_CTRL (CRL_APB_CLK_BASE + 0x94)
+#define CRL_APB_ADMA_REF_CTRL (CRL_APB_CLK_BASE + 0x98)
+#define CRL_APB_PL0_REF_CTRL (CRL_APB_CLK_BASE + 0xa0)
+#define CRL_APB_PL1_REF_CTRL (CRL_APB_CLK_BASE + 0xa4)
+#define CRL_APB_PL2_REF_CTRL (CRL_APB_CLK_BASE + 0xa8)
+#define CRL_APB_PL3_REF_CTRL (CRL_APB_CLK_BASE + 0xac)
+#define CRL_APB_PL0_THR_CNT (CRL_APB_CLK_BASE + 0xb4)
+#define CRL_APB_PL1_THR_CNT (CRL_APB_CLK_BASE + 0xbc)
+#define CRL_APB_PL2_THR_CNT (CRL_APB_CLK_BASE + 0xc4)
+#define CRL_APB_PL3_THR_CNT (CRL_APB_CLK_BASE + 0xdc)
+#define CRL_APB_GEM_TSU_REF_CTRL (CRL_APB_CLK_BASE + 0xe0)
+#define CRL_APB_DLL_REF_CTRL (CRL_APB_CLK_BASE + 0xe4)
+#define CRL_APB_AMS_REF_CTRL (CRL_APB_CLK_BASE + 0xe8)
+#define CRL_APB_I2C0_REF_CTRL (CRL_APB_CLK_BASE + 0x100)
+#define CRL_APB_I2C1_REF_CTRL (CRL_APB_CLK_BASE + 0x104)
+#define CRL_APB_TIMESTAMP_REF_CTRL (CRL_APB_CLK_BASE + 0x108)
+#define IOU_SLCR_GEM_CLK_CTRL (IOU_SLCR_BASEADDR + 0x308)
+#define IOU_SLCR_CAN_MIO_CTRL (IOU_SLCR_BASEADDR + 0x304)
+#define FPD_SLCR_WDT_CLK_SEL (FPD_SLCR_BASEADDR + 0x100)
+#define IOU_SLCR_WDT_CLK_SEL (IOU_SLCR_BASEADDR + 0x300)
+
+/* Global general storage register base address */
+#define GGS_BASEADDR (0xFFD80030U)
+#define GGS_NUM_REGS U(4)
+
+/* Persistent global general storage register base address */
+#define PGGS_BASEADDR (0xFFD80050U)
+#define PGGS_NUM_REGS U(4)
+
+/* PMU GGS4 register 4 is used for warm restart boot health status */
+#define PMU_GLOBAL_GEN_STORAGE4 (GGS_BASEADDR + 0x10)
+/* Warm restart boot health status mask */
+#define PM_BOOT_HEALTH_STATUS_MASK U(0x01)
+/* WDT restart scope shift and mask */
+#define RESTART_SCOPE_SHIFT (3)
+#define RESTART_SCOPE_MASK (0x3U << RESTART_SCOPE_SHIFT)
+
+/* AFI registers */
+#define AFIFM6_WRCTRL U(13)
+#define FABRIC_WIDTH U(3)
+
+/* CSUDMA Module Base Address*/
+#define CSUDMA_BASE U(0xFFC80000)
+
+/* RSA-CORE Module Base Address*/
+#define RSA_CORE_BASE U(0xFFCE0000)
+
+#endif /* ZYNQMP_DEF_H */
diff --git a/plat/xilinx/zynqmp/plat_psci.c b/plat/xilinx/zynqmp/plat_psci.c
new file mode 100644
index 0000000..b7408b1
--- /dev/null
+++ b/plat/xilinx/zynqmp/plat_psci.c
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <errno.h>
+
+#include <arch_helpers.h>
+#include <common/debug.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/psci/psci.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat/common/platform.h>
+
+#include <plat_private.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+
+static uintptr_t zynqmp_sec_entry;
+
+static void zynqmp_cpu_standby(plat_local_state_t cpu_state)
+{
+ VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state);
+
+ dsb();
+ wfi();
+}
+
+static int32_t zynqmp_pwr_domain_on(u_register_t mpidr)
+{
+ uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr);
+ const struct pm_proc *proc;
+ uint32_t buff[3];
+ enum pm_ret_status ret;
+
+ VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr);
+
+ if (cpu_id == -1) {
+ return PSCI_E_INTERN_FAIL;
+ }
+ proc = pm_get_proc(cpu_id);
+
+ /* Check the APU proc status before wakeup */
+ ret = pm_get_node_status(proc->node_id, buff);
+ if ((ret != PM_RET_SUCCESS) || (buff[0] == PM_PROC_STATE_SUSPENDING)) {
+ return PSCI_E_INTERN_FAIL;
+ }
+
+ /* Clear power down request */
+ pm_client_wakeup(proc);
+
+ /* Send request to PMU to wake up selected APU CPU core */
+ pm_req_wakeup(proc->node_id, 1, zynqmp_sec_entry, REQ_ACK_BLOCKING);
+
+ return PSCI_E_SUCCESS;
+}
+
+static void zynqmp_pwr_domain_off(const psci_power_state_t *target_state)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+ for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+ }
+
+ /* Prevent interrupts from spuriously waking up this cpu */
+ gicv2_cpuif_disable();
+
+ /*
+ * Send request to PMU to power down the appropriate APU CPU
+ * core.
+ * According to PSCI specification, CPU_off function does not
+ * have resume address and CPU core can only be woken up
+ * invoking CPU_on function, during which resume address will
+ * be set.
+ */
+ pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0);
+}
+
+static void zynqmp_pwr_domain_suspend(const psci_power_state_t *target_state)
+{
+ uint32_t state;
+ uint32_t cpu_id = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+ for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++)
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+
+ state = target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE ?
+ PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE;
+
+ /* Send request to PMU to suspend this core */
+ pm_self_suspend(proc->node_id, MAX_LATENCY, state, zynqmp_sec_entry);
+
+ /* APU is to be turned off */
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ /* disable coherency */
+ plat_arm_interconnect_exit_coherency();
+ }
+}
+
+static void zynqmp_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+ for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+ }
+ plat_arm_gic_pcpu_init();
+ gicv2_cpuif_enable();
+}
+
+static void zynqmp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
+{
+ uint32_t cpu_id = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpu_id);
+
+ for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) {
+ VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n",
+ __func__, i, target_state->pwr_domain_state[i]);
+ }
+
+ /* Clear the APU power control register for this cpu */
+ pm_client_wakeup(proc);
+
+ /* enable coherency */
+ plat_arm_interconnect_enter_coherency();
+ /* APU was turned off */
+ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) {
+ plat_arm_gic_init();
+ } else {
+ gicv2_cpuif_enable();
+ gicv2_pcpu_distif_init();
+ }
+}
+
+/*******************************************************************************
+ * ZynqMP handlers to shutdown/reboot the system
+ ******************************************************************************/
+
+static void __dead2 zynqmp_system_off(void)
+{
+ /* disable coherency */
+ plat_arm_interconnect_exit_coherency();
+
+ /* Send the power down request to the PMU */
+ pm_system_shutdown(PMF_SHUTDOWN_TYPE_SHUTDOWN,
+ pm_get_shutdown_scope());
+
+ while (1) {
+ wfi();
+ }
+}
+
+static void __dead2 zynqmp_system_reset(void)
+{
+ /* disable coherency */
+ plat_arm_interconnect_exit_coherency();
+
+ /* Send the system reset request to the PMU */
+ pm_system_shutdown(PMF_SHUTDOWN_TYPE_RESET,
+ pm_get_shutdown_scope());
+
+ while (1) {
+ wfi();
+ }
+}
+
+static int32_t zynqmp_validate_power_state(uint32_t power_state,
+ psci_power_state_t *req_state)
+{
+ VERBOSE("%s: power_state: 0x%x\n", __func__, power_state);
+
+ uint32_t pstate = psci_get_pstate_type(power_state);
+
+ assert(req_state);
+
+ /* Sanity check the requested state */
+ if (pstate == PSTATE_TYPE_STANDBY) {
+ req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
+ } else {
+ req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE;
+ }
+ /* We expect the 'state id' to be zero */
+ if (psci_get_pstate_id(power_state)) {
+ return PSCI_E_INVALID_PARAMS;
+ }
+
+ return PSCI_E_SUCCESS;
+}
+
+static void zynqmp_get_sys_suspend_power_state(psci_power_state_t *req_state)
+{
+ req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE;
+ req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE;
+}
+
+/*******************************************************************************
+ * Export the platform handlers to enable psci to invoke them
+ ******************************************************************************/
+static const struct plat_psci_ops zynqmp_psci_ops = {
+ .cpu_standby = zynqmp_cpu_standby,
+ .pwr_domain_on = zynqmp_pwr_domain_on,
+ .pwr_domain_off = zynqmp_pwr_domain_off,
+ .pwr_domain_suspend = zynqmp_pwr_domain_suspend,
+ .pwr_domain_on_finish = zynqmp_pwr_domain_on_finish,
+ .pwr_domain_suspend_finish = zynqmp_pwr_domain_suspend_finish,
+ .system_off = zynqmp_system_off,
+ .system_reset = zynqmp_system_reset,
+ .validate_power_state = zynqmp_validate_power_state,
+ .get_sys_suspend_power_state = zynqmp_get_sys_suspend_power_state,
+};
+
+/*******************************************************************************
+ * Export the platform specific power ops.
+ ******************************************************************************/
+int plat_setup_psci_ops(uintptr_t sec_entrypoint,
+ const struct plat_psci_ops **psci_ops)
+{
+ zynqmp_sec_entry = sec_entrypoint;
+
+ *psci_ops = &zynqmp_psci_ops;
+
+ return 0;
+}
diff --git a/plat/xilinx/zynqmp/plat_topology.c b/plat/xilinx/zynqmp/plat_topology.c
new file mode 100644
index 0000000..41add9f
--- /dev/null
+++ b/plat/xilinx/zynqmp/plat_topology.c
@@ -0,0 +1,13 @@
+/*
+ * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#include <stdint.h>
+
+static const uint8_t plat_power_domain_tree_desc[] = {1, 4};
+
+const uint8_t *plat_get_power_domain_tree_desc(void)
+{
+ return plat_power_domain_tree_desc;
+}
diff --git a/plat/xilinx/zynqmp/plat_zynqmp.c b/plat/xilinx/zynqmp/plat_zynqmp.c
new file mode 100644
index 0000000..25ebac6
--- /dev/null
+++ b/plat/xilinx/zynqmp/plat_zynqmp.c
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <plat_private.h>
+#include <plat/common/platform.h>
+
+int32_t plat_core_pos_by_mpidr(u_register_t mpidr)
+{
+ if (mpidr & MPIDR_CLUSTER_MASK) {
+ return -1;
+ }
+
+ if ((mpidr & MPIDR_CPU_MASK) >= PLATFORM_CORE_COUNT) {
+ return -1;
+ }
+
+ return zynqmp_calc_core_pos(mpidr);
+}
diff --git a/plat/xilinx/zynqmp/platform.mk b/plat/xilinx/zynqmp/platform.mk
new file mode 100644
index 0000000..05adbd0
--- /dev/null
+++ b/plat/xilinx/zynqmp/platform.mk
@@ -0,0 +1,143 @@
+#
+# Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
+# Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+override ERRATA_A53_855873 := 1
+override PROGRAMMABLE_RESET_ADDRESS := 1
+PSCI_EXTENDED_STATE_ID := 1
+A53_DISABLE_NON_TEMPORAL_HINT := 0
+SEPARATE_CODE_AND_RODATA := 1
+ZYNQMP_WDT_RESTART := 0
+IPI_CRC_CHECK := 0
+override RESET_TO_BL31 := 1
+override WARMBOOT_ENABLE_DCACHE_EARLY := 1
+
+EL3_EXCEPTION_HANDLING := $(SDEI_SUPPORT)
+
+# pncd SPD requires secure SGI to be handled at EL1
+ifeq (${SPD},pncd)
+ifeq (${ZYNQMP_WDT_RESTART},1)
+$(error "Error: ZYNQMP_WDT_RESTART and SPD=pncd are incompatible")
+endif
+override GICV2_G0_FOR_EL3 := 0
+else
+override GICV2_G0_FOR_EL3 := 1
+endif
+
+# Do not enable SVE
+ENABLE_SVE_FOR_NS := 0
+
+WORKAROUND_CVE_2017_5715 := 0
+
+ARM_XLAT_TABLES_LIB_V1 := 1
+$(eval $(call assert_boolean,ARM_XLAT_TABLES_LIB_V1))
+$(eval $(call add_define,ARM_XLAT_TABLES_LIB_V1))
+
+ifdef ZYNQMP_ATF_MEM_BASE
+ $(eval $(call add_define,ZYNQMP_ATF_MEM_BASE))
+
+ ifndef ZYNQMP_ATF_MEM_SIZE
+ $(error "ZYNQMP_ATF_BASE defined without ZYNQMP_ATF_SIZE")
+ endif
+ $(eval $(call add_define,ZYNQMP_ATF_MEM_SIZE))
+
+ ifdef ZYNQMP_ATF_MEM_PROGBITS_SIZE
+ $(eval $(call add_define,ZYNQMP_ATF_MEM_PROGBITS_SIZE))
+ endif
+endif
+
+ifdef ZYNQMP_BL32_MEM_BASE
+ $(eval $(call add_define,ZYNQMP_BL32_MEM_BASE))
+
+ ifndef ZYNQMP_BL32_MEM_SIZE
+ $(error "ZYNQMP_BL32_BASE defined without ZYNQMP_BL32_SIZE")
+ endif
+ $(eval $(call add_define,ZYNQMP_BL32_MEM_SIZE))
+endif
+
+
+ifdef ZYNQMP_WDT_RESTART
+ $(eval $(call add_define,ZYNQMP_WDT_RESTART))
+endif
+
+ifdef ZYNQMP_IPI_CRC_CHECK
+ $(warning "ZYNQMP_IPI_CRC_CHECK macro is deprecated...instead please use IPI_CRC_CHECK.")
+endif
+
+ifdef IPI_CRC_CHECK
+ $(eval $(call add_define,IPI_CRC_CHECK))
+endif
+
+ifdef ZYNQMP_SECURE_EFUSES
+ $(eval $(call add_define,ZYNQMP_SECURE_EFUSES))
+endif
+
+PLAT_INCLUDES := -Iinclude/plat/arm/common/ \
+ -Iinclude/plat/arm/common/aarch64/ \
+ -Iplat/xilinx/common/include/ \
+ -Iplat/xilinx/common/ipi_mailbox_service/ \
+ -Iplat/xilinx/zynqmp/include/ \
+ -Iplat/xilinx/zynqmp/pm_service/ \
+
+include lib/libfdt/libfdt.mk
+# Include GICv2 driver files
+include drivers/arm/gic/v2/gicv2.mk
+
+PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \
+ lib/xlat_tables/aarch64/xlat_tables.c \
+ drivers/arm/dcc/dcc_console.c \
+ drivers/delay_timer/delay_timer.c \
+ drivers/delay_timer/generic_delay_timer.c \
+ ${GICV2_SOURCES} \
+ drivers/cadence/uart/aarch64/cdns_console.S \
+ plat/arm/common/arm_cci.c \
+ plat/arm/common/arm_common.c \
+ plat/arm/common/arm_gicv2.c \
+ plat/common/plat_gicv2.c \
+ plat/xilinx/common/ipi.c \
+ plat/xilinx/zynqmp/zynqmp_ipi.c \
+ plat/common/aarch64/crash_console_helpers.S \
+ plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S \
+ plat/xilinx/zynqmp/aarch64/zynqmp_common.c
+
+ZYNQMP_CONSOLE ?= cadence
+ifeq (${ZYNQMP_CONSOLE}, $(filter ${ZYNQMP_CONSOLE},cadence cadence0 cadence1 dcc))
+else
+ $(error "Please define ZYNQMP_CONSOLE")
+endif
+$(eval $(call add_define_val,ZYNQMP_CONSOLE,ZYNQMP_CONSOLE_ID_${ZYNQMP_CONSOLE}))
+
+BL31_SOURCES += drivers/arm/cci/cci.c \
+ lib/cpus/aarch64/aem_generic.S \
+ lib/cpus/aarch64/cortex_a53.S \
+ plat/common/plat_psci_common.c \
+ common/fdt_fixup.c \
+ ${LIBFDT_SRCS} \
+ plat/xilinx/common/ipi_mailbox_service/ipi_mailbox_svc.c \
+ plat/xilinx/common/pm_service/pm_ipi.c \
+ plat/xilinx/common/plat_startup.c \
+ plat/xilinx/zynqmp/bl31_zynqmp_setup.c \
+ plat/xilinx/zynqmp/plat_psci.c \
+ plat/xilinx/zynqmp/plat_zynqmp.c \
+ plat/xilinx/zynqmp/plat_topology.c \
+ plat/xilinx/zynqmp/sip_svc_setup.c \
+ plat/xilinx/zynqmp/pm_service/pm_svc_main.c \
+ plat/xilinx/zynqmp/pm_service/pm_api_sys.c \
+ plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c \
+ plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c \
+ plat/xilinx/zynqmp/pm_service/pm_api_clock.c \
+ plat/xilinx/zynqmp/pm_service/pm_client.c
+
+ifeq (${SDEI_SUPPORT},1)
+BL31_SOURCES += plat/xilinx/zynqmp/zynqmp_ehf.c \
+ plat/xilinx/zynqmp/zynqmp_sdei.c
+endif
+
+BL31_CPPFLAGS += -fno-jump-tables
+TF_CFLAGS_aarch64 += -mbranch-protection=none
+
+ifneq (${RESET_TO_BL31},1)
+ $(error "Using BL31 as the reset vector is only one option supported on ZynqMP. Please set RESET_TO_BL31 to 1.")
+endif
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.c b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
new file mode 100644
index 0000000..e61310a
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.c
@@ -0,0 +1,3048 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for clock control.
+ */
+
+#include <stdbool.h>
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+
+#include "pm_api_clock.h"
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_common.h"
+#include "pm_ipi.h"
+
+#define CLK_NODE_MAX (6U)
+
+#define CLK_PARENTS_ID_LEN (16U)
+#define CLK_TOPOLOGY_NODE_OFFSET (16U)
+#define CLK_TOPOLOGY_PAYLOAD_LEN (12U)
+#define CLK_PARENTS_PAYLOAD_LEN (12U)
+#define CLK_TYPE_SHIFT (2U)
+#define CLK_CLKFLAGS_SHIFT (8U)
+#define CLK_TYPEFLAGS_SHIFT (24U)
+#define CLK_TYPEFLAGS2_SHIFT (4U)
+#define CLK_TYPEFLAGS_BITS_MASK (0xFFU)
+#define CLK_TYPEFLAGS2_BITS_MASK (0x0F00U)
+#define CLK_TYPEFLAGS_BITS (8U)
+
+#define CLK_EXTERNAL_PARENT (PARENT_CLK_EXTERNAL << CLK_PARENTS_ID_LEN)
+
+#define NA_MULT (0U)
+#define NA_DIV (0U)
+#define NA_SHIFT (0U)
+#define NA_WIDTH (0U)
+#define NA_CLK_FLAGS (0U)
+#define NA_TYPE_FLAGS (0U)
+
+/* PLL nodes related definitions */
+#define PLL_PRESRC_MUX_SHIFT (20U)
+#define PLL_PRESRC_MUX_WIDTH (3U)
+#define PLL_POSTSRC_MUX_SHIFT (24U)
+#define PLL_POSTSRC_MUX_WIDTH (3U)
+#define PLL_DIV2_MUX_SHIFT (16U)
+#define PLL_DIV2_MUX_WIDTH (1U)
+#define PLL_BYPASS_MUX_SHIFT (3U)
+#define PLL_BYPASS_MUX_WIDTH (1U)
+
+/* Peripheral nodes related definitions */
+/* Peripheral Clocks */
+#define PERIPH_MUX_SHIFT (0U)
+#define PERIPH_MUX_WIDTH (3U)
+#define PERIPH_DIV1_SHIFT (8U)
+#define PERIPH_DIV1_WIDTH (6U)
+#define PERIPH_DIV2_SHIFT (16U)
+#define PERIPH_DIV2_WIDTH (6U)
+#define PERIPH_GATE_SHIFT (24U)
+#define PERIPH_GATE_WIDTH (1U)
+
+#define USB_GATE_SHIFT (25U)
+
+/* External clock related definitions */
+
+#define EXT_CLK_MIO_DATA(mio) \
+ [EXT_CLK_INDEX(EXT_CLK_MIO##mio)] = { \
+ .name = "mio_clk_"#mio, \
+ }
+
+#define EXT_CLK_INDEX(n) (n - CLK_MAX_OUTPUT_CLK)
+
+/* Clock control related definitions */
+#define BIT_MASK(x, y) (((1U << (y)) - 1) << (x))
+
+#define ISPLL(id) (id == CLK_APLL_INT || \
+ id == CLK_DPLL_INT || \
+ id == CLK_VPLL_INT || \
+ id == CLK_IOPLL_INT || \
+ id == CLK_RPLL_INT)
+
+
+#define PLLCTRL_BP_MASK BIT(3)
+#define PLLCTRL_RESET_MASK (1U)
+#define PLL_FRAC_OFFSET (8U)
+#define PLL_FRAC_MODE (1U)
+#define PLL_INT_MODE (0U)
+#define PLL_FRAC_MODE_MASK (0x80000000U)
+#define PLL_FRAC_MODE_SHIFT (31U)
+#define PLL_FRAC_DATA_MASK (0xFFFFU)
+#define PLL_FRAC_DATA_SHIFT (0U)
+#define PLL_FBDIV_MASK (0x7F00U)
+#define PLL_FBDIV_WIDTH (7U)
+#define PLL_FBDIV_SHIFT (8U)
+
+#define CLK_PLL_RESET_ASSERT (1U)
+#define CLK_PLL_RESET_RELEASE (2U)
+#define CLK_PLL_RESET_PULSE (CLK_PLL_RESET_ASSERT | CLK_PLL_RESET_RELEASE)
+
+/* Common topology definitions */
+#define GENERIC_MUX \
+ { \
+ .type = TYPE_MUX, \
+ .offset = PERIPH_MUX_SHIFT, \
+ .width = PERIPH_MUX_WIDTH, \
+ .clkflags = CLK_SET_RATE_NO_REPARENT | \
+ CLK_IS_BASIC, \
+ .typeflags = NA_TYPE_FLAGS, \
+ .mult = NA_MULT, \
+ .div = NA_DIV, \
+ }
+
+#define IGNORE_UNUSED_MUX \
+ { \
+ .type = TYPE_MUX, \
+ .offset = PERIPH_MUX_SHIFT, \
+ .width = PERIPH_MUX_WIDTH, \
+ .clkflags = CLK_IGNORE_UNUSED | \
+ CLK_SET_RATE_NO_REPARENT | \
+ CLK_IS_BASIC, \
+ .typeflags = NA_TYPE_FLAGS, \
+ .mult = NA_MULT, \
+ .div = NA_DIV, \
+ }
+
+#define GENERIC_DIV1 \
+ { \
+ .type = TYPE_DIV1, \
+ .offset = PERIPH_DIV1_SHIFT, \
+ .width = PERIPH_DIV1_WIDTH, \
+ .clkflags = CLK_SET_RATE_NO_REPARENT | \
+ CLK_IS_BASIC, \
+ .typeflags = CLK_DIVIDER_ONE_BASED | \
+ CLK_DIVIDER_ALLOW_ZERO, \
+ .mult = NA_MULT, \
+ .div = NA_DIV, \
+ }
+
+#define GENERIC_DIV2 \
+ { \
+ .type = TYPE_DIV2, \
+ .offset = PERIPH_DIV2_SHIFT, \
+ .width = PERIPH_DIV2_WIDTH, \
+ .clkflags = CLK_SET_RATE_NO_REPARENT | \
+ CLK_SET_RATE_PARENT | \
+ CLK_IS_BASIC, \
+ .typeflags = CLK_DIVIDER_ONE_BASED | \
+ CLK_DIVIDER_ALLOW_ZERO, \
+ .mult = NA_MULT, \
+ .div = NA_DIV, \
+ }
+
+#define IGNORE_UNUSED_DIV(id) \
+ { \
+ .type = TYPE_DIV##id, \
+ .offset = PERIPH_DIV##id##_SHIFT, \
+ .width = PERIPH_DIV##id##_WIDTH, \
+ .clkflags = CLK_IGNORE_UNUSED | \
+ CLK_SET_RATE_NO_REPARENT | \
+ CLK_IS_BASIC, \
+ .typeflags = CLK_DIVIDER_ONE_BASED | \
+ CLK_DIVIDER_ALLOW_ZERO, \
+ .mult = NA_MULT, \
+ .div = NA_DIV, \
+ }
+
+#define GENERIC_GATE \
+ { \
+ .type = TYPE_GATE, \
+ .offset = PERIPH_GATE_SHIFT, \
+ .width = PERIPH_GATE_WIDTH, \
+ .clkflags = CLK_SET_RATE_PARENT | \
+ CLK_SET_RATE_GATE | \
+ CLK_IS_BASIC, \
+ .typeflags = NA_TYPE_FLAGS, \
+ .mult = NA_MULT, \
+ .div = NA_DIV, \
+ }
+
+#define IGNORE_UNUSED_GATE \
+ { \
+ .type = TYPE_GATE, \
+ .offset = PERIPH_GATE_SHIFT, \
+ .width = PERIPH_GATE_WIDTH, \
+ .clkflags = CLK_SET_RATE_PARENT | \
+ CLK_IGNORE_UNUSED | \
+ CLK_IS_BASIC, \
+ .typeflags = NA_TYPE_FLAGS, \
+ .mult = NA_MULT, \
+ .div = NA_DIV, \
+ }
+
+/**
+ * struct pm_clock_node - Clock topology node information
+ * @type: Topology type (mux/div1/div2/gate/pll/fixed factor)
+ * @offset: Offset in control register
+ * @width: Width of the specific type in control register
+ * @clkflags: Clk specific flags
+ * @typeflags: Type specific flags
+ * @mult: Multiplier for fixed factor
+ * @div: Divisor for fixed factor
+ */
+struct pm_clock_node {
+ uint16_t clkflags;
+ uint16_t typeflags;
+ uint8_t type;
+ uint8_t offset;
+ uint8_t width;
+ uint8_t mult:4;
+ uint8_t div:4;
+};
+
+/**
+ * struct pm_clock - Clock structure
+ * @name: Clock name
+ * @control_reg: Control register address
+ * @status_reg: Status register address
+ * @parents: Parents for first clock node. Lower byte indicates parent
+ * clock id and upper byte indicate flags for that id.
+ * pm_clock_node: Clock nodes
+ */
+struct pm_clock {
+ char name[CLK_NAME_LEN];
+ uint8_t num_nodes;
+ uint32_t control_reg;
+ uint32_t status_reg;
+ int32_t (*parents)[];
+ struct pm_clock_node(*nodes)[];
+};
+
+/**
+ * struct pm_clock - Clock structure
+ * @name: Clock name
+ */
+struct pm_ext_clock {
+ char name[CLK_NAME_LEN];
+};
+
+/* PLL Clocks */
+static struct pm_clock_node generic_pll_nodes[] = {
+ {
+ .type = TYPE_PLL,
+ .offset = NA_SHIFT,
+ .width = NA_WIDTH,
+ .clkflags = CLK_SET_RATE_NO_REPARENT,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node ignore_unused_pll_nodes[] = {
+ {
+ .type = TYPE_PLL,
+ .offset = NA_SHIFT,
+ .width = NA_WIDTH,
+ .clkflags = CLK_IGNORE_UNUSED | CLK_SET_RATE_NO_REPARENT,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node generic_pll_pre_src_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = PLL_PRESRC_MUX_SHIFT,
+ .width = PLL_PRESRC_MUX_WIDTH,
+ .clkflags = CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node generic_pll_half_nodes[] = {
+ {
+ .type = TYPE_FIXEDFACTOR,
+ .offset = NA_SHIFT,
+ .width = NA_WIDTH,
+ .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = 1,
+ .div = 2,
+ },
+};
+
+static struct pm_clock_node generic_pll_int_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = PLL_DIV2_MUX_SHIFT,
+ .width = PLL_DIV2_MUX_WIDTH,
+ .clkflags = CLK_SET_RATE_NO_REPARENT |
+ CLK_SET_RATE_PARENT |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node generic_pll_post_src_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = PLL_POSTSRC_MUX_SHIFT,
+ .width = PLL_POSTSRC_MUX_WIDTH,
+ .clkflags = CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node generic_pll_system_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = PLL_BYPASS_MUX_SHIFT,
+ .width = PLL_BYPASS_MUX_WIDTH,
+ .clkflags = CLK_SET_RATE_NO_REPARENT |
+ CLK_SET_RATE_PARENT |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node acpu_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = PERIPH_MUX_SHIFT,
+ .width = PERIPH_MUX_WIDTH,
+ .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+ {
+ .type = TYPE_DIV1,
+ .offset = PERIPH_DIV1_SHIFT,
+ .width = PERIPH_DIV1_WIDTH,
+ .clkflags = CLK_IS_BASIC,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node generic_mux_div_nodes[] = {
+ GENERIC_MUX,
+ GENERIC_DIV1,
+};
+
+static struct pm_clock_node generic_mux_div_gate_nodes[] = {
+ GENERIC_MUX,
+ GENERIC_DIV1,
+ GENERIC_GATE,
+};
+
+static struct pm_clock_node generic_mux_div_unused_gate_nodes[] = {
+ GENERIC_MUX,
+ GENERIC_DIV1,
+ IGNORE_UNUSED_GATE,
+};
+
+static struct pm_clock_node generic_mux_div_div_gate_nodes[] = {
+ GENERIC_MUX,
+ GENERIC_DIV1,
+ GENERIC_DIV2,
+ GENERIC_GATE,
+};
+
+static struct pm_clock_node dp_audio_video_ref_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = PERIPH_MUX_SHIFT,
+ .width = PERIPH_MUX_WIDTH,
+ .clkflags = CLK_SET_RATE_NO_REPARENT |
+ CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+ .typeflags = CLK_FRAC,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+ {
+ .type = TYPE_DIV1,
+ .offset = PERIPH_DIV1_SHIFT,
+ .width = PERIPH_DIV1_WIDTH,
+ .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT |
+ CLK_IS_BASIC,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO |
+ CLK_FRAC,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+ {
+ .type = TYPE_DIV2,
+ .offset = PERIPH_DIV2_SHIFT,
+ .width = PERIPH_DIV2_WIDTH,
+ .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT |
+ CLK_IS_BASIC,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO |
+ CLK_FRAC,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+ {
+ .type = TYPE_GATE,
+ .offset = PERIPH_GATE_SHIFT,
+ .width = PERIPH_GATE_WIDTH,
+ .clkflags = CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_GATE |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node usb_nodes[] = {
+ GENERIC_MUX,
+ GENERIC_DIV1,
+ GENERIC_DIV2,
+ {
+ .type = TYPE_GATE,
+ .offset = USB_GATE_SHIFT,
+ .width = PERIPH_GATE_WIDTH,
+ .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC |
+ CLK_SET_RATE_GATE,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node generic_domain_crossing_nodes[] = {
+ {
+ .type = TYPE_DIV1,
+ .offset = 8,
+ .width = 6,
+ .clkflags = CLK_IS_BASIC,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node rpll_to_fpd_nodes[] = {
+ {
+ .type = TYPE_DIV1,
+ .offset = 8,
+ .width = 6,
+ .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node acpu_half_nodes[] = {
+ {
+ .type = TYPE_FIXEDFACTOR,
+ .offset = 0,
+ .width = 1,
+ .clkflags = 0,
+ .typeflags = 0,
+ .mult = 1,
+ .div = 2,
+ },
+ {
+ .type = TYPE_GATE,
+ .offset = 25,
+ .width = PERIPH_GATE_WIDTH,
+ .clkflags = CLK_IGNORE_UNUSED |
+ CLK_SET_RATE_PARENT |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node acpu_full_nodes[] = {
+ {
+ .type = TYPE_GATE,
+ .offset = 24,
+ .width = PERIPH_GATE_WIDTH,
+ .clkflags = CLK_IGNORE_UNUSED |
+ CLK_SET_RATE_PARENT |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node wdt_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = 0,
+ .width = 1,
+ .clkflags = CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_NO_REPARENT |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node ddr_nodes[] = {
+ GENERIC_MUX,
+ {
+ .type = TYPE_DIV1,
+ .offset = 8,
+ .width = 6,
+ .clkflags = CLK_IS_BASIC | CLK_IS_CRITICAL,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node pl_nodes[] = {
+ GENERIC_MUX,
+ {
+ .type = TYPE_DIV1,
+ .offset = PERIPH_DIV1_SHIFT,
+ .width = PERIPH_DIV1_WIDTH,
+ .clkflags = CLK_IS_BASIC,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+ {
+ .type = TYPE_DIV2,
+ .offset = PERIPH_DIV2_SHIFT,
+ .width = PERIPH_DIV2_WIDTH,
+ .clkflags = CLK_IS_BASIC | CLK_SET_RATE_PARENT,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+ {
+ .type = TYPE_GATE,
+ .offset = PERIPH_GATE_SHIFT,
+ .width = PERIPH_GATE_WIDTH,
+ .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node gpu_pp0_nodes[] = {
+ {
+ .type = TYPE_GATE,
+ .offset = 25,
+ .width = PERIPH_GATE_WIDTH,
+ .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node gpu_pp1_nodes[] = {
+ {
+ .type = TYPE_GATE,
+ .offset = 26,
+ .width = PERIPH_GATE_WIDTH,
+ .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node gem_ref_ungated_nodes[] = {
+ GENERIC_MUX,
+ {
+ .type = TYPE_DIV1,
+ .offset = 8,
+ .width = 6,
+ .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+ {
+ .type = TYPE_DIV2,
+ .offset = 16,
+ .width = 6,
+ .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC |
+ CLK_SET_RATE_PARENT,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node gem0_ref_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = 1,
+ .width = 1,
+ .clkflags = CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_NO_REPARENT |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node gem1_ref_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = 6,
+ .width = 1,
+ .clkflags = CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_NO_REPARENT |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node gem2_ref_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = 11,
+ .width = 1,
+ .clkflags = CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_NO_REPARENT |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node gem3_ref_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = 16,
+ .width = 1,
+ .clkflags = CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_NO_REPARENT |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node gem_tx_nodes[] = {
+ {
+ .type = TYPE_GATE,
+ .offset = 25,
+ .width = PERIPH_GATE_WIDTH,
+ .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node gem_rx_nodes[] = {
+ {
+ .type = TYPE_GATE,
+ .offset = 26,
+ .width = PERIPH_GATE_WIDTH,
+ .clkflags = CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node gem_tsu_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = 20,
+ .width = 2,
+ .clkflags = CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_NO_REPARENT |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node can0_mio_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = 0,
+ .width = 7,
+ .clkflags = CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_NO_REPARENT |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node can1_mio_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = 15,
+ .width = 1,
+ .clkflags = CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_NO_REPARENT |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node can0_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = 7,
+ .width = 1,
+ .clkflags = CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_NO_REPARENT |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node can1_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = 22,
+ .width = 1,
+ .clkflags = CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_NO_REPARENT |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node cpu_r5_core_nodes[] = {
+ {
+ .type = TYPE_GATE,
+ .offset = 25,
+ .width = PERIPH_GATE_WIDTH,
+ .clkflags = CLK_IGNORE_UNUSED |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node dll_ref_nodes[] = {
+ {
+ .type = TYPE_MUX,
+ .offset = 0,
+ .width = 3,
+ .clkflags = CLK_SET_RATE_PARENT |
+ CLK_SET_RATE_NO_REPARENT |
+ CLK_IS_BASIC,
+ .typeflags = NA_TYPE_FLAGS,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+};
+
+static struct pm_clock_node timestamp_ref_nodes[] = {
+ GENERIC_MUX,
+ {
+ .type = TYPE_DIV1,
+ .offset = 8,
+ .width = 6,
+ .clkflags = CLK_IS_BASIC,
+ .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
+ .mult = NA_MULT,
+ .div = NA_DIV,
+ },
+ IGNORE_UNUSED_GATE,
+};
+
+static int32_t can_mio_parents[] = {
+ EXT_CLK_MIO0, EXT_CLK_MIO1, EXT_CLK_MIO2, EXT_CLK_MIO3,
+ EXT_CLK_MIO4, EXT_CLK_MIO5, EXT_CLK_MIO6, EXT_CLK_MIO7,
+ EXT_CLK_MIO8, EXT_CLK_MIO9, EXT_CLK_MIO10, EXT_CLK_MIO11,
+ EXT_CLK_MIO12, EXT_CLK_MIO13, EXT_CLK_MIO14, EXT_CLK_MIO15,
+ EXT_CLK_MIO16, EXT_CLK_MIO17, EXT_CLK_MIO18, EXT_CLK_MIO19,
+ EXT_CLK_MIO20, EXT_CLK_MIO21, EXT_CLK_MIO22, EXT_CLK_MIO23,
+ EXT_CLK_MIO24, EXT_CLK_MIO25, EXT_CLK_MIO26, EXT_CLK_MIO27,
+ EXT_CLK_MIO28, EXT_CLK_MIO29, EXT_CLK_MIO30, EXT_CLK_MIO31,
+ EXT_CLK_MIO32, EXT_CLK_MIO33, EXT_CLK_MIO34, EXT_CLK_MIO35,
+ EXT_CLK_MIO36, EXT_CLK_MIO37, EXT_CLK_MIO38, EXT_CLK_MIO39,
+ EXT_CLK_MIO40, EXT_CLK_MIO41, EXT_CLK_MIO42, EXT_CLK_MIO43,
+ EXT_CLK_MIO44, EXT_CLK_MIO45, EXT_CLK_MIO46, EXT_CLK_MIO47,
+ EXT_CLK_MIO48, EXT_CLK_MIO49, EXT_CLK_MIO50, EXT_CLK_MIO51,
+ EXT_CLK_MIO52, EXT_CLK_MIO53, EXT_CLK_MIO54, EXT_CLK_MIO55,
+ EXT_CLK_MIO56, EXT_CLK_MIO57, EXT_CLK_MIO58, EXT_CLK_MIO59,
+ EXT_CLK_MIO60, EXT_CLK_MIO61, EXT_CLK_MIO62, EXT_CLK_MIO63,
+ EXT_CLK_MIO64, EXT_CLK_MIO65, EXT_CLK_MIO66, EXT_CLK_MIO67,
+ EXT_CLK_MIO68, EXT_CLK_MIO69, EXT_CLK_MIO70, EXT_CLK_MIO71,
+ EXT_CLK_MIO72, EXT_CLK_MIO73, EXT_CLK_MIO74, EXT_CLK_MIO75,
+ EXT_CLK_MIO76, EXT_CLK_MIO77, CLK_NA_PARENT
+};
+
+/* Clock array containing clock informaton */
+static struct pm_clock clocks[] = {
+ [CLK_APLL_INT] = {
+ .name = "apll_int",
+ .control_reg = CRF_APB_APLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {CLK_APLL_PRE_SRC, CLK_NA_PARENT}),
+ .nodes = &ignore_unused_pll_nodes,
+ .num_nodes = ARRAY_SIZE(ignore_unused_pll_nodes),
+ },
+ [CLK_APLL_PRE_SRC] = {
+ .name = "apll_pre_src",
+ .control_reg = CRF_APB_APLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_pre_src_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_pre_src_nodes),
+ },
+ [CLK_APLL_HALF] = {
+ .name = "apll_half",
+ .control_reg = CRF_APB_APLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {CLK_APLL_INT, CLK_NA_PARENT}),
+ .nodes = &generic_pll_half_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_half_nodes),
+ },
+ [CLK_APLL_INT_MUX] = {
+ .name = "apll_int_mux",
+ .control_reg = CRF_APB_APLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ CLK_APLL_INT,
+ CLK_APLL_HALF,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_int_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_int_nodes),
+ },
+ [CLK_APLL_POST_SRC] = {
+ .name = "apll_post_src",
+ .control_reg = CRF_APB_APLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_post_src_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_post_src_nodes),
+ },
+ [CLK_APLL] = {
+ .name = "apll",
+ .control_reg = CRF_APB_APLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ CLK_APLL_INT_MUX,
+ CLK_APLL_POST_SRC,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_system_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_system_nodes),
+ },
+ [CLK_DPLL_INT] = {
+ .name = "dpll_int",
+ .control_reg = CRF_APB_DPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {CLK_DPLL_PRE_SRC, CLK_NA_PARENT}),
+ .nodes = &generic_pll_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_nodes),
+ },
+ [CLK_DPLL_PRE_SRC] = {
+ .name = "dpll_pre_src",
+ .control_reg = CRF_APB_DPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_pre_src_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_pre_src_nodes),
+ },
+ [CLK_DPLL_HALF] = {
+ .name = "dpll_half",
+ .control_reg = CRF_APB_DPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {CLK_DPLL_INT, CLK_NA_PARENT}),
+ .nodes = &generic_pll_half_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_half_nodes),
+ },
+ [CLK_DPLL_INT_MUX] = {
+ .name = "dpll_int_mux",
+ .control_reg = CRF_APB_DPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ CLK_DPLL_INT,
+ CLK_DPLL_HALF,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_int_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_int_nodes),
+ },
+ [CLK_DPLL_POST_SRC] = {
+ .name = "dpll_post_src",
+ .control_reg = CRF_APB_DPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_post_src_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_post_src_nodes),
+ },
+ [CLK_DPLL] = {
+ .name = "dpll",
+ .control_reg = CRF_APB_DPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ CLK_DPLL_INT_MUX,
+ CLK_DPLL_POST_SRC,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_system_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_system_nodes),
+ },
+ [CLK_VPLL_INT] = {
+ .name = "vpll_int",
+ .control_reg = CRF_APB_VPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {CLK_VPLL_PRE_SRC, CLK_NA_PARENT}),
+ .nodes = &ignore_unused_pll_nodes,
+ .num_nodes = ARRAY_SIZE(ignore_unused_pll_nodes),
+ },
+ [CLK_VPLL_PRE_SRC] = {
+ .name = "vpll_pre_src",
+ .control_reg = CRF_APB_VPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_pre_src_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_pre_src_nodes),
+ },
+ [CLK_VPLL_HALF] = {
+ .name = "vpll_half",
+ .control_reg = CRF_APB_VPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {CLK_VPLL_INT, CLK_NA_PARENT}),
+ .nodes = &generic_pll_half_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_half_nodes),
+ },
+ [CLK_VPLL_INT_MUX] = {
+ .name = "vpll_int_mux",
+ .control_reg = CRF_APB_VPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ CLK_VPLL_INT,
+ CLK_VPLL_HALF,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_int_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_int_nodes),
+ },
+ [CLK_VPLL_POST_SRC] = {
+ .name = "vpll_post_src",
+ .control_reg = CRF_APB_VPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_post_src_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_post_src_nodes),
+ },
+ [CLK_VPLL] = {
+ .name = "vpll",
+ .control_reg = CRF_APB_VPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ CLK_VPLL_INT_MUX,
+ CLK_VPLL_POST_SRC,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_system_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_system_nodes),
+ },
+ [CLK_IOPLL_INT] = {
+ .name = "iopll_int",
+ .control_reg = CRL_APB_IOPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {CLK_IOPLL_PRE_SRC, CLK_NA_PARENT}),
+ .nodes = &generic_pll_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_nodes),
+ },
+ [CLK_IOPLL_PRE_SRC] = {
+ .name = "iopll_pre_src",
+ .control_reg = CRL_APB_IOPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_pre_src_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_pre_src_nodes),
+ },
+ [CLK_IOPLL_HALF] = {
+ .name = "iopll_half",
+ .control_reg = CRL_APB_IOPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {CLK_IOPLL_INT, CLK_NA_PARENT}),
+ .nodes = &generic_pll_half_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_half_nodes),
+ },
+ [CLK_IOPLL_INT_MUX] = {
+ .name = "iopll_int_mux",
+ .control_reg = CRL_APB_IOPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ CLK_IOPLL_INT,
+ CLK_IOPLL_HALF,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_int_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_int_nodes),
+ },
+ [CLK_IOPLL_POST_SRC] = {
+ .name = "iopll_post_src",
+ .control_reg = CRL_APB_IOPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_post_src_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_post_src_nodes),
+ },
+ [CLK_IOPLL] = {
+ .name = "iopll",
+ .control_reg = CRL_APB_IOPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ CLK_IOPLL_INT_MUX,
+ CLK_IOPLL_POST_SRC,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_system_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_system_nodes),
+ },
+ [CLK_RPLL_INT] = {
+ .name = "rpll_int",
+ .control_reg = CRL_APB_RPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {CLK_RPLL_PRE_SRC, CLK_NA_PARENT}),
+ .nodes = &generic_pll_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_nodes),
+ },
+ [CLK_RPLL_PRE_SRC] = {
+ .name = "rpll_pre_src",
+ .control_reg = CRL_APB_RPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+
+ .nodes = &generic_pll_pre_src_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_pre_src_nodes),
+ },
+ [CLK_RPLL_HALF] = {
+ .name = "rpll_half",
+ .control_reg = CRL_APB_RPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {CLK_RPLL_INT, CLK_NA_PARENT}),
+ .nodes = &generic_pll_half_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_half_nodes),
+ },
+ [CLK_RPLL_INT_MUX] = {
+ .name = "rpll_int_mux",
+ .control_reg = CRL_APB_RPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ CLK_RPLL_INT,
+ CLK_RPLL_HALF,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_int_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_int_nodes),
+ },
+ [CLK_RPLL_POST_SRC] = {
+ .name = "rpll_post_src",
+ .control_reg = CRL_APB_RPLL_CTRL,
+ .status_reg = CRF_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_post_src_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_post_src_nodes),
+ },
+ [CLK_RPLL] = {
+ .name = "rpll",
+ .control_reg = CRL_APB_RPLL_CTRL,
+ .status_reg = CRL_APB_PLL_STATUS,
+ .parents = &((int32_t []) {
+ CLK_RPLL_INT_MUX,
+ CLK_RPLL_POST_SRC,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_pll_system_nodes,
+ .num_nodes = ARRAY_SIZE(generic_pll_system_nodes),
+ },
+ /* Peripheral Clocks */
+ [CLK_ACPU] = {
+ .name = "acpu",
+ .control_reg = CRF_APB_ACPU_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_APLL,
+ CLK_DUMMY_PARENT,
+ CLK_DPLL,
+ CLK_VPLL,
+ CLK_NA_PARENT
+ }),
+ .nodes = &acpu_nodes,
+ .num_nodes = ARRAY_SIZE(acpu_nodes),
+ },
+ [CLK_ACPU_FULL] = {
+ .name = "acpu_full",
+ .control_reg = CRF_APB_ACPU_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_ACPU | PARENT_CLK_NODE2 << CLK_PARENTS_ID_LEN,
+ CLK_NA_PARENT
+ }),
+ .nodes = &acpu_full_nodes,
+ .num_nodes = ARRAY_SIZE(acpu_full_nodes),
+ },
+ [CLK_DBG_TRACE] = {
+ .name = "dbg_trace",
+ .control_reg = CRF_APB_DBG_TRACE_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL_TO_FPD,
+ CLK_DUMMY_PARENT,
+ CLK_DPLL,
+ CLK_APLL,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+ },
+ [CLK_DBG_FPD] = {
+ .name = "dbg_fpd",
+ .control_reg = CRF_APB_DBG_FPD_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL_TO_FPD,
+ CLK_DUMMY_PARENT,
+ CLK_DPLL,
+ CLK_APLL,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+ },
+ [CLK_DBG_TSTMP] = {
+ .name = "dbg_tstmp",
+ .control_reg = CRF_APB_DBG_TSTMP_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL_TO_FPD,
+ CLK_DUMMY_PARENT,
+ CLK_DPLL,
+ CLK_APLL,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_nodes),
+ },
+ [CLK_DP_VIDEO_REF] = {
+ .name = "dp_video_ref",
+ .control_reg = CRF_APB_DP_VIDEO_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_VPLL,
+ CLK_DUMMY_PARENT,
+ CLK_DPLL,
+ CLK_RPLL_TO_FPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &dp_audio_video_ref_nodes,
+ .num_nodes = ARRAY_SIZE(dp_audio_video_ref_nodes),
+ },
+ [CLK_DP_AUDIO_REF] = {
+ .name = "dp_audio_ref",
+ .control_reg = CRF_APB_DP_AUDIO_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_VPLL,
+ CLK_DUMMY_PARENT,
+ CLK_DPLL,
+ CLK_RPLL_TO_FPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &dp_audio_video_ref_nodes,
+ .num_nodes = ARRAY_SIZE(dp_audio_video_ref_nodes),
+ },
+ [CLK_DP_STC_REF] = {
+ .name = "dp_stc_ref",
+ .control_reg = CRF_APB_DP_STC_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_VPLL,
+ CLK_DUMMY_PARENT,
+ CLK_DPLL,
+ CLK_RPLL_TO_FPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+ },
+ [CLK_DPDMA_REF] = {
+ .name = "dpdma_ref",
+ .control_reg = CRF_APB_DPDMA_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_APLL,
+ CLK_DUMMY_PARENT,
+ CLK_VPLL,
+ CLK_DPLL,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+ },
+ [CLK_DDR_REF] = {
+ .name = "ddr_ref",
+ .control_reg = CRF_APB_DDR_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_DPLL,
+ CLK_VPLL,
+ CLK_NA_PARENT
+ }),
+ .nodes = &ddr_nodes,
+ .num_nodes = ARRAY_SIZE(ddr_nodes),
+ },
+ [CLK_GPU_REF] = {
+ .name = "gpu_ref",
+ .control_reg = CRF_APB_GPU_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL_TO_FPD,
+ CLK_DUMMY_PARENT,
+ CLK_VPLL,
+ CLK_DPLL,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+ },
+ [CLK_SATA_REF] = {
+ .name = "sata_ref",
+ .control_reg = CRF_APB_SATA_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL_TO_FPD,
+ CLK_DUMMY_PARENT,
+ CLK_APLL,
+ CLK_DPLL,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+ },
+ [CLK_PCIE_REF] = {
+ .name = "pcie_ref",
+ .control_reg = CRF_APB_PCIE_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL_TO_FPD,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL_TO_FPD,
+ CLK_DPLL,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+ },
+ [CLK_GDMA_REF] = {
+ .name = "gdma_ref",
+ .control_reg = CRF_APB_GDMA_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_APLL,
+ CLK_DUMMY_PARENT,
+ CLK_VPLL,
+ CLK_DPLL,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+ },
+ [CLK_GTGREF0_REF] = {
+ .name = "gtgref0_ref",
+ .control_reg = CRF_APB_GTGREF0_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL_TO_FPD,
+ CLK_DUMMY_PARENT,
+ CLK_APLL,
+ CLK_DPLL,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+ },
+ [CLK_TOPSW_MAIN] = {
+ .name = "topsw_main",
+ .control_reg = CRF_APB_TOPSW_MAIN_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_APLL,
+ CLK_DUMMY_PARENT,
+ CLK_VPLL,
+ CLK_DPLL,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_unused_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes),
+ },
+ [CLK_TOPSW_LSBUS] = {
+ .name = "topsw_lsbus",
+ .control_reg = CRF_APB_TOPSW_LSBUS_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_APLL,
+ CLK_DUMMY_PARENT,
+ CLK_IOPLL_TO_FPD,
+ CLK_DPLL,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_unused_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes),
+ },
+ [CLK_IOU_SWITCH] = {
+ .name = "iou_switch",
+ .control_reg = CRL_APB_IOU_SWITCH_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_RPLL,
+ CLK_DUMMY_PARENT,
+ CLK_IOPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_unused_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes),
+ },
+ [CLK_GEM0_REF_UNGATED] = {
+ .name = "gem0_ref_ung",
+ .control_reg = CRL_APB_GEM0_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_ref_ungated_nodes,
+ .num_nodes = ARRAY_SIZE(gem_ref_ungated_nodes),
+ },
+ [CLK_GEM1_REF_UNGATED] = {
+ .name = "gem1_ref_ung",
+ .control_reg = CRL_APB_GEM1_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_ref_ungated_nodes,
+ .num_nodes = ARRAY_SIZE(gem_ref_ungated_nodes),
+ },
+ [CLK_GEM2_REF_UNGATED] = {
+ .name = "gem2_ref_ung",
+ .control_reg = CRL_APB_GEM2_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_ref_ungated_nodes,
+ .num_nodes = ARRAY_SIZE(gem_ref_ungated_nodes),
+ },
+ [CLK_GEM3_REF_UNGATED] = {
+ .name = "gem3_ref_ung",
+ .control_reg = CRL_APB_GEM3_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_ref_ungated_nodes,
+ .num_nodes = ARRAY_SIZE(gem_ref_ungated_nodes),
+ },
+ [CLK_GEM0_REF] = {
+ .name = "gem0_ref",
+ .control_reg = IOU_SLCR_GEM_CLK_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM0_REF_UNGATED |
+ (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN),
+ EXT_CLK_GEM0_TX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem0_ref_nodes,
+ .num_nodes = ARRAY_SIZE(gem0_ref_nodes),
+ },
+ [CLK_GEM1_REF] = {
+ .name = "gem1_ref",
+ .control_reg = IOU_SLCR_GEM_CLK_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM1_REF_UNGATED |
+ (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN),
+ EXT_CLK_GEM1_TX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem1_ref_nodes,
+ .num_nodes = ARRAY_SIZE(gem1_ref_nodes),
+ },
+ [CLK_GEM2_REF] = {
+ .name = "gem2_ref",
+ .control_reg = IOU_SLCR_GEM_CLK_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM2_REF_UNGATED |
+ (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN),
+ EXT_CLK_GEM2_TX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem2_ref_nodes,
+ .num_nodes = ARRAY_SIZE(gem2_ref_nodes),
+ },
+ [CLK_GEM3_REF] = {
+ .name = "gem3_ref",
+ .control_reg = IOU_SLCR_GEM_CLK_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM3_REF_UNGATED |
+ (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN),
+ EXT_CLK_GEM3_TX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem3_ref_nodes,
+ .num_nodes = ARRAY_SIZE(gem3_ref_nodes),
+ },
+ [CLK_USB0_BUS_REF] = {
+ .name = "usb0_bus_ref",
+ .control_reg = CRL_APB_USB0_BUS_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &usb_nodes,
+ .num_nodes = ARRAY_SIZE(usb_nodes),
+ },
+ [CLK_USB1_BUS_REF] = {
+ .name = "usb1_bus_ref",
+ .control_reg = CRL_APB_USB1_BUS_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &usb_nodes,
+ .num_nodes = ARRAY_SIZE(usb_nodes),
+ },
+ [CLK_USB3_DUAL_REF] = {
+ .name = "usb3_dual_ref",
+ .control_reg = CRL_APB_USB3_DUAL_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &usb_nodes,
+ .num_nodes = ARRAY_SIZE(usb_nodes),
+ },
+ [CLK_QSPI_REF] = {
+ .name = "qspi_ref",
+ .control_reg = CRL_APB_QSPI_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+ },
+ [CLK_SDIO0_REF] = {
+ .name = "sdio0_ref",
+ .control_reg = CRL_APB_SDIO0_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_VPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+ },
+ [CLK_SDIO1_REF] = {
+ .name = "sdio1_ref",
+ .control_reg = CRL_APB_SDIO1_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_VPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+ },
+ [CLK_UART0_REF] = {
+ .name = "uart0_ref",
+ .control_reg = CRL_APB_UART0_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+ },
+ [CLK_UART1_REF] = {
+ .name = "uart1_ref",
+ .control_reg = CRL_APB_UART1_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+ },
+ [CLK_SPI0_REF] = {
+ .name = "spi0_ref",
+ .control_reg = CRL_APB_SPI0_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+ },
+ [CLK_SPI1_REF] = {
+ .name = "spi1_ref",
+ .control_reg = CRL_APB_SPI1_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+ },
+ [CLK_CAN0_REF] = {
+ .name = "can0_ref",
+ .control_reg = CRL_APB_CAN0_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+ },
+ [CLK_CAN1_REF] = {
+ .name = "can1_ref",
+ .control_reg = CRL_APB_CAN1_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+ },
+ [CLK_NAND_REF] = {
+ .name = "nand_ref",
+ .control_reg = CRL_APB_NAND_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+ },
+ [CLK_GEM_TSU_REF] = {
+ .name = "gem_tsu_ref",
+ .control_reg = CRL_APB_GEM_TSU_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+ },
+ [CLK_DLL_REF] = {
+ .name = "dll_ref",
+ .control_reg = CRL_APB_DLL_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_RPLL,
+ CLK_NA_PARENT
+ }),
+ .nodes = &dll_ref_nodes,
+ .num_nodes = ARRAY_SIZE(dll_ref_nodes),
+ },
+ [CLK_ADMA_REF] = {
+ .name = "adma_ref",
+ .control_reg = CRL_APB_ADMA_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_RPLL,
+ CLK_DUMMY_PARENT,
+ CLK_IOPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+ },
+ [CLK_DBG_LPD] = {
+ .name = "dbg_lpd",
+ .control_reg = CRL_APB_DBG_LPD_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_RPLL,
+ CLK_DUMMY_PARENT,
+ CLK_IOPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+ },
+ [CLK_CPU_R5] = {
+ .name = "cpu_r5",
+ .control_reg = CRL_APB_CPU_R5_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_RPLL,
+ CLK_DUMMY_PARENT,
+ CLK_IOPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_unused_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes),
+ },
+ [CLK_CSU_PLL] = {
+ .name = "csu_pll",
+ .control_reg = CRL_APB_CSU_PLL_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+ },
+ [CLK_PCAP] = {
+ .name = "pcap",
+ .control_reg = CRL_APB_PCAP_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes),
+ },
+ [CLK_LPD_LSBUS] = {
+ .name = "lpd_lsbus",
+ .control_reg = CRL_APB_LPD_LSBUS_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_RPLL,
+ CLK_DUMMY_PARENT,
+ CLK_IOPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_unused_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes),
+ },
+ [CLK_LPD_SWITCH] = {
+ .name = "lpd_switch",
+ .control_reg = CRL_APB_LPD_SWITCH_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_RPLL,
+ CLK_DUMMY_PARENT,
+ CLK_IOPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_unused_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes),
+ },
+ [CLK_I2C0_REF] = {
+ .name = "i2c0_ref",
+ .control_reg = CRL_APB_I2C0_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+ },
+ [CLK_I2C1_REF] = {
+ .name = "i2c1_ref",
+ .control_reg = CRL_APB_I2C1_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+ },
+ [CLK_TIMESTAMP_REF] = {
+ .name = "timestamp_ref",
+ .control_reg = CRL_APB_TIMESTAMP_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &timestamp_ref_nodes,
+ .num_nodes = ARRAY_SIZE(timestamp_ref_nodes),
+ },
+ [CLK_PL0_REF] = {
+ .name = "pl0_ref",
+ .control_reg = CRL_APB_PL0_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &pl_nodes,
+ .num_nodes = ARRAY_SIZE(pl_nodes),
+ },
+ [CLK_PL1_REF] = {
+ .name = "pl1_ref",
+ .control_reg = CRL_APB_PL1_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &pl_nodes,
+ .num_nodes = ARRAY_SIZE(pl_nodes),
+ },
+ [CLK_PL2_REF] = {
+ .name = "pl2_ref",
+ .control_reg = CRL_APB_PL2_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &pl_nodes,
+ .num_nodes = ARRAY_SIZE(pl_nodes),
+ },
+ [CLK_PL3_REF] = {
+ .name = "pl3_ref",
+ .control_reg = CRL_APB_PL3_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_IOPLL,
+ CLK_DUMMY_PARENT,
+ CLK_RPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &pl_nodes,
+ .num_nodes = ARRAY_SIZE(pl_nodes),
+ },
+ [CLK_AMS_REF] = {
+ .name = "ams_ref",
+ .control_reg = CRL_APB_AMS_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_RPLL,
+ CLK_DUMMY_PARENT,
+ CLK_IOPLL,
+ CLK_DPLL_TO_LPD,
+ CLK_NA_PARENT
+ }),
+ .nodes = &generic_mux_div_div_gate_nodes,
+ .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes),
+ },
+ [CLK_IOPLL_TO_FPD] = {
+ .name = "iopll_to_fpd",
+ .control_reg = CRL_APB_IOPLL_TO_FPD_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {CLK_IOPLL, CLK_NA_PARENT}),
+ .nodes = &generic_domain_crossing_nodes,
+ .num_nodes = ARRAY_SIZE(generic_domain_crossing_nodes),
+ },
+ [CLK_RPLL_TO_FPD] = {
+ .name = "rpll_to_fpd",
+ .control_reg = CRL_APB_RPLL_TO_FPD_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {CLK_RPLL, CLK_NA_PARENT}),
+ .nodes = &rpll_to_fpd_nodes,
+ .num_nodes = ARRAY_SIZE(rpll_to_fpd_nodes),
+ },
+ [CLK_APLL_TO_LPD] = {
+ .name = "apll_to_lpd",
+ .control_reg = CRF_APB_APLL_TO_LPD_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {CLK_APLL, CLK_NA_PARENT}),
+ .nodes = &generic_domain_crossing_nodes,
+ .num_nodes = ARRAY_SIZE(generic_domain_crossing_nodes),
+ },
+ [CLK_DPLL_TO_LPD] = {
+ .name = "dpll_to_lpd",
+ .control_reg = CRF_APB_DPLL_TO_LPD_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {CLK_DPLL, CLK_NA_PARENT}),
+ .nodes = &generic_domain_crossing_nodes,
+ .num_nodes = ARRAY_SIZE(generic_domain_crossing_nodes),
+ },
+ [CLK_VPLL_TO_LPD] = {
+ .name = "vpll_to_lpd",
+ .control_reg = CRF_APB_VPLL_TO_LPD_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {CLK_VPLL, CLK_NA_PARENT}),
+ .nodes = &generic_domain_crossing_nodes,
+ .num_nodes = ARRAY_SIZE(generic_domain_crossing_nodes),
+ },
+ [CLK_GEM0_TX] = {
+ .name = "gem0_tx",
+ .control_reg = CRL_APB_GEM0_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM0_REF,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_tx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_tx_nodes),
+ },
+ [CLK_GEM1_TX] = {
+ .name = "gem1_tx",
+ .control_reg = CRL_APB_GEM1_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM1_REF,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_tx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_tx_nodes),
+ },
+ [CLK_GEM2_TX] = {
+ .name = "gem2_tx",
+ .control_reg = CRL_APB_GEM2_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM2_REF,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_tx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_tx_nodes),
+ },
+ [CLK_GEM3_TX] = {
+ .name = "gem3_tx",
+ .control_reg = CRL_APB_GEM3_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM3_REF,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_tx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_tx_nodes),
+ },
+ [CLK_GEM0_RX] = {
+ .name = "gem0_rx",
+ .control_reg = CRL_APB_GEM0_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ EXT_CLK_GEM0_RX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_rx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_rx_nodes),
+ },
+ [CLK_GEM1_RX] = {
+ .name = "gem1_rx",
+ .control_reg = CRL_APB_GEM1_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ EXT_CLK_GEM1_RX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_rx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_rx_nodes),
+ },
+ [CLK_GEM2_RX] = {
+ .name = "gem2_rx",
+ .control_reg = CRL_APB_GEM2_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ EXT_CLK_GEM2_RX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_rx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_rx_nodes),
+ },
+ [CLK_GEM3_RX] = {
+ .name = "gem3_rx",
+ .control_reg = CRL_APB_GEM3_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ EXT_CLK_GEM3_RX_EMIO | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_rx_nodes,
+ .num_nodes = ARRAY_SIZE(gem_rx_nodes),
+ },
+ [CLK_ACPU_HALF] = {
+ .name = "acpu_half",
+ .control_reg = CRF_APB_ACPU_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_ACPU | PARENT_CLK_NODE2 << CLK_PARENTS_ID_LEN,
+ CLK_NA_PARENT
+ }),
+ .nodes = &acpu_half_nodes,
+ .num_nodes = ARRAY_SIZE(acpu_half_nodes),
+ },
+ [CLK_FPD_WDT] = {
+ .name = "fpd_wdt",
+ .control_reg = FPD_SLCR_WDT_CLK_SEL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_TOPSW_LSBUS,
+ EXT_CLK_SWDT0 | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &wdt_nodes,
+ .num_nodes = ARRAY_SIZE(wdt_nodes),
+ },
+ [CLK_GPU_PP0_REF] = {
+ .name = "gpu_pp0_ref",
+ .control_reg = CRF_APB_GPU_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GPU_REF | PARENT_CLK_NODE2 << CLK_PARENTS_ID_LEN,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gpu_pp0_nodes,
+ .num_nodes = ARRAY_SIZE(gpu_pp0_nodes),
+ },
+ [CLK_GPU_PP1_REF] = {
+ .name = "gpu_pp1_ref",
+ .control_reg = CRF_APB_GPU_REF_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GPU_REF | PARENT_CLK_NODE2 << CLK_PARENTS_ID_LEN,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gpu_pp1_nodes,
+ .num_nodes = ARRAY_SIZE(gpu_pp1_nodes),
+ },
+ [CLK_GEM_TSU] = {
+ .name = "gem_tsu",
+ .control_reg = IOU_SLCR_GEM_CLK_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_GEM_TSU_REF,
+ CLK_GEM_TSU_REF,
+ EXT_CLK_MIO26 | CLK_EXTERNAL_PARENT,
+ EXT_CLK_MIO50_OR_MIO51 | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &gem_tsu_nodes,
+ .num_nodes = ARRAY_SIZE(gem_tsu_nodes),
+ },
+ [CLK_CPU_R5_CORE] = {
+ .name = "cpu_r5_core",
+ .control_reg = CRL_APB_CPU_R5_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_CPU_R5 | PARENT_CLK_NODE2 << CLK_PARENTS_ID_LEN,
+ CLK_DUMMY_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &cpu_r5_core_nodes,
+ .num_nodes = ARRAY_SIZE(cpu_r5_core_nodes),
+ },
+ [CLK_CAN0_MIO] = {
+ .name = "can0_mio",
+ .control_reg = IOU_SLCR_CAN_MIO_CTRL,
+ .status_reg = 0,
+ .parents = &can_mio_parents,
+ .nodes = &can0_mio_nodes,
+ .num_nodes = ARRAY_SIZE(can0_mio_nodes),
+ },
+ [CLK_CAN1_MIO] = {
+ .name = "can1_mio",
+ .control_reg = IOU_SLCR_CAN_MIO_CTRL,
+ .status_reg = 0,
+ .parents = &can_mio_parents,
+ .nodes = &can1_mio_nodes,
+ .num_nodes = ARRAY_SIZE(can1_mio_nodes),
+ },
+ [CLK_CAN0] = {
+ .name = "can0",
+ .control_reg = IOU_SLCR_CAN_MIO_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_CAN0_REF,
+ CLK_CAN0_MIO,
+ CLK_NA_PARENT
+ }),
+ .nodes = &can0_nodes,
+ .num_nodes = ARRAY_SIZE(can0_nodes),
+ },
+ [CLK_CAN1] = {
+ .name = "can1",
+ .control_reg = IOU_SLCR_CAN_MIO_CTRL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_CAN1_REF,
+ CLK_CAN1_MIO,
+ CLK_NA_PARENT
+ }),
+ .nodes = &can1_nodes,
+ .num_nodes = ARRAY_SIZE(can1_nodes),
+ },
+ [CLK_LPD_WDT] = {
+ .name = "lpd_wdt",
+ .control_reg = IOU_SLCR_WDT_CLK_SEL,
+ .status_reg = 0,
+ .parents = &((int32_t []) {
+ CLK_LPD_LSBUS,
+ EXT_CLK_SWDT1 | CLK_EXTERNAL_PARENT,
+ CLK_NA_PARENT
+ }),
+ .nodes = &wdt_nodes,
+ .num_nodes = ARRAY_SIZE(wdt_nodes),
+ },
+};
+
+static struct pm_ext_clock ext_clocks[] = {
+ [EXT_CLK_INDEX(EXT_CLK_PSS_REF)] = {
+ .name = "pss_ref_clk",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_VIDEO)] = {
+ .name = "video_clk",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_PSS_ALT_REF)] = {
+ .name = "pss_alt_ref_clk",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_AUX_REF)] = {
+ .name = "aux_ref_clk",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GT_CRX_REF)] = {
+ .name = "video_clk",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_SWDT0)] = {
+ .name = "swdt0_ext_clk",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_SWDT1)] = {
+ .name = "swdt1_ext_clk",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GEM0_TX_EMIO)] = {
+ .name = "gem0_tx_ext",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GEM1_TX_EMIO)] = {
+ .name = "gem1_tx_ext",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GEM2_TX_EMIO)] = {
+ .name = "gem2_tx_ext",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GEM3_TX_EMIO)] = {
+ .name = "gem3_tx_ext",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GEM0_RX_EMIO)] = {
+ .name = "gem0_rx_ext",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GEM1_RX_EMIO)] = {
+ .name = "gem1_rx_ext",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GEM2_RX_EMIO)] = {
+ .name = "gem2_rx_ext",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_GEM3_RX_EMIO)] = {
+ .name = "gem3_rx_ext",
+ },
+ [EXT_CLK_INDEX(EXT_CLK_MIO50_OR_MIO51)] = {
+ .name = "mio_clk_50_51",
+ },
+ EXT_CLK_MIO_DATA(0),
+ EXT_CLK_MIO_DATA(1),
+ EXT_CLK_MIO_DATA(2),
+ EXT_CLK_MIO_DATA(3),
+ EXT_CLK_MIO_DATA(4),
+ EXT_CLK_MIO_DATA(5),
+ EXT_CLK_MIO_DATA(6),
+ EXT_CLK_MIO_DATA(7),
+ EXT_CLK_MIO_DATA(8),
+ EXT_CLK_MIO_DATA(9),
+ EXT_CLK_MIO_DATA(10),
+ EXT_CLK_MIO_DATA(11),
+ EXT_CLK_MIO_DATA(12),
+ EXT_CLK_MIO_DATA(13),
+ EXT_CLK_MIO_DATA(14),
+ EXT_CLK_MIO_DATA(15),
+ EXT_CLK_MIO_DATA(16),
+ EXT_CLK_MIO_DATA(17),
+ EXT_CLK_MIO_DATA(18),
+ EXT_CLK_MIO_DATA(19),
+ EXT_CLK_MIO_DATA(20),
+ EXT_CLK_MIO_DATA(21),
+ EXT_CLK_MIO_DATA(22),
+ EXT_CLK_MIO_DATA(23),
+ EXT_CLK_MIO_DATA(24),
+ EXT_CLK_MIO_DATA(25),
+ EXT_CLK_MIO_DATA(26),
+ EXT_CLK_MIO_DATA(27),
+ EXT_CLK_MIO_DATA(28),
+ EXT_CLK_MIO_DATA(29),
+ EXT_CLK_MIO_DATA(30),
+ EXT_CLK_MIO_DATA(31),
+ EXT_CLK_MIO_DATA(32),
+ EXT_CLK_MIO_DATA(33),
+ EXT_CLK_MIO_DATA(34),
+ EXT_CLK_MIO_DATA(35),
+ EXT_CLK_MIO_DATA(36),
+ EXT_CLK_MIO_DATA(37),
+ EXT_CLK_MIO_DATA(38),
+ EXT_CLK_MIO_DATA(39),
+ EXT_CLK_MIO_DATA(40),
+ EXT_CLK_MIO_DATA(41),
+ EXT_CLK_MIO_DATA(42),
+ EXT_CLK_MIO_DATA(43),
+ EXT_CLK_MIO_DATA(44),
+ EXT_CLK_MIO_DATA(45),
+ EXT_CLK_MIO_DATA(46),
+ EXT_CLK_MIO_DATA(47),
+ EXT_CLK_MIO_DATA(48),
+ EXT_CLK_MIO_DATA(49),
+ EXT_CLK_MIO_DATA(50),
+ EXT_CLK_MIO_DATA(51),
+ EXT_CLK_MIO_DATA(52),
+ EXT_CLK_MIO_DATA(53),
+ EXT_CLK_MIO_DATA(54),
+ EXT_CLK_MIO_DATA(55),
+ EXT_CLK_MIO_DATA(56),
+ EXT_CLK_MIO_DATA(57),
+ EXT_CLK_MIO_DATA(58),
+ EXT_CLK_MIO_DATA(59),
+ EXT_CLK_MIO_DATA(60),
+ EXT_CLK_MIO_DATA(61),
+ EXT_CLK_MIO_DATA(62),
+ EXT_CLK_MIO_DATA(63),
+ EXT_CLK_MIO_DATA(64),
+ EXT_CLK_MIO_DATA(65),
+ EXT_CLK_MIO_DATA(66),
+ EXT_CLK_MIO_DATA(67),
+ EXT_CLK_MIO_DATA(68),
+ EXT_CLK_MIO_DATA(69),
+ EXT_CLK_MIO_DATA(70),
+ EXT_CLK_MIO_DATA(71),
+ EXT_CLK_MIO_DATA(72),
+ EXT_CLK_MIO_DATA(73),
+ EXT_CLK_MIO_DATA(74),
+ EXT_CLK_MIO_DATA(75),
+ EXT_CLK_MIO_DATA(76),
+ EXT_CLK_MIO_DATA(77),
+};
+
+/* Array of clock which are invalid for this variant */
+static uint32_t pm_clk_invalid_list[] = {CLK_USB0, CLK_USB1, CLK_CSU_SPB,
+ CLK_ACPU_FULL,
+ CLK_ACPU_HALF,
+ CLK_APLL_TO_LPD,
+ CLK_DBG_FPD,
+ CLK_DBG_LPD,
+ CLK_DBG_TRACE,
+ CLK_DBG_TSTMP,
+ CLK_DDR_REF,
+ CLK_TOPSW_MAIN,
+ CLK_GTGREF0_REF,
+ CLK_LPD_SWITCH,
+ CLK_CPU_R5,
+ CLK_CPU_R5_CORE,
+ CLK_CSU_SPB,
+ CLK_CSU_PLL,
+ CLK_PCAP,
+ CLK_IOU_SWITCH,
+ CLK_DLL_REF,
+ CLK_TIMESTAMP_REF,
+};
+
+/**
+ * pm_clock_valid - Check if clock is valid or not
+ * @clock_id Id of the clock to be queried
+ *
+ * This function is used to check if given clock is valid
+ * or not for the chip variant.
+ *
+ * List of invalid clocks are maintained in array list for
+ * different variants.
+ *
+ * Return: Returns 1 if clock is valid else 0.
+ */
+static bool pm_clock_valid(uint32_t clock_id)
+{
+ unsigned int i;
+
+ for (i = 0U; i < ARRAY_SIZE(pm_clk_invalid_list); i++)
+ if (pm_clk_invalid_list[i] == clock_id)
+ return 0;
+
+ return 1;
+}
+
+/**
+ * pm_clock_type - Get clock's type
+ * @clock_id Id of the clock to be queried
+ *
+ * This function is used to check type of clock (OUTPUT/EXTERNAL).
+ *
+ * Return: Returns type of clock (OUTPUT/EXTERNAL).
+ */
+static uint32_t pm_clock_type(uint32_t clock_id)
+{
+ return (clock_id < CLK_MAX_OUTPUT_CLK) ?
+ CLK_TYPE_OUTPUT : CLK_TYPE_EXTERNAL;
+}
+
+/**
+ * pm_api_clock_get_num_clocks() - PM call to request number of clocks
+ * @nclocks Number of clocks
+ *
+ * This function is used by master to get number of clocks.
+ *
+ * @return Returns success.
+ */
+enum pm_ret_status pm_api_clock_get_num_clocks(uint32_t *nclocks)
+{
+ *nclocks = CLK_MAX;
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_clock_get_name() - PM call to request a clock's name
+ * @clock_id Clock ID
+ * @name Name of clock (max 16 bytes)
+ *
+ * This function is used by master to get nmae of clock specified
+ * by given clock ID.
+ */
+void pm_api_clock_get_name(uint32_t clock_id, char *name)
+{
+ if (clock_id == CLK_MAX) {
+ memcpy(name, END_OF_CLK, sizeof(END_OF_CLK) > CLK_NAME_LEN ?
+ CLK_NAME_LEN : sizeof(END_OF_CLK));
+ } else if (!pm_clock_valid(clock_id)) {
+ memset(name, 0, CLK_NAME_LEN);
+ } else if (clock_id < CLK_MAX_OUTPUT_CLK) {
+ memcpy(name, clocks[clock_id].name, CLK_NAME_LEN);
+ } else {
+ memcpy(name, ext_clocks[clock_id - CLK_MAX_OUTPUT_CLK].name,
+ CLK_NAME_LEN);
+ }
+}
+
+/**
+ * pm_api_clock_get_topology() - PM call to request a clock's topology
+ * @clock_id Clock ID
+ * @index Topology index for next toplogy node
+ * @topology Buffer to store nodes in topology and flags
+ *
+ * This function is used by master to get topology information for the
+ * clock specified by given clock ID. Each response would return 3
+ * topology nodes. To get next nodes, caller needs to call this API with
+ * index of next node. Index starts from 0.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_clock_get_topology(uint32_t clock_id,
+ uint32_t index,
+ uint32_t *topology)
+{
+ struct pm_clock_node *clock_nodes;
+ uint8_t num_nodes;
+ uint32_t i;
+ uint16_t typeflags;
+
+ if (!pm_clock_valid(clock_id)) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT) {
+ return PM_RET_ERROR_NOTSUPPORTED;
+ }
+
+ memset(topology, 0, CLK_TOPOLOGY_PAYLOAD_LEN);
+ clock_nodes = *clocks[clock_id].nodes;
+ num_nodes = clocks[clock_id].num_nodes;
+
+ /* Skip parent till index */
+ if (index >= num_nodes) {
+ return PM_RET_SUCCESS;
+ }
+
+ for (i = 0; i < 3U; i++) {
+ if ((index + i) == num_nodes) {
+ break;
+ }
+
+ topology[i] = clock_nodes[index + i].type;
+ topology[i] |= clock_nodes[index + i].clkflags <<
+ CLK_CLKFLAGS_SHIFT;
+ typeflags = clock_nodes[index + i].typeflags;
+ topology[i] |= (typeflags & CLK_TYPEFLAGS_BITS_MASK) <<
+ CLK_TYPEFLAGS_SHIFT;
+ topology[i] |= (typeflags & CLK_TYPEFLAGS2_BITS_MASK) >>
+ (CLK_TYPEFLAGS_BITS - CLK_TYPEFLAGS2_SHIFT);
+ }
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_clock_get_fixedfactor_params() - PM call to request a clock's fixed
+ * factor parameters for fixed clock
+ * @clock_id Clock ID
+ * @mul Multiplication value
+ * @div Divisor value
+ *
+ * This function is used by master to get fixed factor parameers for the
+ * fixed clock. This API is application only for the fixed clock.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_clock_get_fixedfactor_params(uint32_t clock_id,
+ uint32_t *mul,
+ uint32_t *div)
+{
+ struct pm_clock_node *clock_nodes;
+ uint8_t num_nodes;
+ uint32_t type, i;
+
+ if (!pm_clock_valid(clock_id)) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT) {
+ return PM_RET_ERROR_NOTSUPPORTED;
+ }
+
+ clock_nodes = *clocks[clock_id].nodes;
+ num_nodes = clocks[clock_id].num_nodes;
+
+ for (i = 0; i < num_nodes; i++) {
+ type = clock_nodes[i].type;
+ if (type == TYPE_FIXEDFACTOR) {
+ *mul = clock_nodes[i].mult;
+ *div = clock_nodes[i].div;
+ break;
+ }
+ }
+
+ /* Clock is not fixed clock */
+ if (i == num_nodes) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_clock_get_parents() - PM call to request a clock's first 3 parents
+ * @clock_id Clock ID
+ * @index Index of next parent
+ * @parents Parents of the given clock
+ *
+ * This function is used by master to get clock's parents information.
+ * This API will return 3 parents with a single response. To get other
+ * parents, master should call same API in loop with new parent index
+ * till error is returned.
+ *
+ * E.g First call should have index 0 which will return parents 0, 1 and
+ * 2. Next call, index should be 3 which will return parent 3,4 and 5 and
+ * so on.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_clock_get_parents(uint32_t clock_id,
+ uint32_t index,
+ uint32_t *parents)
+{
+ uint32_t i;
+ int32_t *clk_parents;
+
+ if (!pm_clock_valid(clock_id)) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT) {
+ return PM_RET_ERROR_NOTSUPPORTED;
+ }
+
+ clk_parents = *clocks[clock_id].parents;
+ if (clk_parents == NULL) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ memset(parents, 0, CLK_PARENTS_PAYLOAD_LEN);
+
+ /* Skip parent till index */
+ for (i = 0; i < index; i++) {
+ if (clk_parents[i] == CLK_NA_PARENT) {
+ return PM_RET_SUCCESS;
+ }
+ }
+
+ for (i = 0; i < 3U; i++) {
+ parents[i] = clk_parents[index + i];
+ if (clk_parents[index + i] == CLK_NA_PARENT) {
+ break;
+ }
+ }
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_clock_get_attributes() - PM call to request a clock's attributes
+ * @clock_id Clock ID
+ * @attr Clock attributes
+ *
+ * This function is used by master to get clock's attributes
+ * (e.g. valid, clock type, etc).
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_clock_get_attributes(uint32_t clock_id,
+ uint32_t *attr)
+{
+ if (clock_id >= CLK_MAX) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ /* Clock valid bit */
+ *attr = pm_clock_valid(clock_id);
+
+ /* Clock type (Output/External) */
+ *attr |= (pm_clock_type(clock_id) << CLK_TYPE_SHIFT);
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_clock_get_max_divisor - PM call to get max divisor
+ * @clock_id Clock ID
+ * @div_type Divisor Type (TYPE_DIV1 or TYPE_DIV2)
+ * @max_div Maximum supported divisor
+ *
+ * This function is used by master to get maximum supported value.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_api_clock_get_max_divisor(enum clock_id clock_id,
+ uint8_t div_type,
+ uint32_t *max_div)
+{
+ uint32_t i;
+ struct pm_clock_node *nodes;
+
+ if (clock_id >= CLK_MAX_OUTPUT_CLK) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ nodes = *clocks[clock_id].nodes;
+ for (i = 0; i < clocks[clock_id].num_nodes; i++) {
+ if (nodes[i].type == div_type) {
+ if (CLK_DIVIDER_POWER_OF_TWO &
+ nodes[i].typeflags) {
+ *max_div = (1U << (BIT(nodes[i].width) - 1U));
+ } else {
+ *max_div = BIT(nodes[i].width) - 1U;
+ }
+ return PM_RET_SUCCESS;
+ }
+ }
+
+ return PM_RET_ERROR_ARGS;
+}
+
+/**
+ * struct pm_pll - PLL related data required to map IOCTL-based PLL control
+ * implemented by linux to system-level EEMI APIs
+ * @nid: PLL node ID
+ * @cid: PLL clock ID
+ * @pre_src: Pre-source PLL clock ID
+ * @post_src: Post-source PLL clock ID
+ * @div2: DIV2 PLL clock ID
+ * @bypass: PLL output clock ID that maps to bypass select output
+ * @mode: PLL mode currently set via IOCTL (PLL_FRAC_MODE/PLL_INT_MODE)
+ */
+struct pm_pll {
+ const enum pm_node_id nid;
+ const enum clock_id cid;
+ const enum clock_id pre_src;
+ const enum clock_id post_src;
+ const enum clock_id div2;
+ const enum clock_id bypass;
+ uint8_t mode;
+};
+
+static struct pm_pll pm_plls[] = {
+ {
+ .nid = NODE_IOPLL,
+ .cid = CLK_IOPLL_INT,
+ .pre_src = CLK_IOPLL_PRE_SRC,
+ .post_src = CLK_IOPLL_POST_SRC,
+ .div2 = CLK_IOPLL_INT_MUX,
+ .bypass = CLK_IOPLL,
+ }, {
+ .nid = NODE_RPLL,
+ .cid = CLK_RPLL_INT,
+ .pre_src = CLK_RPLL_PRE_SRC,
+ .post_src = CLK_RPLL_POST_SRC,
+ .div2 = CLK_RPLL_INT_MUX,
+ .bypass = CLK_RPLL,
+ }, {
+ .nid = NODE_APLL,
+ .cid = CLK_APLL_INT,
+ .pre_src = CLK_APLL_PRE_SRC,
+ .post_src = CLK_APLL_POST_SRC,
+ .div2 = CLK_APLL_INT_MUX,
+ .bypass = CLK_APLL,
+ }, {
+ .nid = NODE_VPLL,
+ .cid = CLK_VPLL_INT,
+ .pre_src = CLK_VPLL_PRE_SRC,
+ .post_src = CLK_VPLL_POST_SRC,
+ .div2 = CLK_VPLL_INT_MUX,
+ .bypass = CLK_VPLL,
+ }, {
+ .nid = NODE_DPLL,
+ .cid = CLK_DPLL_INT,
+ .pre_src = CLK_DPLL_PRE_SRC,
+ .post_src = CLK_DPLL_POST_SRC,
+ .div2 = CLK_DPLL_INT_MUX,
+ .bypass = CLK_DPLL,
+ },
+};
+
+/**
+ * pm_clock_get_pll() - Get PLL structure by PLL clock ID
+ * @clock_id Clock ID of the target PLL
+ *
+ * @return Pointer to PLL structure if found, NULL otherwise
+ */
+struct pm_pll *pm_clock_get_pll(enum clock_id clock_id)
+{
+ uint32_t i;
+
+ for (i = 0; i < ARRAY_SIZE(pm_plls); i++) {
+ if (pm_plls[i].cid == clock_id) {
+ return &pm_plls[i];
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * pm_clock_get_pll_node_id() - Get PLL node ID by PLL clock ID
+ * @clock_id Clock ID of the target PLL
+ * @node_id Location to store node ID of the target PLL
+ *
+ * @return PM_RET_SUCCESS if node ID is found, PM_RET_ERROR_ARGS otherwise
+ */
+enum pm_ret_status pm_clock_get_pll_node_id(enum clock_id clock_id,
+ enum pm_node_id *node_id)
+{
+ struct pm_pll *pll = pm_clock_get_pll(clock_id);
+
+ if (pll) {
+ *node_id = pll->nid;
+ return PM_RET_SUCCESS;
+ }
+
+ return PM_RET_ERROR_ARGS;
+}
+
+/**
+ * pm_clock_get_pll_by_related_clk() - Get PLL structure by PLL-related clock ID
+ * @clock_id Clock ID
+ *
+ * @return Pointer to PLL structure if found, NULL otherwise
+ */
+struct pm_pll *pm_clock_get_pll_by_related_clk(enum clock_id clock_id)
+{
+ uint32_t i;
+
+ for (i = 0; i < ARRAY_SIZE(pm_plls); i++) {
+ if (pm_plls[i].pre_src == clock_id ||
+ pm_plls[i].post_src == clock_id ||
+ pm_plls[i].div2 == clock_id ||
+ pm_plls[i].bypass == clock_id) {
+ return &pm_plls[i];
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * pm_clock_pll_enable() - "Enable" the PLL clock (lock the PLL)
+ * @pll: PLL to be locked
+ *
+ * This function is used to map IOCTL/linux-based PLL handling to system-level
+ * EEMI APIs
+ *
+ * Return: Error if the argument is not valid or status as returned by PMU
+ */
+enum pm_ret_status pm_clock_pll_enable(struct pm_pll *pll)
+{
+ if (pll == NULL) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ /* Set the PLL mode according to the buffered mode value */
+ if (pll->mode == PLL_FRAC_MODE) {
+ return pm_pll_set_mode(pll->nid, PM_PLL_MODE_FRACTIONAL);
+ }
+
+ return pm_pll_set_mode(pll->nid, PM_PLL_MODE_INTEGER);
+}
+
+/**
+ * pm_clock_pll_disable - "Disable" the PLL clock (bypass/reset the PLL)
+ * @pll PLL to be bypassed/reset
+ *
+ * This function is used to map IOCTL/linux-based PLL handling to system-level
+ * EEMI APIs
+ *
+ * Return: Error if the argument is not valid or status as returned by PMU
+ */
+enum pm_ret_status pm_clock_pll_disable(struct pm_pll *pll)
+{
+ if (pll == NULL) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ return pm_pll_set_mode(pll->nid, PM_PLL_MODE_RESET);
+}
+
+/**
+ * pm_clock_pll_get_state - Get state of the PLL
+ * @pll Pointer to the target PLL structure
+ * @state Location to store the state: 1/0 ("Enabled"/"Disabled")
+ *
+ * "Enable" actually means that the PLL is locked and its bypass is deasserted,
+ * "Disable" means that it is bypassed.
+ *
+ * Return: PM_RET_ERROR_ARGS error if the argument is not valid, success if
+ * returned state value is valid or an error if returned by PMU
+ */
+enum pm_ret_status pm_clock_pll_get_state(struct pm_pll *pll,
+ uint32_t *state)
+{
+ enum pm_ret_status status;
+ enum pm_pll_mode mode;
+
+ if ((pll == NULL) || !state) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ status = pm_pll_get_mode(pll->nid, &mode);
+ if (status != PM_RET_SUCCESS) {
+ return status;
+ }
+
+ if (mode == PM_PLL_MODE_RESET) {
+ *state = 0;
+ } else {
+ *state = 1;
+ }
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_clock_pll_set_parent - Set the clock parent for PLL-related clock id
+ * @pll Target PLL structure
+ * @clock_id Id of the clock
+ * @parent_index parent index (=mux select value)
+ *
+ * The whole clock-tree implementation relies on the fact that parent indexes
+ * match to the multiplexer select values. This function has to rely on that
+ * assumption as well => parent_index is actually the mux select value.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_pll_set_parent(struct pm_pll *pll,
+ enum clock_id clock_id,
+ uint32_t parent_index)
+{
+ if (pll == NULL) {
+ return PM_RET_ERROR_ARGS;
+ }
+ if (pll->pre_src == clock_id) {
+ return pm_pll_set_parameter(pll->nid, PM_PLL_PARAM_PRE_SRC,
+ parent_index);
+ }
+ if (pll->post_src == clock_id) {
+ return pm_pll_set_parameter(pll->nid, PM_PLL_PARAM_POST_SRC,
+ parent_index);
+ }
+ if (pll->div2 == clock_id) {
+ return pm_pll_set_parameter(pll->nid, PM_PLL_PARAM_DIV2,
+ parent_index);
+ }
+
+ return PM_RET_ERROR_ARGS;
+}
+
+/**
+ * pm_clock_pll_get_parent - Get mux select value of PLL-related clock parent
+ * @pll Target PLL structure
+ * @clock_id Id of the clock
+ * @parent_index parent index (=mux select value)
+ *
+ * This function is used by master to get parent index for PLL-related clock.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_pll_get_parent(struct pm_pll *pll,
+ enum clock_id clock_id,
+ uint32_t *parent_index)
+{
+ if (pll == NULL) {
+ return PM_RET_ERROR_ARGS;
+ }
+ if (pll->pre_src == clock_id) {
+ return pm_pll_get_parameter(pll->nid, PM_PLL_PARAM_PRE_SRC,
+ parent_index);
+ }
+ if (pll->post_src == clock_id) {
+ return pm_pll_get_parameter(pll->nid, PM_PLL_PARAM_POST_SRC,
+ parent_index);
+ }
+ if (pll->div2 == clock_id) {
+ return pm_pll_get_parameter(pll->nid, PM_PLL_PARAM_DIV2,
+ parent_index);
+ }
+ if (pll->bypass == clock_id) {
+ *parent_index = 0;
+ return PM_RET_SUCCESS;
+ }
+
+ return PM_RET_ERROR_ARGS;
+}
+
+/**
+ * pm_clock_set_pll_mode() - Set PLL mode
+ * @clock_id PLL clock id
+ * @mode Mode fractional/integer
+ *
+ * This function buffers/saves the PLL mode that is set.
+ *
+ * @return Success if mode is buffered or error if an argument is invalid
+ */
+enum pm_ret_status pm_clock_set_pll_mode(enum clock_id clock_id,
+ uint32_t mode)
+{
+ struct pm_pll *pll = pm_clock_get_pll(clock_id);
+
+ if ((pll == NULL) || (mode != PLL_FRAC_MODE && mode != PLL_INT_MODE)) {
+ return PM_RET_ERROR_ARGS;
+ }
+ pll->mode = mode;
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_clock_get_pll_mode() - Get PLL mode
+ * @clock_id PLL clock id
+ * @mode Location to store the mode (fractional/integer)
+ *
+ * This function returns buffered PLL mode.
+ *
+ * @return Success if mode is stored or error if an argument is invalid
+ */
+enum pm_ret_status pm_clock_get_pll_mode(enum clock_id clock_id,
+ uint32_t *mode)
+{
+ struct pm_pll *pll = pm_clock_get_pll(clock_id);
+
+ if ((pll == NULL) || !mode) {
+ return PM_RET_ERROR_ARGS;
+ }
+ *mode = pll->mode;
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_clock_id_is_valid() - Check if given clock ID is valid
+ * @clock_id ID of the clock to be checked
+ *
+ * @return Returns success if clock_id is valid, otherwise an error
+ */
+enum pm_ret_status pm_clock_id_is_valid(uint32_t clock_id)
+{
+ if (!pm_clock_valid(clock_id)) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT) {
+ return PM_RET_ERROR_NOTSUPPORTED;
+ }
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_clock_has_div() - Check if the clock has divider with given ID
+ * @clock_id Clock ID
+ * @div_id Divider ID
+ *
+ * @return True(1)=clock has the divider, false(0)=otherwise
+ */
+uint8_t pm_clock_has_div(uint32_t clock_id, enum pm_clock_div_id div_id)
+{
+ uint32_t i;
+ struct pm_clock_node *nodes;
+
+ if (clock_id >= CLK_MAX_OUTPUT_CLK) {
+ return 0;
+ }
+
+ nodes = *clocks[clock_id].nodes;
+ for (i = 0; i < clocks[clock_id].num_nodes; i++) {
+ if (nodes[i].type == TYPE_DIV1) {
+ if (div_id == PM_CLOCK_DIV0_ID)
+ return 1;
+ } else if (nodes[i].type == TYPE_DIV2) {
+ if (div_id == PM_CLOCK_DIV1_ID)
+ return 1;
+ } else {
+ /* To fix the misra 15.7 warning */
+ }
+ }
+
+ return 0;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_clock.h b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
new file mode 100644
index 0000000..cc0dacc
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_clock.h
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for clock control.
+ */
+
+#ifndef PM_API_CLOCK_H
+#define PM_API_CLOCK_H
+
+#include <lib/utils_def.h>
+
+#include "pm_common.h"
+
+#define CLK_NAME_LEN (15U)
+#define MAX_PARENTS (100U)
+#define CLK_NA_PARENT -1
+#define CLK_DUMMY_PARENT -2
+
+/* Flags for parent id */
+#define PARENT_CLK_SELF (0U)
+#define PARENT_CLK_NODE1 (1U)
+#define PARENT_CLK_NODE2 (2U)
+#define PARENT_CLK_NODE3 (3U)
+#define PARENT_CLK_NODE4 (4U)
+#define PARENT_CLK_EXTERNAL (5U)
+#define PARENT_CLK_MIO0_MIO77 (6U)
+
+#define CLK_SET_RATE_GATE BIT(0) /* must be gated across rate change */
+#define CLK_SET_PARENT_GATE BIT(1) /* must be gated across re-parent */
+#define CLK_SET_RATE_PARENT BIT(2) /* propagate rate change up one level */
+#define CLK_IGNORE_UNUSED BIT(3) /* do not gate even if unused */
+/* unused */
+#define CLK_IS_BASIC BIT(5) /* Basic clk, can't do a to_clk_foo() */
+#define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */
+#define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */
+#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */
+#define CLK_RECALC_NEW_RATES BIT(9) /* recalc rates after notifications */
+#define CLK_SET_RATE_UNGATE BIT(10) /* clock needs to run to set rate */
+#define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */
+/* parents need enable during gate/ungate, set rate and re-parent */
+#define CLK_OPS_PARENT_ENABLE BIT(12)
+
+#define CLK_DIVIDER_ONE_BASED BIT(0)
+#define CLK_DIVIDER_POWER_OF_TWO BIT(1)
+#define CLK_DIVIDER_ALLOW_ZERO BIT(2)
+#define CLK_DIVIDER_HIWORD_MASK BIT(3)
+#define CLK_DIVIDER_ROUND_CLOSEST BIT(4)
+#define CLK_DIVIDER_READ_ONLY BIT(5)
+#define CLK_DIVIDER_MAX_AT_ZERO BIT(6)
+#define CLK_FRAC BIT(8)
+
+#define END_OF_CLK "END_OF_CLK"
+
+//CLock Ids
+enum clock_id {
+ CLK_IOPLL = (0U),
+ CLK_RPLL = (1U),
+ CLK_APLL = (2U),
+ CLK_DPLL = (3U),
+ CLK_VPLL = (4U),
+ CLK_IOPLL_TO_FPD = (5U),
+ CLK_RPLL_TO_FPD = (6U),
+ CLK_APLL_TO_LPD = (7U),
+ CLK_DPLL_TO_LPD = (8U),
+ CLK_VPLL_TO_LPD = (9U),
+ CLK_ACPU = (10U),
+ CLK_ACPU_HALF = (11U),
+ CLK_DBG_FPD = (12U),
+ CLK_DBG_LPD = (13U),
+ CLK_DBG_TRACE = (14U),
+ CLK_DBG_TSTMP = (15U),
+ CLK_DP_VIDEO_REF = (16U),
+ CLK_DP_AUDIO_REF = (17U),
+ CLK_DP_STC_REF = (18U),
+ CLK_GDMA_REF = (19U),
+ CLK_DPDMA_REF = (20U),
+ CLK_DDR_REF = (21U),
+ CLK_SATA_REF = (22U),
+ CLK_PCIE_REF = (23U),
+ CLK_GPU_REF = (24U),
+ CLK_GPU_PP0_REF = (25U),
+ CLK_GPU_PP1_REF = (26U),
+ CLK_TOPSW_MAIN = (27U),
+ CLK_TOPSW_LSBUS = (28U),
+ CLK_GTGREF0_REF = (29U),
+ CLK_LPD_SWITCH = (30U),
+ CLK_LPD_LSBUS = (31U),
+ CLK_USB0_BUS_REF = (32U),
+ CLK_USB1_BUS_REF = (33U),
+ CLK_USB3_DUAL_REF = (34U),
+ CLK_USB0 = (35U),
+ CLK_USB1 = (36U),
+ CLK_CPU_R5 = (37U),
+ CLK_CPU_R5_CORE = (38U),
+ CLK_CSU_SPB = (39U),
+ CLK_CSU_PLL = (40U),
+ CLK_PCAP = (41U),
+ CLK_IOU_SWITCH = (42U),
+ CLK_GEM_TSU_REF = (43U),
+ CLK_GEM_TSU = (44U),
+ CLK_GEM0_TX = (45U),
+ CLK_GEM1_TX = (46U),
+ CLK_GEM2_TX = (47U),
+ CLK_GEM3_TX = (48U),
+ CLK_GEM0_RX = (49U),
+ CLK_GEM1_RX = (50U),
+ CLK_GEM2_RX = (51U),
+ CLK_GEM3_RX = (52U),
+ CLK_QSPI_REF = (53U),
+ CLK_SDIO0_REF = (54U),
+ CLK_SDIO1_REF = (55U),
+ CLK_UART0_REF = (56U),
+ CLK_UART1_REF = (57U),
+ CLK_SPI0_REF = (58U),
+ CLK_SPI1_REF = (59U),
+ CLK_NAND_REF = (60U),
+ CLK_I2C0_REF = (61U),
+ CLK_I2C1_REF = (62U),
+ CLK_CAN0_REF = (63U),
+ CLK_CAN1_REF = (64U),
+ CLK_CAN0 = (65U),
+ CLK_CAN1 = (66U),
+ CLK_DLL_REF = (67U),
+ CLK_ADMA_REF = (68U),
+ CLK_TIMESTAMP_REF = (69U),
+ CLK_AMS_REF = (70U),
+ CLK_PL0_REF = (71U),
+ CLK_PL1_REF = (72U),
+ CLK_PL2_REF = (73U),
+ CLK_PL3_REF = (74U),
+ CLK_FPD_WDT = (75U),
+ CLK_IOPLL_INT = (76U),
+ CLK_IOPLL_PRE_SRC = (77U),
+ CLK_IOPLL_HALF = (78U),
+ CLK_IOPLL_INT_MUX = (79U),
+ CLK_IOPLL_POST_SRC = (80U),
+ CLK_RPLL_INT = (81U),
+ CLK_RPLL_PRE_SRC = (82U),
+ CLK_RPLL_HALF = (83U),
+ CLK_RPLL_INT_MUX = (84U),
+ CLK_RPLL_POST_SRC = (85U),
+ CLK_APLL_INT = (86U),
+ CLK_APLL_PRE_SRC = (87U),
+ CLK_APLL_HALF = (88U),
+ CLK_APLL_INT_MUX = (89U),
+ CLK_APLL_POST_SRC = (90U),
+ CLK_DPLL_INT = (91U),
+ CLK_DPLL_PRE_SRC = (92U),
+ CLK_DPLL_HALF = (93U),
+ CLK_DPLL_INT_MUX = (94U),
+ CLK_DPLL_POST_SRC = (95U),
+ CLK_VPLL_INT = (96U),
+ CLK_VPLL_PRE_SRC = (97U),
+ CLK_VPLL_HALF = (98U),
+ CLK_VPLL_INT_MUX = (99U),
+ CLK_VPLL_POST_SRC = (100U),
+ CLK_CAN0_MIO = (101U),
+ CLK_CAN1_MIO = (102U),
+ CLK_ACPU_FULL = (103U),
+ CLK_GEM0_REF = (104U),
+ CLK_GEM1_REF = (105U),
+ CLK_GEM2_REF = (106U),
+ CLK_GEM3_REF = (107U),
+ CLK_GEM0_REF_UNGATED = (108U),
+ CLK_GEM1_REF_UNGATED = (109U),
+ CLK_GEM2_REF_UNGATED = (110U),
+ CLK_GEM3_REF_UNGATED = (111U),
+ CLK_LPD_WDT = (112U),
+ END_OF_OUTPUT_CLKS = (113U),
+};
+
+#define CLK_MAX_OUTPUT_CLK END_OF_OUTPUT_CLKS
+
+//External clock ids
+enum {
+ EXT_CLK_PSS_REF = END_OF_OUTPUT_CLKS,
+ EXT_CLK_VIDEO = (114U),
+ EXT_CLK_PSS_ALT_REF = (115U),
+ EXT_CLK_AUX_REF = (116U),
+ EXT_CLK_GT_CRX_REF = (117U),
+ EXT_CLK_SWDT0 = (118U),
+ EXT_CLK_SWDT1 = (119U),
+ EXT_CLK_GEM0_TX_EMIO = (120U),
+ EXT_CLK_GEM1_TX_EMIO = (121U),
+ EXT_CLK_GEM2_TX_EMIO = (122U),
+ EXT_CLK_GEM3_TX_EMIO = (123U),
+ EXT_CLK_GEM0_RX_EMIO = (124U),
+ EXT_CLK_GEM1_RX_EMIO = (125U),
+ EXT_CLK_GEM2_RX_EMIO = (126U),
+ EXT_CLK_GEM3_RX_EMIO = (127U),
+ EXT_CLK_MIO50_OR_MIO51 = (128U),
+ EXT_CLK_MIO0 = (129U),
+ EXT_CLK_MIO1 = (130U),
+ EXT_CLK_MIO2 = (131U),
+ EXT_CLK_MIO3 = (132U),
+ EXT_CLK_MIO4 = (133U),
+ EXT_CLK_MIO5 = (134U),
+ EXT_CLK_MIO6 = (135U),
+ EXT_CLK_MIO7 = (136U),
+ EXT_CLK_MIO8 = (137U),
+ EXT_CLK_MIO9 = (138U),
+ EXT_CLK_MIO10 = (139U),
+ EXT_CLK_MIO11 = (140U),
+ EXT_CLK_MIO12 = (141U),
+ EXT_CLK_MIO13 = (142U),
+ EXT_CLK_MIO14 = (143U),
+ EXT_CLK_MIO15 = (144U),
+ EXT_CLK_MIO16 = (145U),
+ EXT_CLK_MIO17 = (146U),
+ EXT_CLK_MIO18 = (147U),
+ EXT_CLK_MIO19 = (148U),
+ EXT_CLK_MIO20 = (149U),
+ EXT_CLK_MIO21 = (150U),
+ EXT_CLK_MIO22 = (151U),
+ EXT_CLK_MIO23 = (152U),
+ EXT_CLK_MIO24 = (153U),
+ EXT_CLK_MIO25 = (154U),
+ EXT_CLK_MIO26 = (155U),
+ EXT_CLK_MIO27 = (156U),
+ EXT_CLK_MIO28 = (157U),
+ EXT_CLK_MIO29 = (158U),
+ EXT_CLK_MIO30 = (159U),
+ EXT_CLK_MIO31 = (160U),
+ EXT_CLK_MIO32 = (161U),
+ EXT_CLK_MIO33 = (162U),
+ EXT_CLK_MIO34 = (163U),
+ EXT_CLK_MIO35 = (164U),
+ EXT_CLK_MIO36 = (165U),
+ EXT_CLK_MIO37 = (166U),
+ EXT_CLK_MIO38 = (167U),
+ EXT_CLK_MIO39 = (168U),
+ EXT_CLK_MIO40 = (169U),
+ EXT_CLK_MIO41 = (170U),
+ EXT_CLK_MIO42 = (171U),
+ EXT_CLK_MIO43 = (172U),
+ EXT_CLK_MIO44 = (173U),
+ EXT_CLK_MIO45 = (174U),
+ EXT_CLK_MIO46 = (175U),
+ EXT_CLK_MIO47 = (176U),
+ EXT_CLK_MIO48 = (177U),
+ EXT_CLK_MIO49 = (178U),
+ EXT_CLK_MIO50 = (179U),
+ EXT_CLK_MIO51 = (180U),
+ EXT_CLK_MIO52 = (181U),
+ EXT_CLK_MIO53 = (182U),
+ EXT_CLK_MIO54 = (183U),
+ EXT_CLK_MIO55 = (184U),
+ EXT_CLK_MIO56 = (185U),
+ EXT_CLK_MIO57 = (186U),
+ EXT_CLK_MIO58 = (187U),
+ EXT_CLK_MIO59 = (188U),
+ EXT_CLK_MIO60 = (189U),
+ EXT_CLK_MIO61 = (190U),
+ EXT_CLK_MIO62 = (191U),
+ EXT_CLK_MIO63 = (192U),
+ EXT_CLK_MIO64 = (193U),
+ EXT_CLK_MIO65 = (194U),
+ EXT_CLK_MIO66 = (195U),
+ EXT_CLK_MIO67 = (196U),
+ EXT_CLK_MIO68 = (197U),
+ EXT_CLK_MIO69 = (198U),
+ EXT_CLK_MIO70 = (199U),
+ EXT_CLK_MIO71 = (200U),
+ EXT_CLK_MIO72 = (201U),
+ EXT_CLK_MIO73 = (202U),
+ EXT_CLK_MIO74 = (203U),
+ EXT_CLK_MIO75 = (204U),
+ EXT_CLK_MIO76 = (205U),
+ EXT_CLK_MIO77 = (206U),
+ END_OF_CLKS = (207U),
+};
+
+#define CLK_MAX END_OF_CLKS
+
+//CLock types
+#define CLK_TYPE_OUTPUT 0U
+#define CLK_TYPE_EXTERNAL 1U
+
+//Topology types
+#define TYPE_INVALID 0U
+#define TYPE_MUX 1U
+#define TYPE_PLL 2U
+#define TYPE_FIXEDFACTOR 3U
+#define TYPE_DIV1 4U
+#define TYPE_DIV2 5U
+#define TYPE_GATE 6U
+
+struct pm_pll;
+struct pm_pll *pm_clock_get_pll(enum clock_id clock_id);
+struct pm_pll *pm_clock_get_pll_by_related_clk(enum clock_id clock_id);
+uint8_t pm_clock_has_div(uint32_t clock_id, enum pm_clock_div_id div_id);
+
+void pm_api_clock_get_name(uint32_t clock_id, char *name);
+enum pm_ret_status pm_api_clock_get_num_clocks(uint32_t *nclocks);
+enum pm_ret_status pm_api_clock_get_topology(uint32_t clock_id,
+ uint32_t index,
+ uint32_t *topology);
+enum pm_ret_status pm_api_clock_get_fixedfactor_params(uint32_t clock_id,
+ uint32_t *mul,
+ uint32_t *div);
+enum pm_ret_status pm_api_clock_get_parents(uint32_t clock_id,
+ uint32_t index,
+ uint32_t *parents);
+enum pm_ret_status pm_api_clock_get_attributes(uint32_t clock_id,
+ uint32_t *attr);
+enum pm_ret_status pm_api_clock_get_max_divisor(enum clock_id clock_id,
+ uint8_t div_type,
+ uint32_t *max_div);
+
+enum pm_ret_status pm_clock_get_pll_node_id(enum clock_id clock_id,
+ enum pm_node_id *node_id);
+enum pm_ret_status pm_clock_id_is_valid(uint32_t clock_id);
+
+enum pm_ret_status pm_clock_pll_enable(struct pm_pll *pll);
+enum pm_ret_status pm_clock_pll_disable(struct pm_pll *pll);
+enum pm_ret_status pm_clock_pll_get_state(struct pm_pll *pll,
+ uint32_t *state);
+enum pm_ret_status pm_clock_pll_set_parent(struct pm_pll *pll,
+ enum clock_id clock_id,
+ uint32_t parent_index);
+enum pm_ret_status pm_clock_pll_get_parent(struct pm_pll *pll,
+ enum clock_id clock_id,
+ uint32_t *parent_index);
+enum pm_ret_status pm_clock_set_pll_mode(enum clock_id clock_id,
+ uint32_t mode);
+enum pm_ret_status pm_clock_get_pll_mode(enum clock_id clock_id,
+ uint32_t *mode);
+
+#endif /* PM_API_CLOCK_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c
new file mode 100644
index 0000000..c0bfd51
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c
@@ -0,0 +1,767 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for ioctl.
+ */
+
+#include <arch_helpers.h>
+#include <drivers/delay_timer.h>
+#include <lib/mmio.h>
+#include <plat/common/platform.h>
+#include <zynqmp_def.h>
+
+#include "pm_api_clock.h"
+#include "pm_api_ioctl.h"
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_common.h"
+#include "pm_ipi.h"
+
+/**
+ * pm_ioctl_get_rpu_oper_mode () - Get current RPU operation mode
+ * @mode Buffer to store value of oper mode(Split/Lock-step)
+ *
+ * This function provides current configured RPU operational mode.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_get_rpu_oper_mode(uint32_t *mode)
+{
+ uint32_t val;
+
+ val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
+ val &= ZYNQMP_SLSPLIT_MASK;
+ if (val == 0U) {
+ *mode = PM_RPU_MODE_LOCKSTEP;
+ } else {
+ *mode = PM_RPU_MODE_SPLIT;
+ }
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_ioctl_set_rpu_oper_mode () - Configure RPU operation mode
+ * @mode Value to set for oper mode(Split/Lock-step)
+ *
+ * This function configures RPU operational mode(Split/Lock-step).
+ * It also sets TCM combined mode in RPU lock-step and TCM non-combined
+ * mode for RPU split mode. In case of Lock step mode, RPU1's output is
+ * clamped.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_set_rpu_oper_mode(uint32_t mode)
+{
+ uint32_t val;
+
+ if (mmio_read_32(CRL_APB_RST_LPD_TOP) & CRL_APB_RPU_AMBA_RESET) {
+ return PM_RET_ERROR_ACCESS;
+ }
+
+ val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
+
+ if (mode == PM_RPU_MODE_SPLIT) {
+ val |= ZYNQMP_SLSPLIT_MASK;
+ val &= ~ZYNQMP_TCM_COMB_MASK;
+ val &= ~ZYNQMP_SLCLAMP_MASK;
+ } else if (mode == PM_RPU_MODE_LOCKSTEP) {
+ val &= ~ZYNQMP_SLSPLIT_MASK;
+ val |= ZYNQMP_TCM_COMB_MASK;
+ val |= ZYNQMP_SLCLAMP_MASK;
+ } else {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ mmio_write_32(ZYNQMP_RPU_GLBL_CNTL, val);
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_ioctl_config_boot_addr() - Configure RPU boot address
+ * @nid Node ID of RPU
+ * @value Value to set for boot address (TCM/OCM)
+ *
+ * This function configures RPU boot address(memory).
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_config_boot_addr(enum pm_node_id nid,
+ uint32_t value)
+{
+ uint32_t rpu_cfg_addr, val;
+
+ if (nid == NODE_RPU_0) {
+ rpu_cfg_addr = ZYNQMP_RPU0_CFG;
+ } else if (nid == NODE_RPU_1) {
+ rpu_cfg_addr = ZYNQMP_RPU1_CFG;
+ } else {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ val = mmio_read_32(rpu_cfg_addr);
+
+ if (value == PM_RPU_BOOTMEM_LOVEC) {
+ val &= ~ZYNQMP_VINITHI_MASK;
+ } else if (value == PM_RPU_BOOTMEM_HIVEC) {
+ val |= ZYNQMP_VINITHI_MASK;
+ } else {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ mmio_write_32(rpu_cfg_addr, val);
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_ioctl_config_tcm_comb() - Configure TCM combined mode
+ * @value Value to set (Split/Combined)
+ *
+ * This function configures TCM to be in split mode or combined
+ * mode.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_config_tcm_comb(uint32_t value)
+{
+ uint32_t val;
+
+ val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL);
+
+ if (value == PM_RPU_TCM_SPLIT) {
+ val &= ~ZYNQMP_TCM_COMB_MASK;
+ } else if (value == PM_RPU_TCM_COMB) {
+ val |= ZYNQMP_TCM_COMB_MASK;
+ } else {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ mmio_write_32(ZYNQMP_RPU_GLBL_CNTL, val);
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_ioctl_set_tapdelay_bypass() - Enable/Disable tap delay bypass
+ * @type Type of tap delay to enable/disable (e.g. QSPI)
+ * @value Enable/Disable
+ *
+ * This function enable/disable tap delay bypass.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_set_tapdelay_bypass(uint32_t type,
+ uint32_t value)
+{
+ if ((value != PM_TAPDELAY_BYPASS_ENABLE &&
+ value != PM_TAPDELAY_BYPASS_DISABLE) || type >= PM_TAPDELAY_MAX) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ return pm_mmio_write(IOU_TAPDLY_BYPASS, TAP_DELAY_MASK, value << type);
+}
+
+/**
+ * pm_ioctl_set_sgmii_mode() - Set SGMII mode for the GEM device
+ * @nid Node ID of the device
+ * @value Enable/Disable
+ *
+ * This function enable/disable SGMII mode for the GEM device.
+ * While enabling SGMII mode, it also ties the GEM PCS Signal
+ * Detect to 1 and selects EMIO for RX clock generation.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_set_sgmii_mode(enum pm_node_id nid,
+ uint32_t value)
+{
+ uint32_t val, mask, shift;
+ enum pm_ret_status ret;
+
+ if (value != PM_SGMII_DISABLE && value != PM_SGMII_ENABLE) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ switch (nid) {
+ case NODE_ETH_0:
+ shift = 0;
+ break;
+ case NODE_ETH_1:
+ shift = 1;
+ break;
+ case NODE_ETH_2:
+ shift = 2;
+ break;
+ case NODE_ETH_3:
+ shift = 3;
+ break;
+ default:
+ return PM_RET_ERROR_ARGS;
+ }
+
+ if (value == PM_SGMII_DISABLE) {
+ mask = GEM_SGMII_MASK << GEM_CLK_CTRL_OFFSET * shift;
+ ret = pm_mmio_write(IOU_GEM_CLK_CTRL, mask, 0U);
+ } else {
+ /* Tie the GEM PCS Signal Detect to 1 */
+ mask = SGMII_SD_MASK << SGMII_SD_OFFSET * shift;
+ val = SGMII_PCS_SD_1 << SGMII_SD_OFFSET * shift;
+ ret = pm_mmio_write(IOU_GEM_CTRL, mask, val);
+ if (ret != PM_RET_SUCCESS) {
+ return ret;
+ }
+
+ /* Set the GEM to SGMII mode */
+ mask = GEM_CLK_CTRL_MASK << GEM_CLK_CTRL_OFFSET * shift;
+ val = GEM_RX_SRC_SEL_GTR | GEM_SGMII_MODE;
+ val <<= GEM_CLK_CTRL_OFFSET * shift;
+ ret = pm_mmio_write(IOU_GEM_CLK_CTRL, mask, val);
+ }
+
+ return ret;
+}
+
+/**
+ * pm_ioctl_sd_dll_reset() - Reset DLL logic
+ * @nid Node ID of the device
+ * @type Reset type
+ *
+ * This function resets DLL logic for the SD device.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_sd_dll_reset(enum pm_node_id nid,
+ uint32_t type)
+{
+ uint32_t mask, val;
+ enum pm_ret_status ret;
+
+ if (nid == NODE_SD_0) {
+ mask = ZYNQMP_SD0_DLL_RST_MASK;
+ val = ZYNQMP_SD0_DLL_RST;
+ } else if (nid == NODE_SD_1) {
+ mask = ZYNQMP_SD1_DLL_RST_MASK;
+ val = ZYNQMP_SD1_DLL_RST;
+ } else {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ switch (type) {
+ case PM_DLL_RESET_ASSERT:
+ case PM_DLL_RESET_PULSE:
+ ret = pm_mmio_write(ZYNQMP_SD_DLL_CTRL, mask, val);
+ if (ret != PM_RET_SUCCESS) {
+ return ret;
+ }
+
+ if (type == PM_DLL_RESET_ASSERT) {
+ break;
+ }
+ mdelay(1);
+ /* Fallthrough */
+ case PM_DLL_RESET_RELEASE:
+ ret = pm_mmio_write(ZYNQMP_SD_DLL_CTRL, mask, 0);
+ break;
+ default:
+ ret = PM_RET_ERROR_ARGS;
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pm_ioctl_sd_set_tapdelay() - Set tap delay for the SD device
+ * @nid Node ID of the device
+ * @type Type of tap delay to set (input/output)
+ * @value Value to set fot the tap delay
+ *
+ * This function sets input/output tap delay for the SD device.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_sd_set_tapdelay(enum pm_node_id nid,
+ enum tap_delay_type type,
+ uint32_t value)
+{
+ uint32_t shift;
+ enum pm_ret_status ret;
+ uint32_t val, mask;
+
+ if (nid == NODE_SD_0) {
+ shift = 0;
+ mask = ZYNQMP_SD0_DLL_RST_MASK;
+ } else if (nid == NODE_SD_1) {
+ shift = ZYNQMP_SD_TAP_OFFSET;
+ mask = ZYNQMP_SD1_DLL_RST_MASK;
+ } else {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ ret = pm_mmio_read(ZYNQMP_SD_DLL_CTRL, &val);
+ if (ret != PM_RET_SUCCESS) {
+ return ret;
+ }
+
+ if ((val & mask) == 0U) {
+ ret = pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_ASSERT);
+ if (ret != PM_RET_SUCCESS) {
+ return ret;
+ }
+ }
+
+ if (type == PM_TAPDELAY_INPUT) {
+ ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
+ (ZYNQMP_SD_ITAPCHGWIN_MASK << shift),
+ (ZYNQMP_SD_ITAPCHGWIN << shift));
+
+ if (ret != PM_RET_SUCCESS) {
+ goto reset_release;
+ }
+
+ if (value == 0U) {
+ ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
+ (ZYNQMP_SD_ITAPDLYENA_MASK <<
+ shift), 0);
+ } else {
+ ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
+ (ZYNQMP_SD_ITAPDLYENA_MASK <<
+ shift), (ZYNQMP_SD_ITAPDLYENA <<
+ shift));
+ }
+
+ if (ret != PM_RET_SUCCESS) {
+ goto reset_release;
+ }
+
+ ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
+ (ZYNQMP_SD_ITAPDLYSEL_MASK << shift),
+ (value << shift));
+
+ if (ret != PM_RET_SUCCESS) {
+ goto reset_release;
+ }
+
+ ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY,
+ (ZYNQMP_SD_ITAPCHGWIN_MASK << shift), 0);
+ } else if (type == PM_TAPDELAY_OUTPUT) {
+ ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY,
+ (ZYNQMP_SD_OTAPDLYENA_MASK << shift), 0);
+
+ if (ret != PM_RET_SUCCESS) {
+ goto reset_release;
+ }
+
+ ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY,
+ (ZYNQMP_SD_OTAPDLYSEL_MASK << shift),
+ (value << shift));
+ } else {
+ ret = PM_RET_ERROR_ARGS;
+ }
+
+reset_release:
+ if ((val & mask) == 0) {
+ (void)pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_RELEASE);
+ }
+
+ return ret;
+}
+
+/**
+ * pm_ioctl_set_pll_frac_mode() - Ioctl function for
+ * setting pll mode
+ * @pll PLL clock id
+ * @mode Mode fraction/integar
+ *
+ * This function sets PLL mode
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_set_pll_frac_mode
+ (uint32_t pll, uint32_t mode)
+{
+ return pm_clock_set_pll_mode(pll, mode);
+}
+
+/**
+ * pm_ioctl_get_pll_frac_mode() - Ioctl function for
+ * getting pll mode
+ * @pll PLL clock id
+ * @mode Mode fraction/integar
+ *
+ * This function return current PLL mode
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_get_pll_frac_mode
+ (uint32_t pll, uint32_t *mode)
+{
+ return pm_clock_get_pll_mode(pll, mode);
+}
+
+/**
+ * pm_ioctl_set_pll_frac_data() - Ioctl function for
+ * setting pll fraction data
+ * @pll PLL clock id
+ * @data fraction data
+ *
+ * This function sets fraction data.
+ * It is valid for fraction mode only.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_set_pll_frac_data
+ (uint32_t pll, uint32_t data)
+{
+ enum pm_node_id pll_nid;
+ enum pm_ret_status status;
+
+ /* Get PLL node ID using PLL clock ID */
+ status = pm_clock_get_pll_node_id(pll, &pll_nid);
+ if (status != PM_RET_SUCCESS) {
+ return status;
+ }
+
+ return pm_pll_set_parameter(pll_nid, PM_PLL_PARAM_DATA, data);
+}
+
+/**
+ * pm_ioctl_get_pll_frac_data() - Ioctl function for
+ * getting pll fraction data
+ * @pll PLL clock id
+ * @data fraction data
+ *
+ * This function returns fraction data value.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_get_pll_frac_data
+ (uint32_t pll, uint32_t *data)
+{
+ enum pm_node_id pll_nid;
+ enum pm_ret_status status;
+
+ /* Get PLL node ID using PLL clock ID */
+ status = pm_clock_get_pll_node_id(pll, &pll_nid);
+ if (status != PM_RET_SUCCESS) {
+ return status;
+ }
+
+ return pm_pll_get_parameter(pll_nid, PM_PLL_PARAM_DATA, data);
+}
+
+/**
+ * pm_ioctl_write_ggs() - Ioctl function for writing
+ * global general storage (ggs)
+ * @index GGS register index
+ * @value Register value to be written
+ *
+ * This function writes value to GGS register.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_write_ggs(uint32_t index,
+ uint32_t value)
+{
+ if (index >= GGS_NUM_REGS) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ return pm_mmio_write(GGS_BASEADDR + (index << 2),
+ 0xFFFFFFFFU, value);
+}
+
+/**
+ * pm_ioctl_read_ggs() - Ioctl function for reading
+ * global general storage (ggs)
+ * @index GGS register index
+ * @value Register value
+ *
+ * This function returns GGS register value.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_read_ggs(uint32_t index,
+ uint32_t *value)
+{
+ if (index >= GGS_NUM_REGS) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ return pm_mmio_read(GGS_BASEADDR + (index << 2), value);
+}
+
+/**
+ * pm_ioctl_write_pggs() - Ioctl function for writing persistent
+ * global general storage (pggs)
+ * @index PGGS register index
+ * @value Register value to be written
+ *
+ * This function writes value to PGGS register.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_write_pggs(uint32_t index,
+ uint32_t value)
+{
+ if (index >= PGGS_NUM_REGS) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ return pm_mmio_write(PGGS_BASEADDR + (index << 2),
+ 0xFFFFFFFFU, value);
+}
+
+/**
+ * pm_ioctl_afi() - Ioctl function for writing afi values
+ *
+ * @index AFI register index
+ * @value Register value to be written
+ *
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_afi(uint32_t index,
+ uint32_t value)
+{
+ uint32_t mask;
+ uint32_t regarr[] = {0xFD360000U,
+ 0xFD360014U,
+ 0xFD370000U,
+ 0xFD370014U,
+ 0xFD380000U,
+ 0xFD380014U,
+ 0xFD390000U,
+ 0xFD390014U,
+ 0xFD3a0000U,
+ 0xFD3a0014U,
+ 0xFD3b0000U,
+ 0xFD3b0014U,
+ 0xFF9b0000U,
+ 0xFF9b0014U,
+ 0xFD615000U,
+ 0xFF419000U,
+ };
+
+ if (index >= ARRAY_SIZE(regarr)) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ if (index <= AFIFM6_WRCTRL) {
+ mask = FABRIC_WIDTH;
+ } else {
+ mask = 0xf00;
+ }
+
+ return pm_mmio_write(regarr[index], mask, value);
+}
+
+/**
+ * pm_ioctl_read_pggs() - Ioctl function for reading persistent
+ * global general storage (pggs)
+ * @index PGGS register index
+ * @value Register value
+ *
+ * This function returns PGGS register value.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_read_pggs(uint32_t index,
+ uint32_t *value)
+{
+ if (index >= PGGS_NUM_REGS) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ return pm_mmio_read(PGGS_BASEADDR + (index << 2), value);
+}
+
+/**
+ * pm_ioctl_ulpi_reset() - Ioctl function for performing ULPI reset
+ *
+ * This function peerforms the ULPI reset sequence for resetting
+ * the ULPI transceiver.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_ulpi_reset(void)
+{
+ enum pm_ret_status ret;
+
+ ret = pm_mmio_write(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOT_PIN_MASK,
+ ZYNQMP_ULPI_RESET_VAL_HIGH);
+ if (ret != PM_RET_SUCCESS) {
+ return ret;
+ }
+
+ /* Drive ULPI assert for atleast 1ms */
+ mdelay(1);
+
+ ret = pm_mmio_write(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOT_PIN_MASK,
+ ZYNQMP_ULPI_RESET_VAL_LOW);
+ if (ret != PM_RET_SUCCESS) {
+ return ret;
+ }
+
+ /* Drive ULPI de-assert for atleast 1ms */
+ mdelay(1);
+
+ ret = pm_mmio_write(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOT_PIN_MASK,
+ ZYNQMP_ULPI_RESET_VAL_HIGH);
+
+ return ret;
+}
+
+/**
+ * pm_ioctl_set_boot_health_status() - Ioctl for setting healthy boot status
+ *
+ * This function sets healthy bit value to indicate boot health status
+ * to firmware.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_ioctl_set_boot_health_status(uint32_t value)
+{
+ return pm_mmio_write(PMU_GLOBAL_GEN_STORAGE4,
+ PM_BOOT_HEALTH_STATUS_MASK, value);
+}
+
+/**
+ * pm_api_ioctl() - PM IOCTL API for device control and configs
+ * @node_id Node ID of the device
+ * @ioctl_id ID of the requested IOCTL
+ * @arg1 Argument 1 to requested IOCTL call
+ * @arg2 Argument 2 to requested IOCTL call
+ * @value Returned output value
+ *
+ * This function calls IOCTL to firmware for device control and configuration.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_api_ioctl(enum pm_node_id nid,
+ uint32_t ioctl_id,
+ uint32_t arg1,
+ uint32_t arg2,
+ uint32_t *value)
+{
+ enum pm_ret_status ret;
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ switch (ioctl_id) {
+ case IOCTL_GET_RPU_OPER_MODE:
+ ret = pm_ioctl_get_rpu_oper_mode(value);
+ break;
+ case IOCTL_SET_RPU_OPER_MODE:
+ ret = pm_ioctl_set_rpu_oper_mode(arg1);
+ break;
+ case IOCTL_RPU_BOOT_ADDR_CONFIG:
+ ret = pm_ioctl_config_boot_addr(nid, arg1);
+ break;
+ case IOCTL_TCM_COMB_CONFIG:
+ ret = pm_ioctl_config_tcm_comb(arg1);
+ break;
+ case IOCTL_SET_TAPDELAY_BYPASS:
+ ret = pm_ioctl_set_tapdelay_bypass(arg1, arg2);
+ break;
+ case IOCTL_SET_SGMII_MODE:
+ ret = pm_ioctl_set_sgmii_mode(nid, arg1);
+ break;
+ case IOCTL_SD_DLL_RESET:
+ ret = pm_ioctl_sd_dll_reset(nid, arg1);
+ break;
+ case IOCTL_SET_SD_TAPDELAY:
+ ret = pm_ioctl_sd_set_tapdelay(nid, arg1, arg2);
+ break;
+ case IOCTL_SET_PLL_FRAC_MODE:
+ ret = pm_ioctl_set_pll_frac_mode(arg1, arg2);
+ break;
+ case IOCTL_GET_PLL_FRAC_MODE:
+ ret = pm_ioctl_get_pll_frac_mode(arg1, value);
+ break;
+ case IOCTL_SET_PLL_FRAC_DATA:
+ ret = pm_ioctl_set_pll_frac_data(arg1, arg2);
+ break;
+ case IOCTL_GET_PLL_FRAC_DATA:
+ ret = pm_ioctl_get_pll_frac_data(arg1, value);
+ break;
+ case IOCTL_WRITE_GGS:
+ ret = pm_ioctl_write_ggs(arg1, arg2);
+ break;
+ case IOCTL_READ_GGS:
+ ret = pm_ioctl_read_ggs(arg1, value);
+ break;
+ case IOCTL_WRITE_PGGS:
+ ret = pm_ioctl_write_pggs(arg1, arg2);
+ break;
+ case IOCTL_READ_PGGS:
+ ret = pm_ioctl_read_pggs(arg1, value);
+ break;
+ case IOCTL_ULPI_RESET:
+ ret = pm_ioctl_ulpi_reset();
+ break;
+ case IOCTL_SET_BOOT_HEALTH_STATUS:
+ ret = pm_ioctl_set_boot_health_status(arg1);
+ break;
+ case IOCTL_AFI:
+ ret = pm_ioctl_afi(arg1, arg2);
+ break;
+ default:
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD5(payload, PM_IOCTL, nid, ioctl_id, arg1, arg2);
+
+ ret = pm_ipi_send_sync(primary_proc, payload, value, 1);
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * pm_update_ioctl_bitmask() - API to get supported IOCTL ID mask
+ * @bit_mask Returned bit mask of supported IOCTL IDs
+ */
+enum pm_ret_status atf_ioctl_bitmask(uint32_t *bit_mask)
+{
+ uint8_t supported_ids[] = {
+ IOCTL_GET_RPU_OPER_MODE,
+ IOCTL_SET_RPU_OPER_MODE,
+ IOCTL_RPU_BOOT_ADDR_CONFIG,
+ IOCTL_TCM_COMB_CONFIG,
+ IOCTL_SET_TAPDELAY_BYPASS,
+ IOCTL_SET_SGMII_MODE,
+ IOCTL_SD_DLL_RESET,
+ IOCTL_SET_SD_TAPDELAY,
+ IOCTL_SET_PLL_FRAC_MODE,
+ IOCTL_GET_PLL_FRAC_MODE,
+ IOCTL_SET_PLL_FRAC_DATA,
+ IOCTL_GET_PLL_FRAC_DATA,
+ IOCTL_WRITE_GGS,
+ IOCTL_READ_GGS,
+ IOCTL_WRITE_PGGS,
+ IOCTL_READ_PGGS,
+ IOCTL_ULPI_RESET,
+ IOCTL_SET_BOOT_HEALTH_STATUS,
+ IOCTL_AFI,
+ };
+ uint8_t i, ioctl_id;
+ int32_t ret;
+
+ for (i = 0U; i < ARRAY_SIZE(supported_ids); i++) {
+ ioctl_id = supported_ids[i];
+ if (ioctl_id >= 64U) {
+ return PM_RET_ERROR_NOTSUPPORTED;
+ }
+ ret = check_api_dependency(ioctl_id);
+ if (ret == PM_RET_SUCCESS) {
+ bit_mask[ioctl_id / 32U] |= BIT(ioctl_id % 32U);
+ }
+ }
+
+ return PM_RET_SUCCESS;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h
new file mode 100644
index 0000000..3b0d6ee
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for pin control.
+ */
+
+#ifndef PM_API_IOCTL_H
+#define PM_API_IOCTL_H
+
+#include "pm_common.h"
+
+//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_SET_SGMII_MODE = 5,
+ 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 ATF */
+ IOCTL_REGISTER_SGI = 25,
+};
+
+//RPU operation mode
+#define PM_RPU_MODE_LOCKSTEP 0U
+#define PM_RPU_MODE_SPLIT 1U
+
+//RPU boot mem
+#define PM_RPU_BOOTMEM_LOVEC 0U
+#define PM_RPU_BOOTMEM_HIVEC 1U
+
+//RPU tcm mpde
+#define PM_RPU_TCM_SPLIT 0U
+#define PM_RPU_TCM_COMB 1U
+
+//tap delay signal type
+#define PM_TAPDELAY_NAND_DQS_IN 0U
+#define PM_TAPDELAY_NAND_DQS_OUT 1U
+#define PM_TAPDELAY_QSPI 2U
+#define PM_TAPDELAY_MAX 3U
+
+//tap delay bypass
+#define PM_TAPDELAY_BYPASS_DISABLE 0U
+#define PM_TAPDELAY_BYPASS_ENABLE 1U
+
+//sgmii mode
+#define PM_SGMII_DISABLE 0U
+#define PM_SGMII_ENABLE 1U
+
+enum tap_delay_type {
+ PM_TAPDELAY_INPUT,
+ PM_TAPDELAY_OUTPUT,
+};
+
+//dll reset type
+#define PM_DLL_RESET_ASSERT 0U
+#define PM_DLL_RESET_RELEASE 1U
+#define PM_DLL_RESET_PULSE 2U
+
+enum pm_ret_status pm_api_ioctl(enum pm_node_id nid,
+ uint32_t ioctl_id,
+ uint32_t arg1,
+ uint32_t arg2,
+ uint32_t *value);
+enum pm_ret_status atf_ioctl_bitmask(uint32_t *bit_mask);
+#endif /* PM_API_IOCTL_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c
new file mode 100644
index 0000000..8f37341
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c
@@ -0,0 +1,2112 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for pin control.
+ */
+
+#include <string.h>
+
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+#include "pm_api_pinctrl.h"
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_common.h"
+#include "pm_ipi.h"
+
+struct pinctrl_function {
+ char name[FUNCTION_NAME_LEN];
+ uint16_t group_base;
+ uint8_t group_size;
+ uint8_t regval;
+};
+
+/* Max groups for one pin */
+#define MAX_PIN_GROUPS (13U)
+
+struct zynqmp_pin_group {
+ uint16_t (*groups)[];
+};
+
+static struct pinctrl_function pinctrl_functions[MAX_FUNCTION] = {
+ [PINCTRL_FUNC_CAN0] = {
+ .name = "can0",
+ .regval = 0x20,
+ .group_base = PINCTRL_GRP_CAN0_0,
+ .group_size = PINCTRL_GRP_CAN0_18 - PINCTRL_GRP_CAN0_0 + 1U,
+ },
+ [PINCTRL_FUNC_CAN1] = {
+ .name = "can1",
+ .regval = 0x20,
+ .group_base = PINCTRL_GRP_CAN1_0,
+ .group_size = PINCTRL_GRP_CAN1_19 - PINCTRL_GRP_CAN1_0 + 1U,
+ },
+ [PINCTRL_FUNC_ETHERNET0] = {
+ .name = "ethernet0",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_ETHERNET0_0,
+ .group_size = PINCTRL_GRP_ETHERNET0_0 - PINCTRL_GRP_ETHERNET0_0 + 1U,
+ },
+ [PINCTRL_FUNC_ETHERNET1] = {
+ .name = "ethernet1",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_ETHERNET1_0,
+ .group_size = PINCTRL_GRP_ETHERNET1_0 - PINCTRL_GRP_ETHERNET1_0 + 1U,
+ },
+ [PINCTRL_FUNC_ETHERNET2] = {
+ .name = "ethernet2",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_ETHERNET2_0,
+ .group_size = PINCTRL_GRP_ETHERNET2_0 - PINCTRL_GRP_ETHERNET2_0 + 1U,
+ },
+ [PINCTRL_FUNC_ETHERNET3] = {
+ .name = "ethernet3",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_ETHERNET3_0,
+ .group_size = PINCTRL_GRP_ETHERNET3_0 - PINCTRL_GRP_ETHERNET3_0 + 1U,
+ },
+ [PINCTRL_FUNC_GEMTSU0] = {
+ .name = "gemtsu0",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_GEMTSU0_0,
+ .group_size = PINCTRL_GRP_GEMTSU0_2 - PINCTRL_GRP_GEMTSU0_0 + 1U,
+ },
+ [PINCTRL_FUNC_GPIO0] = {
+ .name = "gpio0",
+ .regval = 0x00,
+ .group_base = PINCTRL_GRP_GPIO0_0,
+ .group_size = PINCTRL_GRP_GPIO0_77 - PINCTRL_GRP_GPIO0_0 + 1U,
+ },
+ [PINCTRL_FUNC_I2C0] = {
+ .name = "i2c0",
+ .regval = 0x40,
+ .group_base = PINCTRL_GRP_I2C0_0,
+ .group_size = PINCTRL_GRP_I2C0_18 - PINCTRL_GRP_I2C0_0 + 1U,
+ },
+ [PINCTRL_FUNC_I2C1] = {
+ .name = "i2c1",
+ .regval = 0x40,
+ .group_base = PINCTRL_GRP_I2C1_0,
+ .group_size = PINCTRL_GRP_I2C1_19 - PINCTRL_GRP_I2C1_0 + 1U,
+ },
+ [PINCTRL_FUNC_MDIO0] = {
+ .name = "mdio0",
+ .regval = 0x60,
+ .group_base = PINCTRL_GRP_MDIO0_0,
+ .group_size = PINCTRL_GRP_MDIO0_0 - PINCTRL_GRP_MDIO0_0 + 1U,
+ },
+ [PINCTRL_FUNC_MDIO1] = {
+ .name = "mdio1",
+ .regval = 0x80,
+ .group_base = PINCTRL_GRP_MDIO1_0,
+ .group_size = PINCTRL_GRP_MDIO1_1 - PINCTRL_GRP_MDIO1_0 + 1U,
+ },
+ [PINCTRL_FUNC_MDIO2] = {
+ .name = "mdio2",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_MDIO2_0,
+ .group_size = PINCTRL_GRP_MDIO2_0 - PINCTRL_GRP_MDIO2_0 + 1U,
+ },
+ [PINCTRL_FUNC_MDIO3] = {
+ .name = "mdio3",
+ .regval = 0xc0,
+ .group_base = PINCTRL_GRP_MDIO3_0,
+ .group_size = PINCTRL_GRP_MDIO3_0 - PINCTRL_GRP_MDIO3_0 + 1U,
+ },
+ [PINCTRL_FUNC_QSPI0] = {
+ .name = "qspi0",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_QSPI0_0,
+ .group_size = PINCTRL_GRP_QSPI0_0 - PINCTRL_GRP_QSPI0_0 + 1U,
+ },
+ [PINCTRL_FUNC_QSPI_FBCLK] = {
+ .name = "qspi_fbclk",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_QSPI_FBCLK,
+ .group_size = PINCTRL_GRP_QSPI_FBCLK - PINCTRL_GRP_QSPI_FBCLK + 1U,
+ },
+ [PINCTRL_FUNC_QSPI_SS] = {
+ .name = "qspi_ss",
+ .regval = 0x02,
+ .group_base = PINCTRL_GRP_QSPI_SS,
+ .group_size = PINCTRL_GRP_QSPI_SS - PINCTRL_GRP_QSPI_SS + 1U,
+ },
+ [PINCTRL_FUNC_SPI0] = {
+ .name = "spi0",
+ .regval = 0x80,
+ .group_base = PINCTRL_GRP_SPI0_0,
+ .group_size = PINCTRL_GRP_SPI0_5 - PINCTRL_GRP_SPI0_0 + 1U,
+ },
+ [PINCTRL_FUNC_SPI1] = {
+ .name = "spi1",
+ .regval = 0x80,
+ .group_base = PINCTRL_GRP_SPI1_0,
+ .group_size = PINCTRL_GRP_SPI1_5 - PINCTRL_GRP_SPI1_0 + 1U,
+ },
+ [PINCTRL_FUNC_SPI0_SS] = {
+ .name = "spi0_ss",
+ .regval = 0x80,
+ .group_base = PINCTRL_GRP_SPI0_0_SS0,
+ .group_size = PINCTRL_GRP_SPI0_5_SS2 - PINCTRL_GRP_SPI0_0_SS0 + 1U,
+ },
+ [PINCTRL_FUNC_SPI1_SS] = {
+ .name = "spi1_ss",
+ .regval = 0x80,
+ .group_base = PINCTRL_GRP_SPI1_0_SS0,
+ .group_size = PINCTRL_GRP_SPI1_5_SS2 - PINCTRL_GRP_SPI1_0_SS0 + 1U,
+ },
+ [PINCTRL_FUNC_SDIO0] = {
+ .name = "sdio0",
+ .regval = 0x08,
+ .group_base = PINCTRL_GRP_SDIO0_0,
+ .group_size = PINCTRL_GRP_SDIO0_1BIT_2_7 - PINCTRL_GRP_SDIO0_0 + 1U,
+ },
+ [PINCTRL_FUNC_SDIO0_PC] = {
+ .name = "sdio0_pc",
+ .regval = 0x08,
+ .group_base = PINCTRL_GRP_SDIO0_0_PC,
+ .group_size = PINCTRL_GRP_SDIO0_2_PC - PINCTRL_GRP_SDIO0_0_PC + 1U,
+ },
+ [PINCTRL_FUNC_SDIO0_CD] = {
+ .name = "sdio0_cd",
+ .regval = 0x08,
+ .group_base = PINCTRL_GRP_SDIO0_0_CD,
+ .group_size = PINCTRL_GRP_SDIO0_2_CD - PINCTRL_GRP_SDIO0_0_CD + 1U,
+ },
+ [PINCTRL_FUNC_SDIO0_WP] = {
+ .name = "sdio0_wp",
+ .regval = 0x08,
+ .group_base = PINCTRL_GRP_SDIO0_0_WP,
+ .group_size = PINCTRL_GRP_SDIO0_2_WP - PINCTRL_GRP_SDIO0_0_WP + 1U,
+ },
+ [PINCTRL_FUNC_SDIO1] = {
+ .name = "sdio1",
+ .regval = 0x10,
+ .group_base = PINCTRL_GRP_SDIO1_0,
+ .group_size = PINCTRL_GRP_SDIO1_1BIT_1_3 - PINCTRL_GRP_SDIO1_0 + 1U,
+ },
+ [PINCTRL_FUNC_SDIO1_PC] = {
+ .name = "sdio1_pc",
+ .regval = 0x10,
+ .group_base = PINCTRL_GRP_SDIO1_0_PC,
+ .group_size = PINCTRL_GRP_SDIO1_1_PC - PINCTRL_GRP_SDIO1_0_PC + 1U,
+ },
+ [PINCTRL_FUNC_SDIO1_CD] = {
+ .name = "sdio1_cd",
+ .regval = 0x10,
+ .group_base = PINCTRL_GRP_SDIO1_0_CD,
+ .group_size = PINCTRL_GRP_SDIO1_1_CD - PINCTRL_GRP_SDIO1_0_CD + 1U,
+ },
+ [PINCTRL_FUNC_SDIO1_WP] = {
+ .name = "sdio1_wp",
+ .regval = 0x10,
+ .group_base = PINCTRL_GRP_SDIO1_0_WP,
+ .group_size = PINCTRL_GRP_SDIO1_1_WP - PINCTRL_GRP_SDIO1_0_WP + 1U,
+ },
+ [PINCTRL_FUNC_NAND0] = {
+ .name = "nand0",
+ .regval = 0x04,
+ .group_base = PINCTRL_GRP_NAND0_0,
+ .group_size = PINCTRL_GRP_NAND0_0 - PINCTRL_GRP_NAND0_0 + 1U,
+ },
+ [PINCTRL_FUNC_NAND0_CE] = {
+ .name = "nand0_ce",
+ .regval = 0x04,
+ .group_base = PINCTRL_GRP_NAND0_0_CE,
+ .group_size = PINCTRL_GRP_NAND0_1_CE - PINCTRL_GRP_NAND0_0_CE + 1U,
+ },
+ [PINCTRL_FUNC_NAND0_RB] = {
+ .name = "nand0_rb",
+ .regval = 0x04,
+ .group_base = PINCTRL_GRP_NAND0_0_RB,
+ .group_size = PINCTRL_GRP_NAND0_1_RB - PINCTRL_GRP_NAND0_0_RB + 1U,
+ },
+ [PINCTRL_FUNC_NAND0_DQS] = {
+ .name = "nand0_dqs",
+ .regval = 0x04,
+ .group_base = PINCTRL_GRP_NAND0_0_DQS,
+ .group_size = PINCTRL_GRP_NAND0_1_DQS - PINCTRL_GRP_NAND0_0_DQS + 1U,
+ },
+ [PINCTRL_FUNC_TTC0_CLK] = {
+ .name = "ttc0_clk",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC0_0_CLK,
+ .group_size = PINCTRL_GRP_TTC0_8_CLK - PINCTRL_GRP_TTC0_0_CLK + 1U,
+ },
+ [PINCTRL_FUNC_TTC0_WAV] = {
+ .name = "ttc0_wav",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC0_0_WAV,
+ .group_size = PINCTRL_GRP_TTC0_8_WAV - PINCTRL_GRP_TTC0_0_WAV + 1U,
+ },
+ [PINCTRL_FUNC_TTC1_CLK] = {
+ .name = "ttc1_clk",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC1_0_CLK,
+ .group_size = PINCTRL_GRP_TTC1_8_CLK - PINCTRL_GRP_TTC1_0_CLK + 1U,
+ },
+ [PINCTRL_FUNC_TTC1_WAV] = {
+ .name = "ttc1_wav",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC1_0_WAV,
+ .group_size = PINCTRL_GRP_TTC1_8_WAV - PINCTRL_GRP_TTC1_0_WAV + 1U,
+ },
+ [PINCTRL_FUNC_TTC2_CLK] = {
+ .name = "ttc2_clk",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC2_0_CLK,
+ .group_size = PINCTRL_GRP_TTC2_8_CLK - PINCTRL_GRP_TTC2_0_CLK + 1U,
+ },
+ [PINCTRL_FUNC_TTC2_WAV] = {
+ .name = "ttc2_wav",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC2_0_WAV,
+ .group_size = PINCTRL_GRP_TTC2_8_WAV - PINCTRL_GRP_TTC2_0_WAV + 1U,
+ },
+ [PINCTRL_FUNC_TTC3_CLK] = {
+ .name = "ttc3_clk",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC3_0_CLK,
+ .group_size = PINCTRL_GRP_TTC3_8_CLK - PINCTRL_GRP_TTC3_0_CLK + 1U,
+ },
+ [PINCTRL_FUNC_TTC3_WAV] = {
+ .name = "ttc3_wav",
+ .regval = 0xa0,
+ .group_base = PINCTRL_GRP_TTC3_0_WAV,
+ .group_size = PINCTRL_GRP_TTC3_8_WAV - PINCTRL_GRP_TTC3_0_WAV + 1U,
+ },
+ [PINCTRL_FUNC_UART0] = {
+ .name = "uart0",
+ .regval = 0xc0,
+ .group_base = PINCTRL_GRP_UART0_0,
+ .group_size = PINCTRL_GRP_UART0_18 - PINCTRL_GRP_UART0_0 + 1U,
+ },
+ [PINCTRL_FUNC_UART1] = {
+ .name = "uart1",
+ .regval = 0xc0,
+ .group_base = PINCTRL_GRP_UART1_0,
+ .group_size = PINCTRL_GRP_UART1_18 - PINCTRL_GRP_UART1_0 + 1U,
+ },
+ [PINCTRL_FUNC_USB0] = {
+ .name = "usb0",
+ .regval = 0x04,
+ .group_base = PINCTRL_GRP_USB0_0,
+ .group_size = PINCTRL_GRP_USB0_0 - PINCTRL_GRP_USB0_0 + 1U,
+ },
+ [PINCTRL_FUNC_USB1] = {
+ .name = "usb1",
+ .regval = 0x04,
+ .group_base = PINCTRL_GRP_USB1_0,
+ .group_size = PINCTRL_GRP_USB1_0 - PINCTRL_GRP_USB1_0 + 1U,
+ },
+ [PINCTRL_FUNC_SWDT0_CLK] = {
+ .name = "swdt0_clk",
+ .regval = 0x60,
+ .group_base = PINCTRL_GRP_SWDT0_0_CLK,
+ .group_size = PINCTRL_GRP_SWDT0_12_CLK - PINCTRL_GRP_SWDT0_0_CLK + 1U,
+ },
+ [PINCTRL_FUNC_SWDT0_RST] = {
+ .name = "swdt0_rst",
+ .regval = 0x60,
+ .group_base = PINCTRL_GRP_SWDT0_0_RST,
+ .group_size = PINCTRL_GRP_SWDT0_12_RST - PINCTRL_GRP_SWDT0_0_RST + 1U,
+ },
+ [PINCTRL_FUNC_SWDT1_CLK] = {
+ .name = "swdt1_clk",
+ .regval = 0x60,
+ .group_base = PINCTRL_GRP_SWDT1_0_CLK,
+ .group_size = PINCTRL_GRP_SWDT1_12_CLK - PINCTRL_GRP_SWDT1_0_CLK + 1U,
+ },
+ [PINCTRL_FUNC_SWDT1_RST] = {
+ .name = "swdt1_rst",
+ .regval = 0x60,
+ .group_base = PINCTRL_GRP_SWDT1_0_RST,
+ .group_size = PINCTRL_GRP_SWDT1_12_RST - PINCTRL_GRP_SWDT1_0_RST + 1U,
+ },
+ [PINCTRL_FUNC_PMU0] = {
+ .name = "pmu0",
+ .regval = 0x08,
+ .group_base = PINCTRL_GRP_PMU0_0,
+ .group_size = PINCTRL_GRP_PMU0_11 - PINCTRL_GRP_PMU0_0 + 1U,
+ },
+ [PINCTRL_FUNC_PCIE0] = {
+ .name = "pcie0",
+ .regval = 0x04,
+ .group_base = PINCTRL_GRP_PCIE0_0,
+ .group_size = PINCTRL_GRP_PCIE0_7 - PINCTRL_GRP_PCIE0_0 + 1U,
+ },
+ [PINCTRL_FUNC_CSU0] = {
+ .name = "csu0",
+ .regval = 0x18,
+ .group_base = PINCTRL_GRP_CSU0_0,
+ .group_size = PINCTRL_GRP_CSU0_11 - PINCTRL_GRP_CSU0_0 + 1U,
+ },
+ [PINCTRL_FUNC_DPAUX0] = {
+ .name = "dpaux0",
+ .regval = 0x18,
+ .group_base = PINCTRL_GRP_DPAUX0_0,
+ .group_size = PINCTRL_GRP_DPAUX0_3 - PINCTRL_GRP_DPAUX0_0 + 1U,
+ },
+ [PINCTRL_FUNC_PJTAG0] = {
+ .name = "pjtag0",
+ .regval = 0x60,
+ .group_base = PINCTRL_GRP_PJTAG0_0,
+ .group_size = PINCTRL_GRP_PJTAG0_5 - PINCTRL_GRP_PJTAG0_0 + 1U,
+ },
+ [PINCTRL_FUNC_TRACE0] = {
+ .name = "trace0",
+ .regval = 0xe0,
+ .group_base = PINCTRL_GRP_TRACE0_0,
+ .group_size = PINCTRL_GRP_TRACE0_2 - PINCTRL_GRP_TRACE0_0 + 1U,
+ },
+ [PINCTRL_FUNC_TRACE0_CLK] = {
+ .name = "trace0_clk",
+ .regval = 0xe0,
+ .group_base = PINCTRL_GRP_TRACE0_0_CLK,
+ .group_size = PINCTRL_GRP_TRACE0_2_CLK - PINCTRL_GRP_TRACE0_0_CLK + 1U,
+ },
+ [PINCTRL_FUNC_TESTSCAN0] = {
+ .name = "testscan0",
+ .regval = 0x10,
+ .group_base = PINCTRL_GRP_TESTSCAN0_0,
+ .group_size = PINCTRL_GRP_TESTSCAN0_0 - PINCTRL_GRP_TESTSCAN0_0 + 1U,
+ },
+};
+
+static struct zynqmp_pin_group zynqmp_pin_groups[MAX_PIN] = {
+ [PINCTRL_PIN_0] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_QSPI0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_0,
+ PINCTRL_GRP_CAN1_0,
+ PINCTRL_GRP_I2C1_0,
+ PINCTRL_GRP_PJTAG0_0,
+ PINCTRL_GRP_SPI0_0,
+ PINCTRL_GRP_TTC3_0_CLK,
+ PINCTRL_GRP_UART1_0,
+ PINCTRL_GRP_TRACE0_0_CLK,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_1] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_QSPI0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_1,
+ PINCTRL_GRP_CAN1_0,
+ PINCTRL_GRP_I2C1_0,
+ PINCTRL_GRP_PJTAG0_0,
+ PINCTRL_GRP_SPI0_0_SS2,
+ PINCTRL_GRP_TTC3_0_WAV,
+ PINCTRL_GRP_UART1_0,
+ PINCTRL_GRP_TRACE0_0_CLK,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_2] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_QSPI0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_2,
+ PINCTRL_GRP_CAN0_0,
+ PINCTRL_GRP_I2C0_0,
+ PINCTRL_GRP_PJTAG0_0,
+ PINCTRL_GRP_SPI0_0_SS1,
+ PINCTRL_GRP_TTC2_0_CLK,
+ PINCTRL_GRP_UART0_0,
+ PINCTRL_GRP_TRACE0_0,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_3] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_QSPI0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_3,
+ PINCTRL_GRP_CAN0_0,
+ PINCTRL_GRP_I2C0_0,
+ PINCTRL_GRP_PJTAG0_0,
+ PINCTRL_GRP_SPI0_0_SS0,
+ PINCTRL_GRP_TTC2_0_WAV,
+ PINCTRL_GRP_UART0_0,
+ PINCTRL_GRP_TRACE0_0,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_4] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_QSPI0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_4,
+ PINCTRL_GRP_CAN1_1,
+ PINCTRL_GRP_I2C1_1,
+ PINCTRL_GRP_SWDT1_0_CLK,
+ PINCTRL_GRP_SPI0_0,
+ PINCTRL_GRP_TTC1_0_CLK,
+ PINCTRL_GRP_UART1_1,
+ PINCTRL_GRP_TRACE0_0,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_5] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_QSPI_SS,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_5,
+ PINCTRL_GRP_CAN1_1,
+ PINCTRL_GRP_I2C1_1,
+ PINCTRL_GRP_SWDT1_0_RST,
+ PINCTRL_GRP_SPI0_0,
+ PINCTRL_GRP_TTC1_0_WAV,
+ PINCTRL_GRP_UART1_1,
+ PINCTRL_GRP_TRACE0_0,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_6] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_QSPI_FBCLK,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_6,
+ PINCTRL_GRP_CAN0_1,
+ PINCTRL_GRP_I2C0_1,
+ PINCTRL_GRP_SWDT0_0_CLK,
+ PINCTRL_GRP_SPI1_0,
+ PINCTRL_GRP_TTC0_0_CLK,
+ PINCTRL_GRP_UART0_1,
+ PINCTRL_GRP_TRACE0_0,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_7] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_QSPI_SS,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_7,
+ PINCTRL_GRP_CAN0_1,
+ PINCTRL_GRP_I2C0_1,
+ PINCTRL_GRP_SWDT0_0_RST,
+ PINCTRL_GRP_SPI1_0_SS2,
+ PINCTRL_GRP_TTC0_0_WAV,
+ PINCTRL_GRP_UART0_1,
+ PINCTRL_GRP_TRACE0_0,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_8] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_QSPI0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_8,
+ PINCTRL_GRP_CAN1_2,
+ PINCTRL_GRP_I2C1_2,
+ PINCTRL_GRP_SWDT1_1_CLK,
+ PINCTRL_GRP_SPI1_0_SS1,
+ PINCTRL_GRP_TTC3_1_CLK,
+ PINCTRL_GRP_UART1_2,
+ PINCTRL_GRP_TRACE0_0,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_9] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_QSPI0_0,
+ PINCTRL_GRP_NAND0_0_CE,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_9,
+ PINCTRL_GRP_CAN1_2,
+ PINCTRL_GRP_I2C1_2,
+ PINCTRL_GRP_SWDT1_1_RST,
+ PINCTRL_GRP_SPI1_0_SS0,
+ PINCTRL_GRP_TTC3_1_WAV,
+ PINCTRL_GRP_UART1_2,
+ PINCTRL_GRP_TRACE0_0,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_10] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_QSPI0_0,
+ PINCTRL_GRP_NAND0_0_RB,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_10,
+ PINCTRL_GRP_CAN0_2,
+ PINCTRL_GRP_I2C0_2,
+ PINCTRL_GRP_SWDT0_1_CLK,
+ PINCTRL_GRP_SPI1_0,
+ PINCTRL_GRP_TTC2_1_CLK,
+ PINCTRL_GRP_UART0_2,
+ PINCTRL_GRP_TRACE0_0,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_11] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_QSPI0_0,
+ PINCTRL_GRP_NAND0_0_RB,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_11,
+ PINCTRL_GRP_CAN0_2,
+ PINCTRL_GRP_I2C0_2,
+ PINCTRL_GRP_SWDT0_1_RST,
+ PINCTRL_GRP_SPI1_0,
+ PINCTRL_GRP_TTC2_1_WAV,
+ PINCTRL_GRP_UART0_2,
+ PINCTRL_GRP_TRACE0_0,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_12] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_QSPI0_0,
+ PINCTRL_GRP_NAND0_0_DQS,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_12,
+ PINCTRL_GRP_CAN1_3,
+ PINCTRL_GRP_I2C1_3,
+ PINCTRL_GRP_PJTAG0_1,
+ PINCTRL_GRP_SPI0_1,
+ PINCTRL_GRP_TTC1_1_CLK,
+ PINCTRL_GRP_UART1_3,
+ PINCTRL_GRP_TRACE0_0,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_13] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_NAND0_0,
+ PINCTRL_GRP_SDIO0_0,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_13,
+ PINCTRL_GRP_CAN1_3,
+ PINCTRL_GRP_I2C1_3,
+ PINCTRL_GRP_PJTAG0_1,
+ PINCTRL_GRP_SPI0_1_SS2,
+ PINCTRL_GRP_TTC1_1_WAV,
+ PINCTRL_GRP_UART1_3,
+ PINCTRL_GRP_TRACE0_0,
+ PINCTRL_GRP_SDIO0_4BIT_0_0,
+ PINCTRL_GRP_SDIO0_1BIT_0_0,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_14] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_NAND0_0,
+ PINCTRL_GRP_SDIO0_0,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_14,
+ PINCTRL_GRP_CAN0_3,
+ PINCTRL_GRP_I2C0_3,
+ PINCTRL_GRP_PJTAG0_1,
+ PINCTRL_GRP_SPI0_1_SS1,
+ PINCTRL_GRP_TTC0_1_CLK,
+ PINCTRL_GRP_UART0_3,
+ PINCTRL_GRP_TRACE0_0,
+ PINCTRL_GRP_SDIO0_4BIT_0_0,
+ PINCTRL_GRP_SDIO0_1BIT_0_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_15] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_NAND0_0,
+ PINCTRL_GRP_SDIO0_0,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_15,
+ PINCTRL_GRP_CAN0_3,
+ PINCTRL_GRP_I2C0_3,
+ PINCTRL_GRP_PJTAG0_1,
+ PINCTRL_GRP_SPI0_1_SS0,
+ PINCTRL_GRP_TTC0_1_WAV,
+ PINCTRL_GRP_UART0_3,
+ PINCTRL_GRP_TRACE0_0,
+ PINCTRL_GRP_SDIO0_4BIT_0_0,
+ PINCTRL_GRP_SDIO0_1BIT_0_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_16] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_NAND0_0,
+ PINCTRL_GRP_SDIO0_0,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_16,
+ PINCTRL_GRP_CAN1_4,
+ PINCTRL_GRP_I2C1_4,
+ PINCTRL_GRP_SWDT1_2_CLK,
+ PINCTRL_GRP_SPI0_1,
+ PINCTRL_GRP_TTC3_2_CLK,
+ PINCTRL_GRP_UART1_4,
+ PINCTRL_GRP_TRACE0_0,
+ PINCTRL_GRP_SDIO0_4BIT_0_0,
+ PINCTRL_GRP_SDIO0_1BIT_0_3,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_17] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_NAND0_0,
+ PINCTRL_GRP_SDIO0_0,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_17,
+ PINCTRL_GRP_CAN1_4,
+ PINCTRL_GRP_I2C1_4,
+ PINCTRL_GRP_SWDT1_2_RST,
+ PINCTRL_GRP_SPI0_1,
+ PINCTRL_GRP_TTC3_2_WAV,
+ PINCTRL_GRP_UART1_4,
+ PINCTRL_GRP_TRACE0_0,
+ PINCTRL_GRP_SDIO0_4BIT_0_1,
+ PINCTRL_GRP_SDIO0_1BIT_0_4,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_18] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_NAND0_0,
+ PINCTRL_GRP_SDIO0_0,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_CSU0_0,
+ PINCTRL_GRP_GPIO0_18,
+ PINCTRL_GRP_CAN0_4,
+ PINCTRL_GRP_I2C0_4,
+ PINCTRL_GRP_SWDT0_2_CLK,
+ PINCTRL_GRP_SPI1_1,
+ PINCTRL_GRP_TTC2_2_CLK,
+ PINCTRL_GRP_UART0_4,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_4BIT_0_1,
+ PINCTRL_GRP_SDIO0_1BIT_0_5,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_19] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_NAND0_0,
+ PINCTRL_GRP_SDIO0_0,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_CSU0_1,
+ PINCTRL_GRP_GPIO0_19,
+ PINCTRL_GRP_CAN0_4,
+ PINCTRL_GRP_I2C0_4,
+ PINCTRL_GRP_SWDT0_2_RST,
+ PINCTRL_GRP_SPI1_1_SS2,
+ PINCTRL_GRP_TTC2_2_WAV,
+ PINCTRL_GRP_UART0_4,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_4BIT_0_1,
+ PINCTRL_GRP_SDIO0_1BIT_0_6,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_20] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_NAND0_0,
+ PINCTRL_GRP_SDIO0_0,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_CSU0_2,
+ PINCTRL_GRP_GPIO0_20,
+ PINCTRL_GRP_CAN1_5,
+ PINCTRL_GRP_I2C1_5,
+ PINCTRL_GRP_SWDT1_3_CLK,
+ PINCTRL_GRP_SPI1_1_SS1,
+ PINCTRL_GRP_TTC1_2_CLK,
+ PINCTRL_GRP_UART1_5,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_4BIT_0_1,
+ PINCTRL_GRP_SDIO0_1BIT_0_7,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_21] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_NAND0_0,
+ PINCTRL_GRP_SDIO0_0,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_CSU0_3,
+ PINCTRL_GRP_GPIO0_21,
+ PINCTRL_GRP_CAN1_5,
+ PINCTRL_GRP_I2C1_5,
+ PINCTRL_GRP_SWDT1_3_RST,
+ PINCTRL_GRP_SPI1_1_SS0,
+ PINCTRL_GRP_TTC1_2_WAV,
+ PINCTRL_GRP_UART1_5,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_4BIT_0_0,
+ PINCTRL_GRP_SDIO0_4BIT_0_1,
+ PINCTRL_GRP_SDIO0_1BIT_0_0,
+ PINCTRL_GRP_SDIO0_1BIT_0_1,
+ PINCTRL_GRP_SDIO0_1BIT_0_2,
+ PINCTRL_GRP_SDIO0_1BIT_0_3,
+ PINCTRL_GRP_SDIO0_1BIT_0_4,
+ PINCTRL_GRP_SDIO0_1BIT_0_5,
+ PINCTRL_GRP_SDIO0_1BIT_0_6,
+ PINCTRL_GRP_SDIO0_1BIT_0_7,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_22] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_NAND0_0,
+ PINCTRL_GRP_SDIO0_0,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_CSU0_4,
+ PINCTRL_GRP_GPIO0_22,
+ PINCTRL_GRP_CAN0_5,
+ PINCTRL_GRP_I2C0_5,
+ PINCTRL_GRP_SWDT0_3_CLK,
+ PINCTRL_GRP_SPI1_1,
+ PINCTRL_GRP_TTC0_2_CLK,
+ PINCTRL_GRP_UART0_5,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_4BIT_0_0,
+ PINCTRL_GRP_SDIO0_4BIT_0_1,
+ PINCTRL_GRP_SDIO0_1BIT_0_0,
+ PINCTRL_GRP_SDIO0_1BIT_0_1,
+ PINCTRL_GRP_SDIO0_1BIT_0_2,
+ PINCTRL_GRP_SDIO0_1BIT_0_3,
+ PINCTRL_GRP_SDIO0_1BIT_0_4,
+ PINCTRL_GRP_SDIO0_1BIT_0_5,
+ PINCTRL_GRP_SDIO0_1BIT_0_6,
+ PINCTRL_GRP_SDIO0_1BIT_0_7,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_23] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_NAND0_0,
+ PINCTRL_GRP_SDIO0_0_PC,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_CSU0_5,
+ PINCTRL_GRP_GPIO0_23,
+ PINCTRL_GRP_CAN0_5,
+ PINCTRL_GRP_I2C0_5,
+ PINCTRL_GRP_SWDT0_3_RST,
+ PINCTRL_GRP_SPI1_1,
+ PINCTRL_GRP_TTC0_2_WAV,
+ PINCTRL_GRP_UART0_5,
+ PINCTRL_GRP_RESERVED,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_24] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_NAND0_0,
+ PINCTRL_GRP_SDIO0_0_CD,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_CSU0_6,
+ PINCTRL_GRP_GPIO0_24,
+ PINCTRL_GRP_CAN1_6,
+ PINCTRL_GRP_I2C1_6,
+ PINCTRL_GRP_SWDT1_4_CLK,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_TTC3_3_CLK,
+ PINCTRL_GRP_UART1_6,
+ PINCTRL_GRP_RESERVED,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_25] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_NAND0_0,
+ PINCTRL_GRP_SDIO0_0_WP,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_CSU0_7,
+ PINCTRL_GRP_GPIO0_25,
+ PINCTRL_GRP_CAN1_6,
+ PINCTRL_GRP_I2C1_6,
+ PINCTRL_GRP_SWDT1_4_RST,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_TTC3_3_WAV,
+ PINCTRL_GRP_UART1_6,
+ PINCTRL_GRP_RESERVED,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_26] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET0_0,
+ PINCTRL_GRP_GEMTSU0_0,
+ PINCTRL_GRP_NAND0_1_CE,
+ PINCTRL_GRP_PMU0_0,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_CSU0_8,
+ PINCTRL_GRP_GPIO0_26,
+ PINCTRL_GRP_CAN0_6,
+ PINCTRL_GRP_I2C0_6,
+ PINCTRL_GRP_PJTAG0_2,
+ PINCTRL_GRP_SPI0_2,
+ PINCTRL_GRP_TTC2_3_CLK,
+ PINCTRL_GRP_UART0_6,
+ PINCTRL_GRP_TRACE0_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_27] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET0_0,
+ PINCTRL_GRP_NAND0_1_RB,
+ PINCTRL_GRP_PMU0_1,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_DPAUX0_0,
+ PINCTRL_GRP_GPIO0_27,
+ PINCTRL_GRP_CAN0_6,
+ PINCTRL_GRP_I2C0_6,
+ PINCTRL_GRP_PJTAG0_2,
+ PINCTRL_GRP_SPI0_2_SS2,
+ PINCTRL_GRP_TTC2_3_WAV,
+ PINCTRL_GRP_UART0_6,
+ PINCTRL_GRP_TRACE0_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_28] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET0_0,
+ PINCTRL_GRP_NAND0_1_RB,
+ PINCTRL_GRP_PMU0_2,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_DPAUX0_0,
+ PINCTRL_GRP_GPIO0_28,
+ PINCTRL_GRP_CAN1_7,
+ PINCTRL_GRP_I2C1_7,
+ PINCTRL_GRP_PJTAG0_2,
+ PINCTRL_GRP_SPI0_2_SS1,
+ PINCTRL_GRP_TTC1_3_CLK,
+ PINCTRL_GRP_UART1_7,
+ PINCTRL_GRP_TRACE0_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_29] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET0_0,
+ PINCTRL_GRP_PCIE0_0,
+ PINCTRL_GRP_PMU0_3,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_DPAUX0_1,
+ PINCTRL_GRP_GPIO0_29,
+ PINCTRL_GRP_CAN1_7,
+ PINCTRL_GRP_I2C1_7,
+ PINCTRL_GRP_PJTAG0_2,
+ PINCTRL_GRP_SPI0_2_SS0,
+ PINCTRL_GRP_TTC1_3_WAV,
+ PINCTRL_GRP_UART1_7,
+ PINCTRL_GRP_TRACE0_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_30] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET0_0,
+ PINCTRL_GRP_PCIE0_1,
+ PINCTRL_GRP_PMU0_4,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_DPAUX0_1,
+ PINCTRL_GRP_GPIO0_30,
+ PINCTRL_GRP_CAN0_7,
+ PINCTRL_GRP_I2C0_7,
+ PINCTRL_GRP_SWDT0_4_CLK,
+ PINCTRL_GRP_SPI0_2,
+ PINCTRL_GRP_TTC0_3_CLK,
+ PINCTRL_GRP_UART0_7,
+ PINCTRL_GRP_TRACE0_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_31] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET0_0,
+ PINCTRL_GRP_PCIE0_2,
+ PINCTRL_GRP_PMU0_5,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_CSU0_9,
+ PINCTRL_GRP_GPIO0_31,
+ PINCTRL_GRP_CAN0_7,
+ PINCTRL_GRP_I2C0_7,
+ PINCTRL_GRP_SWDT0_4_RST,
+ PINCTRL_GRP_SPI0_2,
+ PINCTRL_GRP_TTC0_3_WAV,
+ PINCTRL_GRP_UART0_7,
+ PINCTRL_GRP_TRACE0_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_32] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET0_0,
+ PINCTRL_GRP_NAND0_1_DQS,
+ PINCTRL_GRP_PMU0_6,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_CSU0_10,
+ PINCTRL_GRP_GPIO0_32,
+ PINCTRL_GRP_CAN1_8,
+ PINCTRL_GRP_I2C1_8,
+ PINCTRL_GRP_SWDT1_5_CLK,
+ PINCTRL_GRP_SPI1_2,
+ PINCTRL_GRP_TTC3_4_CLK,
+ PINCTRL_GRP_UART1_8,
+ PINCTRL_GRP_TRACE0_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_33] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET0_0,
+ PINCTRL_GRP_PCIE0_3,
+ PINCTRL_GRP_PMU0_7,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_CSU0_11,
+ PINCTRL_GRP_GPIO0_33,
+ PINCTRL_GRP_CAN1_8,
+ PINCTRL_GRP_I2C1_8,
+ PINCTRL_GRP_SWDT1_5_RST,
+ PINCTRL_GRP_SPI1_2_SS2,
+ PINCTRL_GRP_TTC3_4_WAV,
+ PINCTRL_GRP_UART1_8,
+ PINCTRL_GRP_TRACE0_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_34] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET0_0,
+ PINCTRL_GRP_PCIE0_4,
+ PINCTRL_GRP_PMU0_8,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_DPAUX0_2,
+ PINCTRL_GRP_GPIO0_34,
+ PINCTRL_GRP_CAN0_8,
+ PINCTRL_GRP_I2C0_8,
+ PINCTRL_GRP_SWDT0_5_CLK,
+ PINCTRL_GRP_SPI1_2_SS1,
+ PINCTRL_GRP_TTC2_4_CLK,
+ PINCTRL_GRP_UART0_8,
+ PINCTRL_GRP_TRACE0_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_35] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET0_0,
+ PINCTRL_GRP_PCIE0_5,
+ PINCTRL_GRP_PMU0_9,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_DPAUX0_2,
+ PINCTRL_GRP_GPIO0_35,
+ PINCTRL_GRP_CAN0_8,
+ PINCTRL_GRP_I2C0_8,
+ PINCTRL_GRP_SWDT0_5_RST,
+ PINCTRL_GRP_SPI1_2_SS0,
+ PINCTRL_GRP_TTC2_4_WAV,
+ PINCTRL_GRP_UART0_8,
+ PINCTRL_GRP_TRACE0_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_36] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET0_0,
+ PINCTRL_GRP_PCIE0_6,
+ PINCTRL_GRP_PMU0_10,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_DPAUX0_3,
+ PINCTRL_GRP_GPIO0_36,
+ PINCTRL_GRP_CAN1_9,
+ PINCTRL_GRP_I2C1_9,
+ PINCTRL_GRP_SWDT1_6_CLK,
+ PINCTRL_GRP_SPI1_2,
+ PINCTRL_GRP_TTC1_4_CLK,
+ PINCTRL_GRP_UART1_9,
+ PINCTRL_GRP_TRACE0_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_37] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET0_0,
+ PINCTRL_GRP_PCIE0_7,
+ PINCTRL_GRP_PMU0_11,
+ PINCTRL_GRP_TESTSCAN0_0,
+ PINCTRL_GRP_DPAUX0_3,
+ PINCTRL_GRP_GPIO0_37,
+ PINCTRL_GRP_CAN1_9,
+ PINCTRL_GRP_I2C1_9,
+ PINCTRL_GRP_SWDT1_6_RST,
+ PINCTRL_GRP_SPI1_2,
+ PINCTRL_GRP_TTC1_4_WAV,
+ PINCTRL_GRP_UART1_9,
+ PINCTRL_GRP_TRACE0_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_38] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_1,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_38,
+ PINCTRL_GRP_CAN0_9,
+ PINCTRL_GRP_I2C0_9,
+ PINCTRL_GRP_PJTAG0_3,
+ PINCTRL_GRP_SPI0_3,
+ PINCTRL_GRP_TTC0_4_CLK,
+ PINCTRL_GRP_UART0_9,
+ PINCTRL_GRP_TRACE0_1_CLK,
+ PINCTRL_GRP_SDIO0_4BIT_1_0,
+ PINCTRL_GRP_SDIO0_4BIT_1_1,
+ PINCTRL_GRP_SDIO0_1BIT_1_0,
+ PINCTRL_GRP_SDIO0_1BIT_1_1,
+ PINCTRL_GRP_SDIO0_1BIT_1_2,
+ PINCTRL_GRP_SDIO0_1BIT_1_3,
+ PINCTRL_GRP_SDIO0_1BIT_1_4,
+ PINCTRL_GRP_SDIO0_1BIT_1_5,
+ PINCTRL_GRP_SDIO0_1BIT_1_6,
+ PINCTRL_GRP_SDIO0_1BIT_1_7,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_39] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_1_CD,
+ PINCTRL_GRP_SDIO1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_39,
+ PINCTRL_GRP_CAN0_9,
+ PINCTRL_GRP_I2C0_9,
+ PINCTRL_GRP_PJTAG0_3,
+ PINCTRL_GRP_SPI0_3_SS2,
+ PINCTRL_GRP_TTC0_4_WAV,
+ PINCTRL_GRP_UART0_9,
+ PINCTRL_GRP_TRACE0_1_CLK,
+ PINCTRL_GRP_SDIO1_4BIT_0_0,
+ PINCTRL_GRP_SDIO1_1BIT_0_0,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_40] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_1,
+ PINCTRL_GRP_SDIO1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_40,
+ PINCTRL_GRP_CAN1_10,
+ PINCTRL_GRP_I2C1_10,
+ PINCTRL_GRP_PJTAG0_3,
+ PINCTRL_GRP_SPI0_3_SS1,
+ PINCTRL_GRP_TTC3_5_CLK,
+ PINCTRL_GRP_UART1_10,
+ PINCTRL_GRP_TRACE0_1,
+ PINCTRL_GRP_SDIO0_4BIT_1_0,
+ PINCTRL_GRP_SDIO0_4BIT_1_1,
+ PINCTRL_GRP_SDIO0_1BIT_1_0,
+ PINCTRL_GRP_SDIO0_1BIT_1_1,
+ PINCTRL_GRP_SDIO0_1BIT_1_2,
+ PINCTRL_GRP_SDIO0_1BIT_1_3,
+ PINCTRL_GRP_SDIO0_1BIT_1_4,
+ PINCTRL_GRP_SDIO0_1BIT_1_5,
+ PINCTRL_GRP_SDIO0_1BIT_1_6,
+ PINCTRL_GRP_SDIO0_1BIT_1_7,
+ PINCTRL_GRP_SDIO1_4BIT_0_0,
+ PINCTRL_GRP_SDIO1_1BIT_0_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_41] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_1,
+ PINCTRL_GRP_SDIO1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_41,
+ PINCTRL_GRP_CAN1_10,
+ PINCTRL_GRP_I2C1_10,
+ PINCTRL_GRP_PJTAG0_3,
+ PINCTRL_GRP_SPI0_3_SS0,
+ PINCTRL_GRP_TTC3_5_WAV,
+ PINCTRL_GRP_UART1_10,
+ PINCTRL_GRP_TRACE0_1,
+ PINCTRL_GRP_SDIO0_4BIT_1_0,
+ PINCTRL_GRP_SDIO0_1BIT_1_0,
+ PINCTRL_GRP_SDIO1_4BIT_0_0,
+ PINCTRL_GRP_SDIO1_1BIT_0_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_42] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_1,
+ PINCTRL_GRP_SDIO1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_42,
+ PINCTRL_GRP_CAN0_10,
+ PINCTRL_GRP_I2C0_10,
+ PINCTRL_GRP_SWDT0_6_CLK,
+ PINCTRL_GRP_SPI0_3,
+ PINCTRL_GRP_TTC2_5_CLK,
+ PINCTRL_GRP_UART0_10,
+ PINCTRL_GRP_TRACE0_1,
+ PINCTRL_GRP_SDIO0_1,
+ PINCTRL_GRP_SDIO0_4BIT_1_0,
+ PINCTRL_GRP_SDIO0_1BIT_1_1,
+ PINCTRL_GRP_SDIO1_4BIT_0_0,
+ PINCTRL_GRP_SDIO1_1BIT_0_3,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_43] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_1,
+ PINCTRL_GRP_SDIO1_0_PC,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_43,
+ PINCTRL_GRP_CAN0_10,
+ PINCTRL_GRP_I2C0_10,
+ PINCTRL_GRP_SWDT0_6_RST,
+ PINCTRL_GRP_SPI0_3,
+ PINCTRL_GRP_TTC2_5_WAV,
+ PINCTRL_GRP_UART0_10,
+ PINCTRL_GRP_TRACE0_1,
+ PINCTRL_GRP_SDIO0_4BIT_1_0,
+ PINCTRL_GRP_SDIO0_1BIT_1_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_44] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_1,
+ PINCTRL_GRP_SDIO1_0_WP,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_44,
+ PINCTRL_GRP_CAN1_11,
+ PINCTRL_GRP_I2C1_11,
+ PINCTRL_GRP_SWDT1_7_CLK,
+ PINCTRL_GRP_SPI1_3,
+ PINCTRL_GRP_TTC1_5_CLK,
+ PINCTRL_GRP_UART1_11,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_4BIT_1_0,
+ PINCTRL_GRP_SDIO0_1BIT_1_3,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_45] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_1,
+ PINCTRL_GRP_SDIO1_0_CD,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_45,
+ PINCTRL_GRP_CAN1_11,
+ PINCTRL_GRP_I2C1_11,
+ PINCTRL_GRP_SWDT1_7_RST,
+ PINCTRL_GRP_SPI1_3_SS2,
+ PINCTRL_GRP_TTC1_5_WAV,
+ PINCTRL_GRP_UART1_11,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_4BIT_1_1,
+ PINCTRL_GRP_SDIO0_1BIT_1_4,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_46] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_1,
+ PINCTRL_GRP_SDIO1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_46,
+ PINCTRL_GRP_CAN0_11,
+ PINCTRL_GRP_I2C0_11,
+ PINCTRL_GRP_SWDT0_7_CLK,
+ PINCTRL_GRP_SPI1_3_SS1,
+ PINCTRL_GRP_TTC0_5_CLK,
+ PINCTRL_GRP_UART0_11,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_4BIT_1_1,
+ PINCTRL_GRP_SDIO0_1BIT_1_5,
+ PINCTRL_GRP_SDIO1_4BIT_0_1,
+ PINCTRL_GRP_SDIO1_1BIT_0_4,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_47] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_1,
+ PINCTRL_GRP_SDIO1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_47,
+ PINCTRL_GRP_CAN0_11,
+ PINCTRL_GRP_I2C0_11,
+ PINCTRL_GRP_SWDT0_7_RST,
+ PINCTRL_GRP_SPI1_3_SS0,
+ PINCTRL_GRP_TTC0_5_WAV,
+ PINCTRL_GRP_UART0_11,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_4BIT_1_1,
+ PINCTRL_GRP_SDIO0_1BIT_1_6,
+ PINCTRL_GRP_SDIO1_4BIT_0_1,
+ PINCTRL_GRP_SDIO1_1BIT_0_5,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_48] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_1,
+ PINCTRL_GRP_SDIO1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_48,
+ PINCTRL_GRP_CAN1_12,
+ PINCTRL_GRP_I2C1_12,
+ PINCTRL_GRP_SWDT1_8_CLK,
+ PINCTRL_GRP_SPI1_3,
+ PINCTRL_GRP_TTC3_6_CLK,
+ PINCTRL_GRP_UART1_12,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_4BIT_1_1,
+ PINCTRL_GRP_SDIO0_1BIT_1_7,
+ PINCTRL_GRP_SDIO1_4BIT_0_1,
+ PINCTRL_GRP_SDIO1_1BIT_0_6,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_49] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_1_PC,
+ PINCTRL_GRP_SDIO1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_49,
+ PINCTRL_GRP_CAN1_12,
+ PINCTRL_GRP_I2C1_12,
+ PINCTRL_GRP_SWDT1_8_RST,
+ PINCTRL_GRP_SPI1_3,
+ PINCTRL_GRP_TTC3_6_WAV,
+ PINCTRL_GRP_UART1_12,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO1_4BIT_0_1,
+ PINCTRL_GRP_SDIO1_1BIT_0_7,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_50] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_GEMTSU0_1,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_1_WP,
+ PINCTRL_GRP_SDIO1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_50,
+ PINCTRL_GRP_CAN0_12,
+ PINCTRL_GRP_I2C0_12,
+ PINCTRL_GRP_SWDT0_8_CLK,
+ PINCTRL_GRP_MDIO1_0,
+ PINCTRL_GRP_TTC2_6_CLK,
+ PINCTRL_GRP_UART0_12,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO1_4BIT_0_0,
+ PINCTRL_GRP_SDIO1_4BIT_0_1,
+ PINCTRL_GRP_SDIO1_1BIT_0_0,
+ PINCTRL_GRP_SDIO1_1BIT_0_1,
+ PINCTRL_GRP_SDIO1_1BIT_0_2,
+ PINCTRL_GRP_SDIO1_1BIT_0_3,
+ PINCTRL_GRP_SDIO1_1BIT_0_4,
+ PINCTRL_GRP_SDIO1_1BIT_0_5,
+ PINCTRL_GRP_SDIO1_1BIT_0_6,
+ PINCTRL_GRP_SDIO1_1BIT_0_7,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_51] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_GEMTSU0_2,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_51,
+ PINCTRL_GRP_CAN0_12,
+ PINCTRL_GRP_I2C0_12,
+ PINCTRL_GRP_SWDT0_8_RST,
+ PINCTRL_GRP_MDIO1_0,
+ PINCTRL_GRP_TTC2_6_WAV,
+ PINCTRL_GRP_UART0_12,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO1_4BIT_0_0,
+ PINCTRL_GRP_SDIO1_4BIT_0_1,
+ PINCTRL_GRP_SDIO1_1BIT_0_0,
+ PINCTRL_GRP_SDIO1_1BIT_0_1,
+ PINCTRL_GRP_SDIO1_1BIT_0_2,
+ PINCTRL_GRP_SDIO1_1BIT_0_3,
+ PINCTRL_GRP_SDIO1_1BIT_0_4,
+ PINCTRL_GRP_SDIO1_1BIT_0_5,
+ PINCTRL_GRP_SDIO1_1BIT_0_6,
+ PINCTRL_GRP_SDIO1_1BIT_0_7,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_52] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET2_0,
+ PINCTRL_GRP_USB0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_52,
+ PINCTRL_GRP_CAN1_13,
+ PINCTRL_GRP_I2C1_13,
+ PINCTRL_GRP_PJTAG0_4,
+ PINCTRL_GRP_SPI0_4,
+ PINCTRL_GRP_TTC1_6_CLK,
+ PINCTRL_GRP_UART1_13,
+ PINCTRL_GRP_TRACE0_2_CLK,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_53] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET2_0,
+ PINCTRL_GRP_USB0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_53,
+ PINCTRL_GRP_CAN1_13,
+ PINCTRL_GRP_I2C1_13,
+ PINCTRL_GRP_PJTAG0_4,
+ PINCTRL_GRP_SPI0_4_SS2,
+ PINCTRL_GRP_TTC1_6_WAV,
+ PINCTRL_GRP_UART1_13,
+ PINCTRL_GRP_TRACE0_2_CLK,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_54] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET2_0,
+ PINCTRL_GRP_USB0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_54,
+ PINCTRL_GRP_CAN0_13,
+ PINCTRL_GRP_I2C0_13,
+ PINCTRL_GRP_PJTAG0_4,
+ PINCTRL_GRP_SPI0_4_SS1,
+ PINCTRL_GRP_TTC0_6_CLK,
+ PINCTRL_GRP_UART0_13,
+ PINCTRL_GRP_TRACE0_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_55] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET2_0,
+ PINCTRL_GRP_USB0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_55,
+ PINCTRL_GRP_CAN0_13,
+ PINCTRL_GRP_I2C0_13,
+ PINCTRL_GRP_PJTAG0_4,
+ PINCTRL_GRP_SPI0_4_SS0,
+ PINCTRL_GRP_TTC0_6_WAV,
+ PINCTRL_GRP_UART0_13,
+ PINCTRL_GRP_TRACE0_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_56] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET2_0,
+ PINCTRL_GRP_USB0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_56,
+ PINCTRL_GRP_CAN1_14,
+ PINCTRL_GRP_I2C1_14,
+ PINCTRL_GRP_SWDT1_9_CLK,
+ PINCTRL_GRP_SPI0_4,
+ PINCTRL_GRP_TTC3_7_CLK,
+ PINCTRL_GRP_UART1_14,
+ PINCTRL_GRP_TRACE0_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_57] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET2_0,
+ PINCTRL_GRP_USB0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_57,
+ PINCTRL_GRP_CAN1_14,
+ PINCTRL_GRP_I2C1_14,
+ PINCTRL_GRP_SWDT1_9_RST,
+ PINCTRL_GRP_SPI0_4,
+ PINCTRL_GRP_TTC3_7_WAV,
+ PINCTRL_GRP_UART1_14,
+ PINCTRL_GRP_TRACE0_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_58] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET2_0,
+ PINCTRL_GRP_USB0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_58,
+ PINCTRL_GRP_CAN0_14,
+ PINCTRL_GRP_I2C0_14,
+ PINCTRL_GRP_PJTAG0_5,
+ PINCTRL_GRP_SPI1_4,
+ PINCTRL_GRP_TTC2_7_CLK,
+ PINCTRL_GRP_UART0_14,
+ PINCTRL_GRP_TRACE0_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_59] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET2_0,
+ PINCTRL_GRP_USB0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_59,
+ PINCTRL_GRP_CAN0_14,
+ PINCTRL_GRP_I2C0_14,
+ PINCTRL_GRP_PJTAG0_5,
+ PINCTRL_GRP_SPI1_4_SS2,
+ PINCTRL_GRP_TTC2_7_WAV,
+ PINCTRL_GRP_UART0_14,
+ PINCTRL_GRP_TRACE0_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_60] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET2_0,
+ PINCTRL_GRP_USB0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_60,
+ PINCTRL_GRP_CAN1_15,
+ PINCTRL_GRP_I2C1_15,
+ PINCTRL_GRP_PJTAG0_5,
+ PINCTRL_GRP_SPI1_4_SS1,
+ PINCTRL_GRP_TTC1_7_CLK,
+ PINCTRL_GRP_UART1_15,
+ PINCTRL_GRP_TRACE0_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_61] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET2_0,
+ PINCTRL_GRP_USB0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_61,
+ PINCTRL_GRP_CAN1_15,
+ PINCTRL_GRP_I2C1_15,
+ PINCTRL_GRP_PJTAG0_5,
+ PINCTRL_GRP_SPI1_4_SS0,
+ PINCTRL_GRP_TTC1_7_WAV,
+ PINCTRL_GRP_UART1_15,
+ PINCTRL_GRP_TRACE0_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_62] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET2_0,
+ PINCTRL_GRP_USB0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_62,
+ PINCTRL_GRP_CAN0_15,
+ PINCTRL_GRP_I2C0_15,
+ PINCTRL_GRP_SWDT0_9_CLK,
+ PINCTRL_GRP_SPI1_4,
+ PINCTRL_GRP_TTC0_7_CLK,
+ PINCTRL_GRP_UART0_15,
+ PINCTRL_GRP_TRACE0_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_63] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET2_0,
+ PINCTRL_GRP_USB0_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_63,
+ PINCTRL_GRP_CAN0_15,
+ PINCTRL_GRP_I2C0_15,
+ PINCTRL_GRP_SWDT0_9_RST,
+ PINCTRL_GRP_SPI1_4,
+ PINCTRL_GRP_TTC0_7_WAV,
+ PINCTRL_GRP_UART0_15,
+ PINCTRL_GRP_TRACE0_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_64] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET3_0,
+ PINCTRL_GRP_USB1_0,
+ PINCTRL_GRP_SDIO0_2,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_64,
+ PINCTRL_GRP_CAN1_16,
+ PINCTRL_GRP_I2C1_16,
+ PINCTRL_GRP_SWDT1_10_CLK,
+ PINCTRL_GRP_SPI0_5,
+ PINCTRL_GRP_TTC3_8_CLK,
+ PINCTRL_GRP_UART1_16,
+ PINCTRL_GRP_TRACE0_2,
+ PINCTRL_GRP_SDIO0_4BIT_2_0,
+ PINCTRL_GRP_SDIO0_4BIT_2_1,
+ PINCTRL_GRP_SDIO0_1BIT_2_0,
+ PINCTRL_GRP_SDIO0_1BIT_2_1,
+ PINCTRL_GRP_SDIO0_1BIT_2_2,
+ PINCTRL_GRP_SDIO0_1BIT_2_3,
+ PINCTRL_GRP_SDIO0_1BIT_2_4,
+ PINCTRL_GRP_SDIO0_1BIT_2_5,
+ PINCTRL_GRP_SDIO0_1BIT_2_6,
+ PINCTRL_GRP_SDIO0_1BIT_2_7,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_65] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET3_0,
+ PINCTRL_GRP_USB1_0,
+ PINCTRL_GRP_SDIO0_2_CD,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_65,
+ PINCTRL_GRP_CAN1_16,
+ PINCTRL_GRP_I2C1_16,
+ PINCTRL_GRP_SWDT1_10_RST,
+ PINCTRL_GRP_SPI0_5_SS2,
+ PINCTRL_GRP_TTC3_8_WAV,
+ PINCTRL_GRP_UART1_16,
+ PINCTRL_GRP_TRACE0_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_66] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET3_0,
+ PINCTRL_GRP_USB1_0,
+ PINCTRL_GRP_SDIO0_2,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_66,
+ PINCTRL_GRP_CAN0_16,
+ PINCTRL_GRP_I2C0_16,
+ PINCTRL_GRP_SWDT0_10_CLK,
+ PINCTRL_GRP_SPI0_5_SS1,
+ PINCTRL_GRP_TTC2_8_CLK,
+ PINCTRL_GRP_UART0_16,
+ PINCTRL_GRP_TRACE0_2,
+ PINCTRL_GRP_SDIO0_4BIT_2_0,
+ PINCTRL_GRP_SDIO0_4BIT_2_1,
+ PINCTRL_GRP_SDIO0_1BIT_2_0,
+ PINCTRL_GRP_SDIO0_1BIT_2_1,
+ PINCTRL_GRP_SDIO0_1BIT_2_2,
+ PINCTRL_GRP_SDIO0_1BIT_2_3,
+ PINCTRL_GRP_SDIO0_1BIT_2_4,
+ PINCTRL_GRP_SDIO0_1BIT_2_5,
+ PINCTRL_GRP_SDIO0_1BIT_2_6,
+ PINCTRL_GRP_SDIO0_1BIT_2_7,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_67] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET3_0,
+ PINCTRL_GRP_USB1_0,
+ PINCTRL_GRP_SDIO0_2,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_67,
+ PINCTRL_GRP_CAN0_16,
+ PINCTRL_GRP_I2C0_16,
+ PINCTRL_GRP_SWDT0_10_RST,
+ PINCTRL_GRP_SPI0_5_SS0,
+ PINCTRL_GRP_TTC2_8_WAV,
+ PINCTRL_GRP_UART0_16,
+ PINCTRL_GRP_TRACE0_2,
+ PINCTRL_GRP_SDIO0_4BIT_2_0,
+ PINCTRL_GRP_SDIO0_1BIT_2_0,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_68] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET3_0,
+ PINCTRL_GRP_USB1_0,
+ PINCTRL_GRP_SDIO0_2,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_68,
+ PINCTRL_GRP_CAN1_17,
+ PINCTRL_GRP_I2C1_17,
+ PINCTRL_GRP_SWDT1_11_CLK,
+ PINCTRL_GRP_SPI0_5,
+ PINCTRL_GRP_TTC1_8_CLK,
+ PINCTRL_GRP_UART1_17,
+ PINCTRL_GRP_TRACE0_2,
+ PINCTRL_GRP_SDIO0_4BIT_2_0,
+ PINCTRL_GRP_SDIO0_1BIT_2_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_69] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET3_0,
+ PINCTRL_GRP_USB1_0,
+ PINCTRL_GRP_SDIO0_2,
+ PINCTRL_GRP_SDIO1_1_WP,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_69,
+ PINCTRL_GRP_CAN1_17,
+ PINCTRL_GRP_I2C1_17,
+ PINCTRL_GRP_SWDT1_11_RST,
+ PINCTRL_GRP_SPI0_5,
+ PINCTRL_GRP_TTC1_8_WAV,
+ PINCTRL_GRP_UART1_17,
+ PINCTRL_GRP_TRACE0_2,
+ PINCTRL_GRP_SDIO0_4BIT_2_0,
+ PINCTRL_GRP_SDIO0_1BIT_2_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_70] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET3_0,
+ PINCTRL_GRP_USB1_0,
+ PINCTRL_GRP_SDIO0_2,
+ PINCTRL_GRP_SDIO1_1_PC,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_70,
+ PINCTRL_GRP_CAN0_17,
+ PINCTRL_GRP_I2C0_17,
+ PINCTRL_GRP_SWDT0_11_CLK,
+ PINCTRL_GRP_SPI1_5,
+ PINCTRL_GRP_TTC0_8_CLK,
+ PINCTRL_GRP_UART0_17,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_4BIT_2_0,
+ PINCTRL_GRP_SDIO0_1BIT_2_3,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_71] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET3_0,
+ PINCTRL_GRP_USB1_0,
+ PINCTRL_GRP_SDIO0_2,
+ PINCTRL_GRP_SDIO1_4BIT_1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_71,
+ PINCTRL_GRP_CAN0_17,
+ PINCTRL_GRP_I2C0_17,
+ PINCTRL_GRP_SWDT0_11_RST,
+ PINCTRL_GRP_SPI1_5_SS2,
+ PINCTRL_GRP_TTC0_8_WAV,
+ PINCTRL_GRP_UART0_17,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_2,
+ PINCTRL_GRP_SDIO0_4BIT_2_1,
+ PINCTRL_GRP_SDIO0_1BIT_2_4,
+ PINCTRL_GRP_SDIO1_1BIT_1_0,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_72] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET3_0,
+ PINCTRL_GRP_USB1_0,
+ PINCTRL_GRP_SDIO0_2,
+ PINCTRL_GRP_SDIO1_4BIT_1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_72,
+ PINCTRL_GRP_CAN1_18,
+ PINCTRL_GRP_I2C1_18,
+ PINCTRL_GRP_SWDT1_12_CLK,
+ PINCTRL_GRP_SPI1_5_SS1,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_UART1_18,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_4BIT_2_1,
+ PINCTRL_GRP_SDIO0_1BIT_2_5,
+ PINCTRL_GRP_SDIO1_1BIT_1_1,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_73] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET3_0,
+ PINCTRL_GRP_USB1_0,
+ PINCTRL_GRP_SDIO0_2,
+ PINCTRL_GRP_SDIO1_4BIT_1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_73,
+ PINCTRL_GRP_CAN1_18,
+ PINCTRL_GRP_I2C1_18,
+ PINCTRL_GRP_SWDT1_12_RST,
+ PINCTRL_GRP_SPI1_5_SS0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_UART1_18,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_4BIT_2_1,
+ PINCTRL_GRP_SDIO0_1BIT_2_6,
+ PINCTRL_GRP_SDIO1_1BIT_1_2,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_74] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET3_0,
+ PINCTRL_GRP_USB1_0,
+ PINCTRL_GRP_SDIO0_2,
+ PINCTRL_GRP_SDIO1_4BIT_1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_74,
+ PINCTRL_GRP_CAN0_18,
+ PINCTRL_GRP_I2C0_18,
+ PINCTRL_GRP_SWDT0_12_CLK,
+ PINCTRL_GRP_SPI1_5,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_UART0_18,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_4BIT_2_1,
+ PINCTRL_GRP_SDIO0_1BIT_2_7,
+ PINCTRL_GRP_SDIO1_1BIT_1_3,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_75] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_ETHERNET3_0,
+ PINCTRL_GRP_USB1_0,
+ PINCTRL_GRP_SDIO0_2_PC,
+ PINCTRL_GRP_SDIO1_4BIT_1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_75,
+ PINCTRL_GRP_CAN0_18,
+ PINCTRL_GRP_I2C0_18,
+ PINCTRL_GRP_SWDT0_12_RST,
+ PINCTRL_GRP_SPI1_5,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_UART0_18,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO1_1BIT_1_0,
+ PINCTRL_GRP_SDIO1_1BIT_1_1,
+ PINCTRL_GRP_SDIO1_1BIT_1_2,
+ PINCTRL_GRP_SDIO1_1BIT_1_3,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_76] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO0_2_WP,
+ PINCTRL_GRP_SDIO1_4BIT_1_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_76,
+ PINCTRL_GRP_CAN1_19,
+ PINCTRL_GRP_I2C1_19,
+ PINCTRL_GRP_MDIO0_0,
+ PINCTRL_GRP_MDIO1_1,
+ PINCTRL_GRP_MDIO2_0,
+ PINCTRL_GRP_MDIO3_0,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO1_1BIT_1_0,
+ PINCTRL_GRP_SDIO1_1BIT_1_1,
+ PINCTRL_GRP_SDIO1_1BIT_1_2,
+ PINCTRL_GRP_SDIO1_1BIT_1_3,
+ END_OF_GROUPS,
+ }),
+ },
+ [PINCTRL_PIN_77] = {
+ .groups = &((uint16_t []) {
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_SDIO1_1_CD,
+ PINCTRL_GRP_RESERVED,
+ PINCTRL_GRP_GPIO0_77,
+ PINCTRL_GRP_CAN1_19,
+ PINCTRL_GRP_I2C1_19,
+ PINCTRL_GRP_MDIO0_0,
+ PINCTRL_GRP_MDIO1_1,
+ PINCTRL_GRP_MDIO2_0,
+ PINCTRL_GRP_MDIO3_0,
+ PINCTRL_GRP_RESERVED,
+ END_OF_GROUPS,
+ }),
+ },
+};
+
+/**
+ * pm_api_pinctrl_get_num_pins() - PM call to request number of pins
+ * @npins Number of pins
+ *
+ * This function is used by master to get number of pins
+ *
+ * @return Returns success.
+ */
+enum pm_ret_status pm_api_pinctrl_get_num_pins(uint32_t *npins)
+{
+ *npins = MAX_PIN;
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_pinctrl_get_num_functions() - PM call to request number of functions
+ * @nfuncs Number of functions
+ *
+ * This function is used by master to get number of functions
+ *
+ * @return Returns success.
+ */
+enum pm_ret_status pm_api_pinctrl_get_num_functions(uint32_t *nfuncs)
+{
+ *nfuncs = MAX_FUNCTION;
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_pinctrl_get_num_func_groups() - PM call to request number of
+ * function groups
+ * @fid Function Id
+ * @ngroups Number of function groups
+ *
+ * This function is used by master to get number of function groups
+ *
+ * @return Returns success.
+ */
+enum pm_ret_status pm_api_pinctrl_get_num_func_groups(uint32_t fid,
+ uint32_t *ngroups)
+{
+ if (fid >= MAX_FUNCTION) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ *ngroups = pinctrl_functions[fid].group_size;
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_pinctrl_get_function_name() - PM call to request a function name
+ * @fid Function ID
+ * @name Name of function (max 16 bytes)
+ *
+ * This function is used by master to get name of function specified
+ * by given function ID.
+ */
+void pm_api_pinctrl_get_function_name(uint32_t fid, char *name)
+{
+ if (fid >= MAX_FUNCTION) {
+ memcpy(name, END_OF_FUNCTION, FUNCTION_NAME_LEN);
+ } else {
+ memcpy(name, pinctrl_functions[fid].name, FUNCTION_NAME_LEN);
+ }
+}
+
+/**
+ * pm_api_pinctrl_get_function_groups() - PM call to request first 6 function
+ * groups of function Id
+ * @fid Function ID
+ * @index Index of next function groups
+ * @groups Function groups
+ *
+ * This function is used by master to get function groups specified
+ * by given function Id. This API will return 6 function groups with
+ * a single response. To get other function groups, master should call
+ * same API in loop with new function groups index till error is returned.
+ *
+ * E.g First call should have index 0 which will return function groups
+ * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return
+ * function groups 6, 7, 8, 9, 10 and 11 and so on.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_api_pinctrl_get_function_groups(uint32_t fid,
+ uint32_t index,
+ uint16_t *groups)
+{
+ uint16_t grps;
+ uint16_t end_of_grp_offset;
+ uint16_t i;
+
+ if (fid >= MAX_FUNCTION) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ memset(groups, END_OF_GROUPS, GROUPS_PAYLOAD_LEN);
+
+ grps = pinctrl_functions[fid].group_base;
+ end_of_grp_offset = grps + pinctrl_functions[fid].group_size;
+
+ for (i = 0U; i < NUM_GROUPS_PER_RESP; i++) {
+ if ((grps + index + i) >= end_of_grp_offset) {
+ break;
+ }
+ groups[i] = (grps + index + i);
+ }
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * pm_api_pinctrl_get_pin_groups() - PM call to request first 6 pin
+ * groups of pin
+ * @pin Pin
+ * @index Index of next pin groups
+ * @groups pin groups
+ *
+ * This function is used by master to get pin groups specified
+ * by given pin Id. This API will return 6 pin groups with
+ * a single response. To get other pin groups, master should call
+ * same API in loop with new pin groups index till error is returned.
+ *
+ * E.g First call should have index 0 which will return pin groups
+ * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return
+ * pin groups 6, 7, 8, 9, 10 and 11 and so on.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_api_pinctrl_get_pin_groups(uint32_t pin,
+ uint32_t index,
+ uint16_t *groups)
+{
+ uint32_t i;
+ uint16_t *grps;
+
+ if (pin >= MAX_PIN) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ memset(groups, END_OF_GROUPS, GROUPS_PAYLOAD_LEN);
+
+ grps = *zynqmp_pin_groups[pin].groups;
+ if (grps == NULL) {
+ return PM_RET_SUCCESS;
+ }
+
+ /* Skip groups till index */
+ for (i = 0; i < index; i++) {
+ if (grps[i] == (uint16_t)END_OF_GROUPS) {
+ return PM_RET_SUCCESS;
+ }
+ }
+
+ for (i = 0; i < NUM_GROUPS_PER_RESP; i++) {
+ groups[i] = grps[index + i];
+ if (groups[i] == (uint16_t)END_OF_GROUPS) {
+ break;
+ }
+ }
+
+ return PM_RET_SUCCESS;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h
new file mode 100644
index 0000000..5c4cb45
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h
@@ -0,0 +1,723 @@
+/*
+ * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions for pin control.
+ */
+
+#ifndef PM_API_PINCTRL_H
+#define PM_API_PINCTRL_H
+
+#include "pm_common.h"
+
+#define FUNCTION_NAME_LEN (16U)
+#define GROUPS_PAYLOAD_LEN (12U)
+#define NUM_GROUPS_PER_RESP (6U)
+#define END_OF_FUNCTION "END_OF_FUNCTION"
+#define END_OF_GROUPS -1
+#define PINCTRL_GRP_RESERVED -2
+
+//pinctrl function ids
+enum {
+ PINCTRL_FUNC_CAN0 = (0U),
+ PINCTRL_FUNC_CAN1 = (1U),
+ PINCTRL_FUNC_ETHERNET0 = (2U),
+ PINCTRL_FUNC_ETHERNET1 = (3U),
+ PINCTRL_FUNC_ETHERNET2 = (4U),
+ PINCTRL_FUNC_ETHERNET3 = (5U),
+ PINCTRL_FUNC_GEMTSU0 = (6U),
+ PINCTRL_FUNC_GPIO0 = (7U),
+ PINCTRL_FUNC_I2C0 = (8U),
+ PINCTRL_FUNC_I2C1 = (9U),
+ PINCTRL_FUNC_MDIO0 = (10U),
+ PINCTRL_FUNC_MDIO1 = (11U),
+ PINCTRL_FUNC_MDIO2 = (12U),
+ PINCTRL_FUNC_MDIO3 = (13U),
+ PINCTRL_FUNC_QSPI0 = (14U),
+ PINCTRL_FUNC_QSPI_FBCLK = (15U),
+ PINCTRL_FUNC_QSPI_SS = (16U),
+ PINCTRL_FUNC_SPI0 = (17U),
+ PINCTRL_FUNC_SPI1 = (18U),
+ PINCTRL_FUNC_SPI0_SS = (19U),
+ PINCTRL_FUNC_SPI1_SS = (20U),
+ PINCTRL_FUNC_SDIO0 = (21U),
+ PINCTRL_FUNC_SDIO0_PC = (22U),
+ PINCTRL_FUNC_SDIO0_CD = (23U),
+ PINCTRL_FUNC_SDIO0_WP = (24U),
+ PINCTRL_FUNC_SDIO1 = (25U),
+ PINCTRL_FUNC_SDIO1_PC = (26U),
+ PINCTRL_FUNC_SDIO1_CD = (27U),
+ PINCTRL_FUNC_SDIO1_WP = (28U),
+ PINCTRL_FUNC_NAND0 = (29U),
+ PINCTRL_FUNC_NAND0_CE = (30U),
+ PINCTRL_FUNC_NAND0_RB = (31U),
+ PINCTRL_FUNC_NAND0_DQS = (32U),
+ PINCTRL_FUNC_TTC0_CLK = (33U),
+ PINCTRL_FUNC_TTC0_WAV = (34U),
+ PINCTRL_FUNC_TTC1_CLK = (35U),
+ PINCTRL_FUNC_TTC1_WAV = (36U),
+ PINCTRL_FUNC_TTC2_CLK = (37U),
+ PINCTRL_FUNC_TTC2_WAV = (38U),
+ PINCTRL_FUNC_TTC3_CLK = (39U),
+ PINCTRL_FUNC_TTC3_WAV = (40U),
+ PINCTRL_FUNC_UART0 = (41U),
+ PINCTRL_FUNC_UART1 = (42U),
+ PINCTRL_FUNC_USB0 = (43U),
+ PINCTRL_FUNC_USB1 = (44U),
+ PINCTRL_FUNC_SWDT0_CLK = (45U),
+ PINCTRL_FUNC_SWDT0_RST = (46U),
+ PINCTRL_FUNC_SWDT1_CLK = (47U),
+ PINCTRL_FUNC_SWDT1_RST = (48U),
+ PINCTRL_FUNC_PMU0 = (49U),
+ PINCTRL_FUNC_PCIE0 = (50U),
+ PINCTRL_FUNC_CSU0 = (51U),
+ PINCTRL_FUNC_DPAUX0 = (52U),
+ PINCTRL_FUNC_PJTAG0 = (53U),
+ PINCTRL_FUNC_TRACE0 = (54U),
+ PINCTRL_FUNC_TRACE0_CLK = (55U),
+ PINCTRL_FUNC_TESTSCAN0 = (56U),
+ END_FUNCTION = (57U),
+};
+
+#define MAX_FUNCTION END_FUNCTION
+
+// pinctrl pin numbers
+enum {
+ PINCTRL_PIN_0,
+ PINCTRL_PIN_1,
+ PINCTRL_PIN_2,
+ PINCTRL_PIN_3,
+ PINCTRL_PIN_4,
+ PINCTRL_PIN_5,
+ PINCTRL_PIN_6,
+ PINCTRL_PIN_7,
+ PINCTRL_PIN_8,
+ PINCTRL_PIN_9,
+ PINCTRL_PIN_10,
+ PINCTRL_PIN_11,
+ PINCTRL_PIN_12,
+ PINCTRL_PIN_13,
+ PINCTRL_PIN_14,
+ PINCTRL_PIN_15,
+ PINCTRL_PIN_16,
+ PINCTRL_PIN_17,
+ PINCTRL_PIN_18,
+ PINCTRL_PIN_19,
+ PINCTRL_PIN_20,
+ PINCTRL_PIN_21,
+ PINCTRL_PIN_22,
+ PINCTRL_PIN_23,
+ PINCTRL_PIN_24,
+ PINCTRL_PIN_25,
+ PINCTRL_PIN_26,
+ PINCTRL_PIN_27,
+ PINCTRL_PIN_28,
+ PINCTRL_PIN_29,
+ PINCTRL_PIN_30,
+ PINCTRL_PIN_31,
+ PINCTRL_PIN_32,
+ PINCTRL_PIN_33,
+ PINCTRL_PIN_34,
+ PINCTRL_PIN_35,
+ PINCTRL_PIN_36,
+ PINCTRL_PIN_37,
+ PINCTRL_PIN_38,
+ PINCTRL_PIN_39,
+ PINCTRL_PIN_40,
+ PINCTRL_PIN_41,
+ PINCTRL_PIN_42,
+ PINCTRL_PIN_43,
+ PINCTRL_PIN_44,
+ PINCTRL_PIN_45,
+ PINCTRL_PIN_46,
+ PINCTRL_PIN_47,
+ PINCTRL_PIN_48,
+ PINCTRL_PIN_49,
+ PINCTRL_PIN_50,
+ PINCTRL_PIN_51,
+ PINCTRL_PIN_52,
+ PINCTRL_PIN_53,
+ PINCTRL_PIN_54,
+ PINCTRL_PIN_55,
+ PINCTRL_PIN_56,
+ PINCTRL_PIN_57,
+ PINCTRL_PIN_58,
+ PINCTRL_PIN_59,
+ PINCTRL_PIN_60,
+ PINCTRL_PIN_61,
+ PINCTRL_PIN_62,
+ PINCTRL_PIN_63,
+ PINCTRL_PIN_64,
+ PINCTRL_PIN_65,
+ PINCTRL_PIN_66,
+ PINCTRL_PIN_67,
+ PINCTRL_PIN_68,
+ PINCTRL_PIN_69,
+ PINCTRL_PIN_70,
+ PINCTRL_PIN_71,
+ PINCTRL_PIN_72,
+ PINCTRL_PIN_73,
+ PINCTRL_PIN_74,
+ PINCTRL_PIN_75,
+ PINCTRL_PIN_76,
+ PINCTRL_PIN_77,
+ END_PINS = (78U),
+};
+
+#define MAX_PIN END_PINS
+
+// pinctrl group ids
+enum {
+ PINCTRL_GRP_ETHERNET0_0,
+ PINCTRL_GRP_ETHERNET1_0,
+ PINCTRL_GRP_ETHERNET2_0,
+ PINCTRL_GRP_ETHERNET3_0,
+ PINCTRL_GRP_GEMTSU0_0,
+ PINCTRL_GRP_GEMTSU0_1,
+ PINCTRL_GRP_GEMTSU0_2,
+ PINCTRL_GRP_MDIO0_0,
+ PINCTRL_GRP_MDIO1_0,
+ PINCTRL_GRP_MDIO1_1,
+ PINCTRL_GRP_MDIO2_0,
+ PINCTRL_GRP_MDIO3_0,
+ PINCTRL_GRP_QSPI0_0,
+ PINCTRL_GRP_QSPI_SS,
+ PINCTRL_GRP_QSPI_FBCLK,
+ PINCTRL_GRP_SPI0_0,
+ PINCTRL_GRP_SPI0_1,
+ PINCTRL_GRP_SPI0_2,
+ PINCTRL_GRP_SPI0_3,
+ PINCTRL_GRP_SPI0_4,
+ PINCTRL_GRP_SPI0_5,
+ PINCTRL_GRP_SPI0_0_SS0,
+ PINCTRL_GRP_SPI0_0_SS1,
+ PINCTRL_GRP_SPI0_0_SS2,
+ PINCTRL_GRP_SPI0_1_SS0,
+ PINCTRL_GRP_SPI0_1_SS1,
+ PINCTRL_GRP_SPI0_1_SS2,
+ PINCTRL_GRP_SPI0_2_SS0,
+ PINCTRL_GRP_SPI0_2_SS1,
+ PINCTRL_GRP_SPI0_2_SS2,
+ PINCTRL_GRP_SPI0_3_SS0,
+ PINCTRL_GRP_SPI0_3_SS1,
+ PINCTRL_GRP_SPI0_3_SS2,
+ PINCTRL_GRP_SPI0_4_SS0,
+ PINCTRL_GRP_SPI0_4_SS1,
+ PINCTRL_GRP_SPI0_4_SS2,
+ PINCTRL_GRP_SPI0_5_SS0,
+ PINCTRL_GRP_SPI0_5_SS1,
+ PINCTRL_GRP_SPI0_5_SS2,
+ PINCTRL_GRP_SPI1_0,
+ PINCTRL_GRP_SPI1_1,
+ PINCTRL_GRP_SPI1_2,
+ PINCTRL_GRP_SPI1_3,
+ PINCTRL_GRP_SPI1_4,
+ PINCTRL_GRP_SPI1_5,
+ PINCTRL_GRP_SPI1_0_SS0,
+ PINCTRL_GRP_SPI1_0_SS1,
+ PINCTRL_GRP_SPI1_0_SS2,
+ PINCTRL_GRP_SPI1_1_SS0,
+ PINCTRL_GRP_SPI1_1_SS1,
+ PINCTRL_GRP_SPI1_1_SS2,
+ PINCTRL_GRP_SPI1_2_SS0,
+ PINCTRL_GRP_SPI1_2_SS1,
+ PINCTRL_GRP_SPI1_2_SS2,
+ PINCTRL_GRP_SPI1_3_SS0,
+ PINCTRL_GRP_SPI1_3_SS1,
+ PINCTRL_GRP_SPI1_3_SS2,
+ PINCTRL_GRP_SPI1_4_SS0,
+ PINCTRL_GRP_SPI1_4_SS1,
+ PINCTRL_GRP_SPI1_4_SS2,
+ PINCTRL_GRP_SPI1_5_SS0,
+ PINCTRL_GRP_SPI1_5_SS1,
+ PINCTRL_GRP_SPI1_5_SS2,
+ PINCTRL_GRP_SDIO0_0,
+ PINCTRL_GRP_SDIO0_1,
+ PINCTRL_GRP_SDIO0_2,
+ PINCTRL_GRP_SDIO0_4BIT_0_0,
+ PINCTRL_GRP_SDIO0_4BIT_0_1,
+ PINCTRL_GRP_SDIO0_4BIT_1_0,
+ PINCTRL_GRP_SDIO0_4BIT_1_1,
+ PINCTRL_GRP_SDIO0_4BIT_2_0,
+ PINCTRL_GRP_SDIO0_4BIT_2_1,
+ PINCTRL_GRP_SDIO0_1BIT_0_0,
+ PINCTRL_GRP_SDIO0_1BIT_0_1,
+ PINCTRL_GRP_SDIO0_1BIT_0_2,
+ PINCTRL_GRP_SDIO0_1BIT_0_3,
+ PINCTRL_GRP_SDIO0_1BIT_0_4,
+ PINCTRL_GRP_SDIO0_1BIT_0_5,
+ PINCTRL_GRP_SDIO0_1BIT_0_6,
+ PINCTRL_GRP_SDIO0_1BIT_0_7,
+ PINCTRL_GRP_SDIO0_1BIT_1_0,
+ PINCTRL_GRP_SDIO0_1BIT_1_1,
+ PINCTRL_GRP_SDIO0_1BIT_1_2,
+ PINCTRL_GRP_SDIO0_1BIT_1_3,
+ PINCTRL_GRP_SDIO0_1BIT_1_4,
+ PINCTRL_GRP_SDIO0_1BIT_1_5,
+ PINCTRL_GRP_SDIO0_1BIT_1_6,
+ PINCTRL_GRP_SDIO0_1BIT_1_7,
+ PINCTRL_GRP_SDIO0_1BIT_2_0,
+ PINCTRL_GRP_SDIO0_1BIT_2_1,
+ PINCTRL_GRP_SDIO0_1BIT_2_2,
+ PINCTRL_GRP_SDIO0_1BIT_2_3,
+ PINCTRL_GRP_SDIO0_1BIT_2_4,
+ PINCTRL_GRP_SDIO0_1BIT_2_5,
+ PINCTRL_GRP_SDIO0_1BIT_2_6,
+ PINCTRL_GRP_SDIO0_1BIT_2_7,
+ PINCTRL_GRP_SDIO0_0_PC,
+ PINCTRL_GRP_SDIO0_1_PC,
+ PINCTRL_GRP_SDIO0_2_PC,
+ PINCTRL_GRP_SDIO0_0_CD,
+ PINCTRL_GRP_SDIO0_1_CD,
+ PINCTRL_GRP_SDIO0_2_CD,
+ PINCTRL_GRP_SDIO0_0_WP,
+ PINCTRL_GRP_SDIO0_1_WP,
+ PINCTRL_GRP_SDIO0_2_WP,
+ PINCTRL_GRP_SDIO1_0,
+ PINCTRL_GRP_SDIO1_4BIT_0_0,
+ PINCTRL_GRP_SDIO1_4BIT_0_1,
+ PINCTRL_GRP_SDIO1_4BIT_1_0,
+ PINCTRL_GRP_SDIO1_1BIT_0_0,
+ PINCTRL_GRP_SDIO1_1BIT_0_1,
+ PINCTRL_GRP_SDIO1_1BIT_0_2,
+ PINCTRL_GRP_SDIO1_1BIT_0_3,
+ PINCTRL_GRP_SDIO1_1BIT_0_4,
+ PINCTRL_GRP_SDIO1_1BIT_0_5,
+ PINCTRL_GRP_SDIO1_1BIT_0_6,
+ PINCTRL_GRP_SDIO1_1BIT_0_7,
+ PINCTRL_GRP_SDIO1_1BIT_1_0,
+ PINCTRL_GRP_SDIO1_1BIT_1_1,
+ PINCTRL_GRP_SDIO1_1BIT_1_2,
+ PINCTRL_GRP_SDIO1_1BIT_1_3,
+ PINCTRL_GRP_SDIO1_0_PC,
+ PINCTRL_GRP_SDIO1_1_PC,
+ PINCTRL_GRP_SDIO1_0_CD,
+ PINCTRL_GRP_SDIO1_1_CD,
+ PINCTRL_GRP_SDIO1_0_WP,
+ PINCTRL_GRP_SDIO1_1_WP,
+ PINCTRL_GRP_NAND0_0,
+ PINCTRL_GRP_NAND0_0_CE,
+ PINCTRL_GRP_NAND0_1_CE,
+ PINCTRL_GRP_NAND0_0_RB,
+ PINCTRL_GRP_NAND0_1_RB,
+ PINCTRL_GRP_NAND0_0_DQS,
+ PINCTRL_GRP_NAND0_1_DQS,
+ PINCTRL_GRP_CAN0_0,
+ PINCTRL_GRP_CAN0_1,
+ PINCTRL_GRP_CAN0_2,
+ PINCTRL_GRP_CAN0_3,
+ PINCTRL_GRP_CAN0_4,
+ PINCTRL_GRP_CAN0_5,
+ PINCTRL_GRP_CAN0_6,
+ PINCTRL_GRP_CAN0_7,
+ PINCTRL_GRP_CAN0_8,
+ PINCTRL_GRP_CAN0_9,
+ PINCTRL_GRP_CAN0_10,
+ PINCTRL_GRP_CAN0_11,
+ PINCTRL_GRP_CAN0_12,
+ PINCTRL_GRP_CAN0_13,
+ PINCTRL_GRP_CAN0_14,
+ PINCTRL_GRP_CAN0_15,
+ PINCTRL_GRP_CAN0_16,
+ PINCTRL_GRP_CAN0_17,
+ PINCTRL_GRP_CAN0_18,
+ PINCTRL_GRP_CAN1_0,
+ PINCTRL_GRP_CAN1_1,
+ PINCTRL_GRP_CAN1_2,
+ PINCTRL_GRP_CAN1_3,
+ PINCTRL_GRP_CAN1_4,
+ PINCTRL_GRP_CAN1_5,
+ PINCTRL_GRP_CAN1_6,
+ PINCTRL_GRP_CAN1_7,
+ PINCTRL_GRP_CAN1_8,
+ PINCTRL_GRP_CAN1_9,
+ PINCTRL_GRP_CAN1_10,
+ PINCTRL_GRP_CAN1_11,
+ PINCTRL_GRP_CAN1_12,
+ PINCTRL_GRP_CAN1_13,
+ PINCTRL_GRP_CAN1_14,
+ PINCTRL_GRP_CAN1_15,
+ PINCTRL_GRP_CAN1_16,
+ PINCTRL_GRP_CAN1_17,
+ PINCTRL_GRP_CAN1_18,
+ PINCTRL_GRP_CAN1_19,
+ PINCTRL_GRP_UART0_0,
+ PINCTRL_GRP_UART0_1,
+ PINCTRL_GRP_UART0_2,
+ PINCTRL_GRP_UART0_3,
+ PINCTRL_GRP_UART0_4,
+ PINCTRL_GRP_UART0_5,
+ PINCTRL_GRP_UART0_6,
+ PINCTRL_GRP_UART0_7,
+ PINCTRL_GRP_UART0_8,
+ PINCTRL_GRP_UART0_9,
+ PINCTRL_GRP_UART0_10,
+ PINCTRL_GRP_UART0_11,
+ PINCTRL_GRP_UART0_12,
+ PINCTRL_GRP_UART0_13,
+ PINCTRL_GRP_UART0_14,
+ PINCTRL_GRP_UART0_15,
+ PINCTRL_GRP_UART0_16,
+ PINCTRL_GRP_UART0_17,
+ PINCTRL_GRP_UART0_18,
+ PINCTRL_GRP_UART1_0,
+ PINCTRL_GRP_UART1_1,
+ PINCTRL_GRP_UART1_2,
+ PINCTRL_GRP_UART1_3,
+ PINCTRL_GRP_UART1_4,
+ PINCTRL_GRP_UART1_5,
+ PINCTRL_GRP_UART1_6,
+ PINCTRL_GRP_UART1_7,
+ PINCTRL_GRP_UART1_8,
+ PINCTRL_GRP_UART1_9,
+ PINCTRL_GRP_UART1_10,
+ PINCTRL_GRP_UART1_11,
+ PINCTRL_GRP_UART1_12,
+ PINCTRL_GRP_UART1_13,
+ PINCTRL_GRP_UART1_14,
+ PINCTRL_GRP_UART1_15,
+ PINCTRL_GRP_UART1_16,
+ PINCTRL_GRP_UART1_17,
+ PINCTRL_GRP_UART1_18,
+ PINCTRL_GRP_I2C0_0,
+ PINCTRL_GRP_I2C0_1,
+ PINCTRL_GRP_I2C0_2,
+ PINCTRL_GRP_I2C0_3,
+ PINCTRL_GRP_I2C0_4,
+ PINCTRL_GRP_I2C0_5,
+ PINCTRL_GRP_I2C0_6,
+ PINCTRL_GRP_I2C0_7,
+ PINCTRL_GRP_I2C0_8,
+ PINCTRL_GRP_I2C0_9,
+ PINCTRL_GRP_I2C0_10,
+ PINCTRL_GRP_I2C0_11,
+ PINCTRL_GRP_I2C0_12,
+ PINCTRL_GRP_I2C0_13,
+ PINCTRL_GRP_I2C0_14,
+ PINCTRL_GRP_I2C0_15,
+ PINCTRL_GRP_I2C0_16,
+ PINCTRL_GRP_I2C0_17,
+ PINCTRL_GRP_I2C0_18,
+ PINCTRL_GRP_I2C1_0,
+ PINCTRL_GRP_I2C1_1,
+ PINCTRL_GRP_I2C1_2,
+ PINCTRL_GRP_I2C1_3,
+ PINCTRL_GRP_I2C1_4,
+ PINCTRL_GRP_I2C1_5,
+ PINCTRL_GRP_I2C1_6,
+ PINCTRL_GRP_I2C1_7,
+ PINCTRL_GRP_I2C1_8,
+ PINCTRL_GRP_I2C1_9,
+ PINCTRL_GRP_I2C1_10,
+ PINCTRL_GRP_I2C1_11,
+ PINCTRL_GRP_I2C1_12,
+ PINCTRL_GRP_I2C1_13,
+ PINCTRL_GRP_I2C1_14,
+ PINCTRL_GRP_I2C1_15,
+ PINCTRL_GRP_I2C1_16,
+ PINCTRL_GRP_I2C1_17,
+ PINCTRL_GRP_I2C1_18,
+ PINCTRL_GRP_I2C1_19,
+ PINCTRL_GRP_TTC0_0_CLK,
+ PINCTRL_GRP_TTC0_1_CLK,
+ PINCTRL_GRP_TTC0_2_CLK,
+ PINCTRL_GRP_TTC0_3_CLK,
+ PINCTRL_GRP_TTC0_4_CLK,
+ PINCTRL_GRP_TTC0_5_CLK,
+ PINCTRL_GRP_TTC0_6_CLK,
+ PINCTRL_GRP_TTC0_7_CLK,
+ PINCTRL_GRP_TTC0_8_CLK,
+ PINCTRL_GRP_TTC0_0_WAV,
+ PINCTRL_GRP_TTC0_1_WAV,
+ PINCTRL_GRP_TTC0_2_WAV,
+ PINCTRL_GRP_TTC0_3_WAV,
+ PINCTRL_GRP_TTC0_4_WAV,
+ PINCTRL_GRP_TTC0_5_WAV,
+ PINCTRL_GRP_TTC0_6_WAV,
+ PINCTRL_GRP_TTC0_7_WAV,
+ PINCTRL_GRP_TTC0_8_WAV,
+ PINCTRL_GRP_TTC1_0_CLK,
+ PINCTRL_GRP_TTC1_1_CLK,
+ PINCTRL_GRP_TTC1_2_CLK,
+ PINCTRL_GRP_TTC1_3_CLK,
+ PINCTRL_GRP_TTC1_4_CLK,
+ PINCTRL_GRP_TTC1_5_CLK,
+ PINCTRL_GRP_TTC1_6_CLK,
+ PINCTRL_GRP_TTC1_7_CLK,
+ PINCTRL_GRP_TTC1_8_CLK,
+ PINCTRL_GRP_TTC1_0_WAV,
+ PINCTRL_GRP_TTC1_1_WAV,
+ PINCTRL_GRP_TTC1_2_WAV,
+ PINCTRL_GRP_TTC1_3_WAV,
+ PINCTRL_GRP_TTC1_4_WAV,
+ PINCTRL_GRP_TTC1_5_WAV,
+ PINCTRL_GRP_TTC1_6_WAV,
+ PINCTRL_GRP_TTC1_7_WAV,
+ PINCTRL_GRP_TTC1_8_WAV,
+ PINCTRL_GRP_TTC2_0_CLK,
+ PINCTRL_GRP_TTC2_1_CLK,
+ PINCTRL_GRP_TTC2_2_CLK,
+ PINCTRL_GRP_TTC2_3_CLK,
+ PINCTRL_GRP_TTC2_4_CLK,
+ PINCTRL_GRP_TTC2_5_CLK,
+ PINCTRL_GRP_TTC2_6_CLK,
+ PINCTRL_GRP_TTC2_7_CLK,
+ PINCTRL_GRP_TTC2_8_CLK,
+ PINCTRL_GRP_TTC2_0_WAV,
+ PINCTRL_GRP_TTC2_1_WAV,
+ PINCTRL_GRP_TTC2_2_WAV,
+ PINCTRL_GRP_TTC2_3_WAV,
+ PINCTRL_GRP_TTC2_4_WAV,
+ PINCTRL_GRP_TTC2_5_WAV,
+ PINCTRL_GRP_TTC2_6_WAV,
+ PINCTRL_GRP_TTC2_7_WAV,
+ PINCTRL_GRP_TTC2_8_WAV,
+ PINCTRL_GRP_TTC3_0_CLK,
+ PINCTRL_GRP_TTC3_1_CLK,
+ PINCTRL_GRP_TTC3_2_CLK,
+ PINCTRL_GRP_TTC3_3_CLK,
+ PINCTRL_GRP_TTC3_4_CLK,
+ PINCTRL_GRP_TTC3_5_CLK,
+ PINCTRL_GRP_TTC3_6_CLK,
+ PINCTRL_GRP_TTC3_7_CLK,
+ PINCTRL_GRP_TTC3_8_CLK,
+ PINCTRL_GRP_TTC3_0_WAV,
+ PINCTRL_GRP_TTC3_1_WAV,
+ PINCTRL_GRP_TTC3_2_WAV,
+ PINCTRL_GRP_TTC3_3_WAV,
+ PINCTRL_GRP_TTC3_4_WAV,
+ PINCTRL_GRP_TTC3_5_WAV,
+ PINCTRL_GRP_TTC3_6_WAV,
+ PINCTRL_GRP_TTC3_7_WAV,
+ PINCTRL_GRP_TTC3_8_WAV,
+ PINCTRL_GRP_SWDT0_0_CLK,
+ PINCTRL_GRP_SWDT0_1_CLK,
+ PINCTRL_GRP_SWDT0_2_CLK,
+ PINCTRL_GRP_SWDT0_3_CLK,
+ PINCTRL_GRP_SWDT0_4_CLK,
+ PINCTRL_GRP_SWDT0_5_CLK,
+ PINCTRL_GRP_SWDT0_6_CLK,
+ PINCTRL_GRP_SWDT0_7_CLK,
+ PINCTRL_GRP_SWDT0_8_CLK,
+ PINCTRL_GRP_SWDT0_9_CLK,
+ PINCTRL_GRP_SWDT0_10_CLK,
+ PINCTRL_GRP_SWDT0_11_CLK,
+ PINCTRL_GRP_SWDT0_12_CLK,
+ PINCTRL_GRP_SWDT0_0_RST,
+ PINCTRL_GRP_SWDT0_1_RST,
+ PINCTRL_GRP_SWDT0_2_RST,
+ PINCTRL_GRP_SWDT0_3_RST,
+ PINCTRL_GRP_SWDT0_4_RST,
+ PINCTRL_GRP_SWDT0_5_RST,
+ PINCTRL_GRP_SWDT0_6_RST,
+ PINCTRL_GRP_SWDT0_7_RST,
+ PINCTRL_GRP_SWDT0_8_RST,
+ PINCTRL_GRP_SWDT0_9_RST,
+ PINCTRL_GRP_SWDT0_10_RST,
+ PINCTRL_GRP_SWDT0_11_RST,
+ PINCTRL_GRP_SWDT0_12_RST,
+ PINCTRL_GRP_SWDT1_0_CLK,
+ PINCTRL_GRP_SWDT1_1_CLK,
+ PINCTRL_GRP_SWDT1_2_CLK,
+ PINCTRL_GRP_SWDT1_3_CLK,
+ PINCTRL_GRP_SWDT1_4_CLK,
+ PINCTRL_GRP_SWDT1_5_CLK,
+ PINCTRL_GRP_SWDT1_6_CLK,
+ PINCTRL_GRP_SWDT1_7_CLK,
+ PINCTRL_GRP_SWDT1_8_CLK,
+ PINCTRL_GRP_SWDT1_9_CLK,
+ PINCTRL_GRP_SWDT1_10_CLK,
+ PINCTRL_GRP_SWDT1_11_CLK,
+ PINCTRL_GRP_SWDT1_12_CLK,
+ PINCTRL_GRP_SWDT1_0_RST,
+ PINCTRL_GRP_SWDT1_1_RST,
+ PINCTRL_GRP_SWDT1_2_RST,
+ PINCTRL_GRP_SWDT1_3_RST,
+ PINCTRL_GRP_SWDT1_4_RST,
+ PINCTRL_GRP_SWDT1_5_RST,
+ PINCTRL_GRP_SWDT1_6_RST,
+ PINCTRL_GRP_SWDT1_7_RST,
+ PINCTRL_GRP_SWDT1_8_RST,
+ PINCTRL_GRP_SWDT1_9_RST,
+ PINCTRL_GRP_SWDT1_10_RST,
+ PINCTRL_GRP_SWDT1_11_RST,
+ PINCTRL_GRP_SWDT1_12_RST,
+ PINCTRL_GRP_GPIO0_0,
+ PINCTRL_GRP_GPIO0_1,
+ PINCTRL_GRP_GPIO0_2,
+ PINCTRL_GRP_GPIO0_3,
+ PINCTRL_GRP_GPIO0_4,
+ PINCTRL_GRP_GPIO0_5,
+ PINCTRL_GRP_GPIO0_6,
+ PINCTRL_GRP_GPIO0_7,
+ PINCTRL_GRP_GPIO0_8,
+ PINCTRL_GRP_GPIO0_9,
+ PINCTRL_GRP_GPIO0_10,
+ PINCTRL_GRP_GPIO0_11,
+ PINCTRL_GRP_GPIO0_12,
+ PINCTRL_GRP_GPIO0_13,
+ PINCTRL_GRP_GPIO0_14,
+ PINCTRL_GRP_GPIO0_15,
+ PINCTRL_GRP_GPIO0_16,
+ PINCTRL_GRP_GPIO0_17,
+ PINCTRL_GRP_GPIO0_18,
+ PINCTRL_GRP_GPIO0_19,
+ PINCTRL_GRP_GPIO0_20,
+ PINCTRL_GRP_GPIO0_21,
+ PINCTRL_GRP_GPIO0_22,
+ PINCTRL_GRP_GPIO0_23,
+ PINCTRL_GRP_GPIO0_24,
+ PINCTRL_GRP_GPIO0_25,
+ PINCTRL_GRP_GPIO0_26,
+ PINCTRL_GRP_GPIO0_27,
+ PINCTRL_GRP_GPIO0_28,
+ PINCTRL_GRP_GPIO0_29,
+ PINCTRL_GRP_GPIO0_30,
+ PINCTRL_GRP_GPIO0_31,
+ PINCTRL_GRP_GPIO0_32,
+ PINCTRL_GRP_GPIO0_33,
+ PINCTRL_GRP_GPIO0_34,
+ PINCTRL_GRP_GPIO0_35,
+ PINCTRL_GRP_GPIO0_36,
+ PINCTRL_GRP_GPIO0_37,
+ PINCTRL_GRP_GPIO0_38,
+ PINCTRL_GRP_GPIO0_39,
+ PINCTRL_GRP_GPIO0_40,
+ PINCTRL_GRP_GPIO0_41,
+ PINCTRL_GRP_GPIO0_42,
+ PINCTRL_GRP_GPIO0_43,
+ PINCTRL_GRP_GPIO0_44,
+ PINCTRL_GRP_GPIO0_45,
+ PINCTRL_GRP_GPIO0_46,
+ PINCTRL_GRP_GPIO0_47,
+ PINCTRL_GRP_GPIO0_48,
+ PINCTRL_GRP_GPIO0_49,
+ PINCTRL_GRP_GPIO0_50,
+ PINCTRL_GRP_GPIO0_51,
+ PINCTRL_GRP_GPIO0_52,
+ PINCTRL_GRP_GPIO0_53,
+ PINCTRL_GRP_GPIO0_54,
+ PINCTRL_GRP_GPIO0_55,
+ PINCTRL_GRP_GPIO0_56,
+ PINCTRL_GRP_GPIO0_57,
+ PINCTRL_GRP_GPIO0_58,
+ PINCTRL_GRP_GPIO0_59,
+ PINCTRL_GRP_GPIO0_60,
+ PINCTRL_GRP_GPIO0_61,
+ PINCTRL_GRP_GPIO0_62,
+ PINCTRL_GRP_GPIO0_63,
+ PINCTRL_GRP_GPIO0_64,
+ PINCTRL_GRP_GPIO0_65,
+ PINCTRL_GRP_GPIO0_66,
+ PINCTRL_GRP_GPIO0_67,
+ PINCTRL_GRP_GPIO0_68,
+ PINCTRL_GRP_GPIO0_69,
+ PINCTRL_GRP_GPIO0_70,
+ PINCTRL_GRP_GPIO0_71,
+ PINCTRL_GRP_GPIO0_72,
+ PINCTRL_GRP_GPIO0_73,
+ PINCTRL_GRP_GPIO0_74,
+ PINCTRL_GRP_GPIO0_75,
+ PINCTRL_GRP_GPIO0_76,
+ PINCTRL_GRP_GPIO0_77,
+ PINCTRL_GRP_USB0_0,
+ PINCTRL_GRP_USB1_0,
+ PINCTRL_GRP_PMU0_0,
+ PINCTRL_GRP_PMU0_1,
+ PINCTRL_GRP_PMU0_2,
+ PINCTRL_GRP_PMU0_3,
+ PINCTRL_GRP_PMU0_4,
+ PINCTRL_GRP_PMU0_5,
+ PINCTRL_GRP_PMU0_6,
+ PINCTRL_GRP_PMU0_7,
+ PINCTRL_GRP_PMU0_8,
+ PINCTRL_GRP_PMU0_9,
+ PINCTRL_GRP_PMU0_10,
+ PINCTRL_GRP_PMU0_11,
+ PINCTRL_GRP_PCIE0_0,
+ PINCTRL_GRP_PCIE0_1,
+ PINCTRL_GRP_PCIE0_2,
+ PINCTRL_GRP_PCIE0_3,
+ PINCTRL_GRP_PCIE0_4,
+ PINCTRL_GRP_PCIE0_5,
+ PINCTRL_GRP_PCIE0_6,
+ PINCTRL_GRP_PCIE0_7,
+ PINCTRL_GRP_CSU0_0,
+ PINCTRL_GRP_CSU0_1,
+ PINCTRL_GRP_CSU0_2,
+ PINCTRL_GRP_CSU0_3,
+ PINCTRL_GRP_CSU0_4,
+ PINCTRL_GRP_CSU0_5,
+ PINCTRL_GRP_CSU0_6,
+ PINCTRL_GRP_CSU0_7,
+ PINCTRL_GRP_CSU0_8,
+ PINCTRL_GRP_CSU0_9,
+ PINCTRL_GRP_CSU0_10,
+ PINCTRL_GRP_CSU0_11,
+ PINCTRL_GRP_DPAUX0_0,
+ PINCTRL_GRP_DPAUX0_1,
+ PINCTRL_GRP_DPAUX0_2,
+ PINCTRL_GRP_DPAUX0_3,
+ PINCTRL_GRP_PJTAG0_0,
+ PINCTRL_GRP_PJTAG0_1,
+ PINCTRL_GRP_PJTAG0_2,
+ PINCTRL_GRP_PJTAG0_3,
+ PINCTRL_GRP_PJTAG0_4,
+ PINCTRL_GRP_PJTAG0_5,
+ PINCTRL_GRP_TRACE0_0,
+ PINCTRL_GRP_TRACE0_1,
+ PINCTRL_GRP_TRACE0_2,
+ PINCTRL_GRP_TRACE0_0_CLK,
+ PINCTRL_GRP_TRACE0_1_CLK,
+ PINCTRL_GRP_TRACE0_2_CLK,
+ PINCTRL_GRP_TESTSCAN0_0,
+};
+
+// pinctrl config parameters
+enum {
+ PINCTRL_CONFIG_SLEW_RATE,
+ PINCTRL_CONFIG_BIAS_STATUS,
+ PINCTRL_CONFIG_PULL_CTRL,
+ PINCTRL_CONFIG_SCHMITT_CMOS,
+ PINCTRL_CONFIG_DRIVE_STRENGTH,
+ PINCTRL_CONFIG_VOLTAGE_STATUS,
+ PINCTRL_CONFIG_MAX,
+};
+
+// pinctrl slew rate
+#define PINCTRL_SLEW_RATE_FAST 0U
+#define PINCTRL_SLEW_RATE_SLOW 1U
+
+// pinctrl bias status
+#define PINCTRL_BIAS_DISABLE 0U
+#define PINCTRL_BIAS_ENABLE 1U
+
+// pinctrl pull control
+#define PINCTRL_BIAS_PULL_DOWN 0U
+#define PINCTRL_BIAS_PULL_UP 1U
+
+// pinctrl schmitt cmos type
+#define PINCTRL_INPUT_TYPE_CMOS 0U
+#define PINCTRL_INPUT_TYPE_SCHMITT 1U
+
+//pinctrl drive strength values
+#define PINCTRL_DRIVE_STRENGTH_2MA 0U
+#define PINCTRL_DRIVE_STRENGTH_4MA 1U
+#define PINCTRL_DRIVE_STRENGTH_8MA 2U
+#define PINCTRL_DRIVE_STRENGTH_12MA 3U
+
+void pm_api_pinctrl_get_function_name(uint32_t fid, char *name);
+enum pm_ret_status pm_api_pinctrl_get_function_groups(uint32_t fid,
+ uint32_t index,
+ uint16_t *groups);
+enum pm_ret_status pm_api_pinctrl_get_pin_groups(uint32_t pin,
+ uint32_t index,
+ uint16_t *groups);
+enum pm_ret_status pm_api_pinctrl_get_num_pins(uint32_t *npins);
+enum pm_ret_status pm_api_pinctrl_get_num_functions(uint32_t *nfuncs);
+enum pm_ret_status pm_api_pinctrl_get_num_func_groups(uint32_t fid,
+ uint32_t *ngroups);
+#endif /* PM_API_PINCTRL_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.c b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
new file mode 100644
index 0000000..a17b6c5
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.c
@@ -0,0 +1,1836 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * ZynqMP system level PM-API functions and communication with PMU via
+ * IPI interrupts
+ */
+
+#include <arch_helpers.h>
+#include <plat/common/platform.h>
+
+#include "pm_api_clock.h"
+#include "pm_api_ioctl.h"
+#include "pm_api_pinctrl.h"
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_common.h"
+#include "pm_ipi.h"
+
+#define PM_QUERY_FEATURE_BITMASK ( \
+ (1ULL << (uint64_t)PM_QID_CLOCK_GET_NAME) | \
+ (1ULL << (uint64_t)PM_QID_CLOCK_GET_TOPOLOGY) | \
+ (1ULL << (uint64_t)PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS) | \
+ (1ULL << (uint64_t)PM_QID_CLOCK_GET_PARENTS) | \
+ (1ULL << (uint64_t)PM_QID_CLOCK_GET_ATTRIBUTES) | \
+ (1ULL << (uint64_t)PM_QID_PINCTRL_GET_NUM_PINS) | \
+ (1ULL << (uint64_t)PM_QID_PINCTRL_GET_NUM_FUNCTIONS) | \
+ (1ULL << (uint64_t)PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS) | \
+ (1ULL << (uint64_t)PM_QID_PINCTRL_GET_FUNCTION_NAME) | \
+ (1ULL << (uint64_t)PM_QID_PINCTRL_GET_FUNCTION_GROUPS) | \
+ (1ULL << (uint64_t)PM_QID_PINCTRL_GET_PIN_GROUPS) | \
+ (1ULL << (uint64_t)PM_QID_CLOCK_GET_NUM_CLOCKS) | \
+ (1ULL << (uint64_t)PM_QID_CLOCK_GET_MAX_DIVISOR))
+
+/**
+ * struct eemi_api_dependency - Dependent EEMI APIs which are implemented
+ * on both the ATF and firmware
+ *
+ * @id: EEMI API id or IOCTL id to be checked
+ * @api_id: Dependent EEMI API
+ */
+typedef struct __attribute__((packed)) {
+ uint8_t id;
+ uint8_t api_id;
+} eemi_api_dependency;
+
+/* Dependent APIs for ATF to check their version from firmware */
+static const eemi_api_dependency api_dep_table[] = {
+ {
+ .id = PM_SELF_SUSPEND,
+ .api_id = PM_SELF_SUSPEND,
+ },
+ {
+ .id = PM_REQ_WAKEUP,
+ .api_id = PM_REQ_WAKEUP,
+ },
+ {
+ .id = PM_ABORT_SUSPEND,
+ .api_id = PM_ABORT_SUSPEND,
+ },
+ {
+ .id = PM_SET_WAKEUP_SOURCE,
+ .api_id = PM_SET_WAKEUP_SOURCE,
+ },
+ {
+ .id = PM_SYSTEM_SHUTDOWN,
+ .api_id = PM_SYSTEM_SHUTDOWN,
+ },
+ {
+ .id = PM_GET_API_VERSION,
+ .api_id = PM_GET_API_VERSION,
+ },
+ {
+ .id = PM_CLOCK_ENABLE,
+ .api_id = PM_PLL_SET_MODE,
+ },
+ {
+ .id = PM_CLOCK_ENABLE,
+ .api_id = PM_CLOCK_ENABLE,
+ },
+ {
+ .id = PM_CLOCK_DISABLE,
+ .api_id = PM_PLL_SET_MODE,
+ },
+ {
+ .id = PM_CLOCK_DISABLE,
+ .api_id = PM_CLOCK_DISABLE,
+ },
+ {
+ .id = PM_CLOCK_GETSTATE,
+ .api_id = PM_PLL_GET_MODE,
+ },
+ {
+ .id = PM_CLOCK_GETSTATE,
+ .api_id = PM_CLOCK_GETSTATE,
+ },
+ {
+ .id = PM_CLOCK_SETDIVIDER,
+ .api_id = PM_PLL_SET_PARAMETER,
+ },
+ {
+ .id = PM_CLOCK_SETDIVIDER,
+ .api_id = PM_CLOCK_SETDIVIDER,
+ },
+ {
+ .id = PM_CLOCK_GETDIVIDER,
+ .api_id = PM_PLL_GET_PARAMETER,
+ },
+ {
+ .id = PM_CLOCK_GETDIVIDER,
+ .api_id = PM_CLOCK_GETDIVIDER,
+ },
+ {
+ .id = PM_CLOCK_SETPARENT,
+ .api_id = PM_PLL_SET_PARAMETER,
+ },
+ {
+ .id = PM_CLOCK_SETPARENT,
+ .api_id = PM_CLOCK_SETPARENT,
+ },
+ {
+ .id = PM_CLOCK_GETPARENT,
+ .api_id = PM_PLL_GET_PARAMETER,
+ },
+ {
+ .id = PM_CLOCK_GETPARENT,
+ .api_id = PM_CLOCK_GETPARENT,
+ },
+ {
+ .id = PM_PLL_SET_PARAMETER,
+ .api_id = PM_PLL_SET_PARAMETER,
+ },
+ {
+ .id = PM_PLL_GET_PARAMETER,
+ .api_id = PM_PLL_GET_PARAMETER,
+ },
+ {
+ .id = PM_PLL_SET_MODE,
+ .api_id = PM_PLL_SET_MODE,
+ },
+ {
+ .id = PM_PLL_GET_MODE,
+ .api_id = PM_PLL_GET_MODE,
+ },
+ {
+ .id = PM_REGISTER_ACCESS,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = PM_REGISTER_ACCESS,
+ .api_id = PM_MMIO_READ,
+ },
+ {
+ .id = PM_FEATURE_CHECK,
+ .api_id = PM_FEATURE_CHECK,
+ },
+ {
+ .id = IOCTL_SET_TAPDELAY_BYPASS,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_SET_SGMII_MODE,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_SD_DLL_RESET,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_SET_SD_TAPDELAY,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_SET_SD_TAPDELAY,
+ .api_id = PM_MMIO_READ,
+ },
+ {
+ .id = IOCTL_SET_PLL_FRAC_DATA,
+ .api_id = PM_PLL_SET_PARAMETER,
+ },
+ {
+ .id = IOCTL_GET_PLL_FRAC_DATA,
+ .api_id = PM_PLL_GET_PARAMETER,
+ },
+ {
+ .id = IOCTL_WRITE_GGS,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_READ_GGS,
+ .api_id = PM_MMIO_READ,
+ },
+ {
+ .id = IOCTL_WRITE_PGGS,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_READ_PGGS,
+ .api_id = PM_MMIO_READ,
+ },
+ {
+ .id = IOCTL_ULPI_RESET,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_SET_BOOT_HEALTH_STATUS,
+ .api_id = PM_MMIO_WRITE,
+ },
+ {
+ .id = IOCTL_AFI,
+ .api_id = PM_MMIO_WRITE,
+ },
+};
+
+/* Expected firmware API version to ATF */
+static const uint8_t atf_expected_ver_id[] = {
+ [PM_SELF_SUSPEND] = FW_API_BASE_VERSION,
+ [PM_REQ_WAKEUP] = FW_API_BASE_VERSION,
+ [PM_ABORT_SUSPEND] = FW_API_BASE_VERSION,
+ [PM_SET_WAKEUP_SOURCE] = FW_API_BASE_VERSION,
+ [PM_SYSTEM_SHUTDOWN] = FW_API_BASE_VERSION,
+ [PM_GET_API_VERSION] = FW_API_BASE_VERSION,
+ [PM_PLL_SET_MODE] = FW_API_BASE_VERSION,
+ [PM_PLL_GET_MODE] = FW_API_BASE_VERSION,
+ [PM_CLOCK_ENABLE] = FW_API_BASE_VERSION,
+ [PM_CLOCK_DISABLE] = FW_API_BASE_VERSION,
+ [PM_CLOCK_GETSTATE] = FW_API_BASE_VERSION,
+ [PM_PLL_SET_PARAMETER] = FW_API_BASE_VERSION,
+ [PM_PLL_GET_PARAMETER] = FW_API_BASE_VERSION,
+ [PM_CLOCK_SETDIVIDER] = FW_API_BASE_VERSION,
+ [PM_CLOCK_GETDIVIDER] = FW_API_BASE_VERSION,
+ [PM_CLOCK_SETPARENT] = FW_API_BASE_VERSION,
+ [PM_CLOCK_GETPARENT] = FW_API_BASE_VERSION,
+ [PM_MMIO_WRITE] = FW_API_BASE_VERSION,
+ [PM_MMIO_READ] = FW_API_BASE_VERSION,
+ [PM_FEATURE_CHECK] = FW_API_VERSION_2,
+};
+
+/* default shutdown/reboot scope is system(2) */
+static uint32_t pm_shutdown_scope = PMF_SHUTDOWN_SUBTYPE_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;
+}
+
+#define EM_PACK_PAYLOAD1(pl, arg0) { \
+ pl[0] = (uint16_t)(0xE) << 16 | (uint16_t)arg0; \
+}
+
+/**
+ * pm_self_suspend() - PM call for processor to suspend itself
+ * @nid Node id of the processor or subsystem
+ * @latency Requested maximum wakeup latency (not supported)
+ * @state Requested state
+ * @address Resume address
+ *
+ * This is a blocking call, it will return only once PMU has responded.
+ * On a wakeup, resume address will be automatically set by PMU.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_self_suspend(enum pm_node_id nid,
+ uint32_t latency,
+ uint32_t state,
+ uintptr_t address)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ uint32_t cpuid = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpuid);
+
+ /*
+ * Do client specific suspend operations
+ * (e.g. set powerdown request bit)
+ */
+ pm_client_suspend(proc, state);
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD6(payload, PM_SELF_SUSPEND, proc->node_id, latency,
+ state, address, (address >> 32));
+ return pm_ipi_send_sync(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)
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_req_suspend(enum pm_node_id target,
+ enum pm_request_ack ack,
+ uint32_t latency, uint32_t state)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD5(payload, PM_REQ_SUSPEND, target, ack, latency, state);
+ if (ack == REQ_ACK_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 Node id of the processor or subsystem to wake up
+ * @ack Flag to specify whether acknowledge requested
+ * @set_address Resume address presence indicator
+ * 1 resume address specified, 0 otherwise
+ * @address Resume address
+ *
+ * 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 PMU.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_req_wakeup(enum pm_node_id target,
+ uint32_t set_address,
+ uintptr_t address,
+ enum pm_request_ack ack)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ uint64_t encoded_address;
+
+
+ /* encode set Address into 1st bit of address */
+ encoded_address = address;
+ encoded_address |= !!set_address;
+
+ /* Send request to the PMU to perform the wake of the PU */
+ PM_PACK_PAYLOAD5(payload, PM_REQ_WAKEUP, target, encoded_address,
+ encoded_address >> 32, ack);
+
+ if (ack == REQ_ACK_BLOCKING) {
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+ } else {
+ return pm_ipi_send(primary_proc, payload);
+ }
+}
+
+/**
+ * pm_force_powerdown() - PM call to request for another PU or subsystem to
+ * be powered down forcefully
+ * @target Node id of the targeted PU or subsystem
+ * @ack Flag to specify whether acknowledge is requested
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_force_powerdown(enum pm_node_id target,
+ enum pm_request_ack ack)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD3(payload, PM_FORCE_POWERDOWN, target, ack);
+
+ if (ack == REQ_ACK_BLOCKING) {
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+ } else {
+ return pm_ipi_send(primary_proc, payload);
+ }
+}
+
+/**
+ * pm_abort_suspend() - PM call to announce that a prior suspend request
+ * is to be aborted.
+ * @reason Reason for the abort
+ *
+ * Calling PU expects the PMU to abort the initiated suspend procedure.
+ * This is a non-blocking call without any acknowledge.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /*
+ * Do client specific abort suspend operations
+ * (e.g. enable interrupts and clear powerdown request bit)
+ */
+ pm_client_abort_suspend();
+ /* Send request to the PMU */
+ /* TODO: allow passing the node ID of the affected CPU */
+ PM_PACK_PAYLOAD3(payload, PM_ABORT_SUSPEND, reason,
+ primary_proc->node_id);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_set_wakeup_source() - PM call to specify the wakeup source while suspended
+ * @target Node id of the targeted PU or subsystem
+ * @wkup_node Node id of the wakeup peripheral
+ * @enable Enable or disable the specified peripheral as wake source
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target,
+ enum pm_node_id wkup_node,
+ uint32_t enable)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ PM_PACK_PAYLOAD4(payload, PM_SET_WAKEUP_SOURCE, target, wkup_node,
+ enable);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_system_shutdown() - PM call to request a system shutdown or restart
+ * @type Shutdown or restart? 0=shutdown, 1=restart, 2=setscope
+ * @subtype Scope: 0=APU-subsystem, 1=PS, 2=system
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ if (type == PMF_SHUTDOWN_TYPE_SETSCOPE_ONLY) {
+ /* Setting scope for subsequent PSCI reboot or shutdown */
+ pm_shutdown_scope = subtype;
+ return PM_RET_SUCCESS;
+ }
+
+ PM_PACK_PAYLOAD3(payload, PM_SYSTEM_SHUTDOWN, type, subtype);
+ return pm_ipi_send_non_blocking(primary_proc, payload);
+}
+
+/* APIs for managing PM slaves: */
+
+/**
+ * pm_req_node() - PM call to request a node with specific capabilities
+ * @nid Node id of the slave
+ * @capabilities Requested capabilities of the slave
+ * @qos Quality of service (not supported)
+ * @ack Flag to specify whether acknowledge is requested
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_req_node(enum pm_node_id nid,
+ uint32_t capabilities,
+ uint32_t qos,
+ enum pm_request_ack ack)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ PM_PACK_PAYLOAD5(payload, PM_REQ_NODE, nid, capabilities, qos, ack);
+
+ if (ack == REQ_ACK_BLOCKING) {
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+ } else {
+ return pm_ipi_send(primary_proc, payload);
+ }
+}
+
+/**
+ * pm_set_requirement() - PM call to set requirement for PM slaves
+ * @nid Node id of the slave
+ * @capabilities Requested capabilities of the slave
+ * @qos Quality of service (not supported)
+ * @ack Flag to specify whether acknowledge is requested
+ *
+ * This API function is to be used for slaves a PU already has requested
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_set_requirement(enum pm_node_id nid,
+ uint32_t capabilities,
+ uint32_t qos,
+ enum pm_request_ack ack)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ PM_PACK_PAYLOAD5(payload, PM_SET_REQUIREMENT, nid, capabilities, qos,
+ ack);
+
+ if (ack == REQ_ACK_BLOCKING) {
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+ } else {
+ return pm_ipi_send(primary_proc, payload);
+ }
+}
+
+/* Miscellaneous API functions */
+
+/**
+ * pm_get_api_version() - Get version number of PMU PM firmware
+ * @version Returns 32-bit version number of PMU Power Management Firmware
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_get_api_version(uint32_t *version)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD1(payload, PM_GET_API_VERSION);
+ return pm_ipi_send_sync(primary_proc, payload, version, 1);
+}
+
+/**
+ * pm_get_node_status() - PM call to request a node's current status
+ * @nid Node id
+ * @ret_buff Buffer for the return values:
+ * [0] - Current power state of the node
+ * [1] - Current requirements for the node (slave nodes only)
+ * [2] - Current usage status for the node (slave nodes only)
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_get_node_status(enum pm_node_id nid,
+ uint32_t *ret_buff)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ PM_PACK_PAYLOAD2(payload, PM_GET_NODE_STATUS, nid);
+ return pm_ipi_send_sync(primary_proc, payload, ret_buff, 3);
+}
+
+/**
+ * pm_mmio_write() - Perform write to protected mmio
+ * @address Address to write to
+ * @mask Mask to apply
+ * @value Value to write
+ *
+ * This function provides access to PM-related control registers
+ * that may not be directly accessible by a particular PU.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_mmio_write(uintptr_t address,
+ uint32_t mask,
+ uint32_t value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD4(payload, PM_MMIO_WRITE, address, mask, value);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_mmio_read() - Read value from protected mmio
+ * @address Address to write to
+ * @value Value to write
+ *
+ * This function provides access to PM-related control registers
+ * that may not be directly accessible by a particular PU.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_mmio_read(uintptr_t address, uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD2(payload, PM_MMIO_READ, address);
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+/**
+ * pm_fpga_load() - Load the bitstream into the PL.
+ *
+ * This function provides access to the xilfpga library to load
+ * the Bit-stream into PL.
+ *
+ * address_low: lower 32-bit Linear memory space address
+ *
+ * address_high: higher 32-bit Linear memory space address
+ *
+ * size: Number of 32bit words
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_fpga_load(uint32_t address_low,
+ uint32_t address_high,
+ uint32_t size,
+ uint32_t flags)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD5(payload, PM_FPGA_LOAD, address_high, address_low,
+ size, flags);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_fpga_get_status() - Read value from fpga status register
+ * @value Value to read
+ *
+ * This function provides access to the xilfpga library to get
+ * the fpga status
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_fpga_get_status(uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD1(payload, PM_FPGA_GET_STATUS);
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+/**
+ * pm_get_chipid() - Read silicon ID registers
+ * @value Buffer for return values. Must be large enough
+ * to hold 8 bytes.
+ *
+ * @return Returns silicon ID registers
+ */
+enum pm_ret_status pm_get_chipid(uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD1(payload, PM_GET_CHIPID);
+ return pm_ipi_send_sync(primary_proc, payload, value, 2);
+}
+
+/**
+ * pm_secure_rsaaes() - Load the secure images.
+ *
+ * This function provides access to the xilsecure library to load
+ * the authenticated, encrypted, and authenicated/encrypted images.
+ *
+ * address_low: lower 32-bit Linear memory space address
+ *
+ * address_high: higher 32-bit Linear memory space address
+ *
+ * size: Number of 32bit words
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_secure_rsaaes(uint32_t address_low,
+ uint32_t address_high,
+ uint32_t size,
+ uint32_t flags)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD5(payload, PM_SECURE_RSA_AES, address_high, address_low,
+ size, flags);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_aes_engine() - Aes data blob encryption/decryption
+ * This function provides access to the xilsecure library to
+ * encrypt/decrypt data blobs.
+ *
+ * address_low: lower 32-bit address of the AesParams structure
+ *
+ * address_high: higher 32-bit address of the AesParams structure
+ *
+ * value: Returned output value
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_aes_engine(uint32_t address_high,
+ uint32_t address_low,
+ uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD3(payload, PM_SECURE_AES, address_high, address_low);
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+/**
+ * pm_get_callbackdata() - Read from IPI response buffer
+ * @data - array of PAYLOAD_ARG_CNT elements
+ *
+ * Read value from ipi buffer response buffer.
+ */
+void pm_get_callbackdata(uint32_t *data, size_t count)
+{
+ /* Return if interrupt is not from PMU */
+ if (!pm_ipi_irq_status(primary_proc)) {
+ return;
+ }
+
+ pm_ipi_buff_read_callb(data, count);
+ pm_ipi_irq_clear(primary_proc);
+}
+
+/**
+ * pm_ioctl() - PM IOCTL API for device control and configs
+ * @node_id Node ID of the device
+ * @ioctl_id ID of the requested IOCTL
+ * @arg1 Argument 1 to requested IOCTL call
+ * @arg2 Argument 2 to requested IOCTL call
+ * @out Returned output value
+ *
+ * This function calls IOCTL to firmware for device control and configuration.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_ioctl(enum pm_node_id nid,
+ uint32_t ioctl_id,
+ uint32_t arg1,
+ uint32_t arg2,
+ uint32_t *value)
+{
+ return pm_api_ioctl(nid, ioctl_id, arg1, arg2, value);
+}
+
+/**
+ * fw_api_version() - Returns API version implemented in firmware
+ * @api_id API ID to check
+ * @version Returned supported API version
+ * @len Number of words to be returned
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status fw_api_version(uint32_t id, uint32_t *version,
+ uint32_t len)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ PM_PACK_PAYLOAD2(payload, PM_FEATURE_CHECK, id);
+ return pm_ipi_send_sync(primary_proc, payload, version, len);
+}
+
+/**
+ * check_api_dependency() - API to check dependent EEMI API version
+ * @id EEMI API ID to check
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status check_api_dependency(uint8_t id)
+{
+ uint8_t i;
+ uint32_t version;
+ int ret;
+
+ for (i = 0U; i < ARRAY_SIZE(api_dep_table); i++) {
+ if (api_dep_table[i].id == id) {
+ if (api_dep_table[i].api_id == 0U) {
+ break;
+ }
+
+ ret = fw_api_version(api_dep_table[i].api_id,
+ &version, 1);
+ if (ret != PM_RET_SUCCESS) {
+ return ret;
+ }
+
+ /* Check if fw version matches ATF expected version */
+ if (version != atf_expected_ver_id[api_dep_table[i].api_id]) {
+ return PM_RET_ERROR_NOTSUPPORTED;
+ }
+ }
+ }
+
+ return PM_RET_SUCCESS;
+}
+
+/**
+ * feature_check_atf() - These are API's completely implemented in ATF
+ * @api_id API ID to check
+ * @version Returned supported API version
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status feature_check_atf(uint32_t api_id, uint32_t *version,
+ uint32_t *bit_mask)
+{
+ switch (api_id) {
+ case PM_QUERY_DATA:
+ *version = ATF_API_BASE_VERSION;
+ bit_mask[0] = (uint32_t)(PM_QUERY_FEATURE_BITMASK);
+ bit_mask[1] = (uint32_t)(PM_QUERY_FEATURE_BITMASK >> 32);
+ return PM_RET_SUCCESS;
+ case PM_GET_CALLBACK_DATA:
+ case PM_GET_TRUSTZONE_VERSION:
+ case PM_SET_SUSPEND_MODE:
+ *version = ATF_API_BASE_VERSION;
+ return PM_RET_SUCCESS;
+ default:
+ return PM_RET_ERROR_NO_FEATURE;
+ }
+}
+
+/**
+ * get_atf_version_for_partial_apis() - Return ATF version for partially
+ * implemented APIs
+ * @api_id API ID to check
+ * @version Returned supported API version
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status get_atf_version_for_partial_apis(uint32_t api_id,
+ uint32_t *version)
+{
+ switch (api_id) {
+ case PM_SELF_SUSPEND:
+ case PM_REQ_WAKEUP:
+ case PM_ABORT_SUSPEND:
+ case PM_SET_WAKEUP_SOURCE:
+ case PM_SYSTEM_SHUTDOWN:
+ case PM_GET_API_VERSION:
+ case PM_CLOCK_ENABLE:
+ case PM_CLOCK_DISABLE:
+ case PM_CLOCK_GETSTATE:
+ case PM_CLOCK_SETDIVIDER:
+ case PM_CLOCK_GETDIVIDER:
+ case PM_CLOCK_SETPARENT:
+ case PM_CLOCK_GETPARENT:
+ case PM_PLL_SET_PARAMETER:
+ case PM_PLL_GET_PARAMETER:
+ case PM_PLL_SET_MODE:
+ case PM_PLL_GET_MODE:
+ case PM_REGISTER_ACCESS:
+ *version = ATF_API_BASE_VERSION;
+ return PM_RET_SUCCESS;
+ case PM_FEATURE_CHECK:
+ *version = FW_API_VERSION_2;
+ return PM_RET_SUCCESS;
+ default:
+ return PM_RET_ERROR_ARGS;
+ }
+}
+
+/**
+ * feature_check_partial() - These are API's partially implemented in
+ * ATF and firmware both
+ * @api_id API ID to check
+ * @version Returned supported API version
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status feature_check_partial(uint32_t api_id,
+ uint32_t *version)
+{
+ uint32_t status;
+
+ switch (api_id) {
+ case PM_SELF_SUSPEND:
+ case PM_REQ_WAKEUP:
+ case PM_ABORT_SUSPEND:
+ case PM_SET_WAKEUP_SOURCE:
+ case PM_SYSTEM_SHUTDOWN:
+ case PM_GET_API_VERSION:
+ case PM_CLOCK_ENABLE:
+ case PM_CLOCK_DISABLE:
+ case PM_CLOCK_GETSTATE:
+ case PM_CLOCK_SETDIVIDER:
+ case PM_CLOCK_GETDIVIDER:
+ case PM_CLOCK_SETPARENT:
+ case PM_CLOCK_GETPARENT:
+ case PM_PLL_SET_PARAMETER:
+ case PM_PLL_GET_PARAMETER:
+ case PM_PLL_SET_MODE:
+ case PM_PLL_GET_MODE:
+ case PM_REGISTER_ACCESS:
+ case PM_FEATURE_CHECK:
+ status = check_api_dependency(api_id);
+ if (status != PM_RET_SUCCESS) {
+ return status;
+ }
+ return get_atf_version_for_partial_apis(api_id, version);
+ default:
+ return PM_RET_ERROR_NO_FEATURE;
+ }
+}
+
+/**
+ * pm_feature_check() - Returns the supported API version if supported
+ * @api_id API ID to check
+ * @version Returned supported API version
+ * @bit_mask Returned supported IOCTL id version
+ * @len Number of bytes to be returned in bit_mask variable
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *version,
+ uint32_t *bit_mask, uint8_t len)
+{
+ uint32_t ret_payload[PAYLOAD_ARG_CNT] = {0U};
+ uint32_t status;
+
+ /* Get API version implemented in ATF */
+ status = feature_check_atf(api_id, version, bit_mask);
+ if (status != PM_RET_ERROR_NO_FEATURE) {
+ return status;
+ }
+
+ /* Get API version implemented by firmware and ATF both */
+ status = feature_check_partial(api_id, version);
+ if (status != PM_RET_ERROR_NO_FEATURE) {
+ return status;
+ }
+
+ /* Get API version implemented by firmware */
+ status = fw_api_version(api_id, ret_payload, 3);
+ /* IOCTL call may return failure whose ID is not implemented in
+ * firmware but implemented in ATF
+ */
+ if ((api_id != PM_IOCTL) && (status != PM_RET_SUCCESS)) {
+ return status;
+ }
+
+ *version = ret_payload[0];
+
+ /* Update IOCTL bit mask which are implemented in ATF */
+ if (api_id == PM_IOCTL) {
+ if (len < 2) {
+ return PM_RET_ERROR_ARGS;
+ }
+ bit_mask[0] = ret_payload[1];
+ bit_mask[1] = ret_payload[2];
+ /* Get IOCTL's implemented by ATF */
+ status = atf_ioctl_bitmask(bit_mask);
+ } else {
+ /* Requires for MISRA */
+ }
+
+ return status;
+}
+
+/**
+ * pm_clock_get_max_divisor - PM call to get max divisor
+ * @clock_id Clock ID
+ * @div_type Divisor ID (TYPE_DIV1 or TYPE_DIV2)
+ * @max_div Maximum supported divisor
+ *
+ * This function is used by master to get maximum supported value.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+static enum pm_ret_status pm_clock_get_max_divisor(uint32_t clock_id,
+ uint8_t div_type,
+ uint32_t *max_div)
+{
+ return pm_api_clock_get_max_divisor(clock_id, div_type, max_div);
+}
+
+/**
+ * pm_clock_get_num_clocks - PM call to request number of clocks
+ * @nclockss: Number of clocks
+ *
+ * This function is used by master to get number of clocks.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+static enum pm_ret_status pm_clock_get_num_clocks(uint32_t *nclocks)
+{
+ return pm_api_clock_get_num_clocks(nclocks);
+}
+
+/**
+ * pm_clock_get_name() - PM call to request a clock's name
+ * @clock_id Clock ID
+ * @name Name of clock (max 16 bytes)
+ *
+ * This function is used by master to get nmae of clock specified
+ * by given clock ID.
+ */
+static void pm_clock_get_name(uint32_t clock_id, char *name)
+{
+ pm_api_clock_get_name(clock_id, name);
+}
+
+/**
+ * pm_clock_get_topology() - PM call to request a clock's topology
+ * @clock_id Clock ID
+ * @index Topology index for next toplogy node
+ * @topology Buffer to store nodes in topology and flags
+ *
+ * This function is used by master to get topology information for the
+ * clock specified by given clock ID. Each response would return 3
+ * topology nodes. To get next nodes, caller needs to call this API with
+ * index of next node. Index starts from 0.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_clock_get_topology(uint32_t clock_id,
+ uint32_t index,
+ uint32_t *topology)
+{
+ return pm_api_clock_get_topology(clock_id, index, topology);
+}
+
+/**
+ * pm_clock_get_fixedfactor_params() - PM call to request a clock's fixed factor
+ * parameters for fixed clock
+ * @clock_id Clock ID
+ * @mul Multiplication value
+ * @div Divisor value
+ *
+ * This function is used by master to get fixed factor parameers for the
+ * fixed clock. This API is application only for the fixed clock.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_clock_get_fixedfactor_params(uint32_t clock_id,
+ uint32_t *mul,
+ uint32_t *div)
+{
+ return pm_api_clock_get_fixedfactor_params(clock_id, mul, div);
+}
+
+/**
+ * pm_clock_get_parents() - PM call to request a clock's first 3 parents
+ * @clock_id Clock ID
+ * @index Index of next parent
+ * @parents Parents of the given clock
+ *
+ * This function is used by master to get clock's parents information.
+ * This API will return 3 parents with a single response. To get other
+ * parents, master should call same API in loop with new parent index
+ * till error is returned.
+ *
+ * E.g First call should have index 0 which will return parents 0, 1 and
+ * 2. Next call, index should be 3 which will return parent 3,4 and 5 and
+ * so on.
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_clock_get_parents(uint32_t clock_id,
+ uint32_t index,
+ uint32_t *parents)
+{
+ return pm_api_clock_get_parents(clock_id, index, parents);
+}
+
+/**
+ * pm_clock_get_attributes() - PM call to request a clock's attributes
+ * @clock_id Clock ID
+ * @attr Clock attributes
+ *
+ * This function is used by master to get clock's attributes
+ * (e.g. valid, clock type, etc).
+ *
+ * @return Returns status, either success or error+reason
+ */
+static enum pm_ret_status pm_clock_get_attributes(uint32_t clock_id,
+ uint32_t *attr)
+{
+ return pm_api_clock_get_attributes(clock_id, attr);
+}
+
+/**
+ * pm_clock_gate() - Configure clock gate
+ * @clock_id Id of the clock to be configured
+ * @enable Flag 0=disable (gate the clock), !0=enable (activate the clock)
+ *
+ * @return Error if an argument is not valid or status as returned by the
+ * PM controller (PMU)
+ */
+static enum pm_ret_status pm_clock_gate(uint32_t clock_id,
+ uint8_t enable)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ enum pm_ret_status status;
+ enum pm_api_id api_id;
+
+ /* Check if clock ID is valid and return an error if it is not */
+ status = pm_clock_id_is_valid(clock_id);
+ if (status != PM_RET_SUCCESS) {
+ return status;
+ }
+
+ if (enable) {
+ api_id = PM_CLOCK_ENABLE;
+ } else {
+ api_id = PM_CLOCK_DISABLE;
+ }
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD2(payload, api_id, clock_id);
+ status = pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+
+ /* If action fails due to the lack of permissions filter the error */
+ if (status == PM_RET_ERROR_ACCESS) {
+ status = PM_RET_SUCCESS;
+ }
+
+ return status;
+}
+
+/**
+ * pm_clock_enable() - Enable the clock for given id
+ * @clock_id: Id of the clock to be enabled
+ *
+ * This function is used by master to enable the clock
+ * including peripherals and PLL clocks.
+ *
+ * @return: Error if an argument is not valid or status as returned by the
+ * pm_clock_gate
+ */
+enum pm_ret_status pm_clock_enable(uint32_t clock_id)
+{
+ struct pm_pll *pll;
+
+ /* First try to handle it as a PLL */
+ pll = pm_clock_get_pll(clock_id);
+ if (pll) {
+ return pm_clock_pll_enable(pll);
+ }
+
+ /* It's an on-chip clock, PMU should configure clock's gate */
+ return pm_clock_gate(clock_id, 1);
+}
+
+/**
+ * pm_clock_disable - Disable the clock for given id
+ * @clock_id: Id of the clock to be disable
+ *
+ * This function is used by master to disable the clock
+ * including peripherals and PLL clocks.
+ *
+ * @return: Error if an argument is not valid or status as returned by the
+ * pm_clock_gate
+ */
+enum pm_ret_status pm_clock_disable(uint32_t clock_id)
+{
+ struct pm_pll *pll;
+
+ /* First try to handle it as a PLL */
+ pll = pm_clock_get_pll(clock_id);
+ if (pll) {
+ return pm_clock_pll_disable(pll);
+ }
+
+ /* It's an on-chip clock, PMU should configure clock's gate */
+ return pm_clock_gate(clock_id, 0);
+}
+
+/**
+ * pm_clock_getstate - Get the clock state for given id
+ * @clock_id: Id of the clock to be queried
+ * @state: 1/0 (Enabled/Disabled)
+ *
+ * This function is used by master to get the state of clock
+ * including peripherals and PLL clocks.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_getstate(uint32_t clock_id,
+ uint32_t *state)
+{
+ struct pm_pll *pll;
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ enum pm_ret_status status;
+
+ /* First try to handle it as a PLL */
+ pll = pm_clock_get_pll(clock_id);
+ if (pll)
+ return pm_clock_pll_get_state(pll, state);
+
+ /* Check if clock ID is a valid on-chip clock */
+ status = pm_clock_id_is_valid(clock_id);
+ if (status != PM_RET_SUCCESS) {
+ return status;
+ }
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD2(payload, PM_CLOCK_GETSTATE, clock_id);
+ return pm_ipi_send_sync(primary_proc, payload, state, 1);
+}
+
+/**
+ * pm_clock_setdivider - Set the clock divider for given id
+ * @clock_id: Id of the clock
+ * @divider: divider value
+ *
+ * This function is used by master to set divider for any clock
+ * to achieve desired rate.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_setdivider(uint32_t clock_id,
+ uint32_t divider)
+{
+ enum pm_ret_status status;
+ enum pm_node_id nid;
+ enum pm_clock_div_id div_id;
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ const uint32_t div0 = 0xFFFF0000;
+ const uint32_t div1 = 0x0000FFFF;
+ uint32_t val;
+
+ /* Get PLL node ID using PLL clock ID */
+ status = pm_clock_get_pll_node_id(clock_id, &nid);
+ if (status == PM_RET_SUCCESS) {
+ return pm_pll_set_parameter(nid, PM_PLL_PARAM_FBDIV, divider);
+ }
+
+ /* Check if clock ID is a valid on-chip clock */
+ status = pm_clock_id_is_valid(clock_id);
+ if (status != PM_RET_SUCCESS) {
+ return status;
+ }
+
+ if (div0 == (divider & div0)) {
+ div_id = PM_CLOCK_DIV0_ID;
+ val = divider & ~div0;
+ } else if (div1 == (divider & div1)) {
+ div_id = PM_CLOCK_DIV1_ID;
+ val = (divider & ~div1) >> 16;
+ } else {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD4(payload, PM_CLOCK_SETDIVIDER, clock_id, div_id, val);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_clock_getdivider - Get the clock divider for given id
+ * @clock_id: Id of the clock
+ * @divider: divider value
+ *
+ * This function is used by master to get divider values
+ * for any clock.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_getdivider(uint32_t clock_id,
+ uint32_t *divider)
+{
+ enum pm_ret_status status;
+ enum pm_node_id nid;
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ uint32_t val;
+
+ /* Get PLL node ID using PLL clock ID */
+ status = pm_clock_get_pll_node_id(clock_id, &nid);
+ if (status == PM_RET_SUCCESS) {
+ return pm_pll_get_parameter(nid, PM_PLL_PARAM_FBDIV, divider);
+ }
+
+ /* Check if clock ID is a valid on-chip clock */
+ status = pm_clock_id_is_valid(clock_id);
+ if (status != PM_RET_SUCCESS) {
+ return status;
+ }
+
+ if (pm_clock_has_div(clock_id, PM_CLOCK_DIV0_ID)) {
+ /* Send request to the PMU to get div0 */
+ PM_PACK_PAYLOAD3(payload, PM_CLOCK_GETDIVIDER, clock_id,
+ PM_CLOCK_DIV0_ID);
+ status = pm_ipi_send_sync(primary_proc, payload, &val, 1);
+ if (status != PM_RET_SUCCESS) {
+ return status;
+ }
+ *divider = val;
+ }
+
+ if (pm_clock_has_div(clock_id, PM_CLOCK_DIV1_ID)) {
+ /* Send request to the PMU to get div1 */
+ PM_PACK_PAYLOAD3(payload, PM_CLOCK_GETDIVIDER, clock_id,
+ PM_CLOCK_DIV1_ID);
+ status = pm_ipi_send_sync(primary_proc, payload, &val, 1);
+ if (status != PM_RET_SUCCESS) {
+ return status;
+ }
+ *divider |= val << 16;
+ }
+
+ return status;
+}
+
+/**
+ * pm_clock_setrate - Set the clock rate for given id
+ * @clock_id: Id of the clock
+ * @rate: rate value in hz
+ *
+ * This function is used by master to set rate for any clock.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_setrate(uint32_t clock_id,
+ uint64_t rate)
+{
+ return PM_RET_ERROR_NOTSUPPORTED;
+}
+
+/**
+ * pm_clock_getrate - Get the clock rate for given id
+ * @clock_id: Id of the clock
+ * @rate: rate value in hz
+ *
+ * This function is used by master to get rate
+ * for any clock.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_getrate(uint32_t clock_id,
+ uint64_t *rate)
+{
+ return PM_RET_ERROR_NOTSUPPORTED;
+}
+
+/**
+ * pm_clock_setparent - Set the clock parent for given id
+ * @clock_id: Id of the clock
+ * @parent_index: Index of the parent clock into clock's parents array
+ *
+ * This function is used by master to set parent for any clock.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_setparent(uint32_t clock_id,
+ uint32_t parent_index)
+{
+ struct pm_pll *pll;
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ enum pm_ret_status status;
+
+ /* First try to handle it as a PLL */
+ pll = pm_clock_get_pll_by_related_clk(clock_id);
+ if (pll) {
+ return pm_clock_pll_set_parent(pll, clock_id, parent_index);
+ }
+
+ /* Check if clock ID is a valid on-chip clock */
+ status = pm_clock_id_is_valid(clock_id);
+ if (status != PM_RET_SUCCESS) {
+ return status;
+ }
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD3(payload, PM_CLOCK_SETPARENT, clock_id, parent_index);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_clock_getparent - Get the clock parent for given id
+ * @clock_id: Id of the clock
+ * @parent_index: parent index
+ *
+ * This function is used by master to get parent index
+ * for any clock.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_clock_getparent(uint32_t clock_id,
+ uint32_t *parent_index)
+{
+ struct pm_pll *pll;
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ enum pm_ret_status status;
+
+ /* First try to handle it as a PLL */
+ pll = pm_clock_get_pll_by_related_clk(clock_id);
+ if (pll) {
+ return pm_clock_pll_get_parent(pll, clock_id, parent_index);
+ }
+
+ /* Check if clock ID is a valid on-chip clock */
+ status = pm_clock_id_is_valid(clock_id);
+ if (status != PM_RET_SUCCESS) {
+ return status;
+ }
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD2(payload, PM_CLOCK_GETPARENT, clock_id);
+ return pm_ipi_send_sync(primary_proc, payload, parent_index, 1);
+}
+
+/**
+ * pm_pinctrl_get_num_pins - PM call to request number of pins
+ * @npins: Number of pins
+ *
+ * This function is used by master to get number of pins
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+static enum pm_ret_status pm_pinctrl_get_num_pins(uint32_t *npins)
+{
+ return pm_api_pinctrl_get_num_pins(npins);
+}
+
+/**
+ * pm_pinctrl_get_num_functions - PM call to request number of functions
+ * @nfuncs: Number of functions
+ *
+ * This function is used by master to get number of functions
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+static enum pm_ret_status pm_pinctrl_get_num_functions(uint32_t *nfuncs)
+{
+ return pm_api_pinctrl_get_num_functions(nfuncs);
+}
+
+/**
+ * pm_pinctrl_get_num_function_groups - PM call to request number of
+ * function groups
+ * @fid: Id of function
+ * @ngroups: Number of function groups
+ *
+ * This function is used by master to get number of function groups specified
+ * by given function Id
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+static enum pm_ret_status pm_pinctrl_get_num_function_groups(uint32_t fid,
+ uint32_t *ngroups)
+{
+ return pm_api_pinctrl_get_num_func_groups(fid, ngroups);
+}
+
+/**
+ * pm_pinctrl_get_function_name - PM call to request function name
+ * @fid: Id of function
+ * @name: Name of function
+ *
+ * This function is used by master to get name of function specified
+ * by given function Id
+ */
+static void pm_pinctrl_get_function_name(uint32_t fid, char *name)
+{
+ pm_api_pinctrl_get_function_name(fid, name);
+}
+
+/**
+ * pm_pinctrl_get_function_groups - PM call to request function groups
+ * @fid: Id of function
+ * @index: Index of next function groups
+ * @groups: Function groups
+ *
+ * This function is used by master to get function groups specified
+ * by given function Id. This API will return 6 function groups with
+ * a single response. To get other function groups, master should call
+ * same API in loop with new function groups index till error is returned.
+ *
+ * E.g First call should have index 0 which will return function groups
+ * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return
+ * function groups 6, 7, 8, 9, 10 and 11 and so on.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+static enum pm_ret_status pm_pinctrl_get_function_groups(uint32_t fid,
+ uint32_t index,
+ uint16_t *groups)
+{
+ return pm_api_pinctrl_get_function_groups(fid, index, groups);
+}
+
+/**
+ * pm_pinctrl_get_pin_groups - PM call to request pin groups
+ * @pin_id: Id of pin
+ * @index: Index of next pin groups
+ * @groups: pin groups
+ *
+ * This function is used by master to get pin groups specified
+ * by given pin Id. This API will return 6 pin groups with
+ * a single response. To get other pin groups, master should call
+ * same API in loop with new pin groups index till error is returned.
+ *
+ * E.g First call should have index 0 which will return pin groups
+ * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return
+ * pin groups 6, 7, 8, 9, 10 and 11 and so on.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+static enum pm_ret_status pm_pinctrl_get_pin_groups(uint32_t pin_id,
+ uint32_t index,
+ uint16_t *groups)
+{
+ return pm_api_pinctrl_get_pin_groups(pin_id, index, groups);
+}
+
+/**
+ * pm_query_data() - PM API for querying firmware data
+ * @arg1 Argument 1 to requested IOCTL call
+ * @arg2 Argument 2 to requested IOCTL call
+ * @arg3 Argument 3 to requested IOCTL call
+ * @arg4 Argument 4 to requested IOCTL call
+ * @data Returned output data
+ *
+ * This function returns requested data.
+ */
+void pm_query_data(enum pm_query_id qid, uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t *data)
+{
+ switch (qid) {
+ case PM_QID_CLOCK_GET_NAME:
+ pm_clock_get_name(arg1, (char *)data);
+ break;
+ case PM_QID_CLOCK_GET_TOPOLOGY:
+ data[0] = pm_clock_get_topology(arg1, arg2, &data[1]);
+ break;
+ case PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS:
+ data[0] = pm_clock_get_fixedfactor_params(arg1, &data[1],
+ &data[2]);
+ break;
+ case PM_QID_CLOCK_GET_PARENTS:
+ data[0] = pm_clock_get_parents(arg1, arg2, &data[1]);
+ break;
+ case PM_QID_CLOCK_GET_ATTRIBUTES:
+ data[0] = pm_clock_get_attributes(arg1, &data[1]);
+ break;
+ case PM_QID_PINCTRL_GET_NUM_PINS:
+ data[0] = pm_pinctrl_get_num_pins(&data[1]);
+ break;
+ case PM_QID_PINCTRL_GET_NUM_FUNCTIONS:
+ data[0] = pm_pinctrl_get_num_functions(&data[1]);
+ break;
+ case PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS:
+ data[0] = pm_pinctrl_get_num_function_groups(arg1, &data[1]);
+ break;
+ case PM_QID_PINCTRL_GET_FUNCTION_NAME:
+ pm_pinctrl_get_function_name(arg1, (char *)data);
+ break;
+ case PM_QID_PINCTRL_GET_FUNCTION_GROUPS:
+ data[0] = pm_pinctrl_get_function_groups(arg1, arg2,
+ (uint16_t *)&data[1]);
+ break;
+ case PM_QID_PINCTRL_GET_PIN_GROUPS:
+ data[0] = pm_pinctrl_get_pin_groups(arg1, arg2,
+ (uint16_t *)&data[1]);
+ break;
+ case PM_QID_CLOCK_GET_NUM_CLOCKS:
+ data[0] = pm_clock_get_num_clocks(&data[1]);
+ break;
+
+ case PM_QID_CLOCK_GET_MAX_DIVISOR:
+ data[0] = pm_clock_get_max_divisor(arg1, arg2, &data[1]);
+ break;
+ default:
+ data[0] = PM_RET_ERROR_ARGS;
+ WARN("Unimplemented query service call: 0x%x\n", qid);
+ break;
+ }
+}
+
+enum pm_ret_status pm_sha_hash(uint32_t address_high,
+ uint32_t address_low,
+ uint32_t size,
+ uint32_t flags)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD5(payload, PM_SECURE_SHA, address_high, address_low,
+ size, flags);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+enum pm_ret_status pm_rsa_core(uint32_t address_high,
+ uint32_t address_low,
+ uint32_t size,
+ uint32_t flags)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD5(payload, PM_SECURE_RSA, address_high, address_low,
+ size, flags);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+enum pm_ret_status pm_secure_image(uint32_t address_low,
+ uint32_t address_high,
+ uint32_t key_lo,
+ uint32_t key_hi,
+ uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD5(payload, PM_SECURE_IMAGE, address_high, address_low,
+ key_hi, key_lo);
+ return pm_ipi_send_sync(primary_proc, payload, value, 2);
+}
+
+/**
+ * pm_fpga_read - Perform the fpga configuration readback
+ *
+ * @reg_numframes: Configuration register offset (or) Number of frames to read
+ * @address_low: lower 32-bit Linear memory space address
+ * @address_high: higher 32-bit Linear memory space address
+ * @readback_type: Type of fpga readback operation
+ * 0 -- Configuration Register readback
+ * 1 -- Configuration Data readback
+ * @value: Value to read
+ *
+ * This function provides access to the xilfpga library to read
+ * the PL configuration.
+ *
+ * Return: Returns status, either success or error+reason.
+ */
+enum pm_ret_status pm_fpga_read(uint32_t reg_numframes,
+ uint32_t address_low,
+ uint32_t address_high,
+ uint32_t readback_type,
+ uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD5(payload, PM_FPGA_READ, reg_numframes, address_low,
+ address_high, readback_type);
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+/*
+ * pm_pll_set_parameter() - Set the PLL parameter value
+ * @nid Node id of the target PLL
+ * @param_id ID of the PLL parameter
+ * @value Parameter value to be set
+ *
+ * Setting the parameter will have physical effect once the PLL mode is set to
+ * integer or fractional.
+ *
+ * @return Error if an argument is not valid or status as returned by the
+ * PM controller (PMU)
+ */
+enum pm_ret_status pm_pll_set_parameter(enum pm_node_id nid,
+ enum pm_pll_param param_id,
+ uint32_t value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Check if given node ID is a PLL node */
+ if (nid < NODE_APLL || nid > NODE_IOPLL) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ /* Check if parameter ID is valid and return an error if it's not */
+ if (param_id >= PM_PLL_PARAM_MAX) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD4(payload, PM_PLL_SET_PARAMETER, nid, param_id, value);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pll_get_parameter() - Get the PLL parameter value
+ * @nid Node id of the target PLL
+ * @param_id ID of the PLL parameter
+ * @value Location to store the parameter value
+ *
+ * @return Error if an argument is not valid or status as returned by the
+ * PM controller (PMU)
+ */
+enum pm_ret_status pm_pll_get_parameter(enum pm_node_id nid,
+ enum pm_pll_param param_id,
+ uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Check if given node ID is a PLL node */
+ if (nid < NODE_APLL || nid > NODE_IOPLL) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ /* Check if parameter ID is valid and return an error if it's not */
+ if (param_id >= PM_PLL_PARAM_MAX) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD3(payload, PM_PLL_GET_PARAMETER, nid, param_id);
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+/**
+ * pm_pll_set_mode() - Set the PLL mode
+ * @nid Node id of the target PLL
+ * @mode PLL mode to be set
+ *
+ * If reset mode is set the PM controller will first bypass the PLL and then
+ * assert the reset. If integer or fractional mode is set the PM controller will
+ * ensure that the complete PLL programming sequence is satisfied. After this
+ * function returns success the PLL is locked and its bypass is deasserted.
+ *
+ * @return Error if an argument is not valid or status as returned by the
+ * PM controller (PMU)
+ */
+enum pm_ret_status pm_pll_set_mode(enum pm_node_id nid, enum pm_pll_mode mode)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Check if given node ID is a PLL node */
+ if (nid < NODE_APLL || nid > NODE_IOPLL) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ /* Check if PLL mode is valid */
+ if (mode >= PM_PLL_MODE_MAX) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD3(payload, PM_PLL_SET_MODE, nid, mode);
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+}
+
+/**
+ * pm_pll_get_mode() - Get the PLL mode
+ * @nid Node id of the target PLL
+ * @mode Location to store the mode of the PLL
+ *
+ * @return Error if an argument is not valid or status as returned by the
+ * PM controller (PMU)
+ */
+enum pm_ret_status pm_pll_get_mode(enum pm_node_id nid, enum pm_pll_mode *mode)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Check if given node ID is a PLL node */
+ if (nid < NODE_APLL || nid > NODE_IOPLL) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD2(payload, PM_PLL_GET_MODE, nid);
+ return pm_ipi_send_sync(primary_proc, payload, mode, 1);
+}
+
+/**
+ * pm_register_access() - PM API for register read/write access data
+ *
+ * @register_access_id Register_access_id which says register read/write
+ *
+ * @address Address of the register to be accessed
+ *
+ * @mask Mask value to be used while writing value
+ *
+ * @value Value to be written to register
+ *
+ * @out Returned output data
+ *
+ * This function returns requested data.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_register_access(uint32_t register_access_id,
+ uint32_t address,
+ uint32_t mask,
+ uint32_t value,
+ uint32_t *out)
+{
+ enum pm_ret_status ret;
+
+ if (((ZYNQMP_CSU_BASEADDR & address) != ZYNQMP_CSU_BASEADDR) &&
+ ((CSUDMA_BASE & address) != CSUDMA_BASE) &&
+ ((RSA_CORE_BASE & address) != RSA_CORE_BASE) &&
+ ((PMU_GLOBAL_BASE & address) != PMU_GLOBAL_BASE)) {
+ return PM_RET_ERROR_ACCESS;
+ }
+
+ switch (register_access_id) {
+ case CONFIG_REG_WRITE:
+ ret = pm_mmio_write(address, mask, value);
+ break;
+ case CONFIG_REG_READ:
+ ret = pm_mmio_read(address, out);
+ break;
+ default:
+ ret = PM_RET_ERROR_ARGS;
+ WARN("Unimplemented register_access call\n\r");
+ break;
+ }
+ return ret;
+}
+
+/**
+ * pm_efuse_access() - To program or read efuse bits.
+ *
+ * This function provides access to the xilskey library to program/read
+ * efuse bits.
+ *
+ * address_low: lower 32-bit Linear memory space address
+ * address_high: higher 32-bit Linear memory space address
+ *
+ * value: Returned output value
+ *
+ * @return Returns status, either success or error+reason
+ *
+ */
+enum pm_ret_status pm_efuse_access(uint32_t address_high,
+ uint32_t address_low,
+ uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD3(payload, PM_EFUSE_ACCESS, address_high, address_low);
+
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+enum pm_ret_status em_set_action(uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ EM_PACK_PAYLOAD1(payload, EM_SET_ACTION);
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+enum pm_ret_status em_remove_action(uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ EM_PACK_PAYLOAD1(payload, EM_REMOVE_ACTION);
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
+
+enum pm_ret_status em_send_errors(uint32_t *value)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ EM_PACK_PAYLOAD1(payload, EM_SEND_ERRORS);
+ return pm_ipi_send_sync(primary_proc, payload, value, 1);
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_api_sys.h b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
new file mode 100644
index 0000000..9ba9475
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_api_sys.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. 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"
+
+enum pm_query_id {
+ PM_QID_INVALID,
+ PM_QID_CLOCK_GET_NAME,
+ PM_QID_CLOCK_GET_TOPOLOGY,
+ PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS,
+ PM_QID_CLOCK_GET_PARENTS,
+ PM_QID_CLOCK_GET_ATTRIBUTES,
+ PM_QID_PINCTRL_GET_NUM_PINS,
+ PM_QID_PINCTRL_GET_NUM_FUNCTIONS,
+ PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS,
+ PM_QID_PINCTRL_GET_FUNCTION_NAME,
+ PM_QID_PINCTRL_GET_FUNCTION_GROUPS,
+ PM_QID_PINCTRL_GET_PIN_GROUPS,
+ PM_QID_CLOCK_GET_NUM_CLOCKS,
+ PM_QID_CLOCK_GET_MAX_DIVISOR,
+};
+
+enum pm_register_access_id {
+ CONFIG_REG_WRITE,
+ CONFIG_REG_READ,
+};
+
+/**
+ * Assigning of argument values into array elements.
+ */
+#define PM_PACK_PAYLOAD1(pl, arg0) { \
+ pl[0] = (uint32_t)(arg0); \
+}
+
+#define PM_PACK_PAYLOAD2(pl, arg0, arg1) { \
+ pl[1] = (uint32_t)(arg1); \
+ PM_PACK_PAYLOAD1(pl, arg0); \
+}
+
+#define PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2) { \
+ pl[2] = (uint32_t)(arg2); \
+ PM_PACK_PAYLOAD2(pl, arg0, arg1); \
+}
+
+#define PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3) { \
+ pl[3] = (uint32_t)(arg3); \
+ PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2); \
+}
+
+#define PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4) { \
+ pl[4] = (uint32_t)(arg4); \
+ PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3); \
+}
+
+#define PM_PACK_PAYLOAD6(pl, arg0, arg1, arg2, arg3, arg4, arg5) { \
+ pl[5] = (uint32_t)(arg5); \
+ PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4); \
+}
+
+/**********************************************************
+ * System-level API function declarations
+ **********************************************************/
+enum pm_ret_status pm_req_suspend(enum pm_node_id target,
+ enum pm_request_ack ack,
+ uint32_t latency,
+ uint32_t state);
+
+enum pm_ret_status pm_self_suspend(enum pm_node_id nid,
+ uint32_t latency,
+ uint32_t state,
+ uintptr_t address);
+
+enum pm_ret_status pm_force_powerdown(enum pm_node_id target,
+ enum pm_request_ack ack);
+
+enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason);
+
+enum pm_ret_status pm_req_wakeup(enum pm_node_id target,
+ uint32_t set_address,
+ uintptr_t address,
+ enum pm_request_ack ack);
+
+enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target,
+ enum pm_node_id wkup_node,
+ uint32_t enable);
+
+enum pm_ret_status pm_system_shutdown(uint32_t type, uint32_t subtype);
+
+/* API functions for managing PM Slaves */
+enum pm_ret_status pm_req_node(enum pm_node_id nid,
+ uint32_t capabilities,
+ uint32_t qos,
+ enum pm_request_ack ack);
+
+enum pm_ret_status pm_set_requirement(enum pm_node_id nid,
+ uint32_t capabilities,
+ uint32_t qos,
+ enum pm_request_ack ack);
+
+/* Miscellaneous API functions */
+enum pm_ret_status pm_get_api_version(uint32_t *version);
+enum pm_ret_status pm_get_node_status(enum pm_node_id nid,
+ uint32_t *ret_buff);
+
+/* Direct-Control API functions */
+enum pm_ret_status pm_mmio_write(uintptr_t address,
+ uint32_t mask,
+ uint32_t value);
+enum pm_ret_status pm_mmio_read(uintptr_t address, uint32_t *value);
+enum pm_ret_status pm_fpga_load(uint32_t address_low,
+ uint32_t address_high,
+ uint32_t size,
+ uint32_t flags);
+enum pm_ret_status pm_fpga_get_status(uint32_t *value);
+
+enum pm_ret_status pm_get_chipid(uint32_t *value);
+enum pm_ret_status pm_secure_rsaaes(uint32_t address_low,
+ uint32_t address_high,
+ uint32_t size,
+ uint32_t flags);
+uint32_t pm_get_shutdown_scope(void);
+void pm_get_callbackdata(uint32_t *data, size_t count);
+enum pm_ret_status pm_ioctl(enum pm_node_id nid,
+ uint32_t ioctl_id,
+ uint32_t arg1,
+ uint32_t arg2,
+ uint32_t *value);
+enum pm_ret_status pm_clock_enable(uint32_t clock_id);
+enum pm_ret_status pm_clock_disable(uint32_t clock_id);
+enum pm_ret_status pm_clock_getstate(uint32_t clock_id,
+ uint32_t *state);
+enum pm_ret_status pm_clock_setdivider(uint32_t clock_id,
+ uint32_t divider);
+enum pm_ret_status pm_clock_getdivider(uint32_t clock_id,
+ uint32_t *divider);
+enum pm_ret_status pm_clock_setrate(uint32_t clock_id,
+ uint64_t rate);
+enum pm_ret_status pm_clock_getrate(uint32_t clock_id,
+ uint64_t *rate);
+enum pm_ret_status pm_clock_setparent(uint32_t clock_id,
+ uint32_t parent_index);
+enum pm_ret_status pm_clock_getparent(uint32_t clock_id,
+ uint32_t *parent_index);
+void pm_query_data(enum pm_query_id qid, uint32_t arg1, uint32_t arg2,
+ uint32_t arg3, uint32_t *data);
+enum pm_ret_status pm_sha_hash(uint32_t address_high,
+ uint32_t address_low,
+ uint32_t size,
+ uint32_t flags);
+enum pm_ret_status pm_rsa_core(uint32_t address_high,
+ uint32_t address_low,
+ uint32_t size,
+ uint32_t flags);
+enum pm_ret_status pm_secure_image(uint32_t address_low,
+ uint32_t address_high,
+ uint32_t key_lo,
+ uint32_t key_hi,
+ uint32_t *value);
+enum pm_ret_status pm_fpga_read(uint32_t reg_numframes,
+ uint32_t address_low,
+ uint32_t address_high,
+ uint32_t readback_type,
+ uint32_t *value);
+enum pm_ret_status pm_aes_engine(uint32_t address_high,
+ uint32_t address_low,
+ uint32_t *value);
+enum pm_ret_status pm_register_access(uint32_t register_access_id,
+ uint32_t address,
+ uint32_t mask,
+ uint32_t value,
+ uint32_t *out);
+enum pm_ret_status pm_pll_set_parameter(enum pm_node_id nid,
+ enum pm_pll_param param_id,
+ uint32_t value);
+enum pm_ret_status pm_pll_get_parameter(enum pm_node_id nid,
+ enum pm_pll_param param_id,
+ uint32_t *value);
+enum pm_ret_status pm_pll_set_mode(enum pm_node_id nid, enum pm_pll_mode mode);
+enum pm_ret_status pm_pll_get_mode(enum pm_node_id nid, enum pm_pll_mode *mode);
+enum pm_ret_status pm_efuse_access(uint32_t address_high,
+ uint32_t address_low, uint32_t *value);
+enum pm_ret_status em_set_action(uint32_t *value);
+enum pm_ret_status em_remove_action(uint32_t *value);
+enum pm_ret_status em_send_errors(uint32_t *value);
+enum pm_ret_status pm_feature_check(uint32_t api_id, uint32_t *version,
+ uint32_t *bit_mask, uint8_t len);
+enum pm_ret_status check_api_dependency(uint8_t id);
+
+#endif /* PM_API_SYS_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.c b/plat/xilinx/zynqmp/pm_service/pm_client.c
new file mode 100644
index 0000000..7217fa1
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_client.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * APU specific definition of processors in the subsystem as well as functions
+ * for getting information about and changing state of the APU.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include <common/bl_common.h>
+#include <drivers/arm/gic_common.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <lib/utils.h>
+
+#include <plat_ipi.h>
+#include <zynqmp_def.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_ipi.h"
+
+#define IRQ_MAX 84U
+#define NUM_GICD_ISENABLER ((IRQ_MAX >> 5U) + 1U)
+#define UNDEFINED_CPUID (~0U)
+
+#define PM_SUSPEND_MODE_STD 0U
+#define PM_SUSPEND_MODE_POWER_OFF 1U
+
+DEFINE_BAKERY_LOCK(pm_client_secure_lock);
+
+extern const struct pm_ipi apu_ipi;
+
+const struct pm_ipi apu_ipi = {
+ .local_ipi_id = IPI_ID_APU,
+ .remote_ipi_id = IPI_ID_PMU0,
+ .buffer_base = IPI_BUFFER_APU_BASE,
+};
+
+static uint32_t suspend_mode = PM_SUSPEND_MODE_STD;
+
+/* Order in pm_procs_all array must match cpu ids */
+static const struct pm_proc pm_procs_all[] = {
+ {
+ .node_id = NODE_APU_0,
+ .pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
+ .ipi = &apu_ipi,
+ },
+ {
+ .node_id = NODE_APU_1,
+ .pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
+ .ipi = &apu_ipi,
+ },
+ {
+ .node_id = NODE_APU_2,
+ .pwrdn_mask = APU_2_PWRCTL_CPUPWRDWNREQ_MASK,
+ .ipi = &apu_ipi,
+ },
+ {
+ .node_id = NODE_APU_3,
+ .pwrdn_mask = APU_3_PWRCTL_CPUPWRDWNREQ_MASK,
+ .ipi = &apu_ipi,
+ },
+};
+
+/* Interrupt to PM node ID map */
+static enum pm_node_id irq_node_map[IRQ_MAX + 1U] = {
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN, /* 3 */
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN, /* 7 */
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN, /* 11 */
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_NAND,
+ NODE_QSPI, /* 15 */
+ NODE_GPIO,
+ NODE_I2C_0,
+ NODE_I2C_1,
+ NODE_SPI_0, /* 19 */
+ NODE_SPI_1,
+ NODE_UART_0,
+ NODE_UART_1,
+ NODE_CAN_0, /* 23 */
+ NODE_CAN_1,
+ NODE_UNKNOWN,
+ NODE_RTC,
+ NODE_RTC, /* 27 */
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN, /* 31 */
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN, /* 35, NODE_IPI_APU */
+ NODE_TTC_0,
+ NODE_TTC_0,
+ NODE_TTC_0,
+ NODE_TTC_1, /* 39 */
+ NODE_TTC_1,
+ NODE_TTC_1,
+ NODE_TTC_2,
+ NODE_TTC_2, /* 43 */
+ NODE_TTC_2,
+ NODE_TTC_3,
+ NODE_TTC_3,
+ NODE_TTC_3, /* 47 */
+ NODE_SD_0,
+ NODE_SD_1,
+ NODE_SD_0,
+ NODE_SD_1, /* 51 */
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN,
+ NODE_UNKNOWN, /* 55 */
+ NODE_UNKNOWN,
+ NODE_ETH_0,
+ NODE_ETH_0,
+ NODE_ETH_1, /* 59 */
+ NODE_ETH_1,
+ NODE_ETH_2,
+ NODE_ETH_2,
+ NODE_ETH_3, /* 63 */
+ NODE_ETH_3,
+ NODE_USB_0,
+ NODE_USB_0,
+ NODE_USB_0, /* 67 */
+ NODE_USB_0,
+ NODE_USB_0,
+ NODE_USB_1,
+ NODE_USB_1, /* 71 */
+ NODE_USB_1,
+ NODE_USB_1,
+ NODE_USB_1,
+ NODE_USB_0, /* 75 */
+ NODE_USB_0,
+ NODE_ADMA,
+ NODE_ADMA,
+ NODE_ADMA, /* 79 */
+ NODE_ADMA,
+ NODE_ADMA,
+ NODE_ADMA,
+ NODE_ADMA, /* 83 */
+ NODE_ADMA,
+};
+
+/**
+ * irq_to_pm_node - Get PM node ID corresponding to the interrupt number
+ * @irq: Interrupt number
+ *
+ * Return: PM node ID corresponding to the specified interrupt
+ */
+static enum pm_node_id irq_to_pm_node(uint32_t irq)
+{
+ assert(irq <= IRQ_MAX);
+ return irq_node_map[irq];
+}
+
+/**
+ * pm_client_set_wakeup_sources - Set all slaves with enabled interrupts as wake
+ * sources in the PMU firmware
+ */
+static void pm_client_set_wakeup_sources(void)
+{
+ uint32_t reg_num;
+ uint8_t pm_wakeup_nodes_set[NODE_MAX] = { 0 };
+ uintptr_t isenabler1 = BASE_GICD_BASE + GICD_ISENABLER + 4U;
+
+ /* In case of power-off suspend, only NODE_EXTERN must be set */
+ if (suspend_mode == PM_SUSPEND_MODE_POWER_OFF) {
+ enum pm_ret_status ret;
+
+ ret = pm_set_wakeup_source(NODE_APU, NODE_EXTERN, 1U);
+ /**
+ * If NODE_EXTERN could not be set as wake source, proceed with
+ * standard suspend (no one will wake the system otherwise)
+ */
+ if (ret == PM_RET_SUCCESS) {
+ return;
+ }
+ }
+
+ zeromem(&pm_wakeup_nodes_set, 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 << 2U));
+
+ if (reg == 0) {
+ continue;
+ }
+
+ while (reg) {
+ enum pm_node_id node;
+ uint32_t idx, ret, irq, lowest_set = reg & (-reg);
+
+ idx = __builtin_ctz(lowest_set);
+ irq = base_irq + idx;
+
+ if (irq > IRQ_MAX) {
+ break;
+ }
+
+ node = irq_to_pm_node(irq);
+ reg &= ~lowest_set;
+
+ if (node > NODE_UNKNOWN && node < NODE_MAX) {
+ if (pm_wakeup_nodes_set[node] == 0U) {
+ ret = pm_set_wakeup_source(NODE_APU, node, 1U);
+ pm_wakeup_nodes_set[node] = (ret == PM_RET_SUCCESS) ? 1U : 0U;
+ }
+ }
+ }
+ }
+}
+
+/**
+ * pm_get_proc() - returns pointer to the proc structure
+ * @cpuid: id of the cpu whose proc struct pointer should be returned
+ *
+ * Return: pointer to a proc structure if proc is found, otherwise NULL
+ */
+const struct pm_proc *pm_get_proc(uint32_t cpuid)
+{
+ if (cpuid < ARRAY_SIZE(pm_procs_all)) {
+ return &pm_procs_all[cpuid];
+ }
+
+ return NULL;
+}
+
+/**
+ * pm_get_proc_by_node() - returns pointer to the proc structure
+ * @nid: node id of the processor
+ *
+ * Return: pointer to a proc structure if proc is found, otherwise NULL
+ */
+const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
+ if (nid == pm_procs_all[i].node_id) {
+ return &pm_procs_all[i];
+ }
+ }
+ return NULL;
+}
+
+/**
+ * pm_get_cpuid() - get the local cpu ID for a global node ID
+ * @nid: node id of the processor
+ *
+ * Return: the cpu ID (starting from 0) for the subsystem
+ */
+static uint32_t pm_get_cpuid(enum pm_node_id nid)
+{
+ for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
+ if (pm_procs_all[i].node_id == nid) {
+ return i;
+ }
+ }
+ return UNDEFINED_CPUID;
+}
+
+const struct pm_proc *primary_proc = &pm_procs_all[0];
+
+/**
+ * pm_client_suspend() - Client-specific suspend actions
+ *
+ * This function should contain any PU-specific actions
+ * required prior to sending suspend request to PMU
+ * Actions taken depend on the state system is suspending to.
+ */
+void pm_client_suspend(const struct pm_proc *proc, uint32_t state)
+{
+ bakery_lock_get(&pm_client_secure_lock);
+
+ if (state == PM_STATE_SUSPEND_TO_RAM) {
+ pm_client_set_wakeup_sources();
+ }
+
+ /* Set powerdown request */
+ mmio_write_32(APU_PWRCTL, mmio_read_32(APU_PWRCTL) | proc->pwrdn_mask);
+
+ bakery_lock_release(&pm_client_secure_lock);
+}
+
+
+/**
+ * pm_client_abort_suspend() - Client-specific abort-suspend actions
+ *
+ * This function should contain any PU-specific actions
+ * required for aborting a prior suspend request
+ */
+void pm_client_abort_suspend(void)
+{
+ /* Enable interrupts at processor level (for current cpu) */
+ gicv2_cpuif_enable();
+
+ bakery_lock_get(&pm_client_secure_lock);
+
+ /* Clear powerdown request */
+ mmio_write_32(APU_PWRCTL,
+ mmio_read_32(APU_PWRCTL) & ~primary_proc->pwrdn_mask);
+
+ bakery_lock_release(&pm_client_secure_lock);
+}
+
+/**
+ * pm_client_wakeup() - Client-specific wakeup actions
+ *
+ * This function should contain any PU-specific actions
+ * required for waking up another APU core
+ */
+void pm_client_wakeup(const struct pm_proc *proc)
+{
+ uint32_t cpuid = pm_get_cpuid(proc->node_id);
+
+ if (cpuid == UNDEFINED_CPUID) {
+ return;
+ }
+
+ bakery_lock_get(&pm_client_secure_lock);
+
+ /* clear powerdown bit for affected cpu */
+ uint32_t val = mmio_read_32(APU_PWRCTL);
+ val &= ~(proc->pwrdn_mask);
+ mmio_write_32(APU_PWRCTL, val);
+
+ bakery_lock_release(&pm_client_secure_lock);
+}
+
+enum pm_ret_status pm_set_suspend_mode(uint32_t mode)
+{
+ if ((mode != PM_SUSPEND_MODE_STD) &&
+ (mode != PM_SUSPEND_MODE_POWER_OFF)) {
+ return PM_RET_ERROR_ARGS;
+ }
+
+ suspend_mode = mode;
+ return PM_RET_SUCCESS;
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_defs.h b/plat/xilinx/zynqmp/pm_service/pm_defs.h
new file mode 100644
index 0000000..e335b94
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_defs.h
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* ZynqMP power management enums and defines */
+
+#ifndef PM_DEFS_H
+#define PM_DEFS_H
+
+/*********************************************************************
+ * Macro definitions
+ ********************************************************************/
+
+/*
+ * Version number is a 32bit value, like:
+ * (PM_VERSION_MAJOR << 16) | PM_VERSION_MINOR
+ */
+#define PM_VERSION_MAJOR 1U
+#define PM_VERSION_MINOR 1U
+
+#define PM_VERSION ((PM_VERSION_MAJOR << 16U) | PM_VERSION_MINOR)
+
+/**
+ * PM API versions
+ */
+/* Expected version of firmware APIs */
+#define FW_API_BASE_VERSION (1U)
+/* Expected version of firmware API for feature check */
+#define FW_API_VERSION_2 (2U)
+/* Version of APIs implemented in ATF */
+#define ATF_API_BASE_VERSION (1U)
+
+/* Capabilities for RAM */
+#define PM_CAP_ACCESS 0x1U
+#define PM_CAP_CONTEXT 0x2U
+
+#define MAX_LATENCY (~0U)
+#define MAX_QOS 100U
+
+/* State arguments of the self suspend */
+#define PM_STATE_CPU_IDLE 0x0U
+#define PM_STATE_SUSPEND_TO_RAM 0xFU
+
+/* APU processor states */
+#define PM_PROC_STATE_FORCEDOFF 0U
+#define PM_PROC_STATE_ACTIVE 1U
+#define PM_PROC_STATE_SLEEP 2U
+#define PM_PROC_STATE_SUSPENDING 3U
+
+#define EM_FUNID_NUM_MASK 0xF0000U
+
+#define PM_GET_CALLBACK_DATA 0xa01
+#define PM_SET_SUSPEND_MODE 0xa02
+#define PM_GET_TRUSTZONE_VERSION 0xa03
+
+/*********************************************************************
+ * Enum definitions
+ ********************************************************************/
+
+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_SETRATE,
+ PM_CLOCK_GETRATE,
+ PM_CLOCK_SETPARENT,
+ 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
+};
+
+enum pm_node_id {
+ NODE_UNKNOWN = 0,
+ NODE_APU,
+ NODE_APU_0,
+ NODE_APU_1,
+ NODE_APU_2,
+ NODE_APU_3,
+ NODE_RPU,
+ NODE_RPU_0,
+ NODE_RPU_1,
+ NODE_PLD,
+ NODE_FPD,
+ NODE_OCM_BANK_0,
+ NODE_OCM_BANK_1,
+ NODE_OCM_BANK_2,
+ NODE_OCM_BANK_3,
+ NODE_TCM_0_A,
+ NODE_TCM_0_B,
+ NODE_TCM_1_A,
+ NODE_TCM_1_B,
+ NODE_L2,
+ NODE_GPU_PP_0,
+ NODE_GPU_PP_1,
+ NODE_USB_0,
+ NODE_USB_1,
+ NODE_TTC_0,
+ NODE_TTC_1,
+ NODE_TTC_2,
+ NODE_TTC_3,
+ NODE_SATA,
+ NODE_ETH_0,
+ NODE_ETH_1,
+ NODE_ETH_2,
+ NODE_ETH_3,
+ NODE_UART_0,
+ NODE_UART_1,
+ NODE_SPI_0,
+ NODE_SPI_1,
+ NODE_I2C_0,
+ NODE_I2C_1,
+ NODE_SD_0,
+ NODE_SD_1,
+ NODE_DP,
+ NODE_GDMA,
+ NODE_ADMA,
+ NODE_NAND,
+ NODE_QSPI,
+ NODE_GPIO,
+ NODE_CAN_0,
+ NODE_CAN_1,
+ NODE_EXTERN,
+ NODE_APLL,
+ NODE_VPLL,
+ NODE_DPLL,
+ NODE_RPLL,
+ NODE_IOPLL,
+ NODE_DDR,
+ NODE_IPI_APU,
+ NODE_IPI_RPU_0,
+ NODE_GPU,
+ NODE_PCIE,
+ NODE_PCAP,
+ NODE_RTC,
+ NODE_LPD,
+ NODE_VCU,
+ NODE_IPI_RPU_1,
+ NODE_IPI_PL_0,
+ NODE_IPI_PL_1,
+ NODE_IPI_PL_2,
+ NODE_IPI_PL_3,
+ NODE_PL,
+ NODE_GEM_TSU,
+ NODE_SWDT_0,
+ NODE_SWDT_1,
+ NODE_CSU,
+ NODE_PJTAG,
+ NODE_TRACE,
+ NODE_TESTSCAN,
+ NODE_PMU,
+ NODE_MAX,
+};
+
+enum pm_request_ack {
+ REQ_ACK_NO = 1,
+ REQ_ACK_BLOCKING,
+ REQ_ACK_NON_BLOCKING,
+};
+
+enum pm_abort_reason {
+ ABORT_REASON_WKUP_EVENT = 100,
+ ABORT_REASON_PU_BUSY,
+ ABORT_REASON_NO_PWRDN,
+ ABORT_REASON_UNKNOWN,
+};
+
+enum pm_suspend_reason {
+ SUSPEND_REASON_PU_REQ = 201,
+ SUSPEND_REASON_ALERT,
+ SUSPEND_REASON_SYS_SHUTDOWN,
+};
+
+enum pm_ram_state {
+ PM_RAM_STATE_OFF = 1,
+ PM_RAM_STATE_RETENTION,
+ PM_RAM_STATE_ON,
+};
+
+enum pm_opchar_type {
+ PM_OPCHAR_TYPE_POWER = 1,
+ PM_OPCHAR_TYPE_TEMP,
+ PM_OPCHAR_TYPE_LATENCY,
+};
+
+/**
+ * @PM_RET_SUCCESS: success
+ * @PM_RET_ERROR_ARGS: illegal arguments provided (deprecated)
+ * @PM_RET_ERROR_NOTSUPPORTED: feature not supported (deprecated)
+ * @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
+ */
+enum pm_ret_status {
+ PM_RET_SUCCESS = (0U),
+ PM_RET_ERROR_ARGS = (1U),
+ PM_RET_ERROR_NOTSUPPORTED = (4U),
+ PM_RET_ERROR_NOT_ENABLED = (29U),
+ PM_RET_ERROR_INTERNAL = (2000U),
+ PM_RET_ERROR_CONFLICT = (2001U),
+ PM_RET_ERROR_ACCESS = (2002U),
+ PM_RET_ERROR_INVALID_NODE = (2003U),
+ PM_RET_ERROR_DOUBLE_REQ = (2004U),
+ PM_RET_ERROR_ABORT_SUSPEND = (2005U),
+ PM_RET_ERROR_TIMEOUT = (2006U),
+ PM_RET_ERROR_NODE_USED = (2007U),
+ PM_RET_ERROR_NO_FEATURE = (2008U)
+};
+
+/**
+ * @PM_INITIAL_BOOT: boot is a fresh system startup
+ * @PM_RESUME: boot is a resume
+ * @PM_BOOT_ERROR: error, boot cause cannot be identified
+ */
+enum pm_boot_status {
+ PM_INITIAL_BOOT,
+ PM_RESUME,
+ PM_BOOT_ERROR,
+};
+
+/**
+ * @PMF_SHUTDOWN_TYPE_SHUTDOWN: shutdown
+ * @PMF_SHUTDOWN_TYPE_RESET: reset/reboot
+ * @PMF_SHUTDOWN_TYPE_SETSCOPE_ONLY: set the shutdown/reboot scope
+ */
+enum pm_shutdown_type {
+ PMF_SHUTDOWN_TYPE_SHUTDOWN,
+ PMF_SHUTDOWN_TYPE_RESET,
+ PMF_SHUTDOWN_TYPE_SETSCOPE_ONLY,
+};
+
+/**
+ * @PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM: shutdown/reboot APU subsystem only
+ * @PMF_SHUTDOWN_SUBTYPE_PS_ONLY: shutdown/reboot entire PS (but not PL)
+ * @PMF_SHUTDOWN_SUBTYPE_SYSTEM: shutdown/reboot entire system
+ */
+enum pm_shutdown_subtype {
+ PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM,
+ PMF_SHUTDOWN_SUBTYPE_PS_ONLY,
+ PMF_SHUTDOWN_SUBTYPE_SYSTEM,
+};
+
+/**
+ * @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
+ */
+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,
+};
+
+/**
+ * @PM_PLL_MODE_RESET: PLL is in reset (not locked)
+ * @PM_PLL_MODE_INTEGER: PLL is locked in integer mode
+ * @PM_PLL_MODE_FRACTIONAL: PLL is locked in fractional mode
+ */
+enum pm_pll_mode {
+ PM_PLL_MODE_RESET,
+ PM_PLL_MODE_INTEGER,
+ PM_PLL_MODE_FRACTIONAL,
+ PM_PLL_MODE_MAX,
+};
+
+/**
+ * @PM_CLOCK_DIV0_ID: Clock divider 0
+ * @PM_CLOCK_DIV1_ID: Clock divider 1
+ */
+enum pm_clock_div_id {
+ PM_CLOCK_DIV0_ID,
+ PM_CLOCK_DIV1_ID,
+};
+
+/**
+ * EM API IDs
+ */
+enum em_api_id {
+ EM_SET_ACTION = 1,
+ EM_REMOVE_ACTION,
+ EM_SEND_ERRORS,
+};
+
+#endif /* PM_DEFS_H */
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
new file mode 100644
index 0000000..03fa316
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c
@@ -0,0 +1,621 @@
+/*
+ * Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Top-level SMC handler for ZynqMP power management calls and
+ * IPI setup functions for communication with PMU.
+ */
+
+#include <errno.h>
+
+#include <common/runtime_svc.h>
+#if ZYNQMP_WDT_RESTART
+#include <arch_helpers.h>
+#include <drivers/arm/gicv2.h>
+#include <lib/mmio.h>
+#include <lib/spinlock.h>
+#include <plat/common/platform.h>
+#endif
+
+#include <plat_private.h>
+#include "pm_api_sys.h"
+#include "pm_client.h"
+#include "pm_defs.h"
+#include "pm_ipi.h"
+
+/* pm_up = !0 - UP, pm_up = 0 - DOWN */
+static int32_t pm_up, ipi_irq_flag;
+
+#if ZYNQMP_WDT_RESTART
+static spinlock_t inc_lock;
+static int active_cores = 0;
+#endif
+
+/**
+ * pm_context - Structure which contains data for power management
+ * @api_version version of PM API, must match with one on PMU side
+ * @payload payload array used to store received
+ * data from ipi buffer registers
+ */
+static struct {
+ uint32_t api_version;
+ uint32_t payload[PAYLOAD_ARG_CNT];
+} pm_ctx;
+
+#if ZYNQMP_WDT_RESTART
+/**
+ * trigger_wdt_restart() - Trigger warm restart event to APU cores
+ *
+ * This function triggers SGI for all active APU CPUs. SGI handler then
+ * power down CPU and call system reset.
+ */
+static void trigger_wdt_restart(void)
+{
+ uint32_t core_count = 0;
+ uint32_t core_status[3];
+ uint32_t target_cpu_list = 0;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ pm_get_node_status(NODE_APU_0 + i, core_status);
+ if (core_status[0] == 1) {
+ core_count++;
+ target_cpu_list |= (1 << i);
+ }
+ }
+
+ spin_lock(&inc_lock);
+ active_cores = core_count;
+ spin_unlock(&inc_lock);
+
+ INFO("Active Cores: %d\n", active_cores);
+
+ for (i = PLATFORM_CORE_COUNT - 1; i >= 0; i--) {
+ if (target_cpu_list & (1 << i)) {
+ /* trigger SGI to active cores */
+ plat_ic_raise_el3_sgi(ARM_IRQ_SEC_SGI_7, i);
+ }
+ }
+}
+
+/**
+ * ttc_fiq_handler() - TTC Handler for timer event
+ * @id number of the highest priority pending interrupt of the type
+ * that this handler was registered for
+ * @flags security state, bit[0]
+ * @handler pointer to 'cpu_context' structure of the current CPU for the
+ * security state specified in the 'flags' parameter
+ * @cookie unused
+ *
+ * Function registered as INTR_TYPE_EL3 interrupt handler
+ *
+ * When WDT event is received in PMU, PMU needs to notify master to do cleanup
+ * if required. PMU sets up timer and starts timer to overflow in zero time upon
+ * WDT event. ATF handles this timer event and takes necessary action required
+ * for warm restart.
+ *
+ * In presence of non-secure software layers (EL1/2) sets the interrupt
+ * at registered entrance in GIC and informs that PMU responsed or demands
+ * action.
+ */
+static uint64_t ttc_fiq_handler(uint32_t id, uint32_t flags, void *handle,
+ void *cookie)
+{
+ INFO("BL31: Got TTC FIQ\n");
+
+ plat_ic_end_of_interrupt(id);
+
+ /* Clear TTC interrupt by reading interrupt register */
+ mmio_read_32(TTC3_INTR_REGISTER_1);
+
+ /* Disable the timer interrupts */
+ mmio_write_32(TTC3_INTR_ENABLE_1, 0);
+
+ trigger_wdt_restart();
+
+ return 0;
+}
+
+/**
+ * zynqmp_sgi7_irq() - Handler for SGI7 IRQ
+ * @id number of the highest priority pending interrupt of the type
+ * that this handler was registered for
+ * @flags security state, bit[0]
+ * @handler pointer to 'cpu_context' structure of the current CPU for the
+ * security state specified in the 'flags' parameter
+ * @cookie unused
+ *
+ * Function registered as INTR_TYPE_EL3 interrupt handler
+ *
+ * On receiving WDT event from PMU, ATF generates SGI7 to all running CPUs.
+ * In response to SGI7 interrupt, each CPUs do clean up if required and last
+ * running CPU calls system restart.
+ */
+static uint64_t __unused __dead2 zynqmp_sgi7_irq(uint32_t id, uint32_t flags,
+ void *handle, void *cookie)
+{
+ int i;
+ uint32_t value;
+
+ /* enter wfi and stay there */
+ INFO("Entering wfi\n");
+
+ spin_lock(&inc_lock);
+ active_cores--;
+
+ for (i = 0; i < 4; i++) {
+ mmio_write_32(BASE_GICD_BASE + GICD_CPENDSGIR + 4 * i,
+ 0xffffffff);
+ }
+
+ dsb();
+
+ spin_unlock(&inc_lock);
+
+ if (active_cores == 0) {
+ pm_mmio_read(PMU_GLOBAL_GEN_STORAGE4, &value);
+ value = (value & RESTART_SCOPE_MASK) >> RESTART_SCOPE_SHIFT;
+ pm_system_shutdown(PMF_SHUTDOWN_TYPE_RESET, value);
+ }
+
+ /* enter wfi and stay there */
+ while (1)
+ wfi();
+}
+
+/**
+ * pm_wdt_restart_setup() - Setup warm restart interrupts
+ *
+ * This function sets up handler for SGI7 and TTC interrupts
+ * used for warm restart.
+ */
+static int pm_wdt_restart_setup(void)
+{
+ int ret;
+
+ /* register IRQ handler for SGI7 */
+ ret = request_intr_type_el3(ARM_IRQ_SEC_SGI_7, zynqmp_sgi7_irq);
+ if (ret) {
+ WARN("BL31: registering SGI7 interrupt failed\n");
+ goto err;
+ }
+
+ ret = request_intr_type_el3(IRQ_TTC3_1, ttc_fiq_handler);
+ if (ret)
+ WARN("BL31: registering TTC3 interrupt failed\n");
+
+err:
+ return ret;
+}
+#endif
+
+/**
+ * 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 ZynqMP power management for
+ * communicaton with PMU.
+ *
+ * Called from sip_svc_setup initialization function with the
+ * rt_svc_init signature.
+ */
+int32_t pm_setup(void)
+{
+
+ pm_ipi_init(primary_proc);
+
+ pm_get_api_version(&pm_ctx.api_version);
+ if (pm_ctx.api_version < PM_VERSION) {
+ ERROR("BL31: Platform Management API version error. Expected: "
+ "v%d.%d - Found: v%d.%d\n", PM_VERSION_MAJOR,
+ PM_VERSION_MINOR, pm_ctx.api_version >> 16,
+ pm_ctx.api_version & 0xFFFFU);
+ return -EINVAL;
+ }
+
+ int32_t status = 0, ret = 0;
+#if ZYNQMP_WDT_RESTART
+ status = pm_wdt_restart_setup();
+ if (status)
+ WARN("BL31: warm-restart setup failed\n");
+#endif
+
+ if (status >= 0) {
+ INFO("BL31: PM Service Init Complete: API v%d.%d\n",
+ PM_VERSION_MAJOR, PM_VERSION_MINOR);
+ ret = 0;
+ } else {
+ INFO("BL31: PM Service Init Failed, Error Code %d!\n", status);
+ ret = status;
+ }
+
+ pm_up = !status;
+
+ return ret;
+}
+
+/**
+ * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2.
+ * @smc_fid - Function Identifier
+ * @x1 - x4 - Arguments
+ * @cookie - Unused
+ * @handler - Pointer to caller's context structure
+ *
+ * @return - Unused
+ *
+ * Determines that smc_fid is valid and supported PM SMC Function ID from the
+ * list of pm_api_ids, otherwise completes the request with
+ * the unknown SMC Function ID
+ *
+ * The SMC calls for PM service are forwarded from SIP Service SMC handler
+ * function with rt_svc_handle signature
+ */
+uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3,
+ uint64_t x4, const void *cookie, void *handle, uint64_t flags)
+{
+ enum pm_ret_status ret;
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ uint32_t pm_arg[5];
+ uint32_t result[PAYLOAD_ARG_CNT] = {0};
+ uint32_t api_id;
+
+ /* Handle case where PM wasn't initialized properly */
+ if (pm_up == 0)
+ SMC_RET1(handle, SMC_UNK);
+
+ pm_arg[0] = (uint32_t)x1;
+ pm_arg[1] = (uint32_t)(x1 >> 32);
+ pm_arg[2] = (uint32_t)x2;
+ pm_arg[3] = (uint32_t)(x2 >> 32);
+ pm_arg[4] = (uint32_t)x3;
+
+ api_id = smc_fid & FUNCID_NUM_MASK;
+
+ switch (api_id) {
+ /* PM API Functions */
+ case PM_SELF_SUSPEND:
+ ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_REQ_SUSPEND:
+ ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_REQ_WAKEUP:
+ {
+ /* Use address flag is encoded in the 1st bit of the low-word */
+ uint32_t set_addr = pm_arg[1] & 0x1U;
+ uint64_t address = (uint64_t)pm_arg[2] << 32U;
+
+ address |= pm_arg[1] & (~0x1U);
+ ret = pm_req_wakeup(pm_arg[0], set_addr, address,
+ pm_arg[3]);
+ SMC_RET1(handle, (uint64_t)ret);
+ }
+
+ case PM_FORCE_POWERDOWN:
+ ret = pm_force_powerdown(pm_arg[0], pm_arg[1]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_ABORT_SUSPEND:
+ ret = pm_abort_suspend(pm_arg[0]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_SET_WAKEUP_SOURCE:
+ ret = pm_set_wakeup_source(pm_arg[0], pm_arg[1], pm_arg[2]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_SYSTEM_SHUTDOWN:
+ ret = pm_system_shutdown(pm_arg[0], pm_arg[1]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_REQ_NODE:
+ ret = pm_req_node(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_SET_REQUIREMENT:
+ ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_GET_API_VERSION:
+ /* Check is PM API version already verified */
+ if (pm_ctx.api_version >= PM_VERSION) {
+ if (ipi_irq_flag == 0U) {
+ /*
+ * 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);
+ ipi_irq_flag = 1U;
+ }
+ SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
+ ((uint64_t)pm_ctx.api_version << 32));
+ }
+
+ case PM_FPGA_LOAD:
+ ret = pm_fpga_load(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_FPGA_GET_STATUS:
+ {
+ uint32_t value = 0;
+
+ ret = pm_fpga_get_status(&value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+ }
+
+ case PM_SECURE_RSA_AES:
+ ret = pm_secure_rsaaes(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_GET_CALLBACK_DATA:
+ pm_get_callbackdata(result, ARRAY_SIZE(result));
+ SMC_RET2(handle,
+ (uint64_t)result[0] | ((uint64_t)result[1] << 32),
+ (uint64_t)result[2] | ((uint64_t)result[3] << 32));
+ case PM_IOCTL:
+ {
+ uint32_t value = 0;
+
+ ret = pm_ioctl(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+ }
+
+ case PM_QUERY_DATA:
+ {
+ uint32_t data[4] = { 0 };
+
+ pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], data);
+ SMC_RET2(handle, (uint64_t)data[0] | ((uint64_t)data[1] << 32),
+ (uint64_t)data[2] | ((uint64_t)data[3] << 32));
+ }
+
+ case PM_CLOCK_ENABLE:
+ ret = pm_clock_enable(pm_arg[0]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_CLOCK_DISABLE:
+ ret = pm_clock_disable(pm_arg[0]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_CLOCK_GETSTATE:
+ {
+ uint32_t value = 0;
+
+ ret = pm_clock_getstate(pm_arg[0], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+ }
+
+ case PM_CLOCK_SETDIVIDER:
+ ret = pm_clock_setdivider(pm_arg[0], pm_arg[1]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_CLOCK_GETDIVIDER:
+ {
+ uint32_t value = 0;
+
+ ret = pm_clock_getdivider(pm_arg[0], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32);
+ }
+
+ case PM_CLOCK_SETRATE:
+ ret = pm_clock_setrate(pm_arg[0],
+ ((uint64_t)pm_arg[2]) << 32 | pm_arg[1]);
+
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_CLOCK_GETRATE:
+ {
+ uint64_t value = 0;
+
+ ret = pm_clock_getrate(pm_arg[0], &value);
+ SMC_RET2(handle, (uint64_t)ret |
+ (((uint64_t)value & 0xFFFFFFFFU) << 32U),
+ (value >> 32U) & 0xFFFFFFFFU);
+
+ }
+
+ case PM_CLOCK_SETPARENT:
+ ret = pm_clock_setparent(pm_arg[0], pm_arg[1]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_CLOCK_GETPARENT:
+ {
+ uint32_t value = 0;
+
+ ret = pm_clock_getparent(pm_arg[0], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ case PM_GET_TRUSTZONE_VERSION:
+ SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS |
+ ((uint64_t)ZYNQMP_TZ_VERSION << 32U));
+
+ case PM_SET_SUSPEND_MODE:
+ ret = pm_set_suspend_mode(pm_arg[0]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_SECURE_SHA:
+ ret = pm_sha_hash(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_SECURE_RSA:
+ ret = pm_rsa_core(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_SECURE_IMAGE:
+ {
+ ret = pm_secure_image(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], &result[0]);
+ SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U),
+ result[1]);
+ }
+
+ case PM_FPGA_READ:
+ {
+ uint32_t value = 0;
+
+ ret = pm_fpga_read(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3],
+ &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ case PM_SECURE_AES:
+ {
+ uint32_t value = 0;
+
+ ret = pm_aes_engine(pm_arg[0], pm_arg[1], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ case PM_PLL_SET_PARAMETER:
+ ret = pm_pll_set_parameter(pm_arg[0], pm_arg[1], pm_arg[2]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_PLL_GET_PARAMETER:
+ {
+ uint32_t value = 0;
+
+ ret = pm_pll_get_parameter(pm_arg[0], pm_arg[1], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value << 32U));
+ }
+
+ case PM_PLL_SET_MODE:
+ ret = pm_pll_set_mode(pm_arg[0], pm_arg[1]);
+ SMC_RET1(handle, (uint64_t)ret);
+
+ case PM_PLL_GET_MODE:
+ {
+ uint32_t mode = 0;
+
+ ret = pm_pll_get_mode(pm_arg[0], &mode);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)mode << 32U));
+ }
+
+ case PM_REGISTER_ACCESS:
+ {
+ uint32_t value = 0;
+
+ ret = pm_register_access(pm_arg[0], pm_arg[1], pm_arg[2],
+ pm_arg[3], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ case PM_EFUSE_ACCESS:
+ {
+ uint32_t value = 0;
+
+#if defined(ZYNQMP_SECURE_EFUSES)
+ if (is_caller_non_secure(flags)) {
+ SMC_RET1(handle,
+ (((uint64_t)PM_RET_ERROR_NOT_ENABLED) << 32U) |
+ (uint64_t)PM_RET_ERROR_ACCESS);
+ }
+#endif
+ ret = pm_efuse_access(pm_arg[0], pm_arg[1], &value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ case PM_FPGA_GET_VERSION:
+ case PM_FPGA_GET_FEATURE_LIST:
+ {
+ uint32_t ret_payload[PAYLOAD_ARG_CNT];
+
+ PM_PACK_PAYLOAD5(payload, smc_fid & FUNCID_NUM_MASK,
+ pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]);
+ ret = pm_ipi_send_sync(primary_proc, payload, ret_payload, 3U);
+ SMC_RET2(handle, (uint64_t)ret | (uint64_t)ret_payload[0] << 32U,
+ (uint64_t)ret_payload[1] | (uint64_t)ret_payload[2] << 32U);
+ }
+
+ case PM_FEATURE_CHECK:
+ {
+ uint32_t version = 0;
+ uint32_t bit_mask[2] = {0};
+
+ ret = pm_feature_check(pm_arg[0], &version, bit_mask,
+ ARRAY_SIZE(bit_mask));
+ SMC_RET2(handle, (uint64_t)ret | ((uint64_t)version << 32U),
+ (uint64_t)bit_mask[0] | ((uint64_t)bit_mask[1] << 32U));
+ }
+
+ default:
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD6(payload, api_id, pm_arg[0], pm_arg[1],
+ pm_arg[2], pm_arg[3], pm_arg[4]);
+ ret = pm_ipi_send_sync(primary_proc, payload, result,
+ PAYLOAD_ARG_CNT);
+ SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32U),
+ (uint64_t)result[1] | ((uint64_t)result[2] << 32U));
+ }
+}
+
+/**
+ * em_smc_handler() - SMC handler for EM-API calls coming from EL1/EL2.
+ * @smc_fid - Function Identifier
+ * @x1 - x4 - Arguments
+ * @cookie - Unused
+ * @handler - Pointer to caller's context structure
+ *
+ * @return - Unused
+ *
+ * Determines that smc_fid is valid and supported EM SMC Function ID from the
+ * list of em_api_ids, otherwise completes the request with
+ * the unknown SMC Function ID
+ *
+ * The SMC calls for EM service are forwarded from SIP Service SMC handler
+ * function with rt_svc_handle signature
+ */
+uint64_t em_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)
+{
+ enum pm_ret_status ret;
+
+ switch (smc_fid & FUNCID_NUM_MASK) {
+ /* EM API Functions */
+ case EM_SET_ACTION:
+ {
+ uint32_t value;
+
+ ret = em_set_action(&value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ case EM_REMOVE_ACTION:
+ {
+ uint32_t value;
+
+ ret = em_remove_action(&value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ case EM_SEND_ERRORS:
+ {
+ uint32_t value;
+
+ ret = em_send_errors(&value);
+ SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32U);
+ }
+
+ default:
+ WARN("Unimplemented EM Service Call: 0x%x\n", smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.h b/plat/xilinx/zynqmp/pm_service/pm_svc_main.h
new file mode 100644
index 0000000..c1781f3
--- /dev/null
+++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef PM_SVC_MAIN_H
+#define PM_SVC_MAIN_H
+
+#include "pm_common.h"
+
+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);
+
+uint64_t em_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 /* PM_SVC_MAIN_H */
diff --git a/plat/xilinx/zynqmp/sip_svc_setup.c b/plat/xilinx/zynqmp/sip_svc_setup.c
new file mode 100644
index 0000000..4ce9b8a
--- /dev/null
+++ b/plat/xilinx/zynqmp/sip_svc_setup.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* Top level SMC handler for SiP calls. Dispatch PM calls to PM SMC handler. */
+
+#include <common/runtime_svc.h>
+#include <tools_share/uuid.h>
+
+#include "ipi_mailbox_svc.h"
+#include "pm_svc_main.h"
+
+/* SMC function IDs for SiP Service queries */
+#define ZYNQMP_SIP_SVC_CALL_COUNT U(0x8200ff00)
+#define ZYNQMP_SIP_SVC_UID U(0x8200ff01)
+#define ZYNQMP_SIP_SVC_VERSION U(0x8200ff03)
+
+/* SiP Service Calls version numbers */
+#define SIP_SVC_VERSION_MAJOR 0
+#define SIP_SVC_VERSION_MINOR 1
+
+/* These macros are used to identify PM, IPI calls from the SMC function ID */
+#define PM_FID_MASK 0xf000u
+#define PM_FID_VALUE 0u
+#define IPI_FID_VALUE 0x1000u
+#define EM_FID_MASK 0xf0000u
+#define EM_FID_VALUE 0xE0000u
+#define is_em_fid(_fid) (((_fid) & EM_FID_MASK) == EM_FID_VALUE)
+#define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE)
+#define is_ipi_fid(_fid) (((_fid) & PM_FID_MASK) == IPI_FID_VALUE)
+
+/* SiP Service UUID */
+DEFINE_SVC_UUID2(zynqmp_sip_uuid,
+ 0x5c9b1b2a, 0x0586, 0x2340, 0xa6, 0x1b,
+ 0xb9, 0x25, 0x82, 0x2d, 0xe3, 0xa5);
+
+/**
+ * sip_svc_setup() - Setup SiP Service
+ *
+ * Invokes PM setup
+ */
+static int32_t sip_svc_setup(void)
+{
+ /* PM implementation as SiP Service */
+ return pm_setup();
+}
+
+/**
+ * sip_svc_smc_handler() - Top-level SiP Service SMC handler
+ *
+ * Handler for all SiP SMC calls. Handles standard SIP requests
+ * and calls PM SMC handler if the call is for a PM-API function.
+ */
+static uintptr_t sip_svc_smc_handler(uint32_t smc_fid,
+ u_register_t x1,
+ u_register_t x2,
+ u_register_t x3,
+ u_register_t x4,
+ void *cookie,
+ void *handle,
+ u_register_t flags)
+{
+ /* Let EM SMC handler deal with EM-related requests */
+ if (is_em_fid(smc_fid)) {
+ return em_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+ flags);
+ } else if (is_pm_fid(smc_fid)) {
+ /* Let PM SMC handler deal with PM-related requests */
+ return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+ flags);
+ }
+
+ /* Let IPI SMC handler deal with IPI-related requests */
+ if (is_ipi_fid(smc_fid)) {
+ return ipi_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle,
+ flags);
+ }
+
+ switch (smc_fid) {
+ case ZYNQMP_SIP_SVC_CALL_COUNT:
+ /* PM functions + default functions */
+ SMC_RET1(handle, PM_API_MAX + 2);
+
+ case ZYNQMP_SIP_SVC_UID:
+ SMC_UUID_RET(handle, zynqmp_sip_uuid);
+
+ case ZYNQMP_SIP_SVC_VERSION:
+ SMC_RET2(handle, SIP_SVC_VERSION_MAJOR, SIP_SVC_VERSION_MINOR);
+
+ default:
+ WARN("Unimplemented SiP Service Call: 0x%x\n", smc_fid);
+ SMC_RET1(handle, SMC_UNK);
+ }
+}
+
+/* Register PM Service Calls as runtime service */
+DECLARE_RT_SVC(
+ sip_svc,
+ OEN_SIP_START,
+ OEN_SIP_END,
+ (uint8_t)SMC_TYPE_FAST,
+ sip_svc_setup,
+ sip_svc_smc_handler);
diff --git a/plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk b/plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk
new file mode 100644
index 0000000..318b01d
--- /dev/null
+++ b/plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk
@@ -0,0 +1,8 @@
+#
+# Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+
+# TSP source files specific to ZynqMP platform
+BL32_SOURCES += plat/common/aarch64/platform_mp_stack.S \
+ plat/xilinx/zynqmp/tsp/tsp_plat_setup.c
diff --git a/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c b/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c
new file mode 100644
index 0000000..352ba82
--- /dev/null
+++ b/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common/bl_common.h>
+#include <common/debug.h>
+#include <drivers/console.h>
+#include <plat/arm/common/plat_arm.h>
+#include <plat_private.h>
+#include <platform_tsp.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;
+ (void)console_cdns_register(ZYNQMP_UART_BASE,
+ zynqmp_get_uart_clk(),
+ ZYNQMP_UART_BAUDRATE,
+ &tsp_boot_console);
+ console_set_scope(&tsp_boot_console,
+ CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_BOOT);
+
+ /* Initialize the platform config for future decision making */
+ zynqmp_config_setup();
+}
+
+/*******************************************************************************
+ * Perform platform specific setup placeholder
+ ******************************************************************************/
+void tsp_platform_setup(void)
+{
+ plat_arm_gic_driver_init();
+ plat_arm_gic_init();
+}
+
+/*******************************************************************************
+ * Perform the very early platform specific architectural setup here. At the
+ * moment this is only intializes 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),
+ MAP_REGION_FLAT(BL_COHERENT_RAM_BASE,
+ BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE,
+ MT_DEVICE | MT_RW | MT_SECURE),
+ {0}
+ };
+
+ setup_page_tables(bl_regions, plat_arm_get_mmap());
+ enable_mmu_el1(0);
+}
diff --git a/plat/xilinx/zynqmp/zynqmp_ehf.c b/plat/xilinx/zynqmp/zynqmp_ehf.c
new file mode 100644
index 0000000..fbf1ed0
--- /dev/null
+++ b/plat/xilinx/zynqmp/zynqmp_ehf.c
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) Siemens AG, 2020-2021
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <platform_def.h>
+
+#include <bl31/ehf.h>
+
+/*
+ * Enumeration of priority levels on ARM platforms.
+ */
+ehf_pri_desc_t zynqmp_exceptions[] = {
+ /* Critical priority SDEI */
+ EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SDEI_CRITICAL_PRI),
+
+ /* Normal priority SDEI */
+ EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SDEI_NORMAL_PRI),
+};
+
+/* Plug in ARM exceptions to Exception Handling Framework. */
+EHF_REGISTER_PRIORITIES(zynqmp_exceptions, ARRAY_SIZE(zynqmp_exceptions), PLAT_PRI_BITS);
diff --git a/plat/xilinx/zynqmp/zynqmp_ipi.c b/plat/xilinx/zynqmp/zynqmp_ipi.c
new file mode 100644
index 0000000..4ea3c6a
--- /dev/null
+++ b/plat/xilinx/zynqmp/zynqmp_ipi.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/*
+ * Zynq UltraScale+ MPSoC 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_ipi.h>
+#include <plat_private.h>
+
+/* Zynqmp ipi configuration table */
+const static struct ipi_config zynqmp_ipi_table[] = {
+ /* APU IPI */
+ {
+ .ipi_bit_mask = 0x1,
+ .ipi_reg_base = 0xFF300000U,
+ .secure_only = 0,
+ },
+ /* RPU0 IPI */
+ {
+ .ipi_bit_mask = 0x100,
+ .ipi_reg_base = 0xFF310000U,
+ .secure_only = 0,
+ },
+ /* RPU1 IPI */
+ {
+ .ipi_bit_mask = 0x200,
+ .ipi_reg_base = 0xFF320000U,
+ .secure_only = 0,
+ },
+ /* PMU0 IPI */
+ {
+ .ipi_bit_mask = 0x10000,
+ .ipi_reg_base = 0xFF330000U,
+ .secure_only = IPI_SECURE_MASK,
+ },
+ /* PMU1 IPI */
+ {
+ .ipi_bit_mask = 0x20000,
+ .ipi_reg_base = 0xFF331000U,
+ .secure_only = 0,
+ },
+ /* PMU2 IPI */
+ {
+ .ipi_bit_mask = 0x40000,
+ .ipi_reg_base = 0xFF332000U,
+ .secure_only = IPI_SECURE_MASK,
+ },
+ /* PMU3 IPI */
+ {
+ .ipi_bit_mask = 0x80000,
+ .ipi_reg_base = 0xFF333000U,
+ .secure_only = IPI_SECURE_MASK,
+ },
+ /* PL0 IPI */
+ {
+ .ipi_bit_mask = 0x1000000,
+ .ipi_reg_base = 0xFF340000U,
+ .secure_only = 0,
+ },
+ /* PL1 IPI */
+ {
+ .ipi_bit_mask = 0x2000000,
+ .ipi_reg_base = 0xFF350000U,
+ .secure_only = 0,
+ },
+ /* PL2 IPI */
+ {
+ .ipi_bit_mask = 0x4000000,
+ .ipi_reg_base = 0xFF360000U,
+ .secure_only = 0,
+ },
+ /* PL3 IPI */
+ {
+ .ipi_bit_mask = 0x8000000,
+ .ipi_reg_base = 0xFF370000U,
+ .secure_only = 0,
+ },
+};
+
+/**
+ * zynqmp_ipi_config_table_init() - Initialize ZynqMP IPI configuration data
+ *
+ */
+void zynqmp_ipi_config_table_init(void)
+{
+ ipi_config_table_init(zynqmp_ipi_table, ARRAY_SIZE(zynqmp_ipi_table));
+}
diff --git a/plat/xilinx/zynqmp/zynqmp_sdei.c b/plat/xilinx/zynqmp/zynqmp_sdei.c
new file mode 100644
index 0000000..7e92b58
--- /dev/null
+++ b/plat/xilinx/zynqmp/zynqmp_sdei.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) Siemens AG, 2020-2021
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* SDEI configuration for ARM platforms */
+
+#include <bl31/ehf.h>
+#include <common/debug.h>
+#include <services/sdei.h>
+
+#include <plat/common/platform.h>
+#include <platform_def.h>
+
+int arm_validate_ns_entrypoint(uintptr_t entrypoint)
+{
+ return (entrypoint < BL31_BASE || entrypoint > BL31_LIMIT) ? 0 : -1;
+}
+
+/* Private event mappings */
+static sdei_ev_map_t zynqmp_sdei_private[] = {
+ SDEI_DEFINE_EVENT_0(ZYNQMP_SDEI_SGI_PRIVATE),
+};
+
+/* Shared event mappings */
+static sdei_ev_map_t zynqmp_sdei_shared[] = {
+};
+
+void plat_sdei_setup(void)
+{
+ INFO("SDEI platform setup\n");
+}
+
+/* Export ARM SDEI events */
+REGISTER_SDEI_MAP(zynqmp_sdei_private, zynqmp_sdei_shared);