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. 4e264b557SSieu 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> 20f06fdb14SSieu Mun Tang #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 21f06fdb14SSieu Mun Tang #include "agilex5_cache.h" 22f06fdb14SSieu Mun Tang #endif 237ac7dadbSSieu Mun Tang #include "ccu/ncore_ccu.h" 24c76d4239SHadi Asyrafi #include "socfpga_mailbox.h" 25c76d4239SHadi Asyrafi #include "socfpga_plat_def.h" 267ac7dadbSSieu Mun Tang #include "socfpga_private.h" 2732cf34acSHadi Asyrafi #include "socfpga_reset_manager.h" 28c703d752SSieu Mun Tang #include "socfpga_sip_svc.h" 296197dc98SJit Loon Lim #include "socfpga_system_manager.h" 30c76d4239SHadi Asyrafi 3179626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 3279626f46SJit Loon Lim void socfpga_wakeup_secondary_cpu(unsigned int cpu_id); 3379626f46SJit Loon Lim extern void plat_secondary_cold_boot_setup(void); 3479626f46SJit Loon Lim #endif 35c76d4239SHadi Asyrafi 36c76d4239SHadi Asyrafi /******************************************************************************* 37c76d4239SHadi Asyrafi * plat handler called when a CPU is about to enter standby. 38c76d4239SHadi Asyrafi ******************************************************************************/ 39c76d4239SHadi Asyrafi void socfpga_cpu_standby(plat_local_state_t cpu_state) 40c76d4239SHadi Asyrafi { 41c76d4239SHadi Asyrafi /* 42c76d4239SHadi Asyrafi * Enter standby state 43c76d4239SHadi Asyrafi * dsb is good practice before using wfi to enter low power states 44c76d4239SHadi Asyrafi */ 45c76d4239SHadi Asyrafi VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state); 46c76d4239SHadi Asyrafi dsb(); 47c76d4239SHadi Asyrafi wfi(); 48c76d4239SHadi Asyrafi } 49c76d4239SHadi Asyrafi 50c76d4239SHadi Asyrafi /******************************************************************************* 51c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned on. The 52c76d4239SHadi Asyrafi * mpidr determines the CPU to be turned on. 53c76d4239SHadi Asyrafi ******************************************************************************/ 54c76d4239SHadi Asyrafi int socfpga_pwr_domain_on(u_register_t mpidr) 55c76d4239SHadi Asyrafi { 56c76d4239SHadi Asyrafi unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); 5779626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 5879626f46SJit Loon Lim /* TODO: Add in CPU FUSE from SDM */ 5979626f46SJit Loon Lim #else 607f7a16a6SJit Loon Lim uint32_t psci_boot = 0x00; 61c76d4239SHadi Asyrafi 62c76d4239SHadi Asyrafi VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); 6379626f46SJit Loon Lim #endif 64c76d4239SHadi Asyrafi 65c76d4239SHadi Asyrafi if (cpu_id == -1) 66c76d4239SHadi Asyrafi return PSCI_E_INTERN_FAIL; 67c76d4239SHadi Asyrafi 6879626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 697f7a16a6SJit Loon Lim if (cpu_id == 0x00) { 707f7a16a6SJit Loon Lim psci_boot = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8)); 71655af4f4SJit Loon Lim psci_boot |= 0x80000; /* bit 19 */ 727f7a16a6SJit Loon Lim mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8), psci_boot); 737f7a16a6SJit Loon Lim } 747f7a16a6SJit Loon Lim 75cf82aff0SHadi Asyrafi mmio_write_64(PLAT_CPUID_RELEASE, cpu_id); 7679626f46SJit Loon Lim #endif 77c76d4239SHadi Asyrafi 78c76d4239SHadi Asyrafi /* release core reset */ 7979626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 8079626f46SJit Loon Lim bl31_plat_set_secondary_cpu_entrypoint(cpu_id); 8179626f46SJit Loon Lim #else 82391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 8379626f46SJit Loon Lim mmio_write_64(PLAT_CPUID_RELEASE, cpu_id); 8479626f46SJit Loon Lim #endif 8579626f46SJit Loon Lim 86c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 87c76d4239SHadi Asyrafi } 88c76d4239SHadi Asyrafi 89c76d4239SHadi Asyrafi /******************************************************************************* 90c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned off. The 91c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 92c76d4239SHadi Asyrafi ******************************************************************************/ 93c76d4239SHadi Asyrafi void socfpga_pwr_domain_off(const psci_power_state_t *target_state) 94c76d4239SHadi Asyrafi { 95c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 96c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 97c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 98c76d4239SHadi Asyrafi 99c76d4239SHadi Asyrafi /* Prevent interrupts from spuriously waking up this cpu */ 10079626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600 10179626f46SJit Loon Lim gicv3_cpuif_disable(plat_my_core_pos()); 10279626f46SJit Loon Lim #else 103c76d4239SHadi Asyrafi gicv2_cpuif_disable(); 10479626f46SJit Loon Lim #endif 10579626f46SJit Loon Lim 106c76d4239SHadi Asyrafi } 107c76d4239SHadi Asyrafi 108c76d4239SHadi Asyrafi /******************************************************************************* 109c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be suspended. The 110c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 111c76d4239SHadi Asyrafi ******************************************************************************/ 112c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state) 113c76d4239SHadi Asyrafi { 11479626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 115c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 11679626f46SJit Loon Lim #endif 117c76d4239SHadi Asyrafi 118c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 119c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 120c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 12132cf34acSHadi Asyrafi 12279626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 123c76d4239SHadi Asyrafi /* assert core reset */ 124391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 12579626f46SJit Loon Lim #endif 126c76d4239SHadi Asyrafi } 127c76d4239SHadi Asyrafi 128c76d4239SHadi Asyrafi /******************************************************************************* 129c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 130c76d4239SHadi Asyrafi * being turned off earlier. The target_state encodes the low power state that 131c76d4239SHadi Asyrafi * each level has woken up from. 132c76d4239SHadi Asyrafi ******************************************************************************/ 133c76d4239SHadi Asyrafi void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state) 134c76d4239SHadi Asyrafi { 135c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 136c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 137c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 138c76d4239SHadi Asyrafi 13979626f46SJit Loon Lim /* Enable the gic cpu interface */ 14079626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600 14179626f46SJit Loon Lim gicv3_rdistif_init(plat_my_core_pos()); 14279626f46SJit Loon Lim gicv3_cpuif_enable(plat_my_core_pos()); 14379626f46SJit Loon Lim #else 144c76d4239SHadi Asyrafi /* Program the gic per-cpu distributor or re-distributor interface */ 145c76d4239SHadi Asyrafi gicv2_pcpu_distif_init(); 146c76d4239SHadi Asyrafi gicv2_set_pe_target_mask(plat_my_core_pos()); 147c76d4239SHadi Asyrafi 148c76d4239SHadi Asyrafi /* Enable the gic cpu interface */ 149c76d4239SHadi Asyrafi gicv2_cpuif_enable(); 15079626f46SJit Loon Lim #endif 151c76d4239SHadi Asyrafi } 152c76d4239SHadi Asyrafi 153c76d4239SHadi Asyrafi /******************************************************************************* 154c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 155c76d4239SHadi Asyrafi * having been suspended earlier. The target_state encodes the low power state 156c76d4239SHadi Asyrafi * that each level has woken up from. 157c76d4239SHadi Asyrafi * TODO: At the moment we reuse the on finisher and reinitialize the secure 158c76d4239SHadi Asyrafi * context. Need to implement a separate suspend finisher. 159c76d4239SHadi Asyrafi ******************************************************************************/ 160c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 161c76d4239SHadi Asyrafi { 16279626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 163c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 16479626f46SJit Loon Lim #endif 165c76d4239SHadi Asyrafi 166c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 167c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 168c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 169c76d4239SHadi Asyrafi 17079626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 171c76d4239SHadi Asyrafi /* release core reset */ 172391eeeefSHadi Asyrafi mmio_clrbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 17379626f46SJit Loon Lim #endif 174c76d4239SHadi Asyrafi } 175c76d4239SHadi Asyrafi 176c76d4239SHadi Asyrafi /******************************************************************************* 177c76d4239SHadi Asyrafi * plat handlers to shutdown/reboot the system 178c76d4239SHadi Asyrafi ******************************************************************************/ 179c76d4239SHadi Asyrafi static void __dead2 socfpga_system_off(void) 180c76d4239SHadi Asyrafi { 181c76d4239SHadi Asyrafi wfi(); 182c76d4239SHadi Asyrafi ERROR("System Off: operation not handled.\n"); 183c76d4239SHadi Asyrafi panic(); 184c76d4239SHadi Asyrafi } 185c76d4239SHadi Asyrafi 186e1f97d9cSHadi Asyrafi extern uint64_t intel_rsu_update_address; 187e1f97d9cSHadi Asyrafi 188c76d4239SHadi Asyrafi static void __dead2 socfpga_system_reset(void) 189c76d4239SHadi Asyrafi { 190ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi uint32_t addr_buf[2]; 191ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi 192e264b557SSieu Mun Tang memcpy_s(addr_buf, sizeof(intel_rsu_update_address), 193e264b557SSieu Mun Tang &intel_rsu_update_address, sizeof(intel_rsu_update_address)); 194e264b557SSieu Mun Tang 1956197dc98SJit Loon Lim if (intel_rsu_update_address) { 196ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi mailbox_rsu_update(addr_buf); 1976197dc98SJit Loon Lim } else { 1987ac7dadbSSieu Mun Tang #if CACHE_FLUSH 1997ac7dadbSSieu Mun Tang /* ATF Flush and Invalidate Cache */ 2007ac7dadbSSieu Mun Tang dcsw_op_all(DCCISW); 2017ac7dadbSSieu Mun Tang invalidate_cache_low_el(); 2027ac7dadbSSieu Mun Tang #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 2037ac7dadbSSieu Mun Tang flush_l3_dcache(); 2047ac7dadbSSieu Mun Tang #endif 2057ac7dadbSSieu Mun Tang #endif 206c76d4239SHadi Asyrafi mailbox_reset_cold(); 2076197dc98SJit Loon Lim } 208c76d4239SHadi Asyrafi 209c76d4239SHadi Asyrafi while (1) 210c76d4239SHadi Asyrafi wfi(); 211c76d4239SHadi Asyrafi } 212c76d4239SHadi Asyrafi 21332cf34acSHadi Asyrafi static int socfpga_system_reset2(int is_vendor, int reset_type, 21432cf34acSHadi Asyrafi u_register_t cookie) 21532cf34acSHadi Asyrafi { 216*c1253b24SSieu Mun Tang 217*c1253b24SSieu Mun Tang #if CACHE_FLUSH 218*c1253b24SSieu Mun Tang /* 219*c1253b24SSieu Mun Tang * ATF Flush and Invalidate Cache due to hardware limitation 220*c1253b24SSieu Mun Tang * of auto Flush and Invalidate Cache. 221*c1253b24SSieu Mun Tang */ 222*c1253b24SSieu Mun Tang dcsw_op_all(DCCISW); 223*c1253b24SSieu Mun Tang invalidate_cache_low_el(); 224*c1253b24SSieu Mun Tang #endif 225*c1253b24SSieu Mun Tang 22679626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 22779626f46SJit Loon Lim mailbox_reset_warm(reset_type); 22879626f46SJit Loon Lim #else 229c703d752SSieu Mun Tang if (cold_reset_for_ecc_dbe()) { 230c703d752SSieu Mun Tang mailbox_reset_cold(); 231c703d752SSieu Mun Tang } 23279626f46SJit Loon Lim #endif 23379626f46SJit Loon Lim 23432cf34acSHadi Asyrafi /* disable cpuif */ 23579626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600 23679626f46SJit Loon Lim gicv3_cpuif_disable(plat_my_core_pos()); 23779626f46SJit Loon Lim #else 23832cf34acSHadi Asyrafi gicv2_cpuif_disable(); 23979626f46SJit Loon Lim #endif 24032cf34acSHadi Asyrafi 24132cf34acSHadi Asyrafi /* Store magic number */ 24232cf34acSHadi Asyrafi mmio_write_32(L2_RESET_DONE_REG, L2_RESET_DONE_STATUS); 24332cf34acSHadi Asyrafi 24432cf34acSHadi Asyrafi /* Increase timeout */ 245391eeeefSHadi Asyrafi mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff); 24632cf34acSHadi Asyrafi 24732cf34acSHadi Asyrafi /* Enable handshakes */ 248391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET); 24932cf34acSHadi Asyrafi 25079626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 25132cf34acSHadi Asyrafi /* Reset L2 module */ 252391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100); 25379626f46SJit Loon Lim #endif 25432cf34acSHadi Asyrafi 25532cf34acSHadi Asyrafi while (1) 25632cf34acSHadi Asyrafi wfi(); 25732cf34acSHadi Asyrafi 25832cf34acSHadi Asyrafi /* Should not reach here */ 25932cf34acSHadi Asyrafi return 0; 26032cf34acSHadi Asyrafi } 26132cf34acSHadi Asyrafi 262c76d4239SHadi Asyrafi int socfpga_validate_power_state(unsigned int power_state, 263c76d4239SHadi Asyrafi psci_power_state_t *req_state) 264c76d4239SHadi Asyrafi { 265c76d4239SHadi Asyrafi VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); 266c76d4239SHadi Asyrafi 267c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 268c76d4239SHadi Asyrafi } 269c76d4239SHadi Asyrafi 270c76d4239SHadi Asyrafi int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint) 271c76d4239SHadi Asyrafi { 272c76d4239SHadi Asyrafi VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint); 273c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 274c76d4239SHadi Asyrafi } 275c76d4239SHadi Asyrafi 276c76d4239SHadi Asyrafi void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state) 277c76d4239SHadi Asyrafi { 278c76d4239SHadi Asyrafi req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; 279c76d4239SHadi Asyrafi req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; 280c76d4239SHadi Asyrafi } 281c76d4239SHadi Asyrafi 282c76d4239SHadi Asyrafi /******************************************************************************* 283c76d4239SHadi Asyrafi * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 284c76d4239SHadi Asyrafi * platform layer will take care of registering the handlers with PSCI. 285c76d4239SHadi Asyrafi ******************************************************************************/ 286c76d4239SHadi Asyrafi const plat_psci_ops_t socfpga_psci_pm_ops = { 287c76d4239SHadi Asyrafi .cpu_standby = socfpga_cpu_standby, 288c76d4239SHadi Asyrafi .pwr_domain_on = socfpga_pwr_domain_on, 289c76d4239SHadi Asyrafi .pwr_domain_off = socfpga_pwr_domain_off, 290c76d4239SHadi Asyrafi .pwr_domain_suspend = socfpga_pwr_domain_suspend, 291c76d4239SHadi Asyrafi .pwr_domain_on_finish = socfpga_pwr_domain_on_finish, 292c76d4239SHadi Asyrafi .pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish, 293c76d4239SHadi Asyrafi .system_off = socfpga_system_off, 294c76d4239SHadi Asyrafi .system_reset = socfpga_system_reset, 29532cf34acSHadi Asyrafi .system_reset2 = socfpga_system_reset2, 296c76d4239SHadi Asyrafi .validate_power_state = socfpga_validate_power_state, 297c76d4239SHadi Asyrafi .validate_ns_entrypoint = socfpga_validate_ns_entrypoint, 298c76d4239SHadi Asyrafi .get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state 299c76d4239SHadi Asyrafi }; 300c76d4239SHadi Asyrafi 301c76d4239SHadi Asyrafi /******************************************************************************* 302c76d4239SHadi Asyrafi * Export the platform specific power ops. 303c76d4239SHadi Asyrafi ******************************************************************************/ 304c76d4239SHadi Asyrafi int plat_setup_psci_ops(uintptr_t sec_entrypoint, 305c76d4239SHadi Asyrafi const struct plat_psci_ops **psci_ops) 306c76d4239SHadi Asyrafi { 307c76d4239SHadi Asyrafi /* Save warm boot entrypoint.*/ 308cf82aff0SHadi Asyrafi mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint); 309c76d4239SHadi Asyrafi *psci_ops = &socfpga_psci_pm_ops; 310cf82aff0SHadi Asyrafi 311c76d4239SHadi Asyrafi return 0; 312c76d4239SHadi Asyrafi } 313