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> 20*7ac7dadbSSieu Mun Tang #include "ccu/ncore_ccu.h" 21c76d4239SHadi Asyrafi #include "socfpga_mailbox.h" 22c76d4239SHadi Asyrafi #include "socfpga_plat_def.h" 23*7ac7dadbSSieu Mun Tang #include "socfpga_private.h" 2432cf34acSHadi Asyrafi #include "socfpga_reset_manager.h" 25c703d752SSieu Mun Tang #include "socfpga_sip_svc.h" 266197dc98SJit Loon Lim #include "socfpga_system_manager.h" 27c76d4239SHadi Asyrafi 2879626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 2979626f46SJit Loon Lim void socfpga_wakeup_secondary_cpu(unsigned int cpu_id); 3079626f46SJit Loon Lim extern void plat_secondary_cold_boot_setup(void); 3179626f46SJit Loon Lim #endif 32c76d4239SHadi Asyrafi 33c76d4239SHadi Asyrafi /******************************************************************************* 34c76d4239SHadi Asyrafi * plat handler called when a CPU is about to enter standby. 35c76d4239SHadi Asyrafi ******************************************************************************/ 36c76d4239SHadi Asyrafi void socfpga_cpu_standby(plat_local_state_t cpu_state) 37c76d4239SHadi Asyrafi { 38c76d4239SHadi Asyrafi /* 39c76d4239SHadi Asyrafi * Enter standby state 40c76d4239SHadi Asyrafi * dsb is good practice before using wfi to enter low power states 41c76d4239SHadi Asyrafi */ 42c76d4239SHadi Asyrafi VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state); 43c76d4239SHadi Asyrafi dsb(); 44c76d4239SHadi Asyrafi wfi(); 45c76d4239SHadi Asyrafi } 46c76d4239SHadi Asyrafi 47c76d4239SHadi Asyrafi /******************************************************************************* 48c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned on. The 49c76d4239SHadi Asyrafi * mpidr determines the CPU to be turned on. 50c76d4239SHadi Asyrafi ******************************************************************************/ 51c76d4239SHadi Asyrafi int socfpga_pwr_domain_on(u_register_t mpidr) 52c76d4239SHadi Asyrafi { 53c76d4239SHadi Asyrafi unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); 5479626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 5579626f46SJit Loon Lim /* TODO: Add in CPU FUSE from SDM */ 5679626f46SJit Loon Lim #else 577f7a16a6SJit Loon Lim uint32_t psci_boot = 0x00; 58c76d4239SHadi Asyrafi 59c76d4239SHadi Asyrafi VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); 6079626f46SJit Loon Lim #endif 61c76d4239SHadi Asyrafi 62c76d4239SHadi Asyrafi if (cpu_id == -1) 63c76d4239SHadi Asyrafi return PSCI_E_INTERN_FAIL; 64c76d4239SHadi Asyrafi 6579626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 667f7a16a6SJit Loon Lim if (cpu_id == 0x00) { 677f7a16a6SJit Loon Lim psci_boot = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8)); 68655af4f4SJit Loon Lim psci_boot |= 0x80000; /* bit 19 */ 697f7a16a6SJit Loon Lim mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8), psci_boot); 707f7a16a6SJit Loon Lim } 717f7a16a6SJit Loon Lim 72cf82aff0SHadi Asyrafi mmio_write_64(PLAT_CPUID_RELEASE, cpu_id); 7379626f46SJit Loon Lim #endif 74c76d4239SHadi Asyrafi 75c76d4239SHadi Asyrafi /* release core reset */ 7679626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 7779626f46SJit Loon Lim bl31_plat_set_secondary_cpu_entrypoint(cpu_id); 7879626f46SJit Loon Lim #else 79391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 8079626f46SJit Loon Lim mmio_write_64(PLAT_CPUID_RELEASE, cpu_id); 8179626f46SJit Loon Lim #endif 8279626f46SJit Loon Lim 83c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 84c76d4239SHadi Asyrafi } 85c76d4239SHadi Asyrafi 86c76d4239SHadi Asyrafi /******************************************************************************* 87c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned off. The 88c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 89c76d4239SHadi Asyrafi ******************************************************************************/ 90c76d4239SHadi Asyrafi void socfpga_pwr_domain_off(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 /* Prevent interrupts from spuriously waking up this cpu */ 9779626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600 9879626f46SJit Loon Lim gicv3_cpuif_disable(plat_my_core_pos()); 9979626f46SJit Loon Lim #else 100c76d4239SHadi Asyrafi gicv2_cpuif_disable(); 10179626f46SJit Loon Lim #endif 10279626f46SJit Loon Lim 103c76d4239SHadi Asyrafi } 104c76d4239SHadi Asyrafi 105c76d4239SHadi Asyrafi /******************************************************************************* 106c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be suspended. The 107c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 108c76d4239SHadi Asyrafi ******************************************************************************/ 109c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state) 110c76d4239SHadi Asyrafi { 11179626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 112c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 11379626f46SJit Loon Lim #endif 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]); 11832cf34acSHadi Asyrafi 11979626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 120c76d4239SHadi Asyrafi /* assert core reset */ 121391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 12279626f46SJit Loon Lim #endif 123c76d4239SHadi Asyrafi } 124c76d4239SHadi Asyrafi 125c76d4239SHadi Asyrafi /******************************************************************************* 126c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 127c76d4239SHadi Asyrafi * being turned off earlier. The target_state encodes the low power state that 128c76d4239SHadi Asyrafi * each level has woken up from. 129c76d4239SHadi Asyrafi ******************************************************************************/ 130c76d4239SHadi Asyrafi void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state) 131c76d4239SHadi Asyrafi { 132c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 133c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 134c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 135c76d4239SHadi Asyrafi 13679626f46SJit Loon Lim /* Enable the gic cpu interface */ 13779626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600 13879626f46SJit Loon Lim gicv3_rdistif_init(plat_my_core_pos()); 13979626f46SJit Loon Lim gicv3_cpuif_enable(plat_my_core_pos()); 14079626f46SJit Loon Lim #else 141c76d4239SHadi Asyrafi /* Program the gic per-cpu distributor or re-distributor interface */ 142c76d4239SHadi Asyrafi gicv2_pcpu_distif_init(); 143c76d4239SHadi Asyrafi gicv2_set_pe_target_mask(plat_my_core_pos()); 144c76d4239SHadi Asyrafi 145c76d4239SHadi Asyrafi /* Enable the gic cpu interface */ 146c76d4239SHadi Asyrafi gicv2_cpuif_enable(); 14779626f46SJit Loon Lim #endif 148c76d4239SHadi Asyrafi } 149c76d4239SHadi Asyrafi 150c76d4239SHadi Asyrafi /******************************************************************************* 151c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 152c76d4239SHadi Asyrafi * having been suspended earlier. The target_state encodes the low power state 153c76d4239SHadi Asyrafi * that each level has woken up from. 154c76d4239SHadi Asyrafi * TODO: At the moment we reuse the on finisher and reinitialize the secure 155c76d4239SHadi Asyrafi * context. Need to implement a separate suspend finisher. 156c76d4239SHadi Asyrafi ******************************************************************************/ 157c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 158c76d4239SHadi Asyrafi { 15979626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 160c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 16179626f46SJit Loon Lim #endif 162c76d4239SHadi Asyrafi 163c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 164c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 165c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 166c76d4239SHadi Asyrafi 16779626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 168c76d4239SHadi Asyrafi /* release core reset */ 169391eeeefSHadi Asyrafi mmio_clrbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 17079626f46SJit Loon Lim #endif 171c76d4239SHadi Asyrafi } 172c76d4239SHadi Asyrafi 173c76d4239SHadi Asyrafi /******************************************************************************* 174c76d4239SHadi Asyrafi * plat handlers to shutdown/reboot the system 175c76d4239SHadi Asyrafi ******************************************************************************/ 176c76d4239SHadi Asyrafi static void __dead2 socfpga_system_off(void) 177c76d4239SHadi Asyrafi { 178c76d4239SHadi Asyrafi wfi(); 179c76d4239SHadi Asyrafi ERROR("System Off: operation not handled.\n"); 180c76d4239SHadi Asyrafi panic(); 181c76d4239SHadi Asyrafi } 182c76d4239SHadi Asyrafi 183e1f97d9cSHadi Asyrafi extern uint64_t intel_rsu_update_address; 184e1f97d9cSHadi Asyrafi 185c76d4239SHadi Asyrafi static void __dead2 socfpga_system_reset(void) 186c76d4239SHadi Asyrafi { 187ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi uint32_t addr_buf[2]; 188ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi 189e264b557SSieu Mun Tang memcpy_s(addr_buf, sizeof(intel_rsu_update_address), 190e264b557SSieu Mun Tang &intel_rsu_update_address, sizeof(intel_rsu_update_address)); 191e264b557SSieu Mun Tang 1926197dc98SJit Loon Lim if (intel_rsu_update_address) { 193ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi mailbox_rsu_update(addr_buf); 1946197dc98SJit Loon Lim } else { 195*7ac7dadbSSieu Mun Tang #if CACHE_FLUSH 196*7ac7dadbSSieu Mun Tang /* ATF Flush and Invalidate Cache */ 197*7ac7dadbSSieu Mun Tang dcsw_op_all(DCCISW); 198*7ac7dadbSSieu Mun Tang invalidate_cache_low_el(); 199*7ac7dadbSSieu Mun Tang #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 200*7ac7dadbSSieu Mun Tang flush_l3_dcache(); 201*7ac7dadbSSieu Mun Tang #endif 202*7ac7dadbSSieu Mun Tang #endif 203c76d4239SHadi Asyrafi mailbox_reset_cold(); 2046197dc98SJit Loon Lim } 205c76d4239SHadi Asyrafi 206c76d4239SHadi Asyrafi while (1) 207c76d4239SHadi Asyrafi wfi(); 208c76d4239SHadi Asyrafi } 209c76d4239SHadi Asyrafi 21032cf34acSHadi Asyrafi static int socfpga_system_reset2(int is_vendor, int reset_type, 21132cf34acSHadi Asyrafi u_register_t cookie) 21232cf34acSHadi Asyrafi { 21379626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 21479626f46SJit Loon Lim mailbox_reset_warm(reset_type); 21579626f46SJit Loon Lim #else 216c703d752SSieu Mun Tang if (cold_reset_for_ecc_dbe()) { 217c703d752SSieu Mun Tang mailbox_reset_cold(); 218c703d752SSieu Mun Tang } 21979626f46SJit Loon Lim #endif 22079626f46SJit Loon Lim 22132cf34acSHadi Asyrafi /* disable cpuif */ 22279626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600 22379626f46SJit Loon Lim gicv3_cpuif_disable(plat_my_core_pos()); 22479626f46SJit Loon Lim #else 22532cf34acSHadi Asyrafi gicv2_cpuif_disable(); 22679626f46SJit Loon Lim #endif 22732cf34acSHadi Asyrafi 22832cf34acSHadi Asyrafi /* Store magic number */ 22932cf34acSHadi Asyrafi mmio_write_32(L2_RESET_DONE_REG, L2_RESET_DONE_STATUS); 23032cf34acSHadi Asyrafi 23132cf34acSHadi Asyrafi /* Increase timeout */ 232391eeeefSHadi Asyrafi mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff); 23332cf34acSHadi Asyrafi 23432cf34acSHadi Asyrafi /* Enable handshakes */ 235391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET); 23632cf34acSHadi Asyrafi 23779626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 23832cf34acSHadi Asyrafi /* Reset L2 module */ 239391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100); 24079626f46SJit Loon Lim #endif 24132cf34acSHadi Asyrafi 24232cf34acSHadi Asyrafi while (1) 24332cf34acSHadi Asyrafi wfi(); 24432cf34acSHadi Asyrafi 24532cf34acSHadi Asyrafi /* Should not reach here */ 24632cf34acSHadi Asyrafi return 0; 24732cf34acSHadi Asyrafi } 24832cf34acSHadi Asyrafi 249c76d4239SHadi Asyrafi int socfpga_validate_power_state(unsigned int power_state, 250c76d4239SHadi Asyrafi psci_power_state_t *req_state) 251c76d4239SHadi Asyrafi { 252c76d4239SHadi Asyrafi VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); 253c76d4239SHadi Asyrafi 254c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 255c76d4239SHadi Asyrafi } 256c76d4239SHadi Asyrafi 257c76d4239SHadi Asyrafi int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint) 258c76d4239SHadi Asyrafi { 259c76d4239SHadi Asyrafi VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint); 260c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 261c76d4239SHadi Asyrafi } 262c76d4239SHadi Asyrafi 263c76d4239SHadi Asyrafi void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state) 264c76d4239SHadi Asyrafi { 265c76d4239SHadi Asyrafi req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; 266c76d4239SHadi Asyrafi req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; 267c76d4239SHadi Asyrafi } 268c76d4239SHadi Asyrafi 269c76d4239SHadi Asyrafi /******************************************************************************* 270c76d4239SHadi Asyrafi * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 271c76d4239SHadi Asyrafi * platform layer will take care of registering the handlers with PSCI. 272c76d4239SHadi Asyrafi ******************************************************************************/ 273c76d4239SHadi Asyrafi const plat_psci_ops_t socfpga_psci_pm_ops = { 274c76d4239SHadi Asyrafi .cpu_standby = socfpga_cpu_standby, 275c76d4239SHadi Asyrafi .pwr_domain_on = socfpga_pwr_domain_on, 276c76d4239SHadi Asyrafi .pwr_domain_off = socfpga_pwr_domain_off, 277c76d4239SHadi Asyrafi .pwr_domain_suspend = socfpga_pwr_domain_suspend, 278c76d4239SHadi Asyrafi .pwr_domain_on_finish = socfpga_pwr_domain_on_finish, 279c76d4239SHadi Asyrafi .pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish, 280c76d4239SHadi Asyrafi .system_off = socfpga_system_off, 281c76d4239SHadi Asyrafi .system_reset = socfpga_system_reset, 28232cf34acSHadi Asyrafi .system_reset2 = socfpga_system_reset2, 283c76d4239SHadi Asyrafi .validate_power_state = socfpga_validate_power_state, 284c76d4239SHadi Asyrafi .validate_ns_entrypoint = socfpga_validate_ns_entrypoint, 285c76d4239SHadi Asyrafi .get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state 286c76d4239SHadi Asyrafi }; 287c76d4239SHadi Asyrafi 288c76d4239SHadi Asyrafi /******************************************************************************* 289c76d4239SHadi Asyrafi * Export the platform specific power ops. 290c76d4239SHadi Asyrafi ******************************************************************************/ 291c76d4239SHadi Asyrafi int plat_setup_psci_ops(uintptr_t sec_entrypoint, 292c76d4239SHadi Asyrafi const struct plat_psci_ops **psci_ops) 293c76d4239SHadi Asyrafi { 294c76d4239SHadi Asyrafi /* Save warm boot entrypoint.*/ 295cf82aff0SHadi Asyrafi mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint); 296c76d4239SHadi Asyrafi *psci_ops = &socfpga_psci_pm_ops; 297cf82aff0SHadi Asyrafi 298c76d4239SHadi Asyrafi return 0; 299c76d4239SHadi Asyrafi } 300