[PATCH/RFC 4/6] drivers: firmware: psci: Fix non-PMIC wake-up if SYSTEM_SUSPEND cuts power

From: Geert Uytterhoeven
Date: Mon Feb 20 2017 - 15:34:10 EST


Nothing in the PSCI specification requires the SoC to remain powered and
to support wake-up sources when suspended using SYSTEM_SUSPEND.
If the firmware implements the PSCI SYSTEM_SUSPEND operation by cutting
power to the SoC, the only possibly wake-up sources are thus the ones
connected to the PMIC.

Document and add support for an "arm,psci-system-suspend-is-power-down"
DT property, so Linux uses a different suspend method when other wake-up
sources (e.g. wake on LAN, UART or GPIO) are enabled.

Signed-off-by: Geert Uytterhoeven <geert+renesas@xxxxxxxxx>
---
Documentation/devicetree/bindings/arm/psci.txt | 11 +++++++++++
drivers/firmware/psci.c | 13 ++++++++++---
2 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/psci.txt b/Documentation/devicetree/bindings/arm/psci.txt
index a2c4f1d524929bb7..16e390ecb7531028 100644
--- a/Documentation/devicetree/bindings/arm/psci.txt
+++ b/Documentation/devicetree/bindings/arm/psci.txt
@@ -68,6 +68,17 @@ state nodes, as per bindings in [1]) must specify the following properties:
Definition: power_state parameter to pass to the PSCI
suspend call.

+ - arm,psci-system-suspend-is-power-down
+ Nothing in the PSCI specification requires the SoC to remain
+ powered and to support wake-up sources when suspended using
+ SYSTEM_SUSPEND.
+ If your firmware implements the PSCI SYSTEM_SUSPEND operation
+ by cutting power to the SoC, the only possibly wake-up sources
+ are thus the ones connected to the PMIC. In such case you
+ should specify this property, so the operating system is aware
+ it should use a different suspend method when other wake-up
+ sources (e.g. wake on LAN, UART or GPIO) are enabled.
+
Example:

Case 1: PSCI v0.1 only.
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c
index 13b4d50bb3577384..0a74c23fd5fe043e 100644
--- a/drivers/firmware/psci.c
+++ b/drivers/firmware/psci.c
@@ -20,6 +20,7 @@
#include <linux/linkage.h>
#include <linux/of.h>
#include <linux/pm.h>
+#include <linux/pm_wakeup.h>
#include <linux/printk.h>
#include <linux/psci.h>
#include <linux/reboot.h>
@@ -86,6 +87,7 @@ static u32 psci_function_id[PSCI_FN_MAX];

static u32 psci_cpu_suspend_feature;
static bool psci_suspend_mem_supported;
+static bool psci_system_suspend_is_power_down;

static inline bool psci_has_ext_power_state(void)
{
@@ -440,12 +442,14 @@ static int psci_system_suspend_valid(suspend_state_t state)
static int psci_system_suspend_enter(suspend_state_t state)
{
switch (state) {
+ case PM_SUSPEND_MEM:
+ if (!psci_system_suspend_is_power_down ||
+ !wakeup_source_available())
+ return cpu_suspend(0, psci_system_suspend);
+ /* fall through */
case PM_SUSPEND_STANDBY:
cpu_do_idle();
break;
-
- case PM_SUSPEND_MEM:
- return cpu_suspend(0, psci_system_suspend);
}

return 0;
@@ -596,6 +600,9 @@ static int __init psci_0_2_init(struct device_node *np)
*/
err = psci_probe();

+ psci_system_suspend_is_power_down = of_property_read_bool(np,
+ "arm,psci-system-suspend-is-power-down");
+
out_put_node:
of_node_put(np);
return err;
--
2.7.4