1b4315306SDan Handley /* 271d4e034SBoyan Karatotev * Copyright (c) 2015-2025, Arm Limited and Contributors. All rights reserved. 3b4315306SDan Handley * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 5b4315306SDan Handley */ 6b4315306SDan Handley 7b4315306SDan Handley #include <assert.h> 809d40e0eSAntonio Nino Diaz 9785fb92bSSoby Mathew #include <platform_def.h> 1009d40e0eSAntonio Nino Diaz 1109d40e0eSAntonio Nino Diaz #include <arch_helpers.h> 1209d40e0eSAntonio Nino Diaz #include <lib/psci/psci.h> 13bd9344f6SAntonio Nino Diaz #include <plat/arm/common/plat_arm.h> 1409d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 1509d40e0eSAntonio Nino Diaz 162a246d2eSDimitris Papastamos /* Allow ARM Standard platforms to override these functions */ 172a246d2eSDimitris Papastamos #pragma weak plat_arm_program_trusted_mailbox 185486a965SSoby Mathew 192204afdeSSoby Mathew #if !ARM_RECOM_STATE_ID_ENC 20b4315306SDan Handley /******************************************************************************* 21b4315306SDan Handley * ARM standard platform handler called to check the validity of the power state 22b4315306SDan Handley * parameter. 23b4315306SDan Handley ******************************************************************************/ arm_validate_power_state(unsigned int power_state,psci_power_state_t * req_state)2438dce70fSSoby Mathewint arm_validate_power_state(unsigned int power_state, 2538dce70fSSoby Mathew psci_power_state_t *req_state) 26b4315306SDan Handley { 272bc3dba9SAntonio Nino Diaz unsigned int pstate = psci_get_pstate_type(power_state); 282bc3dba9SAntonio Nino Diaz unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 292bc3dba9SAntonio Nino Diaz unsigned int i; 3038dce70fSSoby Mathew 31e02f469fSSathees Balya assert(req_state != NULL); 3238dce70fSSoby Mathew 3338dce70fSSoby Mathew if (pwr_lvl > PLAT_MAX_PWR_LVL) 34b4315306SDan Handley return PSCI_E_INVALID_PARAMS; 3538dce70fSSoby Mathew 3638dce70fSSoby Mathew /* Sanity check the requested state */ 3738dce70fSSoby Mathew if (pstate == PSTATE_TYPE_STANDBY) { 3838dce70fSSoby Mathew /* 3938dce70fSSoby Mathew * It's possible to enter standby only on power level 0 4038dce70fSSoby Mathew * Ignore any other power level. 4138dce70fSSoby Mathew */ 4238dce70fSSoby Mathew if (pwr_lvl != ARM_PWR_LVL0) 4338dce70fSSoby Mathew return PSCI_E_INVALID_PARAMS; 4438dce70fSSoby Mathew 4538dce70fSSoby Mathew req_state->pwr_domain_state[ARM_PWR_LVL0] = 4638dce70fSSoby Mathew ARM_LOCAL_STATE_RET; 4738dce70fSSoby Mathew } else { 4838dce70fSSoby Mathew for (i = ARM_PWR_LVL0; i <= pwr_lvl; i++) 4938dce70fSSoby Mathew req_state->pwr_domain_state[i] = 5038dce70fSSoby Mathew ARM_LOCAL_STATE_OFF; 51b4315306SDan Handley } 52b4315306SDan Handley 53b4315306SDan Handley /* 54b4315306SDan Handley * We expect the 'state id' to be zero. 55b4315306SDan Handley */ 562bc3dba9SAntonio Nino Diaz if (psci_get_pstate_id(power_state) != 0U) 57b4315306SDan Handley return PSCI_E_INVALID_PARAMS; 58b4315306SDan Handley 5971d4e034SBoyan Karatotev #if PSCI_OS_INIT_MODE 6071d4e034SBoyan Karatotev req_state->last_at_pwrlvl = psci_get_pstate_pwrlvl(power_state); 6171d4e034SBoyan Karatotev #endif /* __PSCI_OS_INIT_MODE__ */ 6271d4e034SBoyan Karatotev 63b4315306SDan Handley return PSCI_E_SUCCESS; 64b4315306SDan Handley } 652204afdeSSoby Mathew 662204afdeSSoby Mathew #else 672204afdeSSoby Mathew /******************************************************************************* 682204afdeSSoby Mathew * ARM standard platform handler called to check the validity of the power 692204afdeSSoby Mathew * state parameter. The power state parameter has to be a composite power 702204afdeSSoby Mathew * state. 712204afdeSSoby Mathew ******************************************************************************/ arm_validate_power_state(unsigned int power_state,psci_power_state_t * req_state)722204afdeSSoby Mathewint arm_validate_power_state(unsigned int power_state, 732204afdeSSoby Mathew psci_power_state_t *req_state) 742204afdeSSoby Mathew { 752204afdeSSoby Mathew unsigned int state_id; 762204afdeSSoby Mathew int i; 772204afdeSSoby Mathew 78e02f469fSSathees Balya assert(req_state != NULL); 792204afdeSSoby Mathew 802204afdeSSoby Mathew /* 812204afdeSSoby Mathew * Currently we are using a linear search for finding the matching 822204afdeSSoby Mathew * entry in the idle power state array. This can be made a binary 832204afdeSSoby Mathew * search if the number of entries justify the additional complexity. 842204afdeSSoby Mathew */ 852204afdeSSoby Mathew for (i = 0; !!arm_pm_idle_states[i]; i++) { 86e75cc247SWing Li if ((power_state & ~ARM_LAST_AT_PLVL_MASK) == 87e75cc247SWing Li arm_pm_idle_states[i]) 882204afdeSSoby Mathew break; 892204afdeSSoby Mathew } 902204afdeSSoby Mathew 912204afdeSSoby Mathew /* Return error if entry not found in the idle state array */ 922204afdeSSoby Mathew if (!arm_pm_idle_states[i]) 932204afdeSSoby Mathew return PSCI_E_INVALID_PARAMS; 942204afdeSSoby Mathew 952204afdeSSoby Mathew i = 0; 962204afdeSSoby Mathew state_id = psci_get_pstate_id(power_state); 972204afdeSSoby Mathew 982204afdeSSoby Mathew /* Parse the State ID and populate the state info parameter */ 99e75cc247SWing Li for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) { 100e75cc247SWing Li req_state->pwr_domain_state[i] = state_id & 1012204afdeSSoby Mathew ARM_LOCAL_PSTATE_MASK; 1022204afdeSSoby Mathew state_id >>= ARM_LOCAL_PSTATE_WIDTH; 1032204afdeSSoby Mathew } 104e75cc247SWing Li #if PSCI_OS_INIT_MODE 105e75cc247SWing Li req_state->last_at_pwrlvl = state_id & ARM_LOCAL_PSTATE_MASK; 106e75cc247SWing Li #endif /* __PSCI_OS_INIT_MODE__ */ 1072204afdeSSoby Mathew 1082204afdeSSoby Mathew return PSCI_E_SUCCESS; 1092204afdeSSoby Mathew } 1102204afdeSSoby Mathew #endif /* __ARM_RECOM_STATE_ID_ENC__ */ 111f9e858b1SSoby Mathew 112f9e858b1SSoby Mathew /******************************************************************************* 113f9e858b1SSoby Mathew * ARM standard platform handler called to check the validity of the non secure 11471e7a4e5SJeenu Viswambharan * entrypoint. Returns 0 if the entrypoint is valid, or -1 otherwise. 115f9e858b1SSoby Mathew ******************************************************************************/ arm_validate_ns_entrypoint(uintptr_t entrypoint)116f9e858b1SSoby Mathewint arm_validate_ns_entrypoint(uintptr_t entrypoint) 117f9e858b1SSoby Mathew { 118f9e858b1SSoby Mathew /* 119f9e858b1SSoby Mathew * Check if the non secure entrypoint lies within the non 120f9e858b1SSoby Mathew * secure DRAM. 121f9e858b1SSoby Mathew */ 122f9e858b1SSoby Mathew if ((entrypoint >= ARM_NS_DRAM1_BASE) && (entrypoint < 12371e7a4e5SJeenu Viswambharan (ARM_NS_DRAM1_BASE + ARM_NS_DRAM1_SIZE))) { 12471e7a4e5SJeenu Viswambharan return 0; 12571e7a4e5SJeenu Viswambharan } 126402b3cf8SJulius Werner #ifdef __aarch64__ 127f9e858b1SSoby Mathew if ((entrypoint >= ARM_DRAM2_BASE) && (entrypoint < 12871e7a4e5SJeenu Viswambharan (ARM_DRAM2_BASE + ARM_DRAM2_SIZE))) { 12971e7a4e5SJeenu Viswambharan return 0; 13071e7a4e5SJeenu Viswambharan } 1317c7dffd8Sdp-arm #endif 132f9e858b1SSoby Mathew 13371e7a4e5SJeenu Viswambharan return -1; 13471e7a4e5SJeenu Viswambharan } 13571e7a4e5SJeenu Viswambharan arm_validate_psci_entrypoint(uintptr_t entrypoint)13671e7a4e5SJeenu Viswambharanint arm_validate_psci_entrypoint(uintptr_t entrypoint) 13771e7a4e5SJeenu Viswambharan { 138e02f469fSSathees Balya return (arm_validate_ns_entrypoint(entrypoint) == 0) ? PSCI_E_SUCCESS : 13971e7a4e5SJeenu Viswambharan PSCI_E_INVALID_ADDRESS; 140f9e858b1SSoby Mathew } 141785fb92bSSoby Mathew 142c1bb8a05SSoby Mathew /****************************************************************************** 143e35a3fb5SSoby Mathew * Helper function to save the platform state before a system suspend. Save the 144e35a3fb5SSoby Mathew * state of the system components which are not in the Always ON power domain. 145e35a3fb5SSoby Mathew *****************************************************************************/ arm_system_pwr_domain_save(void)146e35a3fb5SSoby Mathewvoid arm_system_pwr_domain_save(void) 147e35a3fb5SSoby Mathew { 148e35a3fb5SSoby Mathew /* Assert system power domain is available on the platform */ 149e35a3fb5SSoby Mathew assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2); 150e35a3fb5SSoby Mathew 151*c5c54e20SBoyan Karatotev gic_save(); 152e35a3fb5SSoby Mathew 153e35a3fb5SSoby Mathew /* 15488a0523eSAntonio Nino Diaz * Unregister console now so that it is not registered for a second 15588a0523eSAntonio Nino Diaz * time during resume. 15688a0523eSAntonio Nino Diaz */ 15788a0523eSAntonio Nino Diaz arm_console_runtime_end(); 15888a0523eSAntonio Nino Diaz 15988a0523eSAntonio Nino Diaz /* 160e35a3fb5SSoby Mathew * All the other peripheral which are configured by ARM TF are 161e35a3fb5SSoby Mathew * re-initialized on resume from system suspend. Hence we 162e35a3fb5SSoby Mathew * don't save their state here. 163e35a3fb5SSoby Mathew */ 164e35a3fb5SSoby Mathew } 165e35a3fb5SSoby Mathew 166e35a3fb5SSoby Mathew /****************************************************************************** 167c1bb8a05SSoby Mathew * Helper function to resume the platform from system suspend. Reinitialize 168c1bb8a05SSoby Mathew * the system components which are not in the Always ON power domain. 169c1bb8a05SSoby Mathew * TODO: Unify the platform setup when waking up from cold boot and system 170c1bb8a05SSoby Mathew * resume in arm_bl31_platform_setup(). 171c1bb8a05SSoby Mathew *****************************************************************************/ arm_system_pwr_domain_resume(void)172c1bb8a05SSoby Mathewvoid arm_system_pwr_domain_resume(void) 173c1bb8a05SSoby Mathew { 17488a0523eSAntonio Nino Diaz /* Initialize the console */ 17588a0523eSAntonio Nino Diaz arm_console_runtime_init(); 176c1bb8a05SSoby Mathew 177c1bb8a05SSoby Mathew /* Assert system power domain is available on the platform */ 178c1bb8a05SSoby Mathew assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2); 179c1bb8a05SSoby Mathew 180*c5c54e20SBoyan Karatotev gic_resume(); 181e35a3fb5SSoby Mathew 182c1bb8a05SSoby Mathew plat_arm_security_setup(); 183c1bb8a05SSoby Mathew arm_configure_sys_timer(); 184c1bb8a05SSoby Mathew } 185c1bb8a05SSoby Mathew 186785fb92bSSoby Mathew /******************************************************************************* 1872a246d2eSDimitris Papastamos * ARM platform function to program the mailbox for a cpu before it is released 188785fb92bSSoby Mathew * from reset. This function assumes that the Trusted mail box base is within 189785fb92bSSoby Mathew * the ARM_SHARED_RAM region 190785fb92bSSoby Mathew ******************************************************************************/ plat_arm_program_trusted_mailbox(uintptr_t address)1912a246d2eSDimitris Papastamosvoid plat_arm_program_trusted_mailbox(uintptr_t address) 192785fb92bSSoby Mathew { 193785fb92bSSoby Mathew uintptr_t *mailbox = (void *) PLAT_ARM_TRUSTED_MAILBOX_BASE; 194785fb92bSSoby Mathew 195785fb92bSSoby Mathew *mailbox = address; 196785fb92bSSoby Mathew 197785fb92bSSoby Mathew /* 198785fb92bSSoby Mathew * Ensure that the PLAT_ARM_TRUSTED_MAILBOX_BASE is within 199785fb92bSSoby Mathew * ARM_SHARED_RAM region. 200785fb92bSSoby Mathew */ 201785fb92bSSoby Mathew assert((PLAT_ARM_TRUSTED_MAILBOX_BASE >= ARM_SHARED_RAM_BASE) && 2029a90d720SElyes Haouas ((PLAT_ARM_TRUSTED_MAILBOX_BASE + sizeof(*mailbox)) <= 203785fb92bSSoby Mathew (ARM_SHARED_RAM_BASE + ARM_SHARED_RAM_SIZE))); 204785fb92bSSoby Mathew } 205785fb92bSSoby Mathew 206785fb92bSSoby Mathew /******************************************************************************* 207785fb92bSSoby Mathew * The ARM Standard platform definition of platform porting API 208785fb92bSSoby Mathew * `plat_setup_psci_ops`. 209785fb92bSSoby Mathew ******************************************************************************/ plat_setup_psci_ops(uintptr_t sec_entrypoint,const plat_psci_ops_t ** psci_ops)2104d010d0dSDaniel Boulbyint __init plat_setup_psci_ops(uintptr_t sec_entrypoint, 211785fb92bSSoby Mathew const plat_psci_ops_t **psci_ops) 212785fb92bSSoby Mathew { 2135486a965SSoby Mathew *psci_ops = plat_arm_psci_override_pm_ops(&plat_arm_psci_pm_ops); 214785fb92bSSoby Mathew 215785fb92bSSoby Mathew /* Setup mailbox with entry point. */ 2162a246d2eSDimitris Papastamos plat_arm_program_trusted_mailbox(sec_entrypoint); 217785fb92bSSoby Mathew return 0; 218785fb92bSSoby Mathew } 219