1 /* 2 * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <string.h> 9 10 #include <arch.h> 11 #include <arch_helpers.h> 12 #include <common/debug.h> 13 #include <lib/pmf/pmf.h> 14 #include <lib/runtime_instr.h> 15 #include <plat/common/platform.h> 16 17 #include "psci_private.h" 18 19 /****************************************************************************** 20 * Construct the psci_power_state to request power OFF at all power levels. 21 ******************************************************************************/ 22 static void psci_set_power_off_state(psci_power_state_t *state_info) 23 { 24 unsigned int lvl; 25 26 for (lvl = PSCI_CPU_PWR_LVL; lvl <= PLAT_MAX_PWR_LVL; lvl++) 27 state_info->pwr_domain_state[lvl] = PLAT_MAX_OFF_STATE; 28 } 29 30 /****************************************************************************** 31 * Top level handler which is called when a cpu wants to power itself down. 32 * It's assumed that along with turning the cpu power domain off, power 33 * domains at higher levels will be turned off as far as possible. It finds 34 * the highest level where a domain has to be powered off by traversing the 35 * node information and then performs generic, architectural, platform setup 36 * and state management required to turn OFF that power domain and domains 37 * below it. e.g. For a cpu that's to be powered OFF, it could mean programming 38 * the power controller whereas for a cluster that's to be powered off, it will 39 * call the platform specific code which will disable coherency at the 40 * interconnect level if the cpu is the last in the cluster and also the 41 * program the power controller. 42 ******************************************************************************/ 43 int psci_do_cpu_off(unsigned int end_pwrlvl) 44 { 45 int rc = PSCI_E_SUCCESS; 46 int idx = (int) plat_my_core_pos(); 47 psci_power_state_t state_info; 48 49 /* 50 * This function must only be called on platforms where the 51 * CPU_OFF platform hooks have been implemented. 52 */ 53 assert(psci_plat_pm_ops->pwr_domain_off != NULL); 54 55 /* Construct the psci_power_state for CPU_OFF */ 56 psci_set_power_off_state(&state_info); 57 58 /* 59 * This function acquires the lock corresponding to each power 60 * level so that by the time all locks are taken, the system topology 61 * is snapshot and state management can be done safely. 62 */ 63 psci_acquire_pwr_domain_locks(end_pwrlvl, idx); 64 65 /* 66 * Call the cpu off handler registered by the Secure Payload Dispatcher 67 * to let it do any bookkeeping. Assume that the SPD always reports an 68 * E_DENIED error if SP refuse to power down 69 */ 70 if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_off != NULL)) { 71 rc = psci_spd_pm->svc_off(0); 72 if (rc != 0) 73 goto exit; 74 } 75 76 /* 77 * This function is passed the requested state info and 78 * it returns the negotiated state info for each power level upto 79 * the end level specified. 80 */ 81 psci_do_state_coordination(end_pwrlvl, &state_info); 82 83 #if ENABLE_PSCI_STAT 84 /* Update the last cpu for each level till end_pwrlvl */ 85 psci_stats_update_pwr_down(end_pwrlvl, &state_info); 86 #endif 87 88 #if ENABLE_RUNTIME_INSTRUMENTATION 89 90 /* 91 * Flush cache line so that even if CPU power down happens 92 * the timestamp update is reflected in memory. 93 */ 94 PMF_CAPTURE_TIMESTAMP(rt_instr_svc, 95 RT_INSTR_ENTER_CFLUSH, 96 PMF_CACHE_MAINT); 97 #endif 98 99 /* 100 * Arch. management. Initiate power down sequence. 101 */ 102 psci_do_pwrdown_sequence(psci_find_max_off_lvl(&state_info)); 103 104 #if ENABLE_RUNTIME_INSTRUMENTATION 105 PMF_CAPTURE_TIMESTAMP(rt_instr_svc, 106 RT_INSTR_EXIT_CFLUSH, 107 PMF_NO_CACHE_MAINT); 108 #endif 109 110 /* 111 * Plat. management: Perform platform specific actions to turn this 112 * cpu off e.g. exit cpu coherency, program the power controller etc. 113 */ 114 psci_plat_pm_ops->pwr_domain_off(&state_info); 115 116 #if ENABLE_PSCI_STAT 117 plat_psci_stat_accounting_start(&state_info); 118 #endif 119 120 exit: 121 /* 122 * Release the locks corresponding to each power level in the 123 * reverse order to which they were acquired. 124 */ 125 psci_release_pwr_domain_locks(end_pwrlvl, idx); 126 127 /* 128 * Check if all actions needed to safely power down this cpu have 129 * successfully completed. 130 */ 131 if (rc == PSCI_E_SUCCESS) { 132 /* 133 * Set the affinity info state to OFF. When caches are disabled, 134 * this writes directly to main memory, so cache maintenance is 135 * required to ensure that later cached reads of aff_info_state 136 * return AFF_STATE_OFF. A dsbish() ensures ordering of the 137 * update to the affinity info state prior to cache line 138 * invalidation. 139 */ 140 psci_flush_cpu_data(psci_svc_cpu_data.aff_info_state); 141 psci_set_aff_info_state(AFF_STATE_OFF); 142 psci_dsbish(); 143 psci_inv_cpu_data(psci_svc_cpu_data.aff_info_state); 144 145 #if ENABLE_RUNTIME_INSTRUMENTATION 146 147 /* 148 * Update the timestamp with cache off. We assume this 149 * timestamp can only be read from the current CPU and the 150 * timestamp cache line will be flushed before return to 151 * normal world on wakeup. 152 */ 153 PMF_CAPTURE_TIMESTAMP(rt_instr_svc, 154 RT_INSTR_ENTER_HW_LOW_PWR, 155 PMF_NO_CACHE_MAINT); 156 #endif 157 158 if (psci_plat_pm_ops->pwr_domain_pwr_down_wfi != NULL) { 159 /* This function must not return */ 160 psci_plat_pm_ops->pwr_domain_pwr_down_wfi(&state_info); 161 } else { 162 /* 163 * Enter a wfi loop which will allow the power 164 * controller to physically power down this cpu. 165 */ 166 psci_power_down_wfi(); 167 } 168 } 169 170 return rc; 171 } 172