1 /* 2 * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 10 * Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * Neither the name of ARM nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific 16 * prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include <arch_helpers.h> 32 #include <arm_def.h> 33 #include <assert.h> 34 #include <errno.h> 35 #include <plat_arm.h> 36 #include <platform_def.h> 37 #include <psci.h> 38 39 /* Standard ARM platforms are expected to export plat_arm_psci_pm_ops */ 40 extern const plat_psci_ops_t plat_arm_psci_pm_ops; 41 42 #if ARM_RECOM_STATE_ID_ENC 43 extern unsigned int arm_pm_idle_states[]; 44 #endif /* __ARM_RECOM_STATE_ID_ENC__ */ 45 46 #if !ARM_RECOM_STATE_ID_ENC 47 /******************************************************************************* 48 * ARM standard platform handler called to check the validity of the power state 49 * parameter. 50 ******************************************************************************/ 51 int arm_validate_power_state(unsigned int power_state, 52 psci_power_state_t *req_state) 53 { 54 int pstate = psci_get_pstate_type(power_state); 55 int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 56 int i; 57 58 assert(req_state); 59 60 if (pwr_lvl > PLAT_MAX_PWR_LVL) 61 return PSCI_E_INVALID_PARAMS; 62 63 /* Sanity check the requested state */ 64 if (pstate == PSTATE_TYPE_STANDBY) { 65 /* 66 * It's possible to enter standby only on power level 0 67 * Ignore any other power level. 68 */ 69 if (pwr_lvl != ARM_PWR_LVL0) 70 return PSCI_E_INVALID_PARAMS; 71 72 req_state->pwr_domain_state[ARM_PWR_LVL0] = 73 ARM_LOCAL_STATE_RET; 74 } else { 75 for (i = ARM_PWR_LVL0; i <= pwr_lvl; i++) 76 req_state->pwr_domain_state[i] = 77 ARM_LOCAL_STATE_OFF; 78 } 79 80 /* 81 * We expect the 'state id' to be zero. 82 */ 83 if (psci_get_pstate_id(power_state)) 84 return PSCI_E_INVALID_PARAMS; 85 86 return PSCI_E_SUCCESS; 87 } 88 89 #else 90 /******************************************************************************* 91 * ARM standard platform handler called to check the validity of the power 92 * state parameter. The power state parameter has to be a composite power 93 * state. 94 ******************************************************************************/ 95 int arm_validate_power_state(unsigned int power_state, 96 psci_power_state_t *req_state) 97 { 98 unsigned int state_id; 99 int i; 100 101 assert(req_state); 102 103 /* 104 * Currently we are using a linear search for finding the matching 105 * entry in the idle power state array. This can be made a binary 106 * search if the number of entries justify the additional complexity. 107 */ 108 for (i = 0; !!arm_pm_idle_states[i]; i++) { 109 if (power_state == arm_pm_idle_states[i]) 110 break; 111 } 112 113 /* Return error if entry not found in the idle state array */ 114 if (!arm_pm_idle_states[i]) 115 return PSCI_E_INVALID_PARAMS; 116 117 i = 0; 118 state_id = psci_get_pstate_id(power_state); 119 120 /* Parse the State ID and populate the state info parameter */ 121 while (state_id) { 122 req_state->pwr_domain_state[i++] = state_id & 123 ARM_LOCAL_PSTATE_MASK; 124 state_id >>= ARM_LOCAL_PSTATE_WIDTH; 125 } 126 127 return PSCI_E_SUCCESS; 128 } 129 #endif /* __ARM_RECOM_STATE_ID_ENC__ */ 130 131 /******************************************************************************* 132 * ARM standard platform handler called to check the validity of the non secure 133 * entrypoint. 134 ******************************************************************************/ 135 int arm_validate_ns_entrypoint(uintptr_t entrypoint) 136 { 137 /* 138 * Check if the non secure entrypoint lies within the non 139 * secure DRAM. 140 */ 141 if ((entrypoint >= ARM_NS_DRAM1_BASE) && (entrypoint < 142 (ARM_NS_DRAM1_BASE + ARM_NS_DRAM1_SIZE))) 143 return PSCI_E_SUCCESS; 144 if ((entrypoint >= ARM_DRAM2_BASE) && (entrypoint < 145 (ARM_DRAM2_BASE + ARM_DRAM2_SIZE))) 146 return PSCI_E_SUCCESS; 147 148 return PSCI_E_INVALID_ADDRESS; 149 } 150 151 /******************************************************************************* 152 * Private function to program the mailbox for a cpu before it is released 153 * from reset. This function assumes that the Trusted mail box base is within 154 * the ARM_SHARED_RAM region 155 ******************************************************************************/ 156 static void arm_program_trusted_mailbox(uintptr_t address) 157 { 158 uintptr_t *mailbox = (void *) PLAT_ARM_TRUSTED_MAILBOX_BASE; 159 160 *mailbox = address; 161 162 /* 163 * Ensure that the PLAT_ARM_TRUSTED_MAILBOX_BASE is within 164 * ARM_SHARED_RAM region. 165 */ 166 assert((PLAT_ARM_TRUSTED_MAILBOX_BASE >= ARM_SHARED_RAM_BASE) && 167 ((PLAT_ARM_TRUSTED_MAILBOX_BASE + sizeof(*mailbox)) <= \ 168 (ARM_SHARED_RAM_BASE + ARM_SHARED_RAM_SIZE))); 169 170 /* Flush data cache if the mail box shared RAM is cached */ 171 #if PLAT_ARM_SHARED_RAM_CACHED 172 flush_dcache_range((uintptr_t) mailbox, sizeof(*mailbox)); 173 #endif 174 } 175 176 /******************************************************************************* 177 * The ARM Standard platform definition of platform porting API 178 * `plat_setup_psci_ops`. 179 ******************************************************************************/ 180 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 181 const plat_psci_ops_t **psci_ops) 182 { 183 *psci_ops = &plat_arm_psci_pm_ops; 184 185 /* Setup mailbox with entry point. */ 186 arm_program_trusted_mailbox(sec_entrypoint); 187 return 0; 188 } 189