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