zynqmp: pm: Add support for setting suspend-to-RAM mode
authorSiva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
Fri, 27 Apr 2018 10:56:47 +0000 (16:26 +0530)
committerSiva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
Thu, 17 May 2018 09:41:33 +0000 (15:11 +0530)
Beside standard suspend-to-RAM state, Zynq MPSoC supports
suspend-to-RAM state with additional power savings, called
power-off suspend-to-RAM. If this mode is set, only NODE_EXTERN
must be set as wake source. Standard suspend-to-RAM procedure
is unchanged.

This patch adds support for setting suspend mode from higher
ELs and ensuring that all conditions for power-off suspend mode
are set.

Signed-off-by: Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
Signed-off-by: Filip Drazic <filip.drazic@aggios.com>
plat/xilinx/zynqmp/pm_service/pm_client.c
plat/xilinx/zynqmp/pm_service/pm_client.h
plat/xilinx/zynqmp/pm_service/pm_svc_main.c

index 9016fd6f33d9c00e648e3dcaa7d2532570e7810c..874b8a9eac9eb5200efa5b699b227add3d5ce3d2 100644 (file)
 #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;
+}
index 16e37d59225ff76ec7ff2c41b93d9eeabf31e68e..070db89908dd4b5a316fd12f6a65e57c7d897992 100644 (file)
@@ -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;
index ec9a93ecfd3a0110a68ebbf7e7e102494cff16d6..2906a41d39af2072ca92f6ea2781d01124a78917 100644 (file)
@@ -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);