1b4315306SDan Handley /* 288a0523eSAntonio Nino Diaz * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. 3b4315306SDan Handley * 482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause 5b4315306SDan Handley */ 6b4315306SDan Handley 7b4315306SDan Handley #include <arch_helpers.h> 8f9e858b1SSoby Mathew #include <arm_def.h> 9c1bb8a05SSoby Mathew #include <arm_gic.h> 10b4315306SDan Handley #include <assert.h> 11b4315306SDan Handley #include <errno.h> 122204afdeSSoby Mathew #include <plat_arm.h> 13e35a3fb5SSoby Mathew #include <platform.h> 14785fb92bSSoby Mathew #include <platform_def.h> 15b4315306SDan Handley #include <psci.h> 16b4315306SDan Handley 172a246d2eSDimitris Papastamos /* Allow ARM Standard platforms to override these functions */ 185486a965SSoby Mathew #pragma weak plat_arm_psci_override_pm_ops 192a246d2eSDimitris Papastamos #pragma weak plat_arm_program_trusted_mailbox 205486a965SSoby Mathew 212204afdeSSoby Mathew #if ARM_RECOM_STATE_ID_ENC 222204afdeSSoby Mathew extern unsigned int arm_pm_idle_states[]; 232204afdeSSoby Mathew #endif /* __ARM_RECOM_STATE_ID_ENC__ */ 242204afdeSSoby Mathew 252204afdeSSoby Mathew #if !ARM_RECOM_STATE_ID_ENC 26b4315306SDan Handley /******************************************************************************* 27b4315306SDan Handley * ARM standard platform handler called to check the validity of the power state 28b4315306SDan Handley * parameter. 29b4315306SDan Handley ******************************************************************************/ 3038dce70fSSoby Mathew int arm_validate_power_state(unsigned int power_state, 3138dce70fSSoby Mathew psci_power_state_t *req_state) 32b4315306SDan Handley { 33*2bc3dba9SAntonio Nino Diaz unsigned int pstate = psci_get_pstate_type(power_state); 34*2bc3dba9SAntonio Nino Diaz unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 35*2bc3dba9SAntonio Nino Diaz unsigned int i; 3638dce70fSSoby Mathew 37*2bc3dba9SAntonio Nino Diaz assert(req_state > 0U); 3838dce70fSSoby Mathew 3938dce70fSSoby Mathew if (pwr_lvl > PLAT_MAX_PWR_LVL) 40b4315306SDan Handley return PSCI_E_INVALID_PARAMS; 4138dce70fSSoby Mathew 4238dce70fSSoby Mathew /* Sanity check the requested state */ 4338dce70fSSoby Mathew if (pstate == PSTATE_TYPE_STANDBY) { 4438dce70fSSoby Mathew /* 4538dce70fSSoby Mathew * It's possible to enter standby only on power level 0 4638dce70fSSoby Mathew * Ignore any other power level. 4738dce70fSSoby Mathew */ 4838dce70fSSoby Mathew if (pwr_lvl != ARM_PWR_LVL0) 4938dce70fSSoby Mathew return PSCI_E_INVALID_PARAMS; 5038dce70fSSoby Mathew 5138dce70fSSoby Mathew req_state->pwr_domain_state[ARM_PWR_LVL0] = 5238dce70fSSoby Mathew ARM_LOCAL_STATE_RET; 5338dce70fSSoby Mathew } else { 5438dce70fSSoby Mathew for (i = ARM_PWR_LVL0; i <= pwr_lvl; i++) 5538dce70fSSoby Mathew req_state->pwr_domain_state[i] = 5638dce70fSSoby Mathew ARM_LOCAL_STATE_OFF; 57b4315306SDan Handley } 58b4315306SDan Handley 59b4315306SDan Handley /* 60b4315306SDan Handley * We expect the 'state id' to be zero. 61b4315306SDan Handley */ 62*2bc3dba9SAntonio Nino Diaz if (psci_get_pstate_id(power_state) != 0U) 63b4315306SDan Handley return PSCI_E_INVALID_PARAMS; 64b4315306SDan Handley 65b4315306SDan Handley return PSCI_E_SUCCESS; 66b4315306SDan Handley } 672204afdeSSoby Mathew 682204afdeSSoby Mathew #else 692204afdeSSoby Mathew /******************************************************************************* 702204afdeSSoby Mathew * ARM standard platform handler called to check the validity of the power 712204afdeSSoby Mathew * state parameter. The power state parameter has to be a composite power 722204afdeSSoby Mathew * state. 732204afdeSSoby Mathew ******************************************************************************/ 742204afdeSSoby Mathew int arm_validate_power_state(unsigned int power_state, 752204afdeSSoby Mathew psci_power_state_t *req_state) 762204afdeSSoby Mathew { 772204afdeSSoby Mathew unsigned int state_id; 782204afdeSSoby Mathew int i; 792204afdeSSoby Mathew 802204afdeSSoby Mathew assert(req_state); 812204afdeSSoby Mathew 822204afdeSSoby Mathew /* 832204afdeSSoby Mathew * Currently we are using a linear search for finding the matching 842204afdeSSoby Mathew * entry in the idle power state array. This can be made a binary 852204afdeSSoby Mathew * search if the number of entries justify the additional complexity. 862204afdeSSoby Mathew */ 872204afdeSSoby Mathew for (i = 0; !!arm_pm_idle_states[i]; i++) { 882204afdeSSoby Mathew if (power_state == arm_pm_idle_states[i]) 892204afdeSSoby Mathew break; 902204afdeSSoby Mathew } 912204afdeSSoby Mathew 922204afdeSSoby Mathew /* Return error if entry not found in the idle state array */ 932204afdeSSoby Mathew if (!arm_pm_idle_states[i]) 942204afdeSSoby Mathew return PSCI_E_INVALID_PARAMS; 952204afdeSSoby Mathew 962204afdeSSoby Mathew i = 0; 972204afdeSSoby Mathew state_id = psci_get_pstate_id(power_state); 982204afdeSSoby Mathew 992204afdeSSoby Mathew /* Parse the State ID and populate the state info parameter */ 1002204afdeSSoby Mathew while (state_id) { 1012204afdeSSoby Mathew req_state->pwr_domain_state[i++] = state_id & 1022204afdeSSoby Mathew ARM_LOCAL_PSTATE_MASK; 1032204afdeSSoby Mathew state_id >>= ARM_LOCAL_PSTATE_WIDTH; 1042204afdeSSoby Mathew } 1052204afdeSSoby Mathew 1062204afdeSSoby Mathew return PSCI_E_SUCCESS; 1072204afdeSSoby Mathew } 1082204afdeSSoby Mathew #endif /* __ARM_RECOM_STATE_ID_ENC__ */ 109f9e858b1SSoby Mathew 110f9e858b1SSoby Mathew /******************************************************************************* 111f9e858b1SSoby Mathew * ARM standard platform handler called to check the validity of the non secure 11271e7a4e5SJeenu Viswambharan * entrypoint. Returns 0 if the entrypoint is valid, or -1 otherwise. 113f9e858b1SSoby Mathew ******************************************************************************/ 114f9e858b1SSoby Mathew int arm_validate_ns_entrypoint(uintptr_t entrypoint) 115f9e858b1SSoby Mathew { 116f9e858b1SSoby Mathew /* 117f9e858b1SSoby Mathew * Check if the non secure entrypoint lies within the non 118f9e858b1SSoby Mathew * secure DRAM. 119f9e858b1SSoby Mathew */ 120f9e858b1SSoby Mathew if ((entrypoint >= ARM_NS_DRAM1_BASE) && (entrypoint < 12171e7a4e5SJeenu Viswambharan (ARM_NS_DRAM1_BASE + ARM_NS_DRAM1_SIZE))) { 12271e7a4e5SJeenu Viswambharan return 0; 12371e7a4e5SJeenu Viswambharan } 1247c7dffd8Sdp-arm #ifndef AARCH32 125f9e858b1SSoby Mathew if ((entrypoint >= ARM_DRAM2_BASE) && (entrypoint < 12671e7a4e5SJeenu Viswambharan (ARM_DRAM2_BASE + ARM_DRAM2_SIZE))) { 12771e7a4e5SJeenu Viswambharan return 0; 12871e7a4e5SJeenu Viswambharan } 1297c7dffd8Sdp-arm #endif 130f9e858b1SSoby Mathew 13171e7a4e5SJeenu Viswambharan return -1; 13271e7a4e5SJeenu Viswambharan } 13371e7a4e5SJeenu Viswambharan 13471e7a4e5SJeenu Viswambharan int arm_validate_psci_entrypoint(uintptr_t entrypoint) 13571e7a4e5SJeenu Viswambharan { 13671e7a4e5SJeenu Viswambharan return arm_validate_ns_entrypoint(entrypoint) == 0 ? PSCI_E_SUCCESS : 13771e7a4e5SJeenu Viswambharan PSCI_E_INVALID_ADDRESS; 138f9e858b1SSoby Mathew } 139785fb92bSSoby Mathew 140c1bb8a05SSoby Mathew /****************************************************************************** 1415486a965SSoby Mathew * Default definition on ARM standard platforms to override the plat_psci_ops. 1425486a965SSoby Mathew *****************************************************************************/ 1435486a965SSoby Mathew const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops) 1445486a965SSoby Mathew { 1455486a965SSoby Mathew return ops; 1465486a965SSoby Mathew } 1475486a965SSoby Mathew 1485486a965SSoby Mathew /****************************************************************************** 149e35a3fb5SSoby Mathew * Helper function to save the platform state before a system suspend. Save the 150e35a3fb5SSoby Mathew * state of the system components which are not in the Always ON power domain. 151e35a3fb5SSoby Mathew *****************************************************************************/ 152e35a3fb5SSoby Mathew void arm_system_pwr_domain_save(void) 153e35a3fb5SSoby Mathew { 154e35a3fb5SSoby Mathew /* Assert system power domain is available on the platform */ 155e35a3fb5SSoby Mathew assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2); 156e35a3fb5SSoby Mathew 157e35a3fb5SSoby Mathew plat_arm_gic_save(); 158e35a3fb5SSoby Mathew 159e35a3fb5SSoby Mathew /* 16088a0523eSAntonio Nino Diaz * Unregister console now so that it is not registered for a second 16188a0523eSAntonio Nino Diaz * time during resume. 16288a0523eSAntonio Nino Diaz */ 16388a0523eSAntonio Nino Diaz arm_console_runtime_end(); 16488a0523eSAntonio Nino Diaz 16588a0523eSAntonio Nino Diaz /* 166e35a3fb5SSoby Mathew * All the other peripheral which are configured by ARM TF are 167e35a3fb5SSoby Mathew * re-initialized on resume from system suspend. Hence we 168e35a3fb5SSoby Mathew * don't save their state here. 169e35a3fb5SSoby Mathew */ 170e35a3fb5SSoby Mathew } 171e35a3fb5SSoby Mathew 172e35a3fb5SSoby Mathew /****************************************************************************** 173c1bb8a05SSoby Mathew * Helper function to resume the platform from system suspend. Reinitialize 174c1bb8a05SSoby Mathew * the system components which are not in the Always ON power domain. 175c1bb8a05SSoby Mathew * TODO: Unify the platform setup when waking up from cold boot and system 176c1bb8a05SSoby Mathew * resume in arm_bl31_platform_setup(). 177c1bb8a05SSoby Mathew *****************************************************************************/ 178c1bb8a05SSoby Mathew void arm_system_pwr_domain_resume(void) 179c1bb8a05SSoby Mathew { 18088a0523eSAntonio Nino Diaz /* Initialize the console */ 18188a0523eSAntonio Nino Diaz arm_console_runtime_init(); 182c1bb8a05SSoby Mathew 183c1bb8a05SSoby Mathew /* Assert system power domain is available on the platform */ 184c1bb8a05SSoby Mathew assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2); 185c1bb8a05SSoby Mathew 186e35a3fb5SSoby Mathew plat_arm_gic_resume(); 187e35a3fb5SSoby Mathew 188c1bb8a05SSoby Mathew plat_arm_security_setup(); 189c1bb8a05SSoby Mathew arm_configure_sys_timer(); 190c1bb8a05SSoby Mathew } 191c1bb8a05SSoby Mathew 192785fb92bSSoby Mathew /******************************************************************************* 1932a246d2eSDimitris Papastamos * ARM platform function to program the mailbox for a cpu before it is released 194785fb92bSSoby Mathew * from reset. This function assumes that the Trusted mail box base is within 195785fb92bSSoby Mathew * the ARM_SHARED_RAM region 196785fb92bSSoby Mathew ******************************************************************************/ 1972a246d2eSDimitris Papastamos void plat_arm_program_trusted_mailbox(uintptr_t address) 198785fb92bSSoby Mathew { 199785fb92bSSoby Mathew uintptr_t *mailbox = (void *) PLAT_ARM_TRUSTED_MAILBOX_BASE; 200785fb92bSSoby Mathew 201785fb92bSSoby Mathew *mailbox = address; 202785fb92bSSoby Mathew 203785fb92bSSoby Mathew /* 204785fb92bSSoby Mathew * Ensure that the PLAT_ARM_TRUSTED_MAILBOX_BASE is within 205785fb92bSSoby Mathew * ARM_SHARED_RAM region. 206785fb92bSSoby Mathew */ 207785fb92bSSoby Mathew assert((PLAT_ARM_TRUSTED_MAILBOX_BASE >= ARM_SHARED_RAM_BASE) && 208785fb92bSSoby Mathew ((PLAT_ARM_TRUSTED_MAILBOX_BASE + sizeof(*mailbox)) <= \ 209785fb92bSSoby Mathew (ARM_SHARED_RAM_BASE + ARM_SHARED_RAM_SIZE))); 210785fb92bSSoby Mathew } 211785fb92bSSoby Mathew 212785fb92bSSoby Mathew /******************************************************************************* 213785fb92bSSoby Mathew * The ARM Standard platform definition of platform porting API 214785fb92bSSoby Mathew * `plat_setup_psci_ops`. 215785fb92bSSoby Mathew ******************************************************************************/ 216785fb92bSSoby Mathew int plat_setup_psci_ops(uintptr_t sec_entrypoint, 217785fb92bSSoby Mathew const plat_psci_ops_t **psci_ops) 218785fb92bSSoby Mathew { 2195486a965SSoby Mathew *psci_ops = plat_arm_psci_override_pm_ops(&plat_arm_psci_pm_ops); 220785fb92bSSoby Mathew 221785fb92bSSoby Mathew /* Setup mailbox with entry point. */ 2222a246d2eSDimitris Papastamos plat_arm_program_trusted_mailbox(sec_entrypoint); 223785fb92bSSoby Mathew return 0; 224785fb92bSSoby Mathew } 225