diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index e1818529bd0926..736370d2e1f7cc 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -20,12 +20,14 @@ #include #include #include +#include #include #include #include #include +#include /* * While a 64-bit OS can make calls with SMC32 calling conventions, for some @@ -223,6 +225,33 @@ static int __init psci_features(u32 psci_func_id) psci_func_id, 0, 0); } +static int psci_system_suspend(unsigned long unused) +{ + return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), + virt_to_phys(cpu_resume), 0, 0); +} + +static int psci_system_suspend_enter(suspend_state_t state) +{ + return cpu_suspend(0, psci_system_suspend); +} + +static const struct platform_suspend_ops psci_suspend_ops = { + .valid = suspend_valid_only_mem, + .enter = psci_system_suspend_enter, +}; + +static void __init psci_init_system_suspend(void) +{ + if (!IS_ENABLED(CONFIG_SUSPEND)) + return; + + if (psci_features(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND))) + return; + + suspend_set_ops(&psci_suspend_ops); +} + static void __init psci_init_cpu_suspend(void) { int feature = psci_features(psci_function_id[PSCI_FN_CPU_SUSPEND]); @@ -318,6 +347,8 @@ static int __init psci_probe(void) psci_init_cpu_suspend(); + psci_init_system_suspend(); + return 0; } diff --git a/include/uapi/linux/psci.h b/include/uapi/linux/psci.h index 0a9485f3c6c370..3d7a0fc021a75a 100644 --- a/include/uapi/linux/psci.h +++ b/include/uapi/linux/psci.h @@ -47,6 +47,9 @@ #define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU PSCI_0_2_FN64(7) #define PSCI_1_0_FN_PSCI_FEATURES PSCI_0_2_FN(10) +#define PSCI_1_0_FN_SYSTEM_SUSPEND PSCI_0_2_FN(14) + +#define PSCI_1_0_FN64_SYSTEM_SUSPEND PSCI_0_2_FN64(14) /* PSCI v0.2 power state encoding for CPU_SUSPEND function */ #define PSCI_0_2_POWER_STATE_ID_MASK 0xffff