1b4315306SDan Handley /* 2b4315306SDan Handley * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. 3b4315306SDan Handley * 4b4315306SDan Handley * Redistribution and use in source and binary forms, with or without 5b4315306SDan Handley * modification, are permitted provided that the following conditions are met: 6b4315306SDan Handley * 7b4315306SDan Handley * Redistributions of source code must retain the above copyright notice, this 8b4315306SDan Handley * list of conditions and the following disclaimer. 9b4315306SDan Handley * 10b4315306SDan Handley * Redistributions in binary form must reproduce the above copyright notice, 11b4315306SDan Handley * this list of conditions and the following disclaimer in the documentation 12b4315306SDan Handley * and/or other materials provided with the distribution. 13b4315306SDan Handley * 14b4315306SDan Handley * Neither the name of ARM nor the names of its contributors may be used 15b4315306SDan Handley * to endorse or promote products derived from this software without specific 16b4315306SDan Handley * prior written permission. 17b4315306SDan Handley * 18b4315306SDan Handley * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19b4315306SDan Handley * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20b4315306SDan Handley * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21b4315306SDan Handley * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22b4315306SDan Handley * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23b4315306SDan Handley * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24b4315306SDan Handley * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25b4315306SDan Handley * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26b4315306SDan Handley * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27b4315306SDan Handley * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28b4315306SDan Handley * POSSIBILITY OF SUCH DAMAGE. 29b4315306SDan Handley */ 30b4315306SDan Handley 31b4315306SDan Handley #include <arch_helpers.h> 32f9e858b1SSoby Mathew #include <arm_def.h> 33b4315306SDan Handley #include <assert.h> 34b4315306SDan Handley #include <errno.h> 352204afdeSSoby Mathew #include <plat_arm.h> 36*785fb92bSSoby Mathew #include <platform_def.h> 37b4315306SDan Handley #include <psci.h> 38b4315306SDan Handley 39*785fb92bSSoby Mathew /* Standard ARM platforms are expected to export plat_arm_psci_pm_ops */ 40*785fb92bSSoby Mathew extern const plat_psci_ops_t plat_arm_psci_pm_ops; 41*785fb92bSSoby Mathew 422204afdeSSoby Mathew #if ARM_RECOM_STATE_ID_ENC 432204afdeSSoby Mathew extern unsigned int arm_pm_idle_states[]; 442204afdeSSoby Mathew #endif /* __ARM_RECOM_STATE_ID_ENC__ */ 452204afdeSSoby Mathew 462204afdeSSoby Mathew #if !ARM_RECOM_STATE_ID_ENC 47b4315306SDan Handley /******************************************************************************* 48b4315306SDan Handley * ARM standard platform handler called to check the validity of the power state 49b4315306SDan Handley * parameter. 50b4315306SDan Handley ******************************************************************************/ 5138dce70fSSoby Mathew int arm_validate_power_state(unsigned int power_state, 5238dce70fSSoby Mathew psci_power_state_t *req_state) 53b4315306SDan Handley { 5438dce70fSSoby Mathew int pstate = psci_get_pstate_type(power_state); 5538dce70fSSoby Mathew int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 5638dce70fSSoby Mathew int i; 5738dce70fSSoby Mathew 5838dce70fSSoby Mathew assert(req_state); 5938dce70fSSoby Mathew 6038dce70fSSoby Mathew if (pwr_lvl > PLAT_MAX_PWR_LVL) 61b4315306SDan Handley return PSCI_E_INVALID_PARAMS; 6238dce70fSSoby Mathew 6338dce70fSSoby Mathew /* Sanity check the requested state */ 6438dce70fSSoby Mathew if (pstate == PSTATE_TYPE_STANDBY) { 6538dce70fSSoby Mathew /* 6638dce70fSSoby Mathew * It's possible to enter standby only on power level 0 6738dce70fSSoby Mathew * Ignore any other power level. 6838dce70fSSoby Mathew */ 6938dce70fSSoby Mathew if (pwr_lvl != ARM_PWR_LVL0) 7038dce70fSSoby Mathew return PSCI_E_INVALID_PARAMS; 7138dce70fSSoby Mathew 7238dce70fSSoby Mathew req_state->pwr_domain_state[ARM_PWR_LVL0] = 7338dce70fSSoby Mathew ARM_LOCAL_STATE_RET; 7438dce70fSSoby Mathew } else { 7538dce70fSSoby Mathew for (i = ARM_PWR_LVL0; i <= pwr_lvl; i++) 7638dce70fSSoby Mathew req_state->pwr_domain_state[i] = 7738dce70fSSoby Mathew ARM_LOCAL_STATE_OFF; 78b4315306SDan Handley } 79b4315306SDan Handley 80b4315306SDan Handley /* 81b4315306SDan Handley * We expect the 'state id' to be zero. 82b4315306SDan Handley */ 83b4315306SDan Handley if (psci_get_pstate_id(power_state)) 84b4315306SDan Handley return PSCI_E_INVALID_PARAMS; 85b4315306SDan Handley 86b4315306SDan Handley return PSCI_E_SUCCESS; 87b4315306SDan Handley } 882204afdeSSoby Mathew 892204afdeSSoby Mathew #else 902204afdeSSoby Mathew /******************************************************************************* 912204afdeSSoby Mathew * ARM standard platform handler called to check the validity of the power 922204afdeSSoby Mathew * state parameter. The power state parameter has to be a composite power 932204afdeSSoby Mathew * state. 942204afdeSSoby Mathew ******************************************************************************/ 952204afdeSSoby Mathew int arm_validate_power_state(unsigned int power_state, 962204afdeSSoby Mathew psci_power_state_t *req_state) 972204afdeSSoby Mathew { 982204afdeSSoby Mathew unsigned int state_id; 992204afdeSSoby Mathew int i; 1002204afdeSSoby Mathew 1012204afdeSSoby Mathew assert(req_state); 1022204afdeSSoby Mathew 1032204afdeSSoby Mathew /* 1042204afdeSSoby Mathew * Currently we are using a linear search for finding the matching 1052204afdeSSoby Mathew * entry in the idle power state array. This can be made a binary 1062204afdeSSoby Mathew * search if the number of entries justify the additional complexity. 1072204afdeSSoby Mathew */ 1082204afdeSSoby Mathew for (i = 0; !!arm_pm_idle_states[i]; i++) { 1092204afdeSSoby Mathew if (power_state == arm_pm_idle_states[i]) 1102204afdeSSoby Mathew break; 1112204afdeSSoby Mathew } 1122204afdeSSoby Mathew 1132204afdeSSoby Mathew /* Return error if entry not found in the idle state array */ 1142204afdeSSoby Mathew if (!arm_pm_idle_states[i]) 1152204afdeSSoby Mathew return PSCI_E_INVALID_PARAMS; 1162204afdeSSoby Mathew 1172204afdeSSoby Mathew i = 0; 1182204afdeSSoby Mathew state_id = psci_get_pstate_id(power_state); 1192204afdeSSoby Mathew 1202204afdeSSoby Mathew /* Parse the State ID and populate the state info parameter */ 1212204afdeSSoby Mathew while (state_id) { 1222204afdeSSoby Mathew req_state->pwr_domain_state[i++] = state_id & 1232204afdeSSoby Mathew ARM_LOCAL_PSTATE_MASK; 1242204afdeSSoby Mathew state_id >>= ARM_LOCAL_PSTATE_WIDTH; 1252204afdeSSoby Mathew } 1262204afdeSSoby Mathew 1272204afdeSSoby Mathew return PSCI_E_SUCCESS; 1282204afdeSSoby Mathew } 1292204afdeSSoby Mathew #endif /* __ARM_RECOM_STATE_ID_ENC__ */ 130f9e858b1SSoby Mathew 131f9e858b1SSoby Mathew /******************************************************************************* 132f9e858b1SSoby Mathew * ARM standard platform handler called to check the validity of the non secure 133f9e858b1SSoby Mathew * entrypoint. 134f9e858b1SSoby Mathew ******************************************************************************/ 135f9e858b1SSoby Mathew int arm_validate_ns_entrypoint(uintptr_t entrypoint) 136f9e858b1SSoby Mathew { 137f9e858b1SSoby Mathew /* 138f9e858b1SSoby Mathew * Check if the non secure entrypoint lies within the non 139f9e858b1SSoby Mathew * secure DRAM. 140f9e858b1SSoby Mathew */ 141f9e858b1SSoby Mathew if ((entrypoint >= ARM_NS_DRAM1_BASE) && (entrypoint < 142f9e858b1SSoby Mathew (ARM_NS_DRAM1_BASE + ARM_NS_DRAM1_SIZE))) 143f9e858b1SSoby Mathew return PSCI_E_SUCCESS; 144f9e858b1SSoby Mathew if ((entrypoint >= ARM_DRAM2_BASE) && (entrypoint < 145f9e858b1SSoby Mathew (ARM_DRAM2_BASE + ARM_DRAM2_SIZE))) 146f9e858b1SSoby Mathew return PSCI_E_SUCCESS; 147f9e858b1SSoby Mathew 148f9e858b1SSoby Mathew return PSCI_E_INVALID_ADDRESS; 149f9e858b1SSoby Mathew } 150*785fb92bSSoby Mathew 151*785fb92bSSoby Mathew /******************************************************************************* 152*785fb92bSSoby Mathew * Private function to program the mailbox for a cpu before it is released 153*785fb92bSSoby Mathew * from reset. This function assumes that the Trusted mail box base is within 154*785fb92bSSoby Mathew * the ARM_SHARED_RAM region 155*785fb92bSSoby Mathew ******************************************************************************/ 156*785fb92bSSoby Mathew static void arm_program_trusted_mailbox(uintptr_t address) 157*785fb92bSSoby Mathew { 158*785fb92bSSoby Mathew uintptr_t *mailbox = (void *) PLAT_ARM_TRUSTED_MAILBOX_BASE; 159*785fb92bSSoby Mathew 160*785fb92bSSoby Mathew *mailbox = address; 161*785fb92bSSoby Mathew 162*785fb92bSSoby Mathew /* 163*785fb92bSSoby Mathew * Ensure that the PLAT_ARM_TRUSTED_MAILBOX_BASE is within 164*785fb92bSSoby Mathew * ARM_SHARED_RAM region. 165*785fb92bSSoby Mathew */ 166*785fb92bSSoby Mathew assert((PLAT_ARM_TRUSTED_MAILBOX_BASE >= ARM_SHARED_RAM_BASE) && 167*785fb92bSSoby Mathew ((PLAT_ARM_TRUSTED_MAILBOX_BASE + sizeof(*mailbox)) <= \ 168*785fb92bSSoby Mathew (ARM_SHARED_RAM_BASE + ARM_SHARED_RAM_SIZE))); 169*785fb92bSSoby Mathew 170*785fb92bSSoby Mathew /* Flush data cache if the mail box shared RAM is cached */ 171*785fb92bSSoby Mathew #if PLAT_ARM_SHARED_RAM_CACHED 172*785fb92bSSoby Mathew flush_dcache_range((uintptr_t) mailbox, sizeof(*mailbox)); 173*785fb92bSSoby Mathew #endif 174*785fb92bSSoby Mathew } 175*785fb92bSSoby Mathew 176*785fb92bSSoby Mathew /******************************************************************************* 177*785fb92bSSoby Mathew * The ARM Standard platform definition of platform porting API 178*785fb92bSSoby Mathew * `plat_setup_psci_ops`. 179*785fb92bSSoby Mathew ******************************************************************************/ 180*785fb92bSSoby Mathew int plat_setup_psci_ops(uintptr_t sec_entrypoint, 181*785fb92bSSoby Mathew const plat_psci_ops_t **psci_ops) 182*785fb92bSSoby Mathew { 183*785fb92bSSoby Mathew *psci_ops = &plat_arm_psci_pm_ops; 184*785fb92bSSoby Mathew 185*785fb92bSSoby Mathew /* Setup mailbox with entry point. */ 186*785fb92bSSoby Mathew arm_program_trusted_mailbox(sec_entrypoint); 187*785fb92bSSoby Mathew return 0; 188*785fb92bSSoby Mathew } 189