1*0654ab7fSJay Buddhabhatti /* 2*0654ab7fSJay Buddhabhatti * Copyright (c) 2022, Xilinx, Inc. All rights reserved. 3*0654ab7fSJay Buddhabhatti * Copyright (C) 2022, Advanced Micro Devices, Inc. All rights reserved. 4*0654ab7fSJay Buddhabhatti * 5*0654ab7fSJay Buddhabhatti * SPDX-License-Identifier: BSD-3-Clause 6*0654ab7fSJay Buddhabhatti */ 7*0654ab7fSJay Buddhabhatti 8*0654ab7fSJay Buddhabhatti #include <assert.h> 9*0654ab7fSJay Buddhabhatti 10*0654ab7fSJay Buddhabhatti #include <common/debug.h> 11*0654ab7fSJay Buddhabhatti #include <lib/mmio.h> 12*0654ab7fSJay Buddhabhatti #include <lib/psci/psci.h> 13*0654ab7fSJay Buddhabhatti #include <plat/arm/common/plat_arm.h> 14*0654ab7fSJay Buddhabhatti #include <plat/common/platform.h> 15*0654ab7fSJay Buddhabhatti #include <plat_arm.h> 16*0654ab7fSJay Buddhabhatti 17*0654ab7fSJay Buddhabhatti #include <plat_private.h> 18*0654ab7fSJay Buddhabhatti #include "pm_api_sys.h" 19*0654ab7fSJay Buddhabhatti #include "pm_client.h" 20*0654ab7fSJay Buddhabhatti #include <pm_common.h> 21*0654ab7fSJay Buddhabhatti #include "pm_svc_main.h" 22*0654ab7fSJay Buddhabhatti #include "versal_net_def.h" 23*0654ab7fSJay Buddhabhatti 24*0654ab7fSJay Buddhabhatti static uintptr_t versal_net_sec_entry; 25*0654ab7fSJay Buddhabhatti 26*0654ab7fSJay Buddhabhatti static int32_t versal_net_pwr_domain_on(u_register_t mpidr) 27*0654ab7fSJay Buddhabhatti { 28*0654ab7fSJay Buddhabhatti uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr); 29*0654ab7fSJay Buddhabhatti const struct pm_proc *proc; 30*0654ab7fSJay Buddhabhatti 31*0654ab7fSJay Buddhabhatti VERBOSE("%s: mpidr: 0x%lx, cpuid: %x\n", 32*0654ab7fSJay Buddhabhatti __func__, mpidr, cpu_id); 33*0654ab7fSJay Buddhabhatti 34*0654ab7fSJay Buddhabhatti if (cpu_id == -1) { 35*0654ab7fSJay Buddhabhatti return PSCI_E_INTERN_FAIL; 36*0654ab7fSJay Buddhabhatti } 37*0654ab7fSJay Buddhabhatti 38*0654ab7fSJay Buddhabhatti proc = pm_get_proc(cpu_id); 39*0654ab7fSJay Buddhabhatti if (!proc) { 40*0654ab7fSJay Buddhabhatti return PSCI_E_INTERN_FAIL; 41*0654ab7fSJay Buddhabhatti } 42*0654ab7fSJay Buddhabhatti 43*0654ab7fSJay Buddhabhatti pm_req_wakeup(proc->node_id, (versal_net_sec_entry & 0xFFFFFFFFU) | 0x1U, 44*0654ab7fSJay Buddhabhatti versal_net_sec_entry >> 32, 0, 0); 45*0654ab7fSJay Buddhabhatti 46*0654ab7fSJay Buddhabhatti /* Clear power down request */ 47*0654ab7fSJay Buddhabhatti pm_client_wakeup(proc); 48*0654ab7fSJay Buddhabhatti 49*0654ab7fSJay Buddhabhatti return PSCI_E_SUCCESS; 50*0654ab7fSJay Buddhabhatti } 51*0654ab7fSJay Buddhabhatti 52*0654ab7fSJay Buddhabhatti /** 53*0654ab7fSJay Buddhabhatti * versal_net_pwr_domain_off() - This function performs actions to turn off core 54*0654ab7fSJay Buddhabhatti * 55*0654ab7fSJay Buddhabhatti * @param target_state Targeted state 56*0654ab7fSJay Buddhabhatti */ 57*0654ab7fSJay Buddhabhatti static void versal_net_pwr_domain_off(const psci_power_state_t *target_state) 58*0654ab7fSJay Buddhabhatti { 59*0654ab7fSJay Buddhabhatti uint32_t cpu_id = plat_my_core_pos(); 60*0654ab7fSJay Buddhabhatti const struct pm_proc *proc = pm_get_proc(cpu_id); 61*0654ab7fSJay Buddhabhatti 62*0654ab7fSJay Buddhabhatti for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) { 63*0654ab7fSJay Buddhabhatti VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 64*0654ab7fSJay Buddhabhatti __func__, i, target_state->pwr_domain_state[i]); 65*0654ab7fSJay Buddhabhatti } 66*0654ab7fSJay Buddhabhatti 67*0654ab7fSJay Buddhabhatti /* Prevent interrupts from spuriously waking up this cpu */ 68*0654ab7fSJay Buddhabhatti plat_versal_net_gic_cpuif_disable(); 69*0654ab7fSJay Buddhabhatti 70*0654ab7fSJay Buddhabhatti /* 71*0654ab7fSJay Buddhabhatti * Send request to PMC to power down the appropriate APU CPU 72*0654ab7fSJay Buddhabhatti * core. 73*0654ab7fSJay Buddhabhatti * According to PSCI specification, CPU_off function does not 74*0654ab7fSJay Buddhabhatti * have resume address and CPU core can only be woken up 75*0654ab7fSJay Buddhabhatti * invoking CPU_on function, during which resume address will 76*0654ab7fSJay Buddhabhatti * be set. 77*0654ab7fSJay Buddhabhatti */ 78*0654ab7fSJay Buddhabhatti pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0, 79*0654ab7fSJay Buddhabhatti SECURE_FLAG); 80*0654ab7fSJay Buddhabhatti } 81*0654ab7fSJay Buddhabhatti 82*0654ab7fSJay Buddhabhatti /** 83*0654ab7fSJay Buddhabhatti * versal_net_system_reset() - This function sends the reset request 84*0654ab7fSJay Buddhabhatti * to firmware for the system to reset. This function does not return. 85*0654ab7fSJay Buddhabhatti */ 86*0654ab7fSJay Buddhabhatti static void __dead2 versal_net_system_reset(void) 87*0654ab7fSJay Buddhabhatti { 88*0654ab7fSJay Buddhabhatti /* Send the system reset request to the PMC */ 89*0654ab7fSJay Buddhabhatti pm_system_shutdown(XPM_SHUTDOWN_TYPE_RESET, 90*0654ab7fSJay Buddhabhatti pm_get_shutdown_scope(), SECURE_FLAG); 91*0654ab7fSJay Buddhabhatti 92*0654ab7fSJay Buddhabhatti while (1) { 93*0654ab7fSJay Buddhabhatti wfi(); 94*0654ab7fSJay Buddhabhatti } 95*0654ab7fSJay Buddhabhatti } 96*0654ab7fSJay Buddhabhatti 97*0654ab7fSJay Buddhabhatti /** 98*0654ab7fSJay Buddhabhatti * versal_net_pwr_domain_suspend() - This function sends request to PMC to suspend 99*0654ab7fSJay Buddhabhatti * core. 100*0654ab7fSJay Buddhabhatti * 101*0654ab7fSJay Buddhabhatti * @param target_state Targeted state 102*0654ab7fSJay Buddhabhatti */ 103*0654ab7fSJay Buddhabhatti static void versal_net_pwr_domain_suspend(const psci_power_state_t *target_state) 104*0654ab7fSJay Buddhabhatti { 105*0654ab7fSJay Buddhabhatti uint32_t state; 106*0654ab7fSJay Buddhabhatti uint32_t cpu_id = plat_my_core_pos(); 107*0654ab7fSJay Buddhabhatti const struct pm_proc *proc = pm_get_proc(cpu_id); 108*0654ab7fSJay Buddhabhatti 109*0654ab7fSJay Buddhabhatti for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) { 110*0654ab7fSJay Buddhabhatti VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 111*0654ab7fSJay Buddhabhatti __func__, i, target_state->pwr_domain_state[i]); 112*0654ab7fSJay Buddhabhatti } 113*0654ab7fSJay Buddhabhatti 114*0654ab7fSJay Buddhabhatti plat_versal_net_gic_cpuif_disable(); 115*0654ab7fSJay Buddhabhatti 116*0654ab7fSJay Buddhabhatti if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) { 117*0654ab7fSJay Buddhabhatti plat_versal_net_gic_save(); 118*0654ab7fSJay Buddhabhatti } 119*0654ab7fSJay Buddhabhatti 120*0654ab7fSJay Buddhabhatti state = target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE ? 121*0654ab7fSJay Buddhabhatti PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE; 122*0654ab7fSJay Buddhabhatti 123*0654ab7fSJay Buddhabhatti /* Send request to PMC to suspend this core */ 124*0654ab7fSJay Buddhabhatti pm_self_suspend(proc->node_id, MAX_LATENCY, state, versal_net_sec_entry, 125*0654ab7fSJay Buddhabhatti SECURE_FLAG); 126*0654ab7fSJay Buddhabhatti 127*0654ab7fSJay Buddhabhatti /* TODO: disable coherency */ 128*0654ab7fSJay Buddhabhatti } 129*0654ab7fSJay Buddhabhatti 130*0654ab7fSJay Buddhabhatti static void versal_net_pwr_domain_on_finish(const psci_power_state_t *target_state) 131*0654ab7fSJay Buddhabhatti { 132*0654ab7fSJay Buddhabhatti (void)target_state; 133*0654ab7fSJay Buddhabhatti 134*0654ab7fSJay Buddhabhatti /* Enable the gic cpu interface */ 135*0654ab7fSJay Buddhabhatti plat_versal_net_gic_pcpu_init(); 136*0654ab7fSJay Buddhabhatti 137*0654ab7fSJay Buddhabhatti /* Program the gic per-cpu distributor or re-distributor interface */ 138*0654ab7fSJay Buddhabhatti plat_versal_net_gic_cpuif_enable(); 139*0654ab7fSJay Buddhabhatti } 140*0654ab7fSJay Buddhabhatti 141*0654ab7fSJay Buddhabhatti /** 142*0654ab7fSJay Buddhabhatti * versal_net_pwr_domain_suspend_finish() - This function performs actions to finish 143*0654ab7fSJay Buddhabhatti * suspend procedure. 144*0654ab7fSJay Buddhabhatti * 145*0654ab7fSJay Buddhabhatti * @param target_state Targeted state 146*0654ab7fSJay Buddhabhatti */ 147*0654ab7fSJay Buddhabhatti static void versal_net_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 148*0654ab7fSJay Buddhabhatti { 149*0654ab7fSJay Buddhabhatti uint32_t cpu_id = plat_my_core_pos(); 150*0654ab7fSJay Buddhabhatti const struct pm_proc *proc = pm_get_proc(cpu_id); 151*0654ab7fSJay Buddhabhatti 152*0654ab7fSJay Buddhabhatti for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 153*0654ab7fSJay Buddhabhatti VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 154*0654ab7fSJay Buddhabhatti __func__, i, target_state->pwr_domain_state[i]); 155*0654ab7fSJay Buddhabhatti 156*0654ab7fSJay Buddhabhatti /* Clear the APU power control register for this cpu */ 157*0654ab7fSJay Buddhabhatti pm_client_wakeup(proc); 158*0654ab7fSJay Buddhabhatti 159*0654ab7fSJay Buddhabhatti /* TODO: enable coherency */ 160*0654ab7fSJay Buddhabhatti 161*0654ab7fSJay Buddhabhatti /* APU was turned off, so restore GIC context */ 162*0654ab7fSJay Buddhabhatti if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) { 163*0654ab7fSJay Buddhabhatti plat_versal_net_gic_resume(); 164*0654ab7fSJay Buddhabhatti } 165*0654ab7fSJay Buddhabhatti 166*0654ab7fSJay Buddhabhatti plat_versal_net_gic_cpuif_enable(); 167*0654ab7fSJay Buddhabhatti } 168*0654ab7fSJay Buddhabhatti 169*0654ab7fSJay Buddhabhatti /** 170*0654ab7fSJay Buddhabhatti * versal_net_system_off() - This function sends the system off request 171*0654ab7fSJay Buddhabhatti * to firmware. This function does not return. 172*0654ab7fSJay Buddhabhatti */ 173*0654ab7fSJay Buddhabhatti static void __dead2 versal_net_system_off(void) 174*0654ab7fSJay Buddhabhatti { 175*0654ab7fSJay Buddhabhatti /* Send the power down request to the PMC */ 176*0654ab7fSJay Buddhabhatti pm_system_shutdown(XPM_SHUTDOWN_TYPE_SHUTDOWN, 177*0654ab7fSJay Buddhabhatti pm_get_shutdown_scope(), SECURE_FLAG); 178*0654ab7fSJay Buddhabhatti 179*0654ab7fSJay Buddhabhatti while (1) { 180*0654ab7fSJay Buddhabhatti wfi(); 181*0654ab7fSJay Buddhabhatti } 182*0654ab7fSJay Buddhabhatti } 183*0654ab7fSJay Buddhabhatti 184*0654ab7fSJay Buddhabhatti /** 185*0654ab7fSJay Buddhabhatti * versal_net_validate_power_state() - This function ensures that the power state 186*0654ab7fSJay Buddhabhatti * parameter in request is valid. 187*0654ab7fSJay Buddhabhatti * 188*0654ab7fSJay Buddhabhatti * @param power_state Power state of core 189*0654ab7fSJay Buddhabhatti * @param req_state Requested state 190*0654ab7fSJay Buddhabhatti * 191*0654ab7fSJay Buddhabhatti * @return Returns status, either PSCI_E_SUCCESS or reason 192*0654ab7fSJay Buddhabhatti */ 193*0654ab7fSJay Buddhabhatti static int32_t versal_net_validate_power_state(unsigned int power_state, 194*0654ab7fSJay Buddhabhatti psci_power_state_t *req_state) 195*0654ab7fSJay Buddhabhatti { 196*0654ab7fSJay Buddhabhatti VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); 197*0654ab7fSJay Buddhabhatti 198*0654ab7fSJay Buddhabhatti int32_t pstate = psci_get_pstate_type(power_state); 199*0654ab7fSJay Buddhabhatti 200*0654ab7fSJay Buddhabhatti assert(req_state); 201*0654ab7fSJay Buddhabhatti 202*0654ab7fSJay Buddhabhatti /* Sanity check the requested state */ 203*0654ab7fSJay Buddhabhatti if (pstate == PSTATE_TYPE_STANDBY) { 204*0654ab7fSJay Buddhabhatti req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE; 205*0654ab7fSJay Buddhabhatti } else { 206*0654ab7fSJay Buddhabhatti req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE; 207*0654ab7fSJay Buddhabhatti } 208*0654ab7fSJay Buddhabhatti 209*0654ab7fSJay Buddhabhatti /* We expect the 'state id' to be zero */ 210*0654ab7fSJay Buddhabhatti if (psci_get_pstate_id(power_state)) { 211*0654ab7fSJay Buddhabhatti return PSCI_E_INVALID_PARAMS; 212*0654ab7fSJay Buddhabhatti } 213*0654ab7fSJay Buddhabhatti 214*0654ab7fSJay Buddhabhatti return PSCI_E_SUCCESS; 215*0654ab7fSJay Buddhabhatti } 216*0654ab7fSJay Buddhabhatti 217*0654ab7fSJay Buddhabhatti /** 218*0654ab7fSJay Buddhabhatti * versal_net_get_sys_suspend_power_state() - Get power state for system suspend 219*0654ab7fSJay Buddhabhatti * 220*0654ab7fSJay Buddhabhatti * @param req_state Requested state 221*0654ab7fSJay Buddhabhatti */ 222*0654ab7fSJay Buddhabhatti static void versal_net_get_sys_suspend_power_state(psci_power_state_t *req_state) 223*0654ab7fSJay Buddhabhatti { 224*0654ab7fSJay Buddhabhatti req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; 225*0654ab7fSJay Buddhabhatti req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; 226*0654ab7fSJay Buddhabhatti } 227*0654ab7fSJay Buddhabhatti 228*0654ab7fSJay Buddhabhatti static const struct plat_psci_ops versal_net_nopmc_psci_ops = { 229*0654ab7fSJay Buddhabhatti .pwr_domain_on = versal_net_pwr_domain_on, 230*0654ab7fSJay Buddhabhatti .pwr_domain_off = versal_net_pwr_domain_off, 231*0654ab7fSJay Buddhabhatti .pwr_domain_on_finish = versal_net_pwr_domain_on_finish, 232*0654ab7fSJay Buddhabhatti .pwr_domain_suspend = versal_net_pwr_domain_suspend, 233*0654ab7fSJay Buddhabhatti .pwr_domain_suspend_finish = versal_net_pwr_domain_suspend_finish, 234*0654ab7fSJay Buddhabhatti .system_off = versal_net_system_off, 235*0654ab7fSJay Buddhabhatti .system_reset = versal_net_system_reset, 236*0654ab7fSJay Buddhabhatti .validate_power_state = versal_net_validate_power_state, 237*0654ab7fSJay Buddhabhatti .get_sys_suspend_power_state = versal_net_get_sys_suspend_power_state, 238*0654ab7fSJay Buddhabhatti }; 239*0654ab7fSJay Buddhabhatti 240*0654ab7fSJay Buddhabhatti /******************************************************************************* 241*0654ab7fSJay Buddhabhatti * Export the platform specific power ops. 242*0654ab7fSJay Buddhabhatti ******************************************************************************/ 243*0654ab7fSJay Buddhabhatti int32_t plat_setup_psci_ops(uintptr_t sec_entrypoint, 244*0654ab7fSJay Buddhabhatti const struct plat_psci_ops **psci_ops) 245*0654ab7fSJay Buddhabhatti { 246*0654ab7fSJay Buddhabhatti versal_net_sec_entry = sec_entrypoint; 247*0654ab7fSJay Buddhabhatti 248*0654ab7fSJay Buddhabhatti VERBOSE("Setting up entry point %lx\n", versal_net_sec_entry); 249*0654ab7fSJay Buddhabhatti 250*0654ab7fSJay Buddhabhatti *psci_ops = &versal_net_nopmc_psci_ops; 251*0654ab7fSJay Buddhabhatti 252*0654ab7fSJay Buddhabhatti return 0; 253*0654ab7fSJay Buddhabhatti } 254*0654ab7fSJay Buddhabhatti 255*0654ab7fSJay Buddhabhatti int32_t sip_svc_setup_init(void) 256*0654ab7fSJay Buddhabhatti { 257*0654ab7fSJay Buddhabhatti return pm_setup(); 258*0654ab7fSJay Buddhabhatti } 259*0654ab7fSJay Buddhabhatti 260*0654ab7fSJay Buddhabhatti uint64_t smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, 261*0654ab7fSJay Buddhabhatti void *cookie, void *handle, uint64_t flags) 262*0654ab7fSJay Buddhabhatti { 263*0654ab7fSJay Buddhabhatti return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); 264*0654ab7fSJay Buddhabhatti } 265