1*532ed618SSoby Mathew /* 2*532ed618SSoby Mathew * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. 3*532ed618SSoby Mathew * 4*532ed618SSoby Mathew * Redistribution and use in source and binary forms, with or without 5*532ed618SSoby Mathew * modification, are permitted provided that the following conditions are met: 6*532ed618SSoby Mathew * 7*532ed618SSoby Mathew * Redistributions of source code must retain the above copyright notice, this 8*532ed618SSoby Mathew * list of conditions and the following disclaimer. 9*532ed618SSoby Mathew * 10*532ed618SSoby Mathew * Redistributions in binary form must reproduce the above copyright notice, 11*532ed618SSoby Mathew * this list of conditions and the following disclaimer in the documentation 12*532ed618SSoby Mathew * and/or other materials provided with the distribution. 13*532ed618SSoby Mathew * 14*532ed618SSoby Mathew * Neither the name of ARM nor the names of its contributors may be used 15*532ed618SSoby Mathew * to endorse or promote products derived from this software without specific 16*532ed618SSoby Mathew * prior written permission. 17*532ed618SSoby Mathew * 18*532ed618SSoby Mathew * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19*532ed618SSoby Mathew * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*532ed618SSoby Mathew * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*532ed618SSoby Mathew * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22*532ed618SSoby Mathew * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23*532ed618SSoby Mathew * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24*532ed618SSoby Mathew * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25*532ed618SSoby Mathew * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26*532ed618SSoby Mathew * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27*532ed618SSoby Mathew * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*532ed618SSoby Mathew * POSSIBILITY OF SUCH DAMAGE. 29*532ed618SSoby Mathew */ 30*532ed618SSoby Mathew 31*532ed618SSoby Mathew #ifndef __PSCI_PRIVATE_H__ 32*532ed618SSoby Mathew #define __PSCI_PRIVATE_H__ 33*532ed618SSoby Mathew 34*532ed618SSoby Mathew #include <arch.h> 35*532ed618SSoby Mathew #include <bakery_lock.h> 36*532ed618SSoby Mathew #include <bl_common.h> 37*532ed618SSoby Mathew #include <cpu_data.h> 38*532ed618SSoby Mathew #include <pmf.h> 39*532ed618SSoby Mathew #include <psci.h> 40*532ed618SSoby Mathew #include <spinlock.h> 41*532ed618SSoby Mathew 42*532ed618SSoby Mathew /* 43*532ed618SSoby Mathew * The following helper macros abstract the interface to the Bakery 44*532ed618SSoby Mathew * Lock API. 45*532ed618SSoby Mathew */ 46*532ed618SSoby Mathew #define psci_lock_init(non_cpu_pd_node, idx) \ 47*532ed618SSoby Mathew ((non_cpu_pd_node)[(idx)].lock_index = (idx)) 48*532ed618SSoby Mathew #define psci_lock_get(non_cpu_pd_node) \ 49*532ed618SSoby Mathew bakery_lock_get(&psci_locks[(non_cpu_pd_node)->lock_index]) 50*532ed618SSoby Mathew #define psci_lock_release(non_cpu_pd_node) \ 51*532ed618SSoby Mathew bakery_lock_release(&psci_locks[(non_cpu_pd_node)->lock_index]) 52*532ed618SSoby Mathew 53*532ed618SSoby Mathew /* 54*532ed618SSoby Mathew * The PSCI capability which are provided by the generic code but does not 55*532ed618SSoby Mathew * depend on the platform or spd capabilities. 56*532ed618SSoby Mathew */ 57*532ed618SSoby Mathew #define PSCI_GENERIC_CAP \ 58*532ed618SSoby Mathew (define_psci_cap(PSCI_VERSION) | \ 59*532ed618SSoby Mathew define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) | \ 60*532ed618SSoby Mathew define_psci_cap(PSCI_FEATURES)) 61*532ed618SSoby Mathew 62*532ed618SSoby Mathew /* 63*532ed618SSoby Mathew * The PSCI capabilities mask for 64 bit functions. 64*532ed618SSoby Mathew */ 65*532ed618SSoby Mathew #define PSCI_CAP_64BIT_MASK \ 66*532ed618SSoby Mathew (define_psci_cap(PSCI_CPU_SUSPEND_AARCH64) | \ 67*532ed618SSoby Mathew define_psci_cap(PSCI_CPU_ON_AARCH64) | \ 68*532ed618SSoby Mathew define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) | \ 69*532ed618SSoby Mathew define_psci_cap(PSCI_MIG_AARCH64) | \ 70*532ed618SSoby Mathew define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64) | \ 71*532ed618SSoby Mathew define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64) | \ 72*532ed618SSoby Mathew define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64) | \ 73*532ed618SSoby Mathew define_psci_cap(PSCI_STAT_COUNT_AARCH64)) 74*532ed618SSoby Mathew 75*532ed618SSoby Mathew /* 76*532ed618SSoby Mathew * Helper macros to get/set the fields of PSCI per-cpu data. 77*532ed618SSoby Mathew */ 78*532ed618SSoby Mathew #define psci_set_aff_info_state(aff_state) \ 79*532ed618SSoby Mathew set_cpu_data(psci_svc_cpu_data.aff_info_state, aff_state) 80*532ed618SSoby Mathew #define psci_get_aff_info_state() \ 81*532ed618SSoby Mathew get_cpu_data(psci_svc_cpu_data.aff_info_state) 82*532ed618SSoby Mathew #define psci_get_aff_info_state_by_idx(idx) \ 83*532ed618SSoby Mathew get_cpu_data_by_index(idx, psci_svc_cpu_data.aff_info_state) 84*532ed618SSoby Mathew #define psci_set_aff_info_state_by_idx(idx, aff_state) \ 85*532ed618SSoby Mathew set_cpu_data_by_index(idx, psci_svc_cpu_data.aff_info_state,\ 86*532ed618SSoby Mathew aff_state) 87*532ed618SSoby Mathew #define psci_get_suspend_pwrlvl() \ 88*532ed618SSoby Mathew get_cpu_data(psci_svc_cpu_data.target_pwrlvl) 89*532ed618SSoby Mathew #define psci_set_suspend_pwrlvl(target_lvl) \ 90*532ed618SSoby Mathew set_cpu_data(psci_svc_cpu_data.target_pwrlvl, target_lvl) 91*532ed618SSoby Mathew #define psci_set_cpu_local_state(state) \ 92*532ed618SSoby Mathew set_cpu_data(psci_svc_cpu_data.local_state, state) 93*532ed618SSoby Mathew #define psci_get_cpu_local_state() \ 94*532ed618SSoby Mathew get_cpu_data(psci_svc_cpu_data.local_state) 95*532ed618SSoby Mathew #define psci_get_cpu_local_state_by_idx(idx) \ 96*532ed618SSoby Mathew get_cpu_data_by_index(idx, psci_svc_cpu_data.local_state) 97*532ed618SSoby Mathew 98*532ed618SSoby Mathew /* 99*532ed618SSoby Mathew * Helper macros for the CPU level spinlocks 100*532ed618SSoby Mathew */ 101*532ed618SSoby Mathew #define psci_spin_lock_cpu(idx) spin_lock(&psci_cpu_pd_nodes[idx].cpu_lock) 102*532ed618SSoby Mathew #define psci_spin_unlock_cpu(idx) spin_unlock(&psci_cpu_pd_nodes[idx].cpu_lock) 103*532ed618SSoby Mathew 104*532ed618SSoby Mathew /* Helper macro to identify a CPU standby request in PSCI Suspend call */ 105*532ed618SSoby Mathew #define is_cpu_standby_req(is_power_down_state, retn_lvl) \ 106*532ed618SSoby Mathew (((!(is_power_down_state)) && ((retn_lvl) == 0)) ? 1 : 0) 107*532ed618SSoby Mathew 108*532ed618SSoby Mathew /* Following are used as ID's to capture time-stamp */ 109*532ed618SSoby Mathew #define PSCI_STAT_ID_ENTER_LOW_PWR 0 110*532ed618SSoby Mathew #define PSCI_STAT_ID_EXIT_LOW_PWR 1 111*532ed618SSoby Mathew #define PSCI_STAT_TOTAL_IDS 2 112*532ed618SSoby Mathew 113*532ed618SSoby Mathew /* Declare PMF service functions for PSCI */ 114*532ed618SSoby Mathew PMF_DECLARE_CAPTURE_TIMESTAMP(psci_svc) 115*532ed618SSoby Mathew PMF_DECLARE_GET_TIMESTAMP(psci_svc) 116*532ed618SSoby Mathew 117*532ed618SSoby Mathew /******************************************************************************* 118*532ed618SSoby Mathew * The following two data structures implement the power domain tree. The tree 119*532ed618SSoby Mathew * is used to track the state of all the nodes i.e. power domain instances 120*532ed618SSoby Mathew * described by the platform. The tree consists of nodes that describe CPU power 121*532ed618SSoby Mathew * domains i.e. leaf nodes and all other power domains which are parents of a 122*532ed618SSoby Mathew * CPU power domain i.e. non-leaf nodes. 123*532ed618SSoby Mathew ******************************************************************************/ 124*532ed618SSoby Mathew typedef struct non_cpu_pwr_domain_node { 125*532ed618SSoby Mathew /* 126*532ed618SSoby Mathew * Index of the first CPU power domain node level 0 which has this node 127*532ed618SSoby Mathew * as its parent. 128*532ed618SSoby Mathew */ 129*532ed618SSoby Mathew unsigned int cpu_start_idx; 130*532ed618SSoby Mathew 131*532ed618SSoby Mathew /* 132*532ed618SSoby Mathew * Number of CPU power domains which are siblings of the domain indexed 133*532ed618SSoby Mathew * by 'cpu_start_idx' i.e. all the domains in the range 'cpu_start_idx 134*532ed618SSoby Mathew * -> cpu_start_idx + ncpus' have this node as their parent. 135*532ed618SSoby Mathew */ 136*532ed618SSoby Mathew unsigned int ncpus; 137*532ed618SSoby Mathew 138*532ed618SSoby Mathew /* 139*532ed618SSoby Mathew * Index of the parent power domain node. 140*532ed618SSoby Mathew * TODO: Figure out whether to whether using pointer is more efficient. 141*532ed618SSoby Mathew */ 142*532ed618SSoby Mathew unsigned int parent_node; 143*532ed618SSoby Mathew 144*532ed618SSoby Mathew plat_local_state_t local_state; 145*532ed618SSoby Mathew 146*532ed618SSoby Mathew unsigned char level; 147*532ed618SSoby Mathew 148*532ed618SSoby Mathew /* For indexing the psci_lock array*/ 149*532ed618SSoby Mathew unsigned char lock_index; 150*532ed618SSoby Mathew } non_cpu_pd_node_t; 151*532ed618SSoby Mathew 152*532ed618SSoby Mathew typedef struct cpu_pwr_domain_node { 153*532ed618SSoby Mathew u_register_t mpidr; 154*532ed618SSoby Mathew 155*532ed618SSoby Mathew /* 156*532ed618SSoby Mathew * Index of the parent power domain node. 157*532ed618SSoby Mathew * TODO: Figure out whether to whether using pointer is more efficient. 158*532ed618SSoby Mathew */ 159*532ed618SSoby Mathew unsigned int parent_node; 160*532ed618SSoby Mathew 161*532ed618SSoby Mathew /* 162*532ed618SSoby Mathew * A CPU power domain does not require state coordination like its 163*532ed618SSoby Mathew * parent power domains. Hence this node does not include a bakery 164*532ed618SSoby Mathew * lock. A spinlock is required by the CPU_ON handler to prevent a race 165*532ed618SSoby Mathew * when multiple CPUs try to turn ON the same target CPU. 166*532ed618SSoby Mathew */ 167*532ed618SSoby Mathew spinlock_t cpu_lock; 168*532ed618SSoby Mathew } cpu_pd_node_t; 169*532ed618SSoby Mathew 170*532ed618SSoby Mathew /******************************************************************************* 171*532ed618SSoby Mathew * Data prototypes 172*532ed618SSoby Mathew ******************************************************************************/ 173*532ed618SSoby Mathew extern const plat_psci_ops_t *psci_plat_pm_ops; 174*532ed618SSoby Mathew extern non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS]; 175*532ed618SSoby Mathew extern cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT]; 176*532ed618SSoby Mathew extern unsigned int psci_caps; 177*532ed618SSoby Mathew 178*532ed618SSoby Mathew /* One bakery lock is required for each non-cpu power domain */ 179*532ed618SSoby Mathew DECLARE_BAKERY_LOCK(psci_locks[PSCI_NUM_NON_CPU_PWR_DOMAINS]); 180*532ed618SSoby Mathew 181*532ed618SSoby Mathew /******************************************************************************* 182*532ed618SSoby Mathew * SPD's power management hooks registered with PSCI 183*532ed618SSoby Mathew ******************************************************************************/ 184*532ed618SSoby Mathew extern const spd_pm_ops_t *psci_spd_pm; 185*532ed618SSoby Mathew 186*532ed618SSoby Mathew /******************************************************************************* 187*532ed618SSoby Mathew * Function prototypes 188*532ed618SSoby Mathew ******************************************************************************/ 189*532ed618SSoby Mathew /* Private exported functions from psci_common.c */ 190*532ed618SSoby Mathew int psci_validate_power_state(unsigned int power_state, 191*532ed618SSoby Mathew psci_power_state_t *state_info); 192*532ed618SSoby Mathew void psci_query_sys_suspend_pwrstate(psci_power_state_t *state_info); 193*532ed618SSoby Mathew int psci_validate_mpidr(u_register_t mpidr); 194*532ed618SSoby Mathew void psci_init_req_local_pwr_states(void); 195*532ed618SSoby Mathew void psci_power_up_finish(void); 196*532ed618SSoby Mathew int psci_validate_entry_point(entry_point_info_t *ep, 197*532ed618SSoby Mathew uintptr_t entrypoint, u_register_t context_id); 198*532ed618SSoby Mathew void psci_get_parent_pwr_domain_nodes(unsigned int cpu_idx, 199*532ed618SSoby Mathew unsigned int end_lvl, 200*532ed618SSoby Mathew unsigned int node_index[]); 201*532ed618SSoby Mathew void psci_do_state_coordination(unsigned int end_pwrlvl, 202*532ed618SSoby Mathew psci_power_state_t *state_info); 203*532ed618SSoby Mathew void psci_acquire_pwr_domain_locks(unsigned int end_pwrlvl, 204*532ed618SSoby Mathew unsigned int cpu_idx); 205*532ed618SSoby Mathew void psci_release_pwr_domain_locks(unsigned int end_pwrlvl, 206*532ed618SSoby Mathew unsigned int cpu_idx); 207*532ed618SSoby Mathew int psci_validate_suspend_req(const psci_power_state_t *state_info, 208*532ed618SSoby Mathew unsigned int is_power_down_state_req); 209*532ed618SSoby Mathew unsigned int psci_find_max_off_lvl(const psci_power_state_t *state_info); 210*532ed618SSoby Mathew unsigned int psci_find_target_suspend_lvl(const psci_power_state_t *state_info); 211*532ed618SSoby Mathew void psci_set_pwr_domains_to_run(unsigned int end_pwrlvl); 212*532ed618SSoby Mathew void psci_print_power_domain_map(void); 213*532ed618SSoby Mathew unsigned int psci_is_last_on_cpu(void); 214*532ed618SSoby Mathew int psci_spd_migrate_info(u_register_t *mpidr); 215*532ed618SSoby Mathew 216*532ed618SSoby Mathew /* Private exported functions from psci_on.c */ 217*532ed618SSoby Mathew int psci_cpu_on_start(u_register_t target_cpu, 218*532ed618SSoby Mathew entry_point_info_t *ep); 219*532ed618SSoby Mathew 220*532ed618SSoby Mathew void psci_cpu_on_finish(unsigned int cpu_idx, 221*532ed618SSoby Mathew psci_power_state_t *state_info); 222*532ed618SSoby Mathew 223*532ed618SSoby Mathew /* Private exported functions from psci_off.c */ 224*532ed618SSoby Mathew int psci_do_cpu_off(unsigned int end_pwrlvl); 225*532ed618SSoby Mathew 226*532ed618SSoby Mathew /* Private exported functions from psci_suspend.c */ 227*532ed618SSoby Mathew void psci_cpu_suspend_start(entry_point_info_t *ep, 228*532ed618SSoby Mathew unsigned int end_pwrlvl, 229*532ed618SSoby Mathew psci_power_state_t *state_info, 230*532ed618SSoby Mathew unsigned int is_power_down_state_req); 231*532ed618SSoby Mathew 232*532ed618SSoby Mathew void psci_cpu_suspend_finish(unsigned int cpu_idx, 233*532ed618SSoby Mathew psci_power_state_t *state_info); 234*532ed618SSoby Mathew 235*532ed618SSoby Mathew /* Private exported functions from psci_helpers.S */ 236*532ed618SSoby Mathew void psci_do_pwrdown_cache_maintenance(unsigned int pwr_level); 237*532ed618SSoby Mathew void psci_do_pwrup_cache_maintenance(void); 238*532ed618SSoby Mathew 239*532ed618SSoby Mathew /* Private exported functions from psci_system_off.c */ 240*532ed618SSoby Mathew void __dead2 psci_system_off(void); 241*532ed618SSoby Mathew void __dead2 psci_system_reset(void); 242*532ed618SSoby Mathew 243*532ed618SSoby Mathew /* Private exported functions from psci_stat.c */ 244*532ed618SSoby Mathew void psci_stats_update_pwr_down(unsigned int end_pwrlvl, 245*532ed618SSoby Mathew const psci_power_state_t *state_info); 246*532ed618SSoby Mathew void psci_stats_update_pwr_up(unsigned int end_pwrlvl, 247*532ed618SSoby Mathew const psci_power_state_t *state_info, 248*532ed618SSoby Mathew unsigned int flags); 249*532ed618SSoby Mathew u_register_t psci_stat_residency(u_register_t target_cpu, 250*532ed618SSoby Mathew unsigned int power_state); 251*532ed618SSoby Mathew u_register_t psci_stat_count(u_register_t target_cpu, 252*532ed618SSoby Mathew unsigned int power_state); 253*532ed618SSoby Mathew 254*532ed618SSoby Mathew #endif /* __PSCI_PRIVATE_H__ */ 255