1*c76d4239SHadi Asyrafi /* 2*c76d4239SHadi Asyrafi * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. 3*c76d4239SHadi Asyrafi * 4*c76d4239SHadi Asyrafi * SPDX-License-Identifier: BSD-3-Clause 5*c76d4239SHadi Asyrafi */ 6*c76d4239SHadi Asyrafi 7*c76d4239SHadi Asyrafi #include <arch_helpers.h> 8*c76d4239SHadi Asyrafi #include <common/debug.h> 9*c76d4239SHadi Asyrafi #include <drivers/arm/gicv2.h> 10*c76d4239SHadi Asyrafi #include <lib/mmio.h> 11*c76d4239SHadi Asyrafi #include <lib/psci/psci.h> 12*c76d4239SHadi Asyrafi #include <plat/common/platform.h> 13*c76d4239SHadi Asyrafi 14*c76d4239SHadi Asyrafi #include "socfpga_mailbox.h" 15*c76d4239SHadi Asyrafi #include "socfpga_plat_def.h" 16*c76d4239SHadi Asyrafi 17*c76d4239SHadi Asyrafi 18*c76d4239SHadi Asyrafi uintptr_t *socfpga_sec_entry = (uintptr_t *) PLAT_SEC_ENTRY; 19*c76d4239SHadi Asyrafi uintptr_t *cpuid_release = (uintptr_t *) PLAT_CPUID_RELEASE; 20*c76d4239SHadi Asyrafi 21*c76d4239SHadi Asyrafi /******************************************************************************* 22*c76d4239SHadi Asyrafi * plat handler called when a CPU is about to enter standby. 23*c76d4239SHadi Asyrafi ******************************************************************************/ 24*c76d4239SHadi Asyrafi void socfpga_cpu_standby(plat_local_state_t cpu_state) 25*c76d4239SHadi Asyrafi { 26*c76d4239SHadi Asyrafi /* 27*c76d4239SHadi Asyrafi * Enter standby state 28*c76d4239SHadi Asyrafi * dsb is good practice before using wfi to enter low power states 29*c76d4239SHadi Asyrafi */ 30*c76d4239SHadi Asyrafi VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state); 31*c76d4239SHadi Asyrafi dsb(); 32*c76d4239SHadi Asyrafi wfi(); 33*c76d4239SHadi Asyrafi } 34*c76d4239SHadi Asyrafi 35*c76d4239SHadi Asyrafi /******************************************************************************* 36*c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned on. The 37*c76d4239SHadi Asyrafi * mpidr determines the CPU to be turned on. 38*c76d4239SHadi Asyrafi ******************************************************************************/ 39*c76d4239SHadi Asyrafi int socfpga_pwr_domain_on(u_register_t mpidr) 40*c76d4239SHadi Asyrafi { 41*c76d4239SHadi Asyrafi unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); 42*c76d4239SHadi Asyrafi 43*c76d4239SHadi Asyrafi VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); 44*c76d4239SHadi Asyrafi 45*c76d4239SHadi Asyrafi if (cpu_id == -1) 46*c76d4239SHadi Asyrafi return PSCI_E_INTERN_FAIL; 47*c76d4239SHadi Asyrafi 48*c76d4239SHadi Asyrafi *cpuid_release = cpu_id; 49*c76d4239SHadi Asyrafi 50*c76d4239SHadi Asyrafi /* release core reset */ 51*c76d4239SHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR_MPUMODRST_OFST, 1 << cpu_id); 52*c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 53*c76d4239SHadi Asyrafi } 54*c76d4239SHadi Asyrafi 55*c76d4239SHadi Asyrafi /******************************************************************************* 56*c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned off. The 57*c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 58*c76d4239SHadi Asyrafi ******************************************************************************/ 59*c76d4239SHadi Asyrafi void socfpga_pwr_domain_off(const psci_power_state_t *target_state) 60*c76d4239SHadi Asyrafi { 61*c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 62*c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 63*c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 64*c76d4239SHadi Asyrafi 65*c76d4239SHadi Asyrafi /* Prevent interrupts from spuriously waking up this cpu */ 66*c76d4239SHadi Asyrafi gicv2_cpuif_disable(); 67*c76d4239SHadi Asyrafi } 68*c76d4239SHadi Asyrafi 69*c76d4239SHadi Asyrafi /******************************************************************************* 70*c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be suspended. The 71*c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 72*c76d4239SHadi Asyrafi ******************************************************************************/ 73*c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state) 74*c76d4239SHadi Asyrafi { 75*c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 76*c76d4239SHadi Asyrafi 77*c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 78*c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 79*c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 80*c76d4239SHadi Asyrafi /* assert core reset */ 81*c76d4239SHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR_MPUMODRST_OFST, 1 << cpu_id); 82*c76d4239SHadi Asyrafi 83*c76d4239SHadi Asyrafi } 84*c76d4239SHadi Asyrafi 85*c76d4239SHadi Asyrafi /******************************************************************************* 86*c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 87*c76d4239SHadi Asyrafi * being turned off earlier. The target_state encodes the low power state that 88*c76d4239SHadi Asyrafi * each level has woken up from. 89*c76d4239SHadi Asyrafi ******************************************************************************/ 90*c76d4239SHadi Asyrafi void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state) 91*c76d4239SHadi Asyrafi { 92*c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 93*c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 94*c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 95*c76d4239SHadi Asyrafi 96*c76d4239SHadi Asyrafi /* Program the gic per-cpu distributor or re-distributor interface */ 97*c76d4239SHadi Asyrafi gicv2_pcpu_distif_init(); 98*c76d4239SHadi Asyrafi gicv2_set_pe_target_mask(plat_my_core_pos()); 99*c76d4239SHadi Asyrafi 100*c76d4239SHadi Asyrafi /* Enable the gic cpu interface */ 101*c76d4239SHadi Asyrafi gicv2_cpuif_enable(); 102*c76d4239SHadi Asyrafi } 103*c76d4239SHadi Asyrafi 104*c76d4239SHadi Asyrafi /******************************************************************************* 105*c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 106*c76d4239SHadi Asyrafi * having been suspended earlier. The target_state encodes the low power state 107*c76d4239SHadi Asyrafi * that each level has woken up from. 108*c76d4239SHadi Asyrafi * TODO: At the moment we reuse the on finisher and reinitialize the secure 109*c76d4239SHadi Asyrafi * context. Need to implement a separate suspend finisher. 110*c76d4239SHadi Asyrafi ******************************************************************************/ 111*c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 112*c76d4239SHadi Asyrafi { 113*c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 114*c76d4239SHadi Asyrafi 115*c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 116*c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 117*c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 118*c76d4239SHadi Asyrafi 119*c76d4239SHadi Asyrafi /* release core reset */ 120*c76d4239SHadi Asyrafi mmio_clrbits_32(SOCFPGA_RSTMGR_MPUMODRST_OFST, 1 << cpu_id); 121*c76d4239SHadi Asyrafi } 122*c76d4239SHadi Asyrafi 123*c76d4239SHadi Asyrafi /******************************************************************************* 124*c76d4239SHadi Asyrafi * plat handlers to shutdown/reboot the system 125*c76d4239SHadi Asyrafi ******************************************************************************/ 126*c76d4239SHadi Asyrafi static void __dead2 socfpga_system_off(void) 127*c76d4239SHadi Asyrafi { 128*c76d4239SHadi Asyrafi wfi(); 129*c76d4239SHadi Asyrafi ERROR("System Off: operation not handled.\n"); 130*c76d4239SHadi Asyrafi panic(); 131*c76d4239SHadi Asyrafi } 132*c76d4239SHadi Asyrafi 133*c76d4239SHadi Asyrafi static void __dead2 socfpga_system_reset(void) 134*c76d4239SHadi Asyrafi { 135*c76d4239SHadi Asyrafi mailbox_reset_cold(); 136*c76d4239SHadi Asyrafi 137*c76d4239SHadi Asyrafi while (1) 138*c76d4239SHadi Asyrafi wfi(); 139*c76d4239SHadi Asyrafi } 140*c76d4239SHadi Asyrafi 141*c76d4239SHadi Asyrafi int socfpga_validate_power_state(unsigned int power_state, 142*c76d4239SHadi Asyrafi psci_power_state_t *req_state) 143*c76d4239SHadi Asyrafi { 144*c76d4239SHadi Asyrafi VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); 145*c76d4239SHadi Asyrafi 146*c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 147*c76d4239SHadi Asyrafi } 148*c76d4239SHadi Asyrafi 149*c76d4239SHadi Asyrafi int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint) 150*c76d4239SHadi Asyrafi { 151*c76d4239SHadi Asyrafi VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint); 152*c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 153*c76d4239SHadi Asyrafi } 154*c76d4239SHadi Asyrafi 155*c76d4239SHadi Asyrafi void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state) 156*c76d4239SHadi Asyrafi { 157*c76d4239SHadi Asyrafi req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; 158*c76d4239SHadi Asyrafi req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; 159*c76d4239SHadi Asyrafi } 160*c76d4239SHadi Asyrafi 161*c76d4239SHadi Asyrafi /******************************************************************************* 162*c76d4239SHadi Asyrafi * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 163*c76d4239SHadi Asyrafi * platform layer will take care of registering the handlers with PSCI. 164*c76d4239SHadi Asyrafi ******************************************************************************/ 165*c76d4239SHadi Asyrafi const plat_psci_ops_t socfpga_psci_pm_ops = { 166*c76d4239SHadi Asyrafi .cpu_standby = socfpga_cpu_standby, 167*c76d4239SHadi Asyrafi .pwr_domain_on = socfpga_pwr_domain_on, 168*c76d4239SHadi Asyrafi .pwr_domain_off = socfpga_pwr_domain_off, 169*c76d4239SHadi Asyrafi .pwr_domain_suspend = socfpga_pwr_domain_suspend, 170*c76d4239SHadi Asyrafi .pwr_domain_on_finish = socfpga_pwr_domain_on_finish, 171*c76d4239SHadi Asyrafi .pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish, 172*c76d4239SHadi Asyrafi .system_off = socfpga_system_off, 173*c76d4239SHadi Asyrafi .system_reset = socfpga_system_reset, 174*c76d4239SHadi Asyrafi .validate_power_state = socfpga_validate_power_state, 175*c76d4239SHadi Asyrafi .validate_ns_entrypoint = socfpga_validate_ns_entrypoint, 176*c76d4239SHadi Asyrafi .get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state 177*c76d4239SHadi Asyrafi }; 178*c76d4239SHadi Asyrafi 179*c76d4239SHadi Asyrafi /******************************************************************************* 180*c76d4239SHadi Asyrafi * Export the platform specific power ops. 181*c76d4239SHadi Asyrafi ******************************************************************************/ 182*c76d4239SHadi Asyrafi int plat_setup_psci_ops(uintptr_t sec_entrypoint, 183*c76d4239SHadi Asyrafi const struct plat_psci_ops **psci_ops) 184*c76d4239SHadi Asyrafi { 185*c76d4239SHadi Asyrafi /* Save warm boot entrypoint.*/ 186*c76d4239SHadi Asyrafi *socfpga_sec_entry = sec_entrypoint; 187*c76d4239SHadi Asyrafi 188*c76d4239SHadi Asyrafi *psci_ops = &socfpga_psci_pm_ops; 189*c76d4239SHadi Asyrafi return 0; 190*c76d4239SHadi Asyrafi } 191