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*8f7575efSBoon Khai Ng * Copyright (c) 2024-2025, 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> 20f06fdb14SSieu Mun Tang #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 21f06fdb14SSieu Mun Tang #include "agilex5_cache.h" 22*8f7575efSBoon Khai Ng #include "agilex5_power_manager.h" 23f06fdb14SSieu Mun Tang #endif 247ac7dadbSSieu Mun Tang #include "ccu/ncore_ccu.h" 25c76d4239SHadi Asyrafi #include "socfpga_mailbox.h" 26c76d4239SHadi Asyrafi #include "socfpga_plat_def.h" 277ac7dadbSSieu Mun Tang #include "socfpga_private.h" 2832cf34acSHadi Asyrafi #include "socfpga_reset_manager.h" 29c703d752SSieu Mun Tang #include "socfpga_sip_svc.h" 306197dc98SJit Loon Lim #include "socfpga_system_manager.h" 31c76d4239SHadi Asyrafi 3279626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 3379626f46SJit Loon Lim void socfpga_wakeup_secondary_cpu(unsigned int cpu_id); 3479626f46SJit Loon Lim extern void plat_secondary_cold_boot_setup(void); 3579626f46SJit Loon Lim #endif 36c76d4239SHadi Asyrafi 37c76d4239SHadi Asyrafi /******************************************************************************* 38c76d4239SHadi Asyrafi * plat handler called when a CPU is about to enter standby. 39c76d4239SHadi Asyrafi ******************************************************************************/ 40c76d4239SHadi Asyrafi void socfpga_cpu_standby(plat_local_state_t cpu_state) 41c76d4239SHadi Asyrafi { 42c76d4239SHadi Asyrafi /* 43c76d4239SHadi Asyrafi * Enter standby state 44c76d4239SHadi Asyrafi * dsb is good practice before using wfi to enter low power states 45c76d4239SHadi Asyrafi */ 46c76d4239SHadi Asyrafi VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state); 47c76d4239SHadi Asyrafi dsb(); 48c76d4239SHadi Asyrafi wfi(); 49c76d4239SHadi Asyrafi } 50c76d4239SHadi Asyrafi 51c76d4239SHadi Asyrafi /******************************************************************************* 52c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned on. The 53c76d4239SHadi Asyrafi * mpidr determines the CPU to be turned on. 54c76d4239SHadi Asyrafi ******************************************************************************/ 55c76d4239SHadi Asyrafi int socfpga_pwr_domain_on(u_register_t mpidr) 56c76d4239SHadi Asyrafi { 57c76d4239SHadi Asyrafi unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); 5879626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 59*8f7575efSBoon Khai Ng unsigned int pch_cpu = 0x0; 6079626f46SJit Loon Lim /* TODO: Add in CPU FUSE from SDM */ 6179626f46SJit Loon Lim #else 627f7a16a6SJit Loon Lim uint32_t psci_boot = 0x00; 63c76d4239SHadi Asyrafi 64c76d4239SHadi Asyrafi VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); 6579626f46SJit Loon Lim #endif 66c76d4239SHadi Asyrafi 67c76d4239SHadi Asyrafi if (cpu_id == -1) 68c76d4239SHadi Asyrafi return PSCI_E_INTERN_FAIL; 69c76d4239SHadi Asyrafi 7079626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 717f7a16a6SJit Loon Lim if (cpu_id == 0x00) { 727f7a16a6SJit Loon Lim psci_boot = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8)); 73655af4f4SJit Loon Lim psci_boot |= 0x80000; /* bit 19 */ 747f7a16a6SJit Loon Lim mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8), psci_boot); 757f7a16a6SJit Loon Lim } 767f7a16a6SJit Loon Lim 77cf82aff0SHadi Asyrafi mmio_write_64(PLAT_CPUID_RELEASE, cpu_id); 7879626f46SJit Loon Lim #endif 79c76d4239SHadi Asyrafi 80c76d4239SHadi Asyrafi /* release core reset */ 8179626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 82*8f7575efSBoon Khai Ng pch_cpu = mmio_read_32(AGX5_PWRMGR(MPU_PCHCTLR)) & 83*8f7575efSBoon Khai Ng AGX5_PWRMGR_CPU_POWER_STATE_MASK; 84*8f7575efSBoon Khai Ng 85*8f7575efSBoon Khai Ng /* Check if the CPU ON Request is post POR */ 86*8f7575efSBoon Khai Ng if ((AGX5_PWRMGR_MPU_TRIGGER_PCH_CPU(1 << cpu_id) & (pch_cpu)) != 0) 87*8f7575efSBoon Khai Ng bl31_plat_reset_secondary_cpu(cpu_id); 88*8f7575efSBoon Khai Ng 8979626f46SJit Loon Lim bl31_plat_set_secondary_cpu_entrypoint(cpu_id); 9079626f46SJit Loon Lim #else 91391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 9279626f46SJit Loon Lim mmio_write_64(PLAT_CPUID_RELEASE, cpu_id); 9379626f46SJit Loon Lim #endif 9479626f46SJit Loon Lim 95c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 96c76d4239SHadi Asyrafi } 97c76d4239SHadi Asyrafi 98c76d4239SHadi Asyrafi /******************************************************************************* 99c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned off. The 100c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 101c76d4239SHadi Asyrafi ******************************************************************************/ 102c76d4239SHadi Asyrafi void socfpga_pwr_domain_off(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 /* Prevent interrupts from spuriously waking up this cpu */ 10979626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600 11079626f46SJit Loon Lim gicv3_cpuif_disable(plat_my_core_pos()); 11179626f46SJit Loon Lim #else 112c76d4239SHadi Asyrafi gicv2_cpuif_disable(); 11379626f46SJit Loon Lim #endif 11479626f46SJit Loon Lim 115c76d4239SHadi Asyrafi } 116c76d4239SHadi Asyrafi 117c76d4239SHadi Asyrafi /******************************************************************************* 118c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be suspended. The 119c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 120c76d4239SHadi Asyrafi ******************************************************************************/ 121c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state) 122c76d4239SHadi Asyrafi { 12379626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 124c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 12579626f46SJit Loon Lim #endif 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]); 13032cf34acSHadi Asyrafi 13179626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 132c76d4239SHadi Asyrafi /* assert core reset */ 133391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 13479626f46SJit Loon Lim #endif 135c76d4239SHadi Asyrafi } 136c76d4239SHadi Asyrafi 137c76d4239SHadi Asyrafi /******************************************************************************* 138c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 139c76d4239SHadi Asyrafi * being turned off earlier. The target_state encodes the low power state that 140c76d4239SHadi Asyrafi * each level has woken up from. 141c76d4239SHadi Asyrafi ******************************************************************************/ 142c76d4239SHadi Asyrafi void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state) 143c76d4239SHadi Asyrafi { 144c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 145c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 146c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 147c76d4239SHadi Asyrafi 14879626f46SJit Loon Lim /* Enable the gic cpu interface */ 14979626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600 15079626f46SJit Loon Lim gicv3_rdistif_init(plat_my_core_pos()); 15179626f46SJit Loon Lim gicv3_cpuif_enable(plat_my_core_pos()); 15279626f46SJit Loon Lim #else 153c76d4239SHadi Asyrafi /* Program the gic per-cpu distributor or re-distributor interface */ 154c76d4239SHadi Asyrafi gicv2_pcpu_distif_init(); 155c76d4239SHadi Asyrafi gicv2_set_pe_target_mask(plat_my_core_pos()); 156c76d4239SHadi Asyrafi 157c76d4239SHadi Asyrafi /* Enable the gic cpu interface */ 158c76d4239SHadi Asyrafi gicv2_cpuif_enable(); 15979626f46SJit Loon Lim #endif 160c76d4239SHadi Asyrafi } 161c76d4239SHadi Asyrafi 162c76d4239SHadi Asyrafi /******************************************************************************* 163c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 164c76d4239SHadi Asyrafi * having been suspended earlier. The target_state encodes the low power state 165c76d4239SHadi Asyrafi * that each level has woken up from. 166c76d4239SHadi Asyrafi * TODO: At the moment we reuse the on finisher and reinitialize the secure 167c76d4239SHadi Asyrafi * context. Need to implement a separate suspend finisher. 168c76d4239SHadi Asyrafi ******************************************************************************/ 169c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 170c76d4239SHadi Asyrafi { 17179626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 172c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 17379626f46SJit Loon Lim #endif 174c76d4239SHadi Asyrafi 175c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 176c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 177c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 178c76d4239SHadi Asyrafi 17979626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 180c76d4239SHadi Asyrafi /* release core reset */ 181391eeeefSHadi Asyrafi mmio_clrbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 18279626f46SJit Loon Lim #endif 183c76d4239SHadi Asyrafi } 184c76d4239SHadi Asyrafi 185c76d4239SHadi Asyrafi /******************************************************************************* 186c76d4239SHadi Asyrafi * plat handlers to shutdown/reboot the system 187c76d4239SHadi Asyrafi ******************************************************************************/ 188c76d4239SHadi Asyrafi static void __dead2 socfpga_system_off(void) 189c76d4239SHadi Asyrafi { 190c76d4239SHadi Asyrafi wfi(); 191c76d4239SHadi Asyrafi ERROR("System Off: operation not handled.\n"); 192c76d4239SHadi Asyrafi panic(); 193c76d4239SHadi Asyrafi } 194c76d4239SHadi Asyrafi 195e1f97d9cSHadi Asyrafi extern uint64_t intel_rsu_update_address; 196e1f97d9cSHadi Asyrafi 197c76d4239SHadi Asyrafi static void __dead2 socfpga_system_reset(void) 198c76d4239SHadi Asyrafi { 199ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi uint32_t addr_buf[2]; 200ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi 201e264b557SSieu Mun Tang memcpy_s(addr_buf, sizeof(intel_rsu_update_address), 202e264b557SSieu Mun Tang &intel_rsu_update_address, sizeof(intel_rsu_update_address)); 203e264b557SSieu Mun Tang 2046197dc98SJit Loon Lim if (intel_rsu_update_address) { 205ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi mailbox_rsu_update(addr_buf); 2066197dc98SJit Loon Lim } else { 2077ac7dadbSSieu Mun Tang #if CACHE_FLUSH 2087ac7dadbSSieu Mun Tang /* ATF Flush and Invalidate Cache */ 2097ac7dadbSSieu Mun Tang dcsw_op_all(DCCISW); 2107ac7dadbSSieu Mun Tang invalidate_cache_low_el(); 2117ac7dadbSSieu Mun Tang #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 2127ac7dadbSSieu Mun Tang flush_l3_dcache(); 2137ac7dadbSSieu Mun Tang #endif 2147ac7dadbSSieu Mun Tang #endif 215c76d4239SHadi Asyrafi mailbox_reset_cold(); 2166197dc98SJit Loon Lim } 217c76d4239SHadi Asyrafi 218c76d4239SHadi Asyrafi while (1) 219c76d4239SHadi Asyrafi wfi(); 220c76d4239SHadi Asyrafi } 221c76d4239SHadi Asyrafi 22232cf34acSHadi Asyrafi static int socfpga_system_reset2(int is_vendor, int reset_type, 22332cf34acSHadi Asyrafi u_register_t cookie) 22432cf34acSHadi Asyrafi { 225c1253b24SSieu Mun Tang 226c1253b24SSieu Mun Tang #if CACHE_FLUSH 227c1253b24SSieu Mun Tang /* 228c1253b24SSieu Mun Tang * ATF Flush and Invalidate Cache due to hardware limitation 229c1253b24SSieu Mun Tang * of auto Flush and Invalidate Cache. 230c1253b24SSieu Mun Tang */ 231c1253b24SSieu Mun Tang dcsw_op_all(DCCISW); 232c1253b24SSieu Mun Tang invalidate_cache_low_el(); 233c1253b24SSieu Mun Tang #endif 234c1253b24SSieu Mun Tang 235646a9a16SJit Loon Lim /* Set warm reset request bit before issuing the command to SDM. */ 236646a9a16SJit Loon Lim mmio_clrsetbits_32(L2_RESET_DONE_REG, BS_REG_MAGIC_KEYS_MASK, 237646a9a16SJit Loon Lim L2_RESET_DONE_STATUS); 238646a9a16SJit Loon Lim 23979626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 24079626f46SJit Loon Lim mailbox_reset_warm(reset_type); 24179626f46SJit Loon Lim #else 242c703d752SSieu Mun Tang if (cold_reset_for_ecc_dbe()) { 243c703d752SSieu Mun Tang mailbox_reset_cold(); 244c703d752SSieu Mun Tang } 24579626f46SJit Loon Lim #endif 24679626f46SJit Loon Lim 24732cf34acSHadi Asyrafi /* disable cpuif */ 24879626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600 24979626f46SJit Loon Lim gicv3_cpuif_disable(plat_my_core_pos()); 25079626f46SJit Loon Lim #else 25132cf34acSHadi Asyrafi gicv2_cpuif_disable(); 25279626f46SJit Loon Lim #endif 25332cf34acSHadi Asyrafi 25432cf34acSHadi Asyrafi /* Increase timeout */ 255391eeeefSHadi Asyrafi mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff); 25632cf34acSHadi Asyrafi 25732cf34acSHadi Asyrafi /* Enable handshakes */ 258391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET); 25932cf34acSHadi Asyrafi 26079626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 26132cf34acSHadi Asyrafi /* Reset L2 module */ 262391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100); 26379626f46SJit Loon Lim #endif 26432cf34acSHadi Asyrafi 26532cf34acSHadi Asyrafi while (1) 26632cf34acSHadi Asyrafi wfi(); 26732cf34acSHadi Asyrafi 26832cf34acSHadi Asyrafi /* Should not reach here */ 26932cf34acSHadi Asyrafi return 0; 27032cf34acSHadi Asyrafi } 27132cf34acSHadi Asyrafi 272c76d4239SHadi Asyrafi int socfpga_validate_power_state(unsigned int power_state, 273c76d4239SHadi Asyrafi psci_power_state_t *req_state) 274c76d4239SHadi Asyrafi { 275c76d4239SHadi Asyrafi VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); 276c76d4239SHadi Asyrafi 277c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 278c76d4239SHadi Asyrafi } 279c76d4239SHadi Asyrafi 280c76d4239SHadi Asyrafi int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint) 281c76d4239SHadi Asyrafi { 282c76d4239SHadi Asyrafi VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint); 283c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 284c76d4239SHadi Asyrafi } 285c76d4239SHadi Asyrafi 286c76d4239SHadi Asyrafi void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state) 287c76d4239SHadi Asyrafi { 288c76d4239SHadi Asyrafi req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; 289c76d4239SHadi Asyrafi req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; 290c76d4239SHadi Asyrafi } 291c76d4239SHadi Asyrafi 292c76d4239SHadi Asyrafi /******************************************************************************* 293c76d4239SHadi Asyrafi * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 294c76d4239SHadi Asyrafi * platform layer will take care of registering the handlers with PSCI. 295c76d4239SHadi Asyrafi ******************************************************************************/ 296c76d4239SHadi Asyrafi const plat_psci_ops_t socfpga_psci_pm_ops = { 297c76d4239SHadi Asyrafi .cpu_standby = socfpga_cpu_standby, 298c76d4239SHadi Asyrafi .pwr_domain_on = socfpga_pwr_domain_on, 299c76d4239SHadi Asyrafi .pwr_domain_off = socfpga_pwr_domain_off, 300c76d4239SHadi Asyrafi .pwr_domain_suspend = socfpga_pwr_domain_suspend, 301c76d4239SHadi Asyrafi .pwr_domain_on_finish = socfpga_pwr_domain_on_finish, 302c76d4239SHadi Asyrafi .pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish, 303c76d4239SHadi Asyrafi .system_off = socfpga_system_off, 304c76d4239SHadi Asyrafi .system_reset = socfpga_system_reset, 30532cf34acSHadi Asyrafi .system_reset2 = socfpga_system_reset2, 306c76d4239SHadi Asyrafi .validate_power_state = socfpga_validate_power_state, 307c76d4239SHadi Asyrafi .validate_ns_entrypoint = socfpga_validate_ns_entrypoint, 308c76d4239SHadi Asyrafi .get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state 309c76d4239SHadi Asyrafi }; 310c76d4239SHadi Asyrafi 311c76d4239SHadi Asyrafi /******************************************************************************* 312c76d4239SHadi Asyrafi * Export the platform specific power ops. 313c76d4239SHadi Asyrafi ******************************************************************************/ 314c76d4239SHadi Asyrafi int plat_setup_psci_ops(uintptr_t sec_entrypoint, 315c76d4239SHadi Asyrafi const struct plat_psci_ops **psci_ops) 316c76d4239SHadi Asyrafi { 317c76d4239SHadi Asyrafi /* Save warm boot entrypoint.*/ 318cf82aff0SHadi Asyrafi mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint); 319c76d4239SHadi Asyrafi *psci_ops = &socfpga_psci_pm_ops; 320cf82aff0SHadi Asyrafi 321c76d4239SHadi Asyrafi return 0; 322c76d4239SHadi Asyrafi } 323