diff options
-rw-r--r-- | plat/xilinx/zynqmp/pm_service/pm_client.c | 28 | ||||
-rw-r--r-- | plat/xilinx/zynqmp/pm_service/pm_client.h | 1 | ||||
-rw-r--r-- | plat/xilinx/zynqmp/pm_service/pm_svc_main.c | 5 |
3 files changed, 34 insertions, 0 deletions
diff --git a/plat/xilinx/zynqmp/pm_service/pm_client.c b/plat/xilinx/zynqmp/pm_service/pm_client.c index 9016fd6f3..874b8a9ea 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_client.c +++ b/plat/xilinx/zynqmp/pm_service/pm_client.c @@ -26,10 +26,15 @@ #define NUM_GICD_ISENABLER ((IRQ_MAX >> 5) + 1) #define UNDEFINED_CPUID (~0) +#define PM_SUSPEND_MODE_STD 0 +#define PM_SUSPEND_MODE_POWER_OFF 1 + DEFINE_BAKERY_LOCK(pm_client_secure_lock); extern const struct pm_ipi apu_ipi; +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[] = { { @@ -165,6 +170,19 @@ static void pm_client_set_wakeup_sources(void) uint8_t pm_wakeup_nodes_set[NODE_MAX]; uintptr_t isenabler1 = BASE_GICD_BASE + GICD_ISENABLER + 4; + /* 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, 1); + /** + * 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 = 0; reg_num < NUM_GICD_ISENABLER; reg_num++) { @@ -305,3 +323,13 @@ void pm_client_wakeup(const struct pm_proc *proc) 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_client.h b/plat/xilinx/zynqmp/pm_service/pm_client.h index 16e37d592..070db8990 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_client.h +++ b/plat/xilinx/zynqmp/pm_service/pm_client.h @@ -20,6 +20,7 @@ void pm_client_suspend(const struct pm_proc *proc, unsigned int state); void pm_client_abort_suspend(void); void pm_client_wakeup(const struct pm_proc *proc); enum pm_ret_status set_ocm_retention(void); +enum pm_ret_status pm_set_suspend_mode(uint32_t mode); /* Global variables to be set in pm_client.c */ extern const struct pm_proc *primary_proc; diff --git a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c index ec9a93ecf..2906a41d3 100644 --- a/plat/xilinx/zynqmp/pm_service/pm_svc_main.c +++ b/plat/xilinx/zynqmp/pm_service/pm_svc_main.c @@ -19,6 +19,7 @@ #include "pm_ipi.h" #define PM_GET_CALLBACK_DATA 0xa01 +#define PM_SET_SUSPEND_MODE 0xa02 #define PM_GET_TRUSTZONE_VERSION 0xa03 /* 0 - UP, !0 - DOWN */ @@ -366,6 +367,10 @@ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS | ((uint64_t)ZYNQMP_TZ_VERSION << 32)); + case PM_SET_SUSPEND_MODE: + ret = pm_set_suspend_mode(pm_arg[0]); + SMC_RET1(handle, (uint64_t)ret); + default: WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid); SMC_RET1(handle, SMC_UNK); |