[COMMON] arm64: kernel: Support customized suspend finisher
authorPark Bumgyu <bumgyu.park@samsung.com>
Tue, 3 May 2016 10:23:54 +0000 (19:23 +0900)
committerChungwoo Park <cww.park@samsung.com>
Mon, 21 May 2018 08:26:28 +0000 (17:26 +0900)
We hope that PSCI framework cover the all platform specific power
states, unfortunately PSCI can support only state managed by cpuidle.
Hence it is not correspond on Exynos.

psci_suspend_customized_finisher supports extra power state which
cpuidle does not handle such as system sleep, system idle clock
down and cluster power down.

Change-Id: I970f5ec2477de8e3fea2e10528bfc564b584c144
Signed-off-by: Park Bumgyu <bumgyu.park@samsung.com>
Signed-off-by: Youngtae Lee <yt0729.lee@samsung.com>
drivers/firmware/psci.c
include/linux/psci.h

index b7244b7b450775046e25c225d5e8a48c59f7fce9..2d7557c77e4b4e8c7a54b900302db2e8ed40af93 100644 (file)
@@ -422,6 +422,41 @@ static u32 psci_power_state_pack(u32 id, u32 type, u32 affinity_level)
                 & PSCI_0_2_POWER_STATE_AFFL_MASK);
 }
 
+/**
+ * We hope that PSCI framework cover the all platform specific power
+ * states, unfortunately PSCI can support only state managed by cpuidle.
+ * psci_suspend_customized_finisher supports extra power state which
+ * cpuidle does not handle. This function is only for Exynos.
+ */
+static int psci_suspend_customized_finisher(unsigned long index)
+{
+       u32 state;
+
+       switch (index) {
+       case PSCI_CLUSTER_SLEEP:
+               state = psci_power_state_pack(0, 0, 1);
+               break;
+       case PSCI_SYSTEM_IDLE:
+       case PSCI_SYSTEM_IDLE_AUDIO:
+               state = psci_power_state_pack(1, 0, 0);
+               break;
+       case PSCI_SYSTEM_IDLE_CLUSTER_SLEEP:
+               state = psci_power_state_pack(1, 0, 1);
+               break;
+       case PSCI_CP_CALL:
+               state = psci_power_state_pack(0, 0, 2);
+               break;
+       case PSCI_SYSTEM_SLEEP:
+               state = psci_power_state_pack(0, 0, 3);
+               break;
+       default:
+               panic("Unsupported psci state, index = %ld\n", index);
+               break;
+       };
+
+       return psci_ops.cpu_suspend(state, virt_to_phys(cpu_resume));
+}
+
 int psci_cpu_suspend_enter(unsigned long index)
 {
        int ret;
@@ -433,6 +468,9 @@ int psci_cpu_suspend_enter(unsigned long index)
        if (WARN_ON_ONCE(!index))
                return -EINVAL;
 
+       if (unlikely(index >= PSCI_UNUSED_INDEX))
+               return cpu_suspend(index, psci_suspend_customized_finisher);
+
        if (!psci_power_state_loses_context(state[index - 1]))
                ret = psci_ops.cpu_suspend(state[index - 1], 0);
        else
index 347077cf19c6928e87a780f38f768677cdcb9810..99095024eb869e68549d3bc358aefea1791e0f63 100644 (file)
 #include <linux/init.h>
 #include <linux/types.h>
 
+#define PSCI_UNUSED_INDEX              128
+#define PSCI_CLUSTER_SLEEP             (PSCI_UNUSED_INDEX)
+#define PSCI_SYSTEM_IDLE               (PSCI_UNUSED_INDEX + 1)
+#define PSCI_SYSTEM_IDLE_CLUSTER_SLEEP (PSCI_UNUSED_INDEX + 2)
+#define PSCI_SYSTEM_IDLE_AUDIO         (PSCI_UNUSED_INDEX + 3)
+#define PSCI_CP_CALL                   (PSCI_UNUSED_INDEX + 4)
+#define PSCI_SYSTEM_SLEEP              (PSCI_UNUSED_INDEX + 5)
+
 #define PSCI_POWER_STATE_TYPE_STANDBY          0
 #define PSCI_POWER_STATE_TYPE_POWER_DOWN       1