1*301d27d9SRadoslaw Biernacki /* 2*301d27d9SRadoslaw Biernacki * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. 3*301d27d9SRadoslaw Biernacki * 4*301d27d9SRadoslaw Biernacki * SPDX-License-Identifier: BSD-3-Clause 5*301d27d9SRadoslaw Biernacki */ 6*301d27d9SRadoslaw Biernacki 7*301d27d9SRadoslaw Biernacki #include <assert.h> 8*301d27d9SRadoslaw Biernacki #include <platform_def.h> 9*301d27d9SRadoslaw Biernacki 10*301d27d9SRadoslaw Biernacki #include <arch_helpers.h> 11*301d27d9SRadoslaw Biernacki #include <common/debug.h> 12*301d27d9SRadoslaw Biernacki #include <lib/psci/psci.h> 13*301d27d9SRadoslaw Biernacki #include <plat/common/platform.h> 14*301d27d9SRadoslaw Biernacki 15*301d27d9SRadoslaw Biernacki #include "qemu_private.h" 16*301d27d9SRadoslaw Biernacki 17*301d27d9SRadoslaw Biernacki /* 18*301d27d9SRadoslaw Biernacki * The secure entry point to be used on warm reset. 19*301d27d9SRadoslaw Biernacki */ 20*301d27d9SRadoslaw Biernacki static unsigned long secure_entrypoint; 21*301d27d9SRadoslaw Biernacki 22*301d27d9SRadoslaw Biernacki /* Make composite power state parameter till power level 0 */ 23*301d27d9SRadoslaw Biernacki #if PSCI_EXTENDED_STATE_ID 24*301d27d9SRadoslaw Biernacki 25*301d27d9SRadoslaw Biernacki #define qemu_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ 26*301d27d9SRadoslaw Biernacki (((lvl0_state) << PSTATE_ID_SHIFT) | \ 27*301d27d9SRadoslaw Biernacki ((type) << PSTATE_TYPE_SHIFT)) 28*301d27d9SRadoslaw Biernacki #else 29*301d27d9SRadoslaw Biernacki #define qemu_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ 30*301d27d9SRadoslaw Biernacki (((lvl0_state) << PSTATE_ID_SHIFT) | \ 31*301d27d9SRadoslaw Biernacki ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \ 32*301d27d9SRadoslaw Biernacki ((type) << PSTATE_TYPE_SHIFT)) 33*301d27d9SRadoslaw Biernacki #endif /* PSCI_EXTENDED_STATE_ID */ 34*301d27d9SRadoslaw Biernacki 35*301d27d9SRadoslaw Biernacki 36*301d27d9SRadoslaw Biernacki #define qemu_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \ 37*301d27d9SRadoslaw Biernacki (((lvl1_state) << PLAT_LOCAL_PSTATE_WIDTH) | \ 38*301d27d9SRadoslaw Biernacki qemu_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type)) 39*301d27d9SRadoslaw Biernacki 40*301d27d9SRadoslaw Biernacki 41*301d27d9SRadoslaw Biernacki 42*301d27d9SRadoslaw Biernacki /* 43*301d27d9SRadoslaw Biernacki * The table storing the valid idle power states. Ensure that the 44*301d27d9SRadoslaw Biernacki * array entries are populated in ascending order of state-id to 45*301d27d9SRadoslaw Biernacki * enable us to use binary search during power state validation. 46*301d27d9SRadoslaw Biernacki * The table must be terminated by a NULL entry. 47*301d27d9SRadoslaw Biernacki */ 48*301d27d9SRadoslaw Biernacki static const unsigned int qemu_pm_idle_states[] = { 49*301d27d9SRadoslaw Biernacki /* State-id - 0x01 */ 50*301d27d9SRadoslaw Biernacki qemu_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_RET, 51*301d27d9SRadoslaw Biernacki MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY), 52*301d27d9SRadoslaw Biernacki /* State-id - 0x02 */ 53*301d27d9SRadoslaw Biernacki qemu_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_OFF, 54*301d27d9SRadoslaw Biernacki MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN), 55*301d27d9SRadoslaw Biernacki /* State-id - 0x22 */ 56*301d27d9SRadoslaw Biernacki qemu_make_pwrstate_lvl1(PLAT_LOCAL_STATE_OFF, PLAT_LOCAL_STATE_OFF, 57*301d27d9SRadoslaw Biernacki MPIDR_AFFLVL1, PSTATE_TYPE_POWERDOWN), 58*301d27d9SRadoslaw Biernacki 0, 59*301d27d9SRadoslaw Biernacki }; 60*301d27d9SRadoslaw Biernacki 61*301d27d9SRadoslaw Biernacki /******************************************************************************* 62*301d27d9SRadoslaw Biernacki * Platform handler called to check the validity of the power state 63*301d27d9SRadoslaw Biernacki * parameter. The power state parameter has to be a composite power state. 64*301d27d9SRadoslaw Biernacki ******************************************************************************/ 65*301d27d9SRadoslaw Biernacki static int qemu_validate_power_state(unsigned int power_state, 66*301d27d9SRadoslaw Biernacki psci_power_state_t *req_state) 67*301d27d9SRadoslaw Biernacki { 68*301d27d9SRadoslaw Biernacki unsigned int state_id; 69*301d27d9SRadoslaw Biernacki int i; 70*301d27d9SRadoslaw Biernacki 71*301d27d9SRadoslaw Biernacki assert(req_state); 72*301d27d9SRadoslaw Biernacki 73*301d27d9SRadoslaw Biernacki /* 74*301d27d9SRadoslaw Biernacki * Currently we are using a linear search for finding the matching 75*301d27d9SRadoslaw Biernacki * entry in the idle power state array. This can be made a binary 76*301d27d9SRadoslaw Biernacki * search if the number of entries justify the additional complexity. 77*301d27d9SRadoslaw Biernacki */ 78*301d27d9SRadoslaw Biernacki for (i = 0; !!qemu_pm_idle_states[i]; i++) { 79*301d27d9SRadoslaw Biernacki if (power_state == qemu_pm_idle_states[i]) 80*301d27d9SRadoslaw Biernacki break; 81*301d27d9SRadoslaw Biernacki } 82*301d27d9SRadoslaw Biernacki 83*301d27d9SRadoslaw Biernacki /* Return error if entry not found in the idle state array */ 84*301d27d9SRadoslaw Biernacki if (!qemu_pm_idle_states[i]) 85*301d27d9SRadoslaw Biernacki return PSCI_E_INVALID_PARAMS; 86*301d27d9SRadoslaw Biernacki 87*301d27d9SRadoslaw Biernacki i = 0; 88*301d27d9SRadoslaw Biernacki state_id = psci_get_pstate_id(power_state); 89*301d27d9SRadoslaw Biernacki 90*301d27d9SRadoslaw Biernacki /* Parse the State ID and populate the state info parameter */ 91*301d27d9SRadoslaw Biernacki while (state_id) { 92*301d27d9SRadoslaw Biernacki req_state->pwr_domain_state[i++] = state_id & 93*301d27d9SRadoslaw Biernacki PLAT_LOCAL_PSTATE_MASK; 94*301d27d9SRadoslaw Biernacki state_id >>= PLAT_LOCAL_PSTATE_WIDTH; 95*301d27d9SRadoslaw Biernacki } 96*301d27d9SRadoslaw Biernacki 97*301d27d9SRadoslaw Biernacki return PSCI_E_SUCCESS; 98*301d27d9SRadoslaw Biernacki } 99*301d27d9SRadoslaw Biernacki 100*301d27d9SRadoslaw Biernacki /******************************************************************************* 101*301d27d9SRadoslaw Biernacki * Platform handler called to check the validity of the non secure 102*301d27d9SRadoslaw Biernacki * entrypoint. 103*301d27d9SRadoslaw Biernacki ******************************************************************************/ 104*301d27d9SRadoslaw Biernacki static int qemu_validate_ns_entrypoint(uintptr_t entrypoint) 105*301d27d9SRadoslaw Biernacki { 106*301d27d9SRadoslaw Biernacki /* 107*301d27d9SRadoslaw Biernacki * Check if the non secure entrypoint lies within the non 108*301d27d9SRadoslaw Biernacki * secure DRAM. 109*301d27d9SRadoslaw Biernacki */ 110*301d27d9SRadoslaw Biernacki if ((entrypoint >= NS_DRAM0_BASE) && 111*301d27d9SRadoslaw Biernacki (entrypoint < (NS_DRAM0_BASE + NS_DRAM0_SIZE))) 112*301d27d9SRadoslaw Biernacki return PSCI_E_SUCCESS; 113*301d27d9SRadoslaw Biernacki return PSCI_E_INVALID_ADDRESS; 114*301d27d9SRadoslaw Biernacki } 115*301d27d9SRadoslaw Biernacki 116*301d27d9SRadoslaw Biernacki /******************************************************************************* 117*301d27d9SRadoslaw Biernacki * Platform handler called when a CPU is about to enter standby. 118*301d27d9SRadoslaw Biernacki ******************************************************************************/ 119*301d27d9SRadoslaw Biernacki static void qemu_cpu_standby(plat_local_state_t cpu_state) 120*301d27d9SRadoslaw Biernacki { 121*301d27d9SRadoslaw Biernacki 122*301d27d9SRadoslaw Biernacki assert(cpu_state == PLAT_LOCAL_STATE_RET); 123*301d27d9SRadoslaw Biernacki 124*301d27d9SRadoslaw Biernacki /* 125*301d27d9SRadoslaw Biernacki * Enter standby state 126*301d27d9SRadoslaw Biernacki * dsb is good practice before using wfi to enter low power states 127*301d27d9SRadoslaw Biernacki */ 128*301d27d9SRadoslaw Biernacki dsb(); 129*301d27d9SRadoslaw Biernacki wfi(); 130*301d27d9SRadoslaw Biernacki } 131*301d27d9SRadoslaw Biernacki 132*301d27d9SRadoslaw Biernacki /******************************************************************************* 133*301d27d9SRadoslaw Biernacki * Platform handler called when a power domain is about to be turned on. The 134*301d27d9SRadoslaw Biernacki * mpidr determines the CPU to be turned on. 135*301d27d9SRadoslaw Biernacki ******************************************************************************/ 136*301d27d9SRadoslaw Biernacki static int qemu_pwr_domain_on(u_register_t mpidr) 137*301d27d9SRadoslaw Biernacki { 138*301d27d9SRadoslaw Biernacki int rc = PSCI_E_SUCCESS; 139*301d27d9SRadoslaw Biernacki unsigned pos = plat_core_pos_by_mpidr(mpidr); 140*301d27d9SRadoslaw Biernacki uint64_t *hold_base = (uint64_t *)PLAT_QEMU_HOLD_BASE; 141*301d27d9SRadoslaw Biernacki 142*301d27d9SRadoslaw Biernacki hold_base[pos] = PLAT_QEMU_HOLD_STATE_GO; 143*301d27d9SRadoslaw Biernacki sev(); 144*301d27d9SRadoslaw Biernacki 145*301d27d9SRadoslaw Biernacki return rc; 146*301d27d9SRadoslaw Biernacki } 147*301d27d9SRadoslaw Biernacki 148*301d27d9SRadoslaw Biernacki /******************************************************************************* 149*301d27d9SRadoslaw Biernacki * Platform handler called when a power domain is about to be turned off. The 150*301d27d9SRadoslaw Biernacki * target_state encodes the power state that each level should transition to. 151*301d27d9SRadoslaw Biernacki ******************************************************************************/ 152*301d27d9SRadoslaw Biernacki void qemu_pwr_domain_off(const psci_power_state_t *target_state) 153*301d27d9SRadoslaw Biernacki { 154*301d27d9SRadoslaw Biernacki assert(0); 155*301d27d9SRadoslaw Biernacki } 156*301d27d9SRadoslaw Biernacki 157*301d27d9SRadoslaw Biernacki /******************************************************************************* 158*301d27d9SRadoslaw Biernacki * Platform handler called when a power domain is about to be suspended. The 159*301d27d9SRadoslaw Biernacki * target_state encodes the power state that each level should transition to. 160*301d27d9SRadoslaw Biernacki ******************************************************************************/ 161*301d27d9SRadoslaw Biernacki void qemu_pwr_domain_suspend(const psci_power_state_t *target_state) 162*301d27d9SRadoslaw Biernacki { 163*301d27d9SRadoslaw Biernacki assert(0); 164*301d27d9SRadoslaw Biernacki } 165*301d27d9SRadoslaw Biernacki 166*301d27d9SRadoslaw Biernacki /******************************************************************************* 167*301d27d9SRadoslaw Biernacki * Platform handler called when a power domain has just been powered on after 168*301d27d9SRadoslaw Biernacki * being turned off earlier. The target_state encodes the low power state that 169*301d27d9SRadoslaw Biernacki * each level has woken up from. 170*301d27d9SRadoslaw Biernacki ******************************************************************************/ 171*301d27d9SRadoslaw Biernacki void qemu_pwr_domain_on_finish(const psci_power_state_t *target_state) 172*301d27d9SRadoslaw Biernacki { 173*301d27d9SRadoslaw Biernacki assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == 174*301d27d9SRadoslaw Biernacki PLAT_LOCAL_STATE_OFF); 175*301d27d9SRadoslaw Biernacki 176*301d27d9SRadoslaw Biernacki qemu_pwr_gic_on_finish(); 177*301d27d9SRadoslaw Biernacki } 178*301d27d9SRadoslaw Biernacki 179*301d27d9SRadoslaw Biernacki /******************************************************************************* 180*301d27d9SRadoslaw Biernacki * Platform handler called when a power domain has just been powered on after 181*301d27d9SRadoslaw Biernacki * having been suspended earlier. The target_state encodes the low power state 182*301d27d9SRadoslaw Biernacki * that each level has woken up from. 183*301d27d9SRadoslaw Biernacki ******************************************************************************/ 184*301d27d9SRadoslaw Biernacki void qemu_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 185*301d27d9SRadoslaw Biernacki { 186*301d27d9SRadoslaw Biernacki assert(0); 187*301d27d9SRadoslaw Biernacki } 188*301d27d9SRadoslaw Biernacki 189*301d27d9SRadoslaw Biernacki /******************************************************************************* 190*301d27d9SRadoslaw Biernacki * Platform handlers to shutdown/reboot the system 191*301d27d9SRadoslaw Biernacki ******************************************************************************/ 192*301d27d9SRadoslaw Biernacki static void __dead2 qemu_system_off(void) 193*301d27d9SRadoslaw Biernacki { 194*301d27d9SRadoslaw Biernacki ERROR("QEMU System Off: operation not handled.\n"); 195*301d27d9SRadoslaw Biernacki panic(); 196*301d27d9SRadoslaw Biernacki } 197*301d27d9SRadoslaw Biernacki 198*301d27d9SRadoslaw Biernacki static void __dead2 qemu_system_reset(void) 199*301d27d9SRadoslaw Biernacki { 200*301d27d9SRadoslaw Biernacki ERROR("QEMU System Reset: operation not handled.\n"); 201*301d27d9SRadoslaw Biernacki panic(); 202*301d27d9SRadoslaw Biernacki } 203*301d27d9SRadoslaw Biernacki 204*301d27d9SRadoslaw Biernacki static const plat_psci_ops_t plat_qemu_psci_pm_ops = { 205*301d27d9SRadoslaw Biernacki .cpu_standby = qemu_cpu_standby, 206*301d27d9SRadoslaw Biernacki .pwr_domain_on = qemu_pwr_domain_on, 207*301d27d9SRadoslaw Biernacki .pwr_domain_off = qemu_pwr_domain_off, 208*301d27d9SRadoslaw Biernacki .pwr_domain_suspend = qemu_pwr_domain_suspend, 209*301d27d9SRadoslaw Biernacki .pwr_domain_on_finish = qemu_pwr_domain_on_finish, 210*301d27d9SRadoslaw Biernacki .pwr_domain_suspend_finish = qemu_pwr_domain_suspend_finish, 211*301d27d9SRadoslaw Biernacki .system_off = qemu_system_off, 212*301d27d9SRadoslaw Biernacki .system_reset = qemu_system_reset, 213*301d27d9SRadoslaw Biernacki .validate_power_state = qemu_validate_power_state, 214*301d27d9SRadoslaw Biernacki .validate_ns_entrypoint = qemu_validate_ns_entrypoint 215*301d27d9SRadoslaw Biernacki }; 216*301d27d9SRadoslaw Biernacki 217*301d27d9SRadoslaw Biernacki int plat_setup_psci_ops(uintptr_t sec_entrypoint, 218*301d27d9SRadoslaw Biernacki const plat_psci_ops_t **psci_ops) 219*301d27d9SRadoslaw Biernacki { 220*301d27d9SRadoslaw Biernacki uintptr_t *mailbox = (void *) PLAT_QEMU_TRUSTED_MAILBOX_BASE; 221*301d27d9SRadoslaw Biernacki 222*301d27d9SRadoslaw Biernacki *mailbox = sec_entrypoint; 223*301d27d9SRadoslaw Biernacki secure_entrypoint = (unsigned long) sec_entrypoint; 224*301d27d9SRadoslaw Biernacki *psci_ops = &plat_qemu_psci_pm_ops; 225*301d27d9SRadoslaw Biernacki 226*301d27d9SRadoslaw Biernacki return 0; 227*301d27d9SRadoslaw Biernacki } 228