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