1c76d4239SHadi Asyrafi /* 2*c703d752SSieu Mun Tang * Copyright (c) 2019-2022, 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" 1632cf34acSHadi Asyrafi #include "socfpga_reset_manager.h" 17*c703d752SSieu Mun Tang #include "socfpga_sip_svc.h" 18c76d4239SHadi Asyrafi 19c76d4239SHadi Asyrafi 20c76d4239SHadi Asyrafi /******************************************************************************* 21c76d4239SHadi Asyrafi * plat handler called when a CPU is about to enter standby. 22c76d4239SHadi Asyrafi ******************************************************************************/ 23c76d4239SHadi Asyrafi void socfpga_cpu_standby(plat_local_state_t cpu_state) 24c76d4239SHadi Asyrafi { 25c76d4239SHadi Asyrafi /* 26c76d4239SHadi Asyrafi * Enter standby state 27c76d4239SHadi Asyrafi * dsb is good practice before using wfi to enter low power states 28c76d4239SHadi Asyrafi */ 29c76d4239SHadi Asyrafi VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state); 30c76d4239SHadi Asyrafi dsb(); 31c76d4239SHadi Asyrafi wfi(); 32c76d4239SHadi Asyrafi } 33c76d4239SHadi Asyrafi 34c76d4239SHadi Asyrafi /******************************************************************************* 35c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned on. The 36c76d4239SHadi Asyrafi * mpidr determines the CPU to be turned on. 37c76d4239SHadi Asyrafi ******************************************************************************/ 38c76d4239SHadi Asyrafi int socfpga_pwr_domain_on(u_register_t mpidr) 39c76d4239SHadi Asyrafi { 40c76d4239SHadi Asyrafi unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); 41c76d4239SHadi Asyrafi 42c76d4239SHadi Asyrafi VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); 43c76d4239SHadi Asyrafi 44c76d4239SHadi Asyrafi if (cpu_id == -1) 45c76d4239SHadi Asyrafi return PSCI_E_INTERN_FAIL; 46c76d4239SHadi Asyrafi 47cf82aff0SHadi Asyrafi mmio_write_64(PLAT_CPUID_RELEASE, cpu_id); 48c76d4239SHadi Asyrafi 49c76d4239SHadi Asyrafi /* release core reset */ 50391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 51c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 52c76d4239SHadi Asyrafi } 53c76d4239SHadi Asyrafi 54c76d4239SHadi Asyrafi /******************************************************************************* 55c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned off. The 56c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 57c76d4239SHadi Asyrafi ******************************************************************************/ 58c76d4239SHadi Asyrafi void socfpga_pwr_domain_off(const psci_power_state_t *target_state) 59c76d4239SHadi Asyrafi { 60c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 61c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 62c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 63c76d4239SHadi Asyrafi 64c76d4239SHadi Asyrafi /* Prevent interrupts from spuriously waking up this cpu */ 65c76d4239SHadi Asyrafi gicv2_cpuif_disable(); 66c76d4239SHadi Asyrafi } 67c76d4239SHadi Asyrafi 68c76d4239SHadi Asyrafi /******************************************************************************* 69c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be suspended. The 70c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 71c76d4239SHadi Asyrafi ******************************************************************************/ 72c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state) 73c76d4239SHadi Asyrafi { 74c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 75c76d4239SHadi Asyrafi 76c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 77c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 78c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 7932cf34acSHadi Asyrafi 80c76d4239SHadi Asyrafi /* assert core reset */ 81391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 82c76d4239SHadi Asyrafi 83c76d4239SHadi Asyrafi } 84c76d4239SHadi Asyrafi 85c76d4239SHadi Asyrafi /******************************************************************************* 86c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 87c76d4239SHadi Asyrafi * being turned off earlier. The target_state encodes the low power state that 88c76d4239SHadi Asyrafi * each level has woken up from. 89c76d4239SHadi Asyrafi ******************************************************************************/ 90c76d4239SHadi Asyrafi void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state) 91c76d4239SHadi Asyrafi { 92c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 93c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 94c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 95c76d4239SHadi Asyrafi 96c76d4239SHadi Asyrafi /* Program the gic per-cpu distributor or re-distributor interface */ 97c76d4239SHadi Asyrafi gicv2_pcpu_distif_init(); 98c76d4239SHadi Asyrafi gicv2_set_pe_target_mask(plat_my_core_pos()); 99c76d4239SHadi Asyrafi 100c76d4239SHadi Asyrafi /* Enable the gic cpu interface */ 101c76d4239SHadi Asyrafi gicv2_cpuif_enable(); 102c76d4239SHadi Asyrafi } 103c76d4239SHadi Asyrafi 104c76d4239SHadi Asyrafi /******************************************************************************* 105c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 106c76d4239SHadi Asyrafi * having been suspended earlier. The target_state encodes the low power state 107c76d4239SHadi Asyrafi * that each level has woken up from. 108c76d4239SHadi Asyrafi * TODO: At the moment we reuse the on finisher and reinitialize the secure 109c76d4239SHadi Asyrafi * context. Need to implement a separate suspend finisher. 110c76d4239SHadi Asyrafi ******************************************************************************/ 111c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 112c76d4239SHadi Asyrafi { 113c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 114c76d4239SHadi Asyrafi 115c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 116c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 117c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 118c76d4239SHadi Asyrafi 119c76d4239SHadi Asyrafi /* release core reset */ 120391eeeefSHadi Asyrafi mmio_clrbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 121c76d4239SHadi Asyrafi } 122c76d4239SHadi Asyrafi 123c76d4239SHadi Asyrafi /******************************************************************************* 124c76d4239SHadi Asyrafi * plat handlers to shutdown/reboot the system 125c76d4239SHadi Asyrafi ******************************************************************************/ 126c76d4239SHadi Asyrafi static void __dead2 socfpga_system_off(void) 127c76d4239SHadi Asyrafi { 128c76d4239SHadi Asyrafi wfi(); 129c76d4239SHadi Asyrafi ERROR("System Off: operation not handled.\n"); 130c76d4239SHadi Asyrafi panic(); 131c76d4239SHadi Asyrafi } 132c76d4239SHadi Asyrafi 133e1f97d9cSHadi Asyrafi extern uint64_t intel_rsu_update_address; 134e1f97d9cSHadi Asyrafi 135c76d4239SHadi Asyrafi static void __dead2 socfpga_system_reset(void) 136c76d4239SHadi Asyrafi { 137ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi uint32_t addr_buf[2]; 138ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi 139ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi memcpy(addr_buf, &intel_rsu_update_address, 140ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi sizeof(intel_rsu_update_address)); 141ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi 142e1f97d9cSHadi Asyrafi if (intel_rsu_update_address) 143ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi mailbox_rsu_update(addr_buf); 144e1f97d9cSHadi Asyrafi else 145c76d4239SHadi Asyrafi mailbox_reset_cold(); 146c76d4239SHadi Asyrafi 147c76d4239SHadi Asyrafi while (1) 148c76d4239SHadi Asyrafi wfi(); 149c76d4239SHadi Asyrafi } 150c76d4239SHadi Asyrafi 15132cf34acSHadi Asyrafi static int socfpga_system_reset2(int is_vendor, int reset_type, 15232cf34acSHadi Asyrafi u_register_t cookie) 15332cf34acSHadi Asyrafi { 154*c703d752SSieu Mun Tang if (cold_reset_for_ecc_dbe()) { 155*c703d752SSieu Mun Tang mailbox_reset_cold(); 156*c703d752SSieu Mun Tang } 15732cf34acSHadi Asyrafi /* disable cpuif */ 15832cf34acSHadi Asyrafi gicv2_cpuif_disable(); 15932cf34acSHadi Asyrafi 16032cf34acSHadi Asyrafi /* Store magic number */ 16132cf34acSHadi Asyrafi mmio_write_32(L2_RESET_DONE_REG, L2_RESET_DONE_STATUS); 16232cf34acSHadi Asyrafi 16332cf34acSHadi Asyrafi /* Increase timeout */ 164391eeeefSHadi Asyrafi mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff); 16532cf34acSHadi Asyrafi 16632cf34acSHadi Asyrafi /* Enable handshakes */ 167391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET); 16832cf34acSHadi Asyrafi 16932cf34acSHadi Asyrafi /* Reset L2 module */ 170391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100); 17132cf34acSHadi Asyrafi 17232cf34acSHadi Asyrafi while (1) 17332cf34acSHadi Asyrafi wfi(); 17432cf34acSHadi Asyrafi 17532cf34acSHadi Asyrafi /* Should not reach here */ 17632cf34acSHadi Asyrafi return 0; 17732cf34acSHadi Asyrafi } 17832cf34acSHadi Asyrafi 179c76d4239SHadi Asyrafi int socfpga_validate_power_state(unsigned int power_state, 180c76d4239SHadi Asyrafi psci_power_state_t *req_state) 181c76d4239SHadi Asyrafi { 182c76d4239SHadi Asyrafi VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); 183c76d4239SHadi Asyrafi 184c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 185c76d4239SHadi Asyrafi } 186c76d4239SHadi Asyrafi 187c76d4239SHadi Asyrafi int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint) 188c76d4239SHadi Asyrafi { 189c76d4239SHadi Asyrafi VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint); 190c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 191c76d4239SHadi Asyrafi } 192c76d4239SHadi Asyrafi 193c76d4239SHadi Asyrafi void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state) 194c76d4239SHadi Asyrafi { 195c76d4239SHadi Asyrafi req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; 196c76d4239SHadi Asyrafi req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; 197c76d4239SHadi Asyrafi } 198c76d4239SHadi Asyrafi 199c76d4239SHadi Asyrafi /******************************************************************************* 200c76d4239SHadi Asyrafi * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 201c76d4239SHadi Asyrafi * platform layer will take care of registering the handlers with PSCI. 202c76d4239SHadi Asyrafi ******************************************************************************/ 203c76d4239SHadi Asyrafi const plat_psci_ops_t socfpga_psci_pm_ops = { 204c76d4239SHadi Asyrafi .cpu_standby = socfpga_cpu_standby, 205c76d4239SHadi Asyrafi .pwr_domain_on = socfpga_pwr_domain_on, 206c76d4239SHadi Asyrafi .pwr_domain_off = socfpga_pwr_domain_off, 207c76d4239SHadi Asyrafi .pwr_domain_suspend = socfpga_pwr_domain_suspend, 208c76d4239SHadi Asyrafi .pwr_domain_on_finish = socfpga_pwr_domain_on_finish, 209c76d4239SHadi Asyrafi .pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish, 210c76d4239SHadi Asyrafi .system_off = socfpga_system_off, 211c76d4239SHadi Asyrafi .system_reset = socfpga_system_reset, 21232cf34acSHadi Asyrafi .system_reset2 = socfpga_system_reset2, 213c76d4239SHadi Asyrafi .validate_power_state = socfpga_validate_power_state, 214c76d4239SHadi Asyrafi .validate_ns_entrypoint = socfpga_validate_ns_entrypoint, 215c76d4239SHadi Asyrafi .get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state 216c76d4239SHadi Asyrafi }; 217c76d4239SHadi Asyrafi 218c76d4239SHadi Asyrafi /******************************************************************************* 219c76d4239SHadi Asyrafi * Export the platform specific power ops. 220c76d4239SHadi Asyrafi ******************************************************************************/ 221c76d4239SHadi Asyrafi int plat_setup_psci_ops(uintptr_t sec_entrypoint, 222c76d4239SHadi Asyrafi const struct plat_psci_ops **psci_ops) 223c76d4239SHadi Asyrafi { 224c76d4239SHadi Asyrafi /* Save warm boot entrypoint.*/ 225cf82aff0SHadi Asyrafi mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint); 226c76d4239SHadi Asyrafi *psci_ops = &socfpga_psci_pm_ops; 227cf82aff0SHadi Asyrafi 228c76d4239SHadi Asyrafi return 0; 229c76d4239SHadi Asyrafi } 230