1*54fd6939SJiyong Park /* 2*54fd6939SJiyong Park * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. 3*54fd6939SJiyong Park * 4*54fd6939SJiyong Park * SPDX-License-Identifier: BSD-3-Clause 5*54fd6939SJiyong Park */ 6*54fd6939SJiyong Park 7*54fd6939SJiyong Park #include <assert.h> 8*54fd6939SJiyong Park 9*54fd6939SJiyong Park #include <platform_def.h> 10*54fd6939SJiyong Park 11*54fd6939SJiyong Park #include <arch_helpers.h> 12*54fd6939SJiyong Park #include <lib/psci/psci.h> 13*54fd6939SJiyong Park #include <plat/arm/common/plat_arm.h> 14*54fd6939SJiyong Park #include <plat/common/platform.h> 15*54fd6939SJiyong Park 16*54fd6939SJiyong Park /* Allow ARM Standard platforms to override these functions */ 17*54fd6939SJiyong Park #pragma weak plat_arm_program_trusted_mailbox 18*54fd6939SJiyong Park 19*54fd6939SJiyong Park #if !ARM_RECOM_STATE_ID_ENC 20*54fd6939SJiyong Park /******************************************************************************* 21*54fd6939SJiyong Park * ARM standard platform handler called to check the validity of the power state 22*54fd6939SJiyong Park * parameter. 23*54fd6939SJiyong Park ******************************************************************************/ arm_validate_power_state(unsigned int power_state,psci_power_state_t * req_state)24*54fd6939SJiyong Parkint arm_validate_power_state(unsigned int power_state, 25*54fd6939SJiyong Park psci_power_state_t *req_state) 26*54fd6939SJiyong Park { 27*54fd6939SJiyong Park unsigned int pstate = psci_get_pstate_type(power_state); 28*54fd6939SJiyong Park unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 29*54fd6939SJiyong Park unsigned int i; 30*54fd6939SJiyong Park 31*54fd6939SJiyong Park assert(req_state != NULL); 32*54fd6939SJiyong Park 33*54fd6939SJiyong Park if (pwr_lvl > PLAT_MAX_PWR_LVL) 34*54fd6939SJiyong Park return PSCI_E_INVALID_PARAMS; 35*54fd6939SJiyong Park 36*54fd6939SJiyong Park /* Sanity check the requested state */ 37*54fd6939SJiyong Park if (pstate == PSTATE_TYPE_STANDBY) { 38*54fd6939SJiyong Park /* 39*54fd6939SJiyong Park * It's possible to enter standby only on power level 0 40*54fd6939SJiyong Park * Ignore any other power level. 41*54fd6939SJiyong Park */ 42*54fd6939SJiyong Park if (pwr_lvl != ARM_PWR_LVL0) 43*54fd6939SJiyong Park return PSCI_E_INVALID_PARAMS; 44*54fd6939SJiyong Park 45*54fd6939SJiyong Park req_state->pwr_domain_state[ARM_PWR_LVL0] = 46*54fd6939SJiyong Park ARM_LOCAL_STATE_RET; 47*54fd6939SJiyong Park } else { 48*54fd6939SJiyong Park for (i = ARM_PWR_LVL0; i <= pwr_lvl; i++) 49*54fd6939SJiyong Park req_state->pwr_domain_state[i] = 50*54fd6939SJiyong Park ARM_LOCAL_STATE_OFF; 51*54fd6939SJiyong Park } 52*54fd6939SJiyong Park 53*54fd6939SJiyong Park /* 54*54fd6939SJiyong Park * We expect the 'state id' to be zero. 55*54fd6939SJiyong Park */ 56*54fd6939SJiyong Park if (psci_get_pstate_id(power_state) != 0U) 57*54fd6939SJiyong Park return PSCI_E_INVALID_PARAMS; 58*54fd6939SJiyong Park 59*54fd6939SJiyong Park return PSCI_E_SUCCESS; 60*54fd6939SJiyong Park } 61*54fd6939SJiyong Park 62*54fd6939SJiyong Park #else 63*54fd6939SJiyong Park /******************************************************************************* 64*54fd6939SJiyong Park * ARM standard platform handler called to check the validity of the power 65*54fd6939SJiyong Park * state parameter. The power state parameter has to be a composite power 66*54fd6939SJiyong Park * state. 67*54fd6939SJiyong Park ******************************************************************************/ arm_validate_power_state(unsigned int power_state,psci_power_state_t * req_state)68*54fd6939SJiyong Parkint arm_validate_power_state(unsigned int power_state, 69*54fd6939SJiyong Park psci_power_state_t *req_state) 70*54fd6939SJiyong Park { 71*54fd6939SJiyong Park unsigned int state_id; 72*54fd6939SJiyong Park int i; 73*54fd6939SJiyong Park 74*54fd6939SJiyong Park assert(req_state != NULL); 75*54fd6939SJiyong Park 76*54fd6939SJiyong Park /* 77*54fd6939SJiyong Park * Currently we are using a linear search for finding the matching 78*54fd6939SJiyong Park * entry in the idle power state array. This can be made a binary 79*54fd6939SJiyong Park * search if the number of entries justify the additional complexity. 80*54fd6939SJiyong Park */ 81*54fd6939SJiyong Park for (i = 0; !!arm_pm_idle_states[i]; i++) { 82*54fd6939SJiyong Park if (power_state == arm_pm_idle_states[i]) 83*54fd6939SJiyong Park break; 84*54fd6939SJiyong Park } 85*54fd6939SJiyong Park 86*54fd6939SJiyong Park /* Return error if entry not found in the idle state array */ 87*54fd6939SJiyong Park if (!arm_pm_idle_states[i]) 88*54fd6939SJiyong Park return PSCI_E_INVALID_PARAMS; 89*54fd6939SJiyong Park 90*54fd6939SJiyong Park i = 0; 91*54fd6939SJiyong Park state_id = psci_get_pstate_id(power_state); 92*54fd6939SJiyong Park 93*54fd6939SJiyong Park /* Parse the State ID and populate the state info parameter */ 94*54fd6939SJiyong Park while (state_id) { 95*54fd6939SJiyong Park req_state->pwr_domain_state[i++] = state_id & 96*54fd6939SJiyong Park ARM_LOCAL_PSTATE_MASK; 97*54fd6939SJiyong Park state_id >>= ARM_LOCAL_PSTATE_WIDTH; 98*54fd6939SJiyong Park } 99*54fd6939SJiyong Park 100*54fd6939SJiyong Park return PSCI_E_SUCCESS; 101*54fd6939SJiyong Park } 102*54fd6939SJiyong Park #endif /* __ARM_RECOM_STATE_ID_ENC__ */ 103*54fd6939SJiyong Park 104*54fd6939SJiyong Park /******************************************************************************* 105*54fd6939SJiyong Park * ARM standard platform handler called to check the validity of the non secure 106*54fd6939SJiyong Park * entrypoint. Returns 0 if the entrypoint is valid, or -1 otherwise. 107*54fd6939SJiyong Park ******************************************************************************/ arm_validate_ns_entrypoint(uintptr_t entrypoint)108*54fd6939SJiyong Parkint arm_validate_ns_entrypoint(uintptr_t entrypoint) 109*54fd6939SJiyong Park { 110*54fd6939SJiyong Park /* 111*54fd6939SJiyong Park * Check if the non secure entrypoint lies within the non 112*54fd6939SJiyong Park * secure DRAM. 113*54fd6939SJiyong Park */ 114*54fd6939SJiyong Park if ((entrypoint >= ARM_NS_DRAM1_BASE) && (entrypoint < 115*54fd6939SJiyong Park (ARM_NS_DRAM1_BASE + ARM_NS_DRAM1_SIZE))) { 116*54fd6939SJiyong Park return 0; 117*54fd6939SJiyong Park } 118*54fd6939SJiyong Park #ifdef __aarch64__ 119*54fd6939SJiyong Park if ((entrypoint >= ARM_DRAM2_BASE) && (entrypoint < 120*54fd6939SJiyong Park (ARM_DRAM2_BASE + ARM_DRAM2_SIZE))) { 121*54fd6939SJiyong Park return 0; 122*54fd6939SJiyong Park } 123*54fd6939SJiyong Park #endif 124*54fd6939SJiyong Park 125*54fd6939SJiyong Park return -1; 126*54fd6939SJiyong Park } 127*54fd6939SJiyong Park arm_validate_psci_entrypoint(uintptr_t entrypoint)128*54fd6939SJiyong Parkint arm_validate_psci_entrypoint(uintptr_t entrypoint) 129*54fd6939SJiyong Park { 130*54fd6939SJiyong Park return (arm_validate_ns_entrypoint(entrypoint) == 0) ? PSCI_E_SUCCESS : 131*54fd6939SJiyong Park PSCI_E_INVALID_ADDRESS; 132*54fd6939SJiyong Park } 133*54fd6939SJiyong Park 134*54fd6939SJiyong Park /****************************************************************************** 135*54fd6939SJiyong Park * Helper function to save the platform state before a system suspend. Save the 136*54fd6939SJiyong Park * state of the system components which are not in the Always ON power domain. 137*54fd6939SJiyong Park *****************************************************************************/ arm_system_pwr_domain_save(void)138*54fd6939SJiyong Parkvoid arm_system_pwr_domain_save(void) 139*54fd6939SJiyong Park { 140*54fd6939SJiyong Park /* Assert system power domain is available on the platform */ 141*54fd6939SJiyong Park assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2); 142*54fd6939SJiyong Park 143*54fd6939SJiyong Park plat_arm_gic_save(); 144*54fd6939SJiyong Park 145*54fd6939SJiyong Park /* 146*54fd6939SJiyong Park * Unregister console now so that it is not registered for a second 147*54fd6939SJiyong Park * time during resume. 148*54fd6939SJiyong Park */ 149*54fd6939SJiyong Park arm_console_runtime_end(); 150*54fd6939SJiyong Park 151*54fd6939SJiyong Park /* 152*54fd6939SJiyong Park * All the other peripheral which are configured by ARM TF are 153*54fd6939SJiyong Park * re-initialized on resume from system suspend. Hence we 154*54fd6939SJiyong Park * don't save their state here. 155*54fd6939SJiyong Park */ 156*54fd6939SJiyong Park } 157*54fd6939SJiyong Park 158*54fd6939SJiyong Park /****************************************************************************** 159*54fd6939SJiyong Park * Helper function to resume the platform from system suspend. Reinitialize 160*54fd6939SJiyong Park * the system components which are not in the Always ON power domain. 161*54fd6939SJiyong Park * TODO: Unify the platform setup when waking up from cold boot and system 162*54fd6939SJiyong Park * resume in arm_bl31_platform_setup(). 163*54fd6939SJiyong Park *****************************************************************************/ arm_system_pwr_domain_resume(void)164*54fd6939SJiyong Parkvoid arm_system_pwr_domain_resume(void) 165*54fd6939SJiyong Park { 166*54fd6939SJiyong Park /* Initialize the console */ 167*54fd6939SJiyong Park arm_console_runtime_init(); 168*54fd6939SJiyong Park 169*54fd6939SJiyong Park /* Assert system power domain is available on the platform */ 170*54fd6939SJiyong Park assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2); 171*54fd6939SJiyong Park 172*54fd6939SJiyong Park plat_arm_gic_resume(); 173*54fd6939SJiyong Park 174*54fd6939SJiyong Park plat_arm_security_setup(); 175*54fd6939SJiyong Park arm_configure_sys_timer(); 176*54fd6939SJiyong Park } 177*54fd6939SJiyong Park 178*54fd6939SJiyong Park /******************************************************************************* 179*54fd6939SJiyong Park * ARM platform function to program the mailbox for a cpu before it is released 180*54fd6939SJiyong Park * from reset. This function assumes that the Trusted mail box base is within 181*54fd6939SJiyong Park * the ARM_SHARED_RAM region 182*54fd6939SJiyong Park ******************************************************************************/ plat_arm_program_trusted_mailbox(uintptr_t address)183*54fd6939SJiyong Parkvoid plat_arm_program_trusted_mailbox(uintptr_t address) 184*54fd6939SJiyong Park { 185*54fd6939SJiyong Park uintptr_t *mailbox = (void *) PLAT_ARM_TRUSTED_MAILBOX_BASE; 186*54fd6939SJiyong Park 187*54fd6939SJiyong Park *mailbox = address; 188*54fd6939SJiyong Park 189*54fd6939SJiyong Park /* 190*54fd6939SJiyong Park * Ensure that the PLAT_ARM_TRUSTED_MAILBOX_BASE is within 191*54fd6939SJiyong Park * ARM_SHARED_RAM region. 192*54fd6939SJiyong Park */ 193*54fd6939SJiyong Park assert((PLAT_ARM_TRUSTED_MAILBOX_BASE >= ARM_SHARED_RAM_BASE) && 194*54fd6939SJiyong Park ((PLAT_ARM_TRUSTED_MAILBOX_BASE + sizeof(*mailbox)) <= \ 195*54fd6939SJiyong Park (ARM_SHARED_RAM_BASE + ARM_SHARED_RAM_SIZE))); 196*54fd6939SJiyong Park } 197*54fd6939SJiyong Park 198*54fd6939SJiyong Park /******************************************************************************* 199*54fd6939SJiyong Park * The ARM Standard platform definition of platform porting API 200*54fd6939SJiyong Park * `plat_setup_psci_ops`. 201*54fd6939SJiyong Park ******************************************************************************/ plat_setup_psci_ops(uintptr_t sec_entrypoint,const plat_psci_ops_t ** psci_ops)202*54fd6939SJiyong Parkint __init plat_setup_psci_ops(uintptr_t sec_entrypoint, 203*54fd6939SJiyong Park const plat_psci_ops_t **psci_ops) 204*54fd6939SJiyong Park { 205*54fd6939SJiyong Park *psci_ops = plat_arm_psci_override_pm_ops(&plat_arm_psci_pm_ops); 206*54fd6939SJiyong Park 207*54fd6939SJiyong Park /* Setup mailbox with entry point. */ 208*54fd6939SJiyong Park plat_arm_program_trusted_mailbox(sec_entrypoint); 209*54fd6939SJiyong Park return 0; 210*54fd6939SJiyong Park } 211