diff options
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/psci.c | 34 |
1 files changed, 32 insertions, 2 deletions
diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index cec948b4ccd5..384224320455 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -75,14 +75,34 @@ static u32 psci_function_id[PSCI_FN_MAX]; PSCI_0_2_POWER_STATE_TYPE_MASK | \ PSCI_0_2_POWER_STATE_AFFL_MASK) +#define PSCI_1_0_EXT_POWER_STATE_MASK \ + (PSCI_1_0_EXT_POWER_STATE_ID_MASK | \ + PSCI_1_0_EXT_POWER_STATE_TYPE_MASK) + +static u32 psci_cpu_suspend_feature; + +static inline bool psci_has_ext_power_state(void) +{ + return psci_cpu_suspend_feature & + PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK; +} + bool psci_power_state_loses_context(u32 state) { - return state & PSCI_0_2_POWER_STATE_TYPE_MASK; + const u32 mask = psci_has_ext_power_state() ? + PSCI_1_0_EXT_POWER_STATE_TYPE_MASK : + PSCI_0_2_POWER_STATE_TYPE_MASK; + + return state & mask; } bool psci_power_state_is_valid(u32 state) { - return !(state & ~PSCI_0_2_POWER_STATE_MASK); + const u32 valid_mask = psci_has_ext_power_state() ? + PSCI_1_0_EXT_POWER_STATE_MASK : + PSCI_0_2_POWER_STATE_MASK; + + return !(state & ~valid_mask); } static int psci_to_linux_errno(int errno) @@ -203,6 +223,14 @@ static int __init psci_features(u32 psci_func_id) psci_func_id, 0, 0); } +static void __init psci_init_cpu_suspend(void) +{ + int feature = psci_features(psci_function_id[PSCI_FN_CPU_SUSPEND]); + + if (feature != PSCI_RET_NOT_SUPPORTED) + psci_cpu_suspend_feature = feature; +} + /* * Detect the presence of a resident Trusted OS which may cause CPU_OFF to * return DENIED (which would be fatal). @@ -287,6 +315,8 @@ static int __init psci_probe(void) psci_init_migrate(); + psci_init_cpu_suspend(); + return 0; } |