1c76d4239SHadi Asyrafi /* 2*6197dc98SJit Loon Lim * Copyright (c) 2019-2023, 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> 9*6197dc98SJit Loon Lim #ifndef SOCFPGA_GIC_V3 10c76d4239SHadi Asyrafi #include <drivers/arm/gicv2.h> 11*6197dc98SJit Loon Lim #else 12*6197dc98SJit Loon Lim #include <drivers/arm/gicv3.h> 13*6197dc98SJit Loon Lim #endif 14c76d4239SHadi Asyrafi #include <lib/mmio.h> 15c76d4239SHadi Asyrafi #include <lib/psci/psci.h> 16c76d4239SHadi Asyrafi #include <plat/common/platform.h> 17c76d4239SHadi Asyrafi 18c76d4239SHadi Asyrafi #include "socfpga_mailbox.h" 19c76d4239SHadi Asyrafi #include "socfpga_plat_def.h" 2032cf34acSHadi Asyrafi #include "socfpga_reset_manager.h" 21c703d752SSieu Mun Tang #include "socfpga_sip_svc.h" 22*6197dc98SJit Loon Lim #include "socfpga_system_manager.h" 23c76d4239SHadi Asyrafi 24c76d4239SHadi Asyrafi 25c76d4239SHadi Asyrafi /******************************************************************************* 26c76d4239SHadi Asyrafi * plat handler called when a CPU is about to enter standby. 27c76d4239SHadi Asyrafi ******************************************************************************/ 28c76d4239SHadi Asyrafi void socfpga_cpu_standby(plat_local_state_t cpu_state) 29c76d4239SHadi Asyrafi { 30c76d4239SHadi Asyrafi /* 31c76d4239SHadi Asyrafi * Enter standby state 32c76d4239SHadi Asyrafi * dsb is good practice before using wfi to enter low power states 33c76d4239SHadi Asyrafi */ 34c76d4239SHadi Asyrafi VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state); 35c76d4239SHadi Asyrafi dsb(); 36c76d4239SHadi Asyrafi wfi(); 37c76d4239SHadi Asyrafi } 38c76d4239SHadi Asyrafi 39c76d4239SHadi Asyrafi /******************************************************************************* 40c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned on. The 41c76d4239SHadi Asyrafi * mpidr determines the CPU to be turned on. 42c76d4239SHadi Asyrafi ******************************************************************************/ 43c76d4239SHadi Asyrafi int socfpga_pwr_domain_on(u_register_t mpidr) 44c76d4239SHadi Asyrafi { 45c76d4239SHadi Asyrafi unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); 467f7a16a6SJit Loon Lim uint32_t psci_boot = 0x00; 47c76d4239SHadi Asyrafi 48c76d4239SHadi Asyrafi VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); 49c76d4239SHadi Asyrafi 50c76d4239SHadi Asyrafi if (cpu_id == -1) 51c76d4239SHadi Asyrafi return PSCI_E_INTERN_FAIL; 52c76d4239SHadi Asyrafi 537f7a16a6SJit Loon Lim if (cpu_id == 0x00) { 547f7a16a6SJit Loon Lim psci_boot = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8)); 557f7a16a6SJit Loon Lim psci_boot |= 0x20000; /* bit 17 */ 567f7a16a6SJit Loon Lim mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8), psci_boot); 577f7a16a6SJit Loon Lim } 587f7a16a6SJit Loon Lim 59cf82aff0SHadi Asyrafi mmio_write_64(PLAT_CPUID_RELEASE, cpu_id); 60c76d4239SHadi Asyrafi 61c76d4239SHadi Asyrafi /* release core reset */ 62391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 63c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 64c76d4239SHadi Asyrafi } 65c76d4239SHadi Asyrafi 66c76d4239SHadi Asyrafi /******************************************************************************* 67c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned off. The 68c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 69c76d4239SHadi Asyrafi ******************************************************************************/ 70c76d4239SHadi Asyrafi void socfpga_pwr_domain_off(const psci_power_state_t *target_state) 71c76d4239SHadi Asyrafi { 72c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 73c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 74c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 75c76d4239SHadi Asyrafi 76c76d4239SHadi Asyrafi /* Prevent interrupts from spuriously waking up this cpu */ 77c76d4239SHadi Asyrafi gicv2_cpuif_disable(); 78c76d4239SHadi Asyrafi } 79c76d4239SHadi Asyrafi 80c76d4239SHadi Asyrafi /******************************************************************************* 81c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be suspended. The 82c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 83c76d4239SHadi Asyrafi ******************************************************************************/ 84c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state) 85c76d4239SHadi Asyrafi { 86c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 87c76d4239SHadi Asyrafi 88c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 89c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 90c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 9132cf34acSHadi Asyrafi 92c76d4239SHadi Asyrafi /* assert core reset */ 93391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 94c76d4239SHadi Asyrafi 95c76d4239SHadi Asyrafi } 96c76d4239SHadi Asyrafi 97c76d4239SHadi Asyrafi /******************************************************************************* 98c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 99c76d4239SHadi Asyrafi * being turned off earlier. The target_state encodes the low power state that 100c76d4239SHadi Asyrafi * each level has woken up from. 101c76d4239SHadi Asyrafi ******************************************************************************/ 102c76d4239SHadi Asyrafi void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state) 103c76d4239SHadi Asyrafi { 104c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 105c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 106c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 107c76d4239SHadi Asyrafi 108c76d4239SHadi Asyrafi /* Program the gic per-cpu distributor or re-distributor interface */ 109c76d4239SHadi Asyrafi gicv2_pcpu_distif_init(); 110c76d4239SHadi Asyrafi gicv2_set_pe_target_mask(plat_my_core_pos()); 111c76d4239SHadi Asyrafi 112c76d4239SHadi Asyrafi /* Enable the gic cpu interface */ 113c76d4239SHadi Asyrafi gicv2_cpuif_enable(); 114c76d4239SHadi Asyrafi } 115c76d4239SHadi Asyrafi 116c76d4239SHadi Asyrafi /******************************************************************************* 117c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 118c76d4239SHadi Asyrafi * having been suspended earlier. The target_state encodes the low power state 119c76d4239SHadi Asyrafi * that each level has woken up from. 120c76d4239SHadi Asyrafi * TODO: At the moment we reuse the on finisher and reinitialize the secure 121c76d4239SHadi Asyrafi * context. Need to implement a separate suspend finisher. 122c76d4239SHadi Asyrafi ******************************************************************************/ 123c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 124c76d4239SHadi Asyrafi { 125c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 126c76d4239SHadi Asyrafi 127c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 128c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 129c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 130c76d4239SHadi Asyrafi 131c76d4239SHadi Asyrafi /* release core reset */ 132391eeeefSHadi Asyrafi mmio_clrbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 133c76d4239SHadi Asyrafi } 134c76d4239SHadi Asyrafi 135c76d4239SHadi Asyrafi /******************************************************************************* 136c76d4239SHadi Asyrafi * plat handlers to shutdown/reboot the system 137c76d4239SHadi Asyrafi ******************************************************************************/ 138c76d4239SHadi Asyrafi static void __dead2 socfpga_system_off(void) 139c76d4239SHadi Asyrafi { 140c76d4239SHadi Asyrafi wfi(); 141c76d4239SHadi Asyrafi ERROR("System Off: operation not handled.\n"); 142c76d4239SHadi Asyrafi panic(); 143c76d4239SHadi Asyrafi } 144c76d4239SHadi Asyrafi 145e1f97d9cSHadi Asyrafi extern uint64_t intel_rsu_update_address; 146e1f97d9cSHadi Asyrafi 147c76d4239SHadi Asyrafi static void __dead2 socfpga_system_reset(void) 148c76d4239SHadi Asyrafi { 149ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi uint32_t addr_buf[2]; 150ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi 151ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi memcpy(addr_buf, &intel_rsu_update_address, 152ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi sizeof(intel_rsu_update_address)); 153*6197dc98SJit Loon Lim if (intel_rsu_update_address) { 154ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi mailbox_rsu_update(addr_buf); 155*6197dc98SJit Loon Lim } else { 156c76d4239SHadi Asyrafi mailbox_reset_cold(); 157*6197dc98SJit Loon Lim } 158c76d4239SHadi Asyrafi 159c76d4239SHadi Asyrafi while (1) 160c76d4239SHadi Asyrafi wfi(); 161c76d4239SHadi Asyrafi } 162c76d4239SHadi Asyrafi 16332cf34acSHadi Asyrafi static int socfpga_system_reset2(int is_vendor, int reset_type, 16432cf34acSHadi Asyrafi u_register_t cookie) 16532cf34acSHadi Asyrafi { 166c703d752SSieu Mun Tang if (cold_reset_for_ecc_dbe()) { 167c703d752SSieu Mun Tang mailbox_reset_cold(); 168c703d752SSieu Mun Tang } 16932cf34acSHadi Asyrafi /* disable cpuif */ 17032cf34acSHadi Asyrafi gicv2_cpuif_disable(); 17132cf34acSHadi Asyrafi 17232cf34acSHadi Asyrafi /* Store magic number */ 17332cf34acSHadi Asyrafi mmio_write_32(L2_RESET_DONE_REG, L2_RESET_DONE_STATUS); 17432cf34acSHadi Asyrafi 17532cf34acSHadi Asyrafi /* Increase timeout */ 176391eeeefSHadi Asyrafi mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff); 17732cf34acSHadi Asyrafi 17832cf34acSHadi Asyrafi /* Enable handshakes */ 179391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET); 18032cf34acSHadi Asyrafi 18132cf34acSHadi Asyrafi /* Reset L2 module */ 182391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100); 18332cf34acSHadi Asyrafi 18432cf34acSHadi Asyrafi while (1) 18532cf34acSHadi Asyrafi wfi(); 18632cf34acSHadi Asyrafi 18732cf34acSHadi Asyrafi /* Should not reach here */ 18832cf34acSHadi Asyrafi return 0; 18932cf34acSHadi Asyrafi } 19032cf34acSHadi Asyrafi 191c76d4239SHadi Asyrafi int socfpga_validate_power_state(unsigned int power_state, 192c76d4239SHadi Asyrafi psci_power_state_t *req_state) 193c76d4239SHadi Asyrafi { 194c76d4239SHadi Asyrafi VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); 195c76d4239SHadi Asyrafi 196c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 197c76d4239SHadi Asyrafi } 198c76d4239SHadi Asyrafi 199c76d4239SHadi Asyrafi int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint) 200c76d4239SHadi Asyrafi { 201c76d4239SHadi Asyrafi VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint); 202c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 203c76d4239SHadi Asyrafi } 204c76d4239SHadi Asyrafi 205c76d4239SHadi Asyrafi void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state) 206c76d4239SHadi Asyrafi { 207c76d4239SHadi Asyrafi req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; 208c76d4239SHadi Asyrafi req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; 209c76d4239SHadi Asyrafi } 210c76d4239SHadi Asyrafi 211c76d4239SHadi Asyrafi /******************************************************************************* 212c76d4239SHadi Asyrafi * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 213c76d4239SHadi Asyrafi * platform layer will take care of registering the handlers with PSCI. 214c76d4239SHadi Asyrafi ******************************************************************************/ 215c76d4239SHadi Asyrafi const plat_psci_ops_t socfpga_psci_pm_ops = { 216c76d4239SHadi Asyrafi .cpu_standby = socfpga_cpu_standby, 217c76d4239SHadi Asyrafi .pwr_domain_on = socfpga_pwr_domain_on, 218c76d4239SHadi Asyrafi .pwr_domain_off = socfpga_pwr_domain_off, 219c76d4239SHadi Asyrafi .pwr_domain_suspend = socfpga_pwr_domain_suspend, 220c76d4239SHadi Asyrafi .pwr_domain_on_finish = socfpga_pwr_domain_on_finish, 221c76d4239SHadi Asyrafi .pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish, 222c76d4239SHadi Asyrafi .system_off = socfpga_system_off, 223c76d4239SHadi Asyrafi .system_reset = socfpga_system_reset, 22432cf34acSHadi Asyrafi .system_reset2 = socfpga_system_reset2, 225c76d4239SHadi Asyrafi .validate_power_state = socfpga_validate_power_state, 226c76d4239SHadi Asyrafi .validate_ns_entrypoint = socfpga_validate_ns_entrypoint, 227c76d4239SHadi Asyrafi .get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state 228c76d4239SHadi Asyrafi }; 229c76d4239SHadi Asyrafi 230c76d4239SHadi Asyrafi /******************************************************************************* 231c76d4239SHadi Asyrafi * Export the platform specific power ops. 232c76d4239SHadi Asyrafi ******************************************************************************/ 233c76d4239SHadi Asyrafi int plat_setup_psci_ops(uintptr_t sec_entrypoint, 234c76d4239SHadi Asyrafi const struct plat_psci_ops **psci_ops) 235c76d4239SHadi Asyrafi { 236c76d4239SHadi Asyrafi /* Save warm boot entrypoint.*/ 237cf82aff0SHadi Asyrafi mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint); 238c76d4239SHadi Asyrafi *psci_ops = &socfpga_psci_pm_ops; 239cf82aff0SHadi Asyrafi 240c76d4239SHadi Asyrafi return 0; 241c76d4239SHadi Asyrafi } 242