1c76d4239SHadi Asyrafi /* 26197dc98SJit Loon Lim * Copyright (c) 2019-2023, ARM Limited and Contributors. All rights reserved. 379626f46SJit Loon Lim * Copyright (c) 2019-2023, Intel Corporation. All rights reserved. 4*e264b557SSieu Mun Tang * Copyright (c) 2024, Altera Corporation. All rights reserved. 5c76d4239SHadi Asyrafi * 6c76d4239SHadi Asyrafi * SPDX-License-Identifier: BSD-3-Clause 7c76d4239SHadi Asyrafi */ 8c76d4239SHadi Asyrafi 9c76d4239SHadi Asyrafi #include <arch_helpers.h> 10c76d4239SHadi Asyrafi #include <common/debug.h> 1179626f46SJit Loon Lim 1279626f46SJit Loon Lim #ifndef GICV3_SUPPORT_GIC600 13c76d4239SHadi Asyrafi #include <drivers/arm/gicv2.h> 146197dc98SJit Loon Lim #else 156197dc98SJit Loon Lim #include <drivers/arm/gicv3.h> 166197dc98SJit Loon Lim #endif 17c76d4239SHadi Asyrafi #include <lib/mmio.h> 18c76d4239SHadi Asyrafi #include <lib/psci/psci.h> 19c76d4239SHadi Asyrafi #include <plat/common/platform.h> 20c76d4239SHadi Asyrafi #include "socfpga_mailbox.h" 21c76d4239SHadi Asyrafi #include "socfpga_plat_def.h" 2232cf34acSHadi Asyrafi #include "socfpga_reset_manager.h" 23c703d752SSieu Mun Tang #include "socfpga_sip_svc.h" 246197dc98SJit Loon Lim #include "socfpga_system_manager.h" 25c76d4239SHadi Asyrafi 2679626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 2779626f46SJit Loon Lim void socfpga_wakeup_secondary_cpu(unsigned int cpu_id); 2879626f46SJit Loon Lim extern void plat_secondary_cold_boot_setup(void); 2979626f46SJit Loon Lim #endif 30c76d4239SHadi Asyrafi 31c76d4239SHadi Asyrafi /******************************************************************************* 32c76d4239SHadi Asyrafi * plat handler called when a CPU is about to enter standby. 33c76d4239SHadi Asyrafi ******************************************************************************/ 34c76d4239SHadi Asyrafi void socfpga_cpu_standby(plat_local_state_t cpu_state) 35c76d4239SHadi Asyrafi { 36c76d4239SHadi Asyrafi /* 37c76d4239SHadi Asyrafi * Enter standby state 38c76d4239SHadi Asyrafi * dsb is good practice before using wfi to enter low power states 39c76d4239SHadi Asyrafi */ 40c76d4239SHadi Asyrafi VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state); 41c76d4239SHadi Asyrafi dsb(); 42c76d4239SHadi Asyrafi wfi(); 43c76d4239SHadi Asyrafi } 44c76d4239SHadi Asyrafi 45c76d4239SHadi Asyrafi /******************************************************************************* 46c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned on. The 47c76d4239SHadi Asyrafi * mpidr determines the CPU to be turned on. 48c76d4239SHadi Asyrafi ******************************************************************************/ 49c76d4239SHadi Asyrafi int socfpga_pwr_domain_on(u_register_t mpidr) 50c76d4239SHadi Asyrafi { 51c76d4239SHadi Asyrafi unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); 5279626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 5379626f46SJit Loon Lim /* TODO: Add in CPU FUSE from SDM */ 5479626f46SJit Loon Lim #else 557f7a16a6SJit Loon Lim uint32_t psci_boot = 0x00; 56c76d4239SHadi Asyrafi 57c76d4239SHadi Asyrafi VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); 5879626f46SJit Loon Lim #endif 59c76d4239SHadi Asyrafi 60c76d4239SHadi Asyrafi if (cpu_id == -1) 61c76d4239SHadi Asyrafi return PSCI_E_INTERN_FAIL; 62c76d4239SHadi Asyrafi 6379626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 647f7a16a6SJit Loon Lim if (cpu_id == 0x00) { 657f7a16a6SJit Loon Lim psci_boot = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8)); 66655af4f4SJit Loon Lim psci_boot |= 0x80000; /* bit 19 */ 677f7a16a6SJit Loon Lim mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8), psci_boot); 687f7a16a6SJit Loon Lim } 697f7a16a6SJit Loon Lim 70cf82aff0SHadi Asyrafi mmio_write_64(PLAT_CPUID_RELEASE, cpu_id); 7179626f46SJit Loon Lim #endif 72c76d4239SHadi Asyrafi 73c76d4239SHadi Asyrafi /* release core reset */ 7479626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 7579626f46SJit Loon Lim bl31_plat_set_secondary_cpu_entrypoint(cpu_id); 7679626f46SJit Loon Lim #else 77391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 7879626f46SJit Loon Lim mmio_write_64(PLAT_CPUID_RELEASE, cpu_id); 7979626f46SJit Loon Lim #endif 8079626f46SJit Loon Lim 81c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 82c76d4239SHadi Asyrafi } 83c76d4239SHadi Asyrafi 84c76d4239SHadi Asyrafi /******************************************************************************* 85c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned off. The 86c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 87c76d4239SHadi Asyrafi ******************************************************************************/ 88c76d4239SHadi Asyrafi void socfpga_pwr_domain_off(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 /* Prevent interrupts from spuriously waking up this cpu */ 9579626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600 9679626f46SJit Loon Lim gicv3_cpuif_disable(plat_my_core_pos()); 9779626f46SJit Loon Lim #else 98c76d4239SHadi Asyrafi gicv2_cpuif_disable(); 9979626f46SJit Loon Lim #endif 10079626f46SJit Loon Lim 101c76d4239SHadi Asyrafi } 102c76d4239SHadi Asyrafi 103c76d4239SHadi Asyrafi /******************************************************************************* 104c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be suspended. The 105c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 106c76d4239SHadi Asyrafi ******************************************************************************/ 107c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state) 108c76d4239SHadi Asyrafi { 10979626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 110c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 11179626f46SJit Loon Lim #endif 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]); 11632cf34acSHadi Asyrafi 11779626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 118c76d4239SHadi Asyrafi /* assert core reset */ 119391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 12079626f46SJit Loon Lim #endif 121c76d4239SHadi Asyrafi } 122c76d4239SHadi Asyrafi 123c76d4239SHadi Asyrafi /******************************************************************************* 124c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 125c76d4239SHadi Asyrafi * being turned off earlier. The target_state encodes the low power state that 126c76d4239SHadi Asyrafi * each level has woken up from. 127c76d4239SHadi Asyrafi ******************************************************************************/ 128c76d4239SHadi Asyrafi void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state) 129c76d4239SHadi Asyrafi { 130c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 131c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 132c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 133c76d4239SHadi Asyrafi 13479626f46SJit Loon Lim /* Enable the gic cpu interface */ 13579626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600 13679626f46SJit Loon Lim gicv3_rdistif_init(plat_my_core_pos()); 13779626f46SJit Loon Lim gicv3_cpuif_enable(plat_my_core_pos()); 13879626f46SJit Loon Lim #else 139c76d4239SHadi Asyrafi /* Program the gic per-cpu distributor or re-distributor interface */ 140c76d4239SHadi Asyrafi gicv2_pcpu_distif_init(); 141c76d4239SHadi Asyrafi gicv2_set_pe_target_mask(plat_my_core_pos()); 142c76d4239SHadi Asyrafi 143c76d4239SHadi Asyrafi /* Enable the gic cpu interface */ 144c76d4239SHadi Asyrafi gicv2_cpuif_enable(); 14579626f46SJit Loon Lim #endif 146c76d4239SHadi Asyrafi } 147c76d4239SHadi Asyrafi 148c76d4239SHadi Asyrafi /******************************************************************************* 149c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 150c76d4239SHadi Asyrafi * having been suspended earlier. The target_state encodes the low power state 151c76d4239SHadi Asyrafi * that each level has woken up from. 152c76d4239SHadi Asyrafi * TODO: At the moment we reuse the on finisher and reinitialize the secure 153c76d4239SHadi Asyrafi * context. Need to implement a separate suspend finisher. 154c76d4239SHadi Asyrafi ******************************************************************************/ 155c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 156c76d4239SHadi Asyrafi { 15779626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 158c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 15979626f46SJit Loon Lim #endif 160c76d4239SHadi Asyrafi 161c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 162c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 163c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 164c76d4239SHadi Asyrafi 16579626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 166c76d4239SHadi Asyrafi /* release core reset */ 167391eeeefSHadi Asyrafi mmio_clrbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 16879626f46SJit Loon Lim #endif 169c76d4239SHadi Asyrafi } 170c76d4239SHadi Asyrafi 171c76d4239SHadi Asyrafi /******************************************************************************* 172c76d4239SHadi Asyrafi * plat handlers to shutdown/reboot the system 173c76d4239SHadi Asyrafi ******************************************************************************/ 174c76d4239SHadi Asyrafi static void __dead2 socfpga_system_off(void) 175c76d4239SHadi Asyrafi { 176c76d4239SHadi Asyrafi wfi(); 177c76d4239SHadi Asyrafi ERROR("System Off: operation not handled.\n"); 178c76d4239SHadi Asyrafi panic(); 179c76d4239SHadi Asyrafi } 180c76d4239SHadi Asyrafi 181e1f97d9cSHadi Asyrafi extern uint64_t intel_rsu_update_address; 182e1f97d9cSHadi Asyrafi 183c76d4239SHadi Asyrafi static void __dead2 socfpga_system_reset(void) 184c76d4239SHadi Asyrafi { 185ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi uint32_t addr_buf[2]; 186ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi 187*e264b557SSieu Mun Tang memcpy_s(addr_buf, sizeof(intel_rsu_update_address), 188*e264b557SSieu Mun Tang &intel_rsu_update_address, sizeof(intel_rsu_update_address)); 189*e264b557SSieu Mun Tang 1906197dc98SJit Loon Lim if (intel_rsu_update_address) { 191ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi mailbox_rsu_update(addr_buf); 1926197dc98SJit Loon Lim } else { 193c76d4239SHadi Asyrafi mailbox_reset_cold(); 1946197dc98SJit Loon Lim } 195c76d4239SHadi Asyrafi 196c76d4239SHadi Asyrafi while (1) 197c76d4239SHadi Asyrafi wfi(); 198c76d4239SHadi Asyrafi } 199c76d4239SHadi Asyrafi 20032cf34acSHadi Asyrafi static int socfpga_system_reset2(int is_vendor, int reset_type, 20132cf34acSHadi Asyrafi u_register_t cookie) 20232cf34acSHadi Asyrafi { 20379626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 20479626f46SJit Loon Lim mailbox_reset_warm(reset_type); 20579626f46SJit Loon Lim #else 206c703d752SSieu Mun Tang if (cold_reset_for_ecc_dbe()) { 207c703d752SSieu Mun Tang mailbox_reset_cold(); 208c703d752SSieu Mun Tang } 20979626f46SJit Loon Lim #endif 21079626f46SJit Loon Lim 21132cf34acSHadi Asyrafi /* disable cpuif */ 21279626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600 21379626f46SJit Loon Lim gicv3_cpuif_disable(plat_my_core_pos()); 21479626f46SJit Loon Lim #else 21532cf34acSHadi Asyrafi gicv2_cpuif_disable(); 21679626f46SJit Loon Lim #endif 21732cf34acSHadi Asyrafi 21832cf34acSHadi Asyrafi /* Store magic number */ 21932cf34acSHadi Asyrafi mmio_write_32(L2_RESET_DONE_REG, L2_RESET_DONE_STATUS); 22032cf34acSHadi Asyrafi 22132cf34acSHadi Asyrafi /* Increase timeout */ 222391eeeefSHadi Asyrafi mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff); 22332cf34acSHadi Asyrafi 22432cf34acSHadi Asyrafi /* Enable handshakes */ 225391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET); 22632cf34acSHadi Asyrafi 22779626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 22832cf34acSHadi Asyrafi /* Reset L2 module */ 229391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100); 23079626f46SJit Loon Lim #endif 23132cf34acSHadi Asyrafi 23232cf34acSHadi Asyrafi while (1) 23332cf34acSHadi Asyrafi wfi(); 23432cf34acSHadi Asyrafi 23532cf34acSHadi Asyrafi /* Should not reach here */ 23632cf34acSHadi Asyrafi return 0; 23732cf34acSHadi Asyrafi } 23832cf34acSHadi Asyrafi 239c76d4239SHadi Asyrafi int socfpga_validate_power_state(unsigned int power_state, 240c76d4239SHadi Asyrafi psci_power_state_t *req_state) 241c76d4239SHadi Asyrafi { 242c76d4239SHadi Asyrafi VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); 243c76d4239SHadi Asyrafi 244c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 245c76d4239SHadi Asyrafi } 246c76d4239SHadi Asyrafi 247c76d4239SHadi Asyrafi int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint) 248c76d4239SHadi Asyrafi { 249c76d4239SHadi Asyrafi VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint); 250c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 251c76d4239SHadi Asyrafi } 252c76d4239SHadi Asyrafi 253c76d4239SHadi Asyrafi void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state) 254c76d4239SHadi Asyrafi { 255c76d4239SHadi Asyrafi req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; 256c76d4239SHadi Asyrafi req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; 257c76d4239SHadi Asyrafi } 258c76d4239SHadi Asyrafi 259c76d4239SHadi Asyrafi /******************************************************************************* 260c76d4239SHadi Asyrafi * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 261c76d4239SHadi Asyrafi * platform layer will take care of registering the handlers with PSCI. 262c76d4239SHadi Asyrafi ******************************************************************************/ 263c76d4239SHadi Asyrafi const plat_psci_ops_t socfpga_psci_pm_ops = { 264c76d4239SHadi Asyrafi .cpu_standby = socfpga_cpu_standby, 265c76d4239SHadi Asyrafi .pwr_domain_on = socfpga_pwr_domain_on, 266c76d4239SHadi Asyrafi .pwr_domain_off = socfpga_pwr_domain_off, 267c76d4239SHadi Asyrafi .pwr_domain_suspend = socfpga_pwr_domain_suspend, 268c76d4239SHadi Asyrafi .pwr_domain_on_finish = socfpga_pwr_domain_on_finish, 269c76d4239SHadi Asyrafi .pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish, 270c76d4239SHadi Asyrafi .system_off = socfpga_system_off, 271c76d4239SHadi Asyrafi .system_reset = socfpga_system_reset, 27232cf34acSHadi Asyrafi .system_reset2 = socfpga_system_reset2, 273c76d4239SHadi Asyrafi .validate_power_state = socfpga_validate_power_state, 274c76d4239SHadi Asyrafi .validate_ns_entrypoint = socfpga_validate_ns_entrypoint, 275c76d4239SHadi Asyrafi .get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state 276c76d4239SHadi Asyrafi }; 277c76d4239SHadi Asyrafi 278c76d4239SHadi Asyrafi /******************************************************************************* 279c76d4239SHadi Asyrafi * Export the platform specific power ops. 280c76d4239SHadi Asyrafi ******************************************************************************/ 281c76d4239SHadi Asyrafi int plat_setup_psci_ops(uintptr_t sec_entrypoint, 282c76d4239SHadi Asyrafi const struct plat_psci_ops **psci_ops) 283c76d4239SHadi Asyrafi { 284c76d4239SHadi Asyrafi /* Save warm boot entrypoint.*/ 285cf82aff0SHadi Asyrafi mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint); 286c76d4239SHadi Asyrafi *psci_ops = &socfpga_psci_pm_ops; 287cf82aff0SHadi Asyrafi 288c76d4239SHadi Asyrafi return 0; 289c76d4239SHadi Asyrafi } 290