Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'firmware/psci-1.0' of git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/linux into next/drivers

This pull request contains patches that enable PSCI 1.0 firmware
features for arm/arm64 platforms:

- Lorenzo Pieralisi adds support for the PSCI_FEATURES call, manages
various 1.0 specifications updates (power state id and functions return
values) and provides PSCI v1.0 DT bindings
- Sudeep Holla implements PSCI v1.0 system suspend support to enable PSCI
based suspend-to-RAM

* tag 'firmware/psci-1.0' of git://git.kernel.org/pub/scm/linux/kernel/git/lpieralisi/linux:
drivers: firmware: psci: add system suspend support
drivers: firmware: psci: define more generic PSCI_FN_NATIVE macro
drivers: firmware: psci: add PSCI v1.0 DT bindings
drivers: firmware: psci: add extended stateid power_state support
drivers: firmware: psci: add PSCI_FEATURES call
drivers: firmware: psci: move power_state handling to generic code
drivers: firmware: psci: add INVALID_ADDRESS return value

Signed-off-by: Olof Johansson <olof@lixom.net>

+123 -24
+6
Documentation/devicetree/bindings/arm/psci.txt
··· 31 31 support, but are permitted to be present for compatibility with 32 32 existing software when "arm,psci" is later in the compatible list. 33 33 34 + * "arm,psci-1.0" : for implementations complying to PSCI 1.0. PSCI 1.0 is 35 + backward compatible with PSCI 0.2 with minor specification updates, 36 + as defined in the PSCI specification[2]. 37 + 34 38 - method : The method of calling the PSCI firmware. Permitted 35 39 values are: 36 40 ··· 104 100 105 101 [1] Kernel documentation - ARM idle states bindings 106 102 Documentation/devicetree/bindings/arm/idle-states.txt 103 + [2] Power State Coordination Interface (PSCI) specification 104 + http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf
-14
arch/arm64/kernel/psci.c
··· 30 30 #include <asm/smp_plat.h> 31 31 #include <asm/suspend.h> 32 32 33 - static bool psci_power_state_loses_context(u32 state) 34 - { 35 - return state & PSCI_0_2_POWER_STATE_TYPE_MASK; 36 - } 37 - 38 - static bool psci_power_state_is_valid(u32 state) 39 - { 40 - const u32 valid_mask = PSCI_0_2_POWER_STATE_ID_MASK | 41 - PSCI_0_2_POWER_STATE_TYPE_MASK | 42 - PSCI_0_2_POWER_STATE_AFFL_MASK; 43 - 44 - return !(state & ~valid_mask); 45 - } 46 - 47 33 static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state); 48 34 49 35 static int __maybe_unused cpu_psci_cpu_init_idle(unsigned int cpu)
+97 -10
drivers/firmware/psci.c
··· 20 20 #include <linux/printk.h> 21 21 #include <linux/psci.h> 22 22 #include <linux/reboot.h> 23 + #include <linux/suspend.h> 23 24 24 25 #include <uapi/linux/psci.h> 25 26 26 27 #include <asm/cputype.h> 27 28 #include <asm/system_misc.h> 28 29 #include <asm/smp_plat.h> 30 + #include <asm/suspend.h> 29 31 30 32 /* 31 33 * While a 64-bit OS can make calls with SMC32 calling conventions, for some 32 - * calls it is necessary to use SMC64 to pass or return 64-bit values. For such 33 - * calls PSCI_0_2_FN_NATIVE(x) will choose the appropriate (native-width) 34 - * function ID. 34 + * calls it is necessary to use SMC64 to pass or return 64-bit values. 35 + * For such calls PSCI_FN_NATIVE(version, name) will choose the appropriate 36 + * (native-width) function ID. 35 37 */ 36 38 #ifdef CONFIG_64BIT 37 - #define PSCI_0_2_FN_NATIVE(name) PSCI_0_2_FN64_##name 39 + #define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN64_##name 38 40 #else 39 - #define PSCI_0_2_FN_NATIVE(name) PSCI_0_2_FN_##name 41 + #define PSCI_FN_NATIVE(version, name) PSCI_##version##_FN_##name 40 42 #endif 41 43 42 44 /* ··· 72 70 73 71 static u32 psci_function_id[PSCI_FN_MAX]; 74 72 73 + #define PSCI_0_2_POWER_STATE_MASK \ 74 + (PSCI_0_2_POWER_STATE_ID_MASK | \ 75 + PSCI_0_2_POWER_STATE_TYPE_MASK | \ 76 + PSCI_0_2_POWER_STATE_AFFL_MASK) 77 + 78 + #define PSCI_1_0_EXT_POWER_STATE_MASK \ 79 + (PSCI_1_0_EXT_POWER_STATE_ID_MASK | \ 80 + PSCI_1_0_EXT_POWER_STATE_TYPE_MASK) 81 + 82 + static u32 psci_cpu_suspend_feature; 83 + 84 + static inline bool psci_has_ext_power_state(void) 85 + { 86 + return psci_cpu_suspend_feature & 87 + PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK; 88 + } 89 + 90 + bool psci_power_state_loses_context(u32 state) 91 + { 92 + const u32 mask = psci_has_ext_power_state() ? 93 + PSCI_1_0_EXT_POWER_STATE_TYPE_MASK : 94 + PSCI_0_2_POWER_STATE_TYPE_MASK; 95 + 96 + return state & mask; 97 + } 98 + 99 + bool psci_power_state_is_valid(u32 state) 100 + { 101 + const u32 valid_mask = psci_has_ext_power_state() ? 102 + PSCI_1_0_EXT_POWER_STATE_MASK : 103 + PSCI_0_2_POWER_STATE_MASK; 104 + 105 + return !(state & ~valid_mask); 106 + } 107 + 75 108 static int psci_to_linux_errno(int errno) 76 109 { 77 110 switch (errno) { ··· 115 78 case PSCI_RET_NOT_SUPPORTED: 116 79 return -EOPNOTSUPP; 117 80 case PSCI_RET_INVALID_PARAMS: 81 + case PSCI_RET_INVALID_ADDRESS: 118 82 return -EINVAL; 119 83 case PSCI_RET_DENIED: 120 84 return -EPERM; ··· 172 134 static int psci_affinity_info(unsigned long target_affinity, 173 135 unsigned long lowest_affinity_level) 174 136 { 175 - return invoke_psci_fn(PSCI_0_2_FN_NATIVE(AFFINITY_INFO), 137 + return invoke_psci_fn(PSCI_FN_NATIVE(0_2, AFFINITY_INFO), 176 138 target_affinity, lowest_affinity_level, 0); 177 139 } 178 140 ··· 183 145 184 146 static unsigned long psci_migrate_info_up_cpu(void) 185 147 { 186 - return invoke_psci_fn(PSCI_0_2_FN_NATIVE(MIGRATE_INFO_UP_CPU), 148 + return invoke_psci_fn(PSCI_FN_NATIVE(0_2, MIGRATE_INFO_UP_CPU), 187 149 0, 0, 0); 188 150 } 189 151 ··· 217 179 static void psci_sys_poweroff(void) 218 180 { 219 181 invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); 182 + } 183 + 184 + static int __init psci_features(u32 psci_func_id) 185 + { 186 + return invoke_psci_fn(PSCI_1_0_FN_PSCI_FEATURES, 187 + psci_func_id, 0, 0); 188 + } 189 + 190 + static int psci_system_suspend(unsigned long unused) 191 + { 192 + return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND), 193 + virt_to_phys(cpu_resume), 0, 0); 194 + } 195 + 196 + static int psci_system_suspend_enter(suspend_state_t state) 197 + { 198 + return cpu_suspend(0, psci_system_suspend); 199 + } 200 + 201 + static const struct platform_suspend_ops psci_suspend_ops = { 202 + .valid = suspend_valid_only_mem, 203 + .enter = psci_system_suspend_enter, 204 + }; 205 + 206 + static void __init psci_init_system_suspend(void) 207 + { 208 + int ret; 209 + 210 + if (!IS_ENABLED(CONFIG_SUSPEND)) 211 + return; 212 + 213 + ret = psci_features(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND)); 214 + 215 + if (ret != PSCI_RET_NOT_SUPPORTED) 216 + suspend_set_ops(&psci_suspend_ops); 217 + } 218 + 219 + static void __init psci_init_cpu_suspend(void) 220 + { 221 + int feature = psci_features(psci_function_id[PSCI_FN_CPU_SUSPEND]); 222 + 223 + if (feature != PSCI_RET_NOT_SUPPORTED) 224 + psci_cpu_suspend_feature = feature; 220 225 } 221 226 222 227 /* ··· 305 224 static void __init psci_0_2_set_functions(void) 306 225 { 307 226 pr_info("Using standard PSCI v0.2 function IDs\n"); 308 - psci_function_id[PSCI_FN_CPU_SUSPEND] = PSCI_0_2_FN_NATIVE(CPU_SUSPEND); 227 + psci_function_id[PSCI_FN_CPU_SUSPEND] = 228 + PSCI_FN_NATIVE(0_2, CPU_SUSPEND); 309 229 psci_ops.cpu_suspend = psci_cpu_suspend; 310 230 311 231 psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF; 312 232 psci_ops.cpu_off = psci_cpu_off; 313 233 314 - psci_function_id[PSCI_FN_CPU_ON] = PSCI_0_2_FN_NATIVE(CPU_ON); 234 + psci_function_id[PSCI_FN_CPU_ON] = PSCI_FN_NATIVE(0_2, CPU_ON); 315 235 psci_ops.cpu_on = psci_cpu_on; 316 236 317 - psci_function_id[PSCI_FN_MIGRATE] = PSCI_0_2_FN_NATIVE(MIGRATE); 237 + psci_function_id[PSCI_FN_MIGRATE] = PSCI_FN_NATIVE(0_2, MIGRATE); 318 238 psci_ops.migrate = psci_migrate; 319 239 320 240 psci_ops.affinity_info = psci_affinity_info; ··· 346 264 psci_0_2_set_functions(); 347 265 348 266 psci_init_migrate(); 267 + 268 + psci_init_cpu_suspend(); 269 + 270 + psci_init_system_suspend(); 349 271 350 272 return 0; 351 273 } ··· 426 340 static const struct of_device_id const psci_of_match[] __initconst = { 427 341 { .compatible = "arm,psci", .data = psci_0_1_init}, 428 342 { .compatible = "arm,psci-0.2", .data = psci_0_2_init}, 343 + { .compatible = "arm,psci-1.0", .data = psci_0_2_init}, 429 344 {}, 430 345 }; 431 346
+2
include/linux/psci.h
··· 21 21 #define PSCI_POWER_STATE_TYPE_POWER_DOWN 1 22 22 23 23 bool psci_tos_resident_on(int cpu); 24 + bool psci_power_state_loses_context(u32 state); 25 + bool psci_power_state_is_valid(u32 state); 24 26 25 27 struct psci_operations { 26 28 int (*cpu_suspend)(u32 state, unsigned long entry_point);
+18
include/uapi/linux/psci.h
··· 46 46 #define PSCI_0_2_FN64_MIGRATE PSCI_0_2_FN64(5) 47 47 #define PSCI_0_2_FN64_MIGRATE_INFO_UP_CPU PSCI_0_2_FN64(7) 48 48 49 + #define PSCI_1_0_FN_PSCI_FEATURES PSCI_0_2_FN(10) 50 + #define PSCI_1_0_FN_SYSTEM_SUSPEND PSCI_0_2_FN(14) 51 + 52 + #define PSCI_1_0_FN64_SYSTEM_SUSPEND PSCI_0_2_FN64(14) 53 + 49 54 /* PSCI v0.2 power state encoding for CPU_SUSPEND function */ 50 55 #define PSCI_0_2_POWER_STATE_ID_MASK 0xffff 51 56 #define PSCI_0_2_POWER_STATE_ID_SHIFT 0 ··· 60 55 #define PSCI_0_2_POWER_STATE_AFFL_SHIFT 24 61 56 #define PSCI_0_2_POWER_STATE_AFFL_MASK \ 62 57 (0x3 << PSCI_0_2_POWER_STATE_AFFL_SHIFT) 58 + 59 + /* PSCI extended power state encoding for CPU_SUSPEND function */ 60 + #define PSCI_1_0_EXT_POWER_STATE_ID_MASK 0xfffffff 61 + #define PSCI_1_0_EXT_POWER_STATE_ID_SHIFT 0 62 + #define PSCI_1_0_EXT_POWER_STATE_TYPE_SHIFT 30 63 + #define PSCI_1_0_EXT_POWER_STATE_TYPE_MASK \ 64 + (0x1 << PSCI_1_0_EXT_POWER_STATE_TYPE_SHIFT) 63 65 64 66 /* PSCI v0.2 affinity level state returned by AFFINITY_INFO */ 65 67 #define PSCI_0_2_AFFINITY_LEVEL_ON 0 ··· 88 76 #define PSCI_VERSION_MINOR(ver) \ 89 77 ((ver) & PSCI_VERSION_MINOR_MASK) 90 78 79 + /* PSCI features decoding (>=1.0) */ 80 + #define PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT 1 81 + #define PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK \ 82 + (0x1 << PSCI_1_0_FEATURES_CPU_SUSPEND_PF_SHIFT) 83 + 91 84 /* PSCI return values (inclusive of all PSCI versions) */ 92 85 #define PSCI_RET_SUCCESS 0 93 86 #define PSCI_RET_NOT_SUPPORTED -1 ··· 103 86 #define PSCI_RET_INTERNAL_FAILURE -6 104 87 #define PSCI_RET_NOT_PRESENT -7 105 88 #define PSCI_RET_DISABLED -8 89 + #define PSCI_RET_INVALID_ADDRESS -9 106 90 107 91 #endif /* _UAPI_LINUX_PSCI_H */