Loading arch/arm/include/asm/psci.h +2 −2 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ struct psci_power_state { }; struct psci_operations { int (*cpu_suspend)(struct psci_power_state state, int (*cpu_suspend)(unsigned long state, unsigned long entry_point); int (*cpu_off)(struct psci_power_state state); int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); Loading @@ -33,7 +33,7 @@ struct psci_operations { unsigned long lowest_affinity_level); int (*migrate_info_type)(void); }; int cpu_psci_cpu_suspend(unsigned long state_id); extern struct psci_operations psci_ops; extern struct smp_operations psci_smp_ops; Loading arch/arm/kernel/psci.c +28 −4 Original line number Diff line number Diff line Loading @@ -25,8 +25,10 @@ #include <asm/errno.h> #include <asm/psci.h> #include <asm/system_misc.h> #include <asm/suspend.h> struct psci_operations psci_ops; #define PSCI_POWER_STATE_BIT BIT(30) static int (*invoke_psci_fn)(u32, u32, u32, u32); typedef int (*psci_initcall_t)(const struct device_node *); Loading Loading @@ -80,15 +82,14 @@ static int psci_get_version(void) return err; } static int psci_cpu_suspend(struct psci_power_state state, static int psci_cpu_suspend(unsigned long state_id, unsigned long entry_point) { int err; u32 fn, power_state; u32 fn; fn = psci_function_id[PSCI_FN_CPU_SUSPEND]; power_state = psci_power_state_pack(state); err = invoke_psci_fn(fn, power_state, entry_point, 0); err = invoke_psci_fn(fn, state_id, entry_point, 0); return psci_to_linux_errno(err); } Loading Loading @@ -176,6 +177,29 @@ static void psci_sys_poweroff(void) invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); } static int psci_suspend_finisher(unsigned long state_id) { return psci_ops.cpu_suspend(state_id, virt_to_phys(cpu_resume)); } /* * The PSCI changes are to support OS initiated low power mode where the * cluster mode aggregation happens in HLOS. In this case, the cpuidle * driver aggregating the cluster low power mode will provide the * composite stateID to be passed down to the PSCI layer. */ int cpu_psci_cpu_suspend(unsigned long state_id) { if (WARN_ON_ONCE(!state_id)) return -EINVAL; if (state_id & PSCI_POWER_STATE_BIT) return __cpu_suspend(state_id, psci_suspend_finisher); else return psci_ops.cpu_suspend(state_id, 0); } EXPORT_SYMBOL(cpu_psci_cpu_suspend); /* * PSCI Function IDs for v0.2+ are well defined so use * standard values. Loading drivers/cpuidle/lpm-levels.c +19 −1 Original line number Diff line number Diff line Loading @@ -810,10 +810,28 @@ bool psci_enter_sleep(struct lpm_cluster *cluster, int idx, bool from_idle) return success; } } #elif defined(CONFIG_ARM_PSCI) bool psci_enter_sleep(struct lpm_cluster *cluster, int idx, bool from_idle) { int affinity_level = 0; int state_id = get_cluster_id(cluster, &affinity_level); int power_state = PSCI_POWER_STATE(cluster->cpu->levels[idx].is_reset); affinity_level = PSCI_AFFINITY_LEVEL(affinity_level); if (!idx) { wfi(); return 1; } state_id |= (power_state | affinity_level | cluster->cpu->levels[idx].psci_id); return !cpu_suspend(state_id); } #else bool psci_enter_sleep(struct lpm_cluster *cluster, int idx, bool from_idle) { WARN_ONCE(true, "PSCI cpu_suspend ops not supported on V7\n"); WARN_ONCE(true, "PSCI cpu_suspend ops not supported\n"); return false; } #endif Loading Loading
arch/arm/include/asm/psci.h +2 −2 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ struct psci_power_state { }; struct psci_operations { int (*cpu_suspend)(struct psci_power_state state, int (*cpu_suspend)(unsigned long state, unsigned long entry_point); int (*cpu_off)(struct psci_power_state state); int (*cpu_on)(unsigned long cpuid, unsigned long entry_point); Loading @@ -33,7 +33,7 @@ struct psci_operations { unsigned long lowest_affinity_level); int (*migrate_info_type)(void); }; int cpu_psci_cpu_suspend(unsigned long state_id); extern struct psci_operations psci_ops; extern struct smp_operations psci_smp_ops; Loading
arch/arm/kernel/psci.c +28 −4 Original line number Diff line number Diff line Loading @@ -25,8 +25,10 @@ #include <asm/errno.h> #include <asm/psci.h> #include <asm/system_misc.h> #include <asm/suspend.h> struct psci_operations psci_ops; #define PSCI_POWER_STATE_BIT BIT(30) static int (*invoke_psci_fn)(u32, u32, u32, u32); typedef int (*psci_initcall_t)(const struct device_node *); Loading Loading @@ -80,15 +82,14 @@ static int psci_get_version(void) return err; } static int psci_cpu_suspend(struct psci_power_state state, static int psci_cpu_suspend(unsigned long state_id, unsigned long entry_point) { int err; u32 fn, power_state; u32 fn; fn = psci_function_id[PSCI_FN_CPU_SUSPEND]; power_state = psci_power_state_pack(state); err = invoke_psci_fn(fn, power_state, entry_point, 0); err = invoke_psci_fn(fn, state_id, entry_point, 0); return psci_to_linux_errno(err); } Loading Loading @@ -176,6 +177,29 @@ static void psci_sys_poweroff(void) invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); } static int psci_suspend_finisher(unsigned long state_id) { return psci_ops.cpu_suspend(state_id, virt_to_phys(cpu_resume)); } /* * The PSCI changes are to support OS initiated low power mode where the * cluster mode aggregation happens in HLOS. In this case, the cpuidle * driver aggregating the cluster low power mode will provide the * composite stateID to be passed down to the PSCI layer. */ int cpu_psci_cpu_suspend(unsigned long state_id) { if (WARN_ON_ONCE(!state_id)) return -EINVAL; if (state_id & PSCI_POWER_STATE_BIT) return __cpu_suspend(state_id, psci_suspend_finisher); else return psci_ops.cpu_suspend(state_id, 0); } EXPORT_SYMBOL(cpu_psci_cpu_suspend); /* * PSCI Function IDs for v0.2+ are well defined so use * standard values. Loading
drivers/cpuidle/lpm-levels.c +19 −1 Original line number Diff line number Diff line Loading @@ -810,10 +810,28 @@ bool psci_enter_sleep(struct lpm_cluster *cluster, int idx, bool from_idle) return success; } } #elif defined(CONFIG_ARM_PSCI) bool psci_enter_sleep(struct lpm_cluster *cluster, int idx, bool from_idle) { int affinity_level = 0; int state_id = get_cluster_id(cluster, &affinity_level); int power_state = PSCI_POWER_STATE(cluster->cpu->levels[idx].is_reset); affinity_level = PSCI_AFFINITY_LEVEL(affinity_level); if (!idx) { wfi(); return 1; } state_id |= (power_state | affinity_level | cluster->cpu->levels[idx].psci_id); return !cpu_suspend(state_id); } #else bool psci_enter_sleep(struct lpm_cluster *cluster, int idx, bool from_idle) { WARN_ONCE(true, "PSCI cpu_suspend ops not supported on V7\n"); WARN_ONCE(true, "PSCI cpu_suspend ops not supported\n"); return false; } #endif Loading