summaryrefslogtreecommitdiff
path: root/plat/xilinx
diff options
context:
space:
mode:
authorTejas Patel <tejas.patel@xilinx.com>2019-12-08 23:29:44 -0800
committerJolly Shah <jolly.shah@xilinx.com>2020-01-15 11:01:47 -0800
commitfbb32695a27536818004e60772bd4240ae3cec1b (patch)
tree4d9edcca5b74f58508c56af88ea372dbacd5e0b6 /plat/xilinx
parent95794c732367ff2bc595f9226d70bb8d6eaaa1d8 (diff)
xilinx: versal: Add support for suspend related APIs
Add support for below suspend related APIs. - self_suspend - abort_suspend - request_suspend Signed-off-by: Tejas Patel <tejas.patel@xilinx.com> Signed-off-by: Jolly Shah <jolly.shah@xilinx.com> Change-Id: If568e0cd33b64754fe66f66fc0cdd0ec62c1b32e
Diffstat (limited to 'plat/xilinx')
-rw-r--r--plat/xilinx/versal/include/versal_def.h2
-rw-r--r--plat/xilinx/versal/pm_service/pm_api_sys.c115
-rw-r--r--plat/xilinx/versal/pm_service/pm_api_sys.h10
-rw-r--r--plat/xilinx/versal/pm_service/pm_client.c57
-rw-r--r--plat/xilinx/versal/pm_service/pm_client.h4
-rw-r--r--plat/xilinx/versal/pm_service/pm_defs.h10
6 files changed, 198 insertions, 0 deletions
diff --git a/plat/xilinx/versal/include/versal_def.h b/plat/xilinx/versal/include/versal_def.h
index 21883a1a9..a77fa30d0 100644
--- a/plat/xilinx/versal/include/versal_def.h
+++ b/plat/xilinx/versal/include/versal_def.h
@@ -105,6 +105,8 @@
#define FPD_APU_PWRCTL (FPD_APU_BASE + 0x90)
#define FPD_APU_CONFIG_0_VINITHI_SHIFT 8
+#define APU_0_PWRCTL_CPUPWRDWNREQ_MASK 1
+#define APU_1_PWRCTL_CPUPWRDWNREQ_MASK 2
/* IPI registers and bitfields */
#define IPI0_REG_BASE 0xFF330000
diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.c b/plat/xilinx/versal/pm_service/pm_api_sys.c
index 618624e88..16c2541b9 100644
--- a/plat/xilinx/versal/pm_service/pm_api_sys.c
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.c
@@ -11,6 +11,7 @@
#include <pm_common.h>
#include <pm_ipi.h>
+#include <plat/common/platform.h>
#include "pm_api_sys.h"
#include "pm_client.h"
@@ -27,6 +28,31 @@
pl[0] = (uint32_t)((uint32_t)((arg0) & 0xFF) | (mid << 8)); \
}
+#define PM_PACK_PAYLOAD2(pl, mid, arg0, arg1) { \
+ pl[1] = (uint32_t)(arg1); \
+ PM_PACK_PAYLOAD1(pl, mid, arg0); \
+}
+
+#define PM_PACK_PAYLOAD3(pl, mid, arg0, arg1, arg2) { \
+ pl[2] = (uint32_t)(arg2); \
+ PM_PACK_PAYLOAD2(pl, mid, arg0, arg1); \
+}
+
+#define PM_PACK_PAYLOAD4(pl, mid, arg0, arg1, arg2, arg3) { \
+ pl[3] = (uint32_t)(arg3); \
+ PM_PACK_PAYLOAD3(pl, mid, arg0, arg1, arg2); \
+}
+
+#define PM_PACK_PAYLOAD5(pl, mid, arg0, arg1, arg2, arg3, arg4) { \
+ pl[4] = (uint32_t)(arg4); \
+ PM_PACK_PAYLOAD4(pl, mid, arg0, arg1, arg2, arg3); \
+}
+
+#define PM_PACK_PAYLOAD6(pl, mid, arg0, arg1, arg2, arg3, arg4, arg5) { \
+ pl[5] = (uint32_t)(arg5); \
+ PM_PACK_PAYLOAD5(pl, mid, arg0, arg1, arg2, arg3, arg4); \
+}
+
/* PM API functions */
/**
@@ -43,3 +69,92 @@ enum pm_ret_status pm_get_api_version(unsigned int *version)
PM_PACK_PAYLOAD1(payload, LIBPM_MODULE_ID, PM_GET_API_VERSION);
return pm_ipi_send_sync(primary_proc, payload, version, 1);
}
+
+/**
+ * pm_self_suspend() - PM call for processor to suspend itself
+ * @nid Node id of the processor or subsystem
+ * @latency Requested maximum wakeup latency (not supported)
+ * @state Requested state
+ * @address Resume address
+ *
+ * This is a blocking call, it will return only once PMU has responded.
+ * On a wakeup, resume address will be automatically set by PMU.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_self_suspend(uint32_t nid,
+ unsigned int latency,
+ unsigned int state,
+ uintptr_t address)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+ unsigned int cpuid = plat_my_core_pos();
+ const struct pm_proc *proc = pm_get_proc(cpuid);
+
+ if (!proc) {
+ WARN("Failed to get proc %d\n", cpuid);
+ return PM_RET_ERROR_INTERNAL;
+ }
+
+ /*
+ * Do client specific suspend operations
+ * (e.g. set powerdown request bit)
+ */
+ pm_client_suspend(proc, state);
+
+ /* Send request to the PLM */
+ PM_PACK_PAYLOAD6(payload, LIBPM_MODULE_ID, PM_SELF_SUSPEND,
+ proc->node_id, latency, state, address,
+ (address >> 32));
+ return pm_ipi_send_sync(proc, payload, NULL, 0);
+}
+
+/**
+ * pm_abort_suspend() - PM call to announce that a prior suspend request
+ * is to be aborted.
+ * @reason Reason for the abort
+ *
+ * Calling PU expects the PMU to abort the initiated suspend procedure.
+ * This is a non-blocking call without any acknowledge.
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /*
+ * Do client specific abort suspend operations
+ * (e.g. enable interrupts and clear powerdown request bit)
+ */
+ pm_client_abort_suspend();
+
+ /* Send request to the PLM */
+ PM_PACK_PAYLOAD3(payload, LIBPM_MODULE_ID, PM_ABORT_SUSPEND, reason,
+ primary_proc->node_id);
+ return pm_ipi_send(primary_proc, payload);
+}
+
+/**
+ * pm_req_suspend() - PM call to request for another PU or subsystem to
+ * be suspended gracefully.
+ * @target Node id of the targeted PU or subsystem
+ * @ack Flag to specify whether acknowledge is requested
+ * @latency Requested wakeup latency (not supported)
+ * @state Requested state (not supported)
+ *
+ * @return Returns status, either success or error+reason
+ */
+enum pm_ret_status pm_req_suspend(uint32_t target, uint8_t ack,
+ unsigned int latency, unsigned int state)
+{
+ uint32_t payload[PAYLOAD_ARG_CNT];
+
+ /* Send request to the PMU */
+ PM_PACK_PAYLOAD4(payload, LIBPM_MODULE_ID, PM_REQ_SUSPEND, target,
+ latency, state);
+ if (ack == IPI_BLOCKING)
+ return pm_ipi_send_sync(primary_proc, payload, NULL, 0);
+ else
+ return pm_ipi_send(primary_proc, payload);
+}
diff --git a/plat/xilinx/versal/pm_service/pm_api_sys.h b/plat/xilinx/versal/pm_service/pm_api_sys.h
index 59f39524d..f67682329 100644
--- a/plat/xilinx/versal/pm_service/pm_api_sys.h
+++ b/plat/xilinx/versal/pm_service/pm_api_sys.h
@@ -8,11 +8,21 @@
#define PM_API_SYS_H
#include <stdint.h>
+#include "pm_defs.h"
/**********************************************************
* PM API function declarations
**********************************************************/
enum pm_ret_status pm_get_api_version(unsigned int *version);
+enum pm_ret_status pm_self_suspend(uint32_t nid,
+ unsigned int latency,
+ unsigned int state,
+ uintptr_t address);
+enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason);
+enum pm_ret_status pm_req_suspend(uint32_t target,
+ uint8_t ack,
+ unsigned int latency,
+ unsigned int state);
#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
index 6183b7822..636b719fd 100644
--- a/plat/xilinx/versal/pm_service/pm_client.c
+++ b/plat/xilinx/versal/pm_service/pm_client.c
@@ -13,6 +13,9 @@
#include <platform_def.h>
#include <versal_def.h>
#include <lib/bakery_lock.h>
+#include <lib/mmio.h>
+#include <drivers/arm/gicv3.h>
+#include <plat/common/platform.h>
#include "pm_client.h"
DEFINE_BAKERY_LOCK(pm_client_secure_lock);
@@ -28,11 +31,65 @@ 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];
+
+/**
+ * pm_client_suspend() - Client-specific suspend actions
+ *
+ * This function should contain any PU-specific actions
+ * required prior to sending suspend request to PMU
+ * Actions taken depend on the state system is suspending to.
+ */
+void pm_client_suspend(const struct pm_proc *proc, unsigned int state)
+{
+ bakery_lock_get(&pm_client_secure_lock);
+
+ /* Set powerdown request */
+ mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) |
+ proc->pwrdn_mask);
+
+ bakery_lock_release(&pm_client_secure_lock);
+}
+
+/**
+ * pm_client_abort_suspend() - Client-specific abort-suspend actions
+ *
+ * This function should contain any PU-specific actions
+ * required for aborting a prior suspend request
+ */
+void pm_client_abort_suspend(void)
+{
+ /* Enable interrupts at processor level (for current cpu) */
+ gicv3_cpuif_enable(plat_my_core_pos());
+
+ bakery_lock_get(&pm_client_secure_lock);
+
+ /* Clear powerdown request */
+ mmio_write_32(FPD_APU_PWRCTL, mmio_read_32(FPD_APU_PWRCTL) &
+ ~primary_proc->pwrdn_mask);
+
+ bakery_lock_release(&pm_client_secure_lock);
+}
+
+/**
+ * pm_get_proc() - returns pointer to the proc structure
+ * @cpuid: id of the cpu whose proc struct pointer should be returned
+ *
+ * Return: pointer to a proc structure if proc is found, otherwise NULL
+ */
+const struct pm_proc *pm_get_proc(unsigned int cpuid)
+{
+ if (cpuid < ARRAY_SIZE(pm_procs_all))
+ return &pm_procs_all[cpuid];
+
+ return NULL;
+}
diff --git a/plat/xilinx/versal/pm_service/pm_client.h b/plat/xilinx/versal/pm_service/pm_client.h
index 6840bb1dd..228094e67 100644
--- a/plat/xilinx/versal/pm_service/pm_client.h
+++ b/plat/xilinx/versal/pm_service/pm_client.h
@@ -15,6 +15,10 @@
#include "pm_common.h"
#include "pm_defs.h"
+/* Functions to be implemented by each PU */
+void pm_client_suspend(const struct pm_proc *proc, unsigned int state);
+void pm_client_abort_suspend(void);
+
/* Global variables to be set in pm_client.c */
extern const struct pm_proc *primary_proc;
diff --git a/plat/xilinx/versal/pm_service/pm_defs.h b/plat/xilinx/versal/pm_service/pm_defs.h
index ff3d26603..d482cb75a 100644
--- a/plat/xilinx/versal/pm_service/pm_defs.h
+++ b/plat/xilinx/versal/pm_service/pm_defs.h
@@ -24,11 +24,21 @@
/* PM API ids */
#define PM_GET_API_VERSION 1U
+#define PM_REQ_SUSPEND 6U
+#define PM_SELF_SUSPEND 7U
+#define PM_ABORT_SUSPEND 9U
/*********************************************************************
* Enum definitions
********************************************************************/
+enum pm_abort_reason {
+ ABORT_REASON_WKUP_EVENT = 100,
+ ABORT_REASON_PU_BUSY,
+ ABORT_REASON_NO_PWRDN,
+ ABORT_REASON_UNKNOWN,
+};
+
/**
* @PM_RET_SUCCESS: success
* @PM_RET_ERROR_ARGS: illegal arguments provided (deprecated)