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. 4c76d4239SHadi Asyrafi * 5c76d4239SHadi Asyrafi * SPDX-License-Identifier: BSD-3-Clause 6c76d4239SHadi Asyrafi */ 7c76d4239SHadi Asyrafi 8c76d4239SHadi Asyrafi #include <arch_helpers.h> 9c76d4239SHadi Asyrafi #include <common/debug.h> 1079626f46SJit Loon Lim 1179626f46SJit Loon Lim #ifndef GICV3_SUPPORT_GIC600 12c76d4239SHadi Asyrafi #include <drivers/arm/gicv2.h> 136197dc98SJit Loon Lim #else 146197dc98SJit Loon Lim #include <drivers/arm/gicv3.h> 156197dc98SJit Loon Lim #endif 16c76d4239SHadi Asyrafi #include <lib/mmio.h> 17c76d4239SHadi Asyrafi #include <lib/psci/psci.h> 18c76d4239SHadi Asyrafi #include <plat/common/platform.h> 19c76d4239SHadi Asyrafi #include "socfpga_mailbox.h" 20c76d4239SHadi Asyrafi #include "socfpga_plat_def.h" 2132cf34acSHadi Asyrafi #include "socfpga_reset_manager.h" 22c703d752SSieu Mun Tang #include "socfpga_sip_svc.h" 236197dc98SJit Loon Lim #include "socfpga_system_manager.h" 24c76d4239SHadi Asyrafi 2579626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 2679626f46SJit Loon Lim void socfpga_wakeup_secondary_cpu(unsigned int cpu_id); 2779626f46SJit Loon Lim extern void plat_secondary_cold_boot_setup(void); 2879626f46SJit Loon Lim #endif 29c76d4239SHadi Asyrafi 30c76d4239SHadi Asyrafi /******************************************************************************* 31c76d4239SHadi Asyrafi * plat handler called when a CPU is about to enter standby. 32c76d4239SHadi Asyrafi ******************************************************************************/ 33c76d4239SHadi Asyrafi void socfpga_cpu_standby(plat_local_state_t cpu_state) 34c76d4239SHadi Asyrafi { 35c76d4239SHadi Asyrafi /* 36c76d4239SHadi Asyrafi * Enter standby state 37c76d4239SHadi Asyrafi * dsb is good practice before using wfi to enter low power states 38c76d4239SHadi Asyrafi */ 39c76d4239SHadi Asyrafi VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state); 40c76d4239SHadi Asyrafi dsb(); 41c76d4239SHadi Asyrafi wfi(); 42c76d4239SHadi Asyrafi } 43c76d4239SHadi Asyrafi 44c76d4239SHadi Asyrafi /******************************************************************************* 45c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned on. The 46c76d4239SHadi Asyrafi * mpidr determines the CPU to be turned on. 47c76d4239SHadi Asyrafi ******************************************************************************/ 48c76d4239SHadi Asyrafi int socfpga_pwr_domain_on(u_register_t mpidr) 49c76d4239SHadi Asyrafi { 50c76d4239SHadi Asyrafi unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); 5179626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 5279626f46SJit Loon Lim /* TODO: Add in CPU FUSE from SDM */ 5379626f46SJit Loon Lim #else 547f7a16a6SJit Loon Lim uint32_t psci_boot = 0x00; 55c76d4239SHadi Asyrafi 56c76d4239SHadi Asyrafi VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); 5779626f46SJit Loon Lim #endif 58c76d4239SHadi Asyrafi 59c76d4239SHadi Asyrafi if (cpu_id == -1) 60c76d4239SHadi Asyrafi return PSCI_E_INTERN_FAIL; 61c76d4239SHadi Asyrafi 6279626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 637f7a16a6SJit Loon Lim if (cpu_id == 0x00) { 647f7a16a6SJit Loon Lim psci_boot = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8)); 65*655af4f4SJit Loon Lim psci_boot |= 0x80000; /* bit 19 */ 667f7a16a6SJit Loon Lim mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8), psci_boot); 677f7a16a6SJit Loon Lim } 687f7a16a6SJit Loon Lim 69cf82aff0SHadi Asyrafi mmio_write_64(PLAT_CPUID_RELEASE, cpu_id); 7079626f46SJit Loon Lim #endif 71c76d4239SHadi Asyrafi 72c76d4239SHadi Asyrafi /* release core reset */ 7379626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 7479626f46SJit Loon Lim bl31_plat_set_secondary_cpu_entrypoint(cpu_id); 7579626f46SJit Loon Lim #else 76391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 7779626f46SJit Loon Lim mmio_write_64(PLAT_CPUID_RELEASE, cpu_id); 7879626f46SJit Loon Lim #endif 7979626f46SJit Loon Lim 80c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 81c76d4239SHadi Asyrafi } 82c76d4239SHadi Asyrafi 83c76d4239SHadi Asyrafi /******************************************************************************* 84c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be turned off. The 85c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 86c76d4239SHadi Asyrafi ******************************************************************************/ 87c76d4239SHadi Asyrafi void socfpga_pwr_domain_off(const psci_power_state_t *target_state) 88c76d4239SHadi Asyrafi { 89c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 90c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 91c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 92c76d4239SHadi Asyrafi 93c76d4239SHadi Asyrafi /* Prevent interrupts from spuriously waking up this cpu */ 9479626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600 9579626f46SJit Loon Lim gicv3_cpuif_disable(plat_my_core_pos()); 9679626f46SJit Loon Lim #else 97c76d4239SHadi Asyrafi gicv2_cpuif_disable(); 9879626f46SJit Loon Lim #endif 9979626f46SJit Loon Lim 100c76d4239SHadi Asyrafi } 101c76d4239SHadi Asyrafi 102c76d4239SHadi Asyrafi /******************************************************************************* 103c76d4239SHadi Asyrafi * plat handler called when a power domain is about to be suspended. The 104c76d4239SHadi Asyrafi * target_state encodes the power state that each level should transition to. 105c76d4239SHadi Asyrafi ******************************************************************************/ 106c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state) 107c76d4239SHadi Asyrafi { 10879626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 109c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 11079626f46SJit Loon Lim #endif 111c76d4239SHadi Asyrafi 112c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 113c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 114c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 11532cf34acSHadi Asyrafi 11679626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 117c76d4239SHadi Asyrafi /* assert core reset */ 118391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 11979626f46SJit Loon Lim #endif 120c76d4239SHadi Asyrafi } 121c76d4239SHadi Asyrafi 122c76d4239SHadi Asyrafi /******************************************************************************* 123c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 124c76d4239SHadi Asyrafi * being turned off earlier. The target_state encodes the low power state that 125c76d4239SHadi Asyrafi * each level has woken up from. 126c76d4239SHadi Asyrafi ******************************************************************************/ 127c76d4239SHadi Asyrafi void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state) 128c76d4239SHadi Asyrafi { 129c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 130c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 131c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 132c76d4239SHadi Asyrafi 13379626f46SJit Loon Lim /* Enable the gic cpu interface */ 13479626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600 13579626f46SJit Loon Lim gicv3_rdistif_init(plat_my_core_pos()); 13679626f46SJit Loon Lim gicv3_cpuif_enable(plat_my_core_pos()); 13779626f46SJit Loon Lim #else 138c76d4239SHadi Asyrafi /* Program the gic per-cpu distributor or re-distributor interface */ 139c76d4239SHadi Asyrafi gicv2_pcpu_distif_init(); 140c76d4239SHadi Asyrafi gicv2_set_pe_target_mask(plat_my_core_pos()); 141c76d4239SHadi Asyrafi 142c76d4239SHadi Asyrafi /* Enable the gic cpu interface */ 143c76d4239SHadi Asyrafi gicv2_cpuif_enable(); 14479626f46SJit Loon Lim #endif 145c76d4239SHadi Asyrafi } 146c76d4239SHadi Asyrafi 147c76d4239SHadi Asyrafi /******************************************************************************* 148c76d4239SHadi Asyrafi * plat handler called when a power domain has just been powered on after 149c76d4239SHadi Asyrafi * having been suspended earlier. The target_state encodes the low power state 150c76d4239SHadi Asyrafi * that each level has woken up from. 151c76d4239SHadi Asyrafi * TODO: At the moment we reuse the on finisher and reinitialize the secure 152c76d4239SHadi Asyrafi * context. Need to implement a separate suspend finisher. 153c76d4239SHadi Asyrafi ******************************************************************************/ 154c76d4239SHadi Asyrafi void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 155c76d4239SHadi Asyrafi { 15679626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 157c76d4239SHadi Asyrafi unsigned int cpu_id = plat_my_core_pos(); 15879626f46SJit Loon Lim #endif 159c76d4239SHadi Asyrafi 160c76d4239SHadi Asyrafi for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 161c76d4239SHadi Asyrafi VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 162c76d4239SHadi Asyrafi __func__, i, target_state->pwr_domain_state[i]); 163c76d4239SHadi Asyrafi 16479626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 165c76d4239SHadi Asyrafi /* release core reset */ 166391eeeefSHadi Asyrafi mmio_clrbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 16779626f46SJit Loon Lim #endif 168c76d4239SHadi Asyrafi } 169c76d4239SHadi Asyrafi 170c76d4239SHadi Asyrafi /******************************************************************************* 171c76d4239SHadi Asyrafi * plat handlers to shutdown/reboot the system 172c76d4239SHadi Asyrafi ******************************************************************************/ 173c76d4239SHadi Asyrafi static void __dead2 socfpga_system_off(void) 174c76d4239SHadi Asyrafi { 175c76d4239SHadi Asyrafi wfi(); 176c76d4239SHadi Asyrafi ERROR("System Off: operation not handled.\n"); 177c76d4239SHadi Asyrafi panic(); 178c76d4239SHadi Asyrafi } 179c76d4239SHadi Asyrafi 180e1f97d9cSHadi Asyrafi extern uint64_t intel_rsu_update_address; 181e1f97d9cSHadi Asyrafi 182c76d4239SHadi Asyrafi static void __dead2 socfpga_system_reset(void) 183c76d4239SHadi Asyrafi { 184ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi uint32_t addr_buf[2]; 185ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi 186ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi memcpy(addr_buf, &intel_rsu_update_address, 187ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi sizeof(intel_rsu_update_address)); 1886197dc98SJit Loon Lim if (intel_rsu_update_address) { 189ea9b9627SAbdul Halim, Muhammad Hadi Asyrafi mailbox_rsu_update(addr_buf); 1906197dc98SJit Loon Lim } else { 191c76d4239SHadi Asyrafi mailbox_reset_cold(); 1926197dc98SJit Loon Lim } 193c76d4239SHadi Asyrafi 194c76d4239SHadi Asyrafi while (1) 195c76d4239SHadi Asyrafi wfi(); 196c76d4239SHadi Asyrafi } 197c76d4239SHadi Asyrafi 19832cf34acSHadi Asyrafi static int socfpga_system_reset2(int is_vendor, int reset_type, 19932cf34acSHadi Asyrafi u_register_t cookie) 20032cf34acSHadi Asyrafi { 20179626f46SJit Loon Lim #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 20279626f46SJit Loon Lim mailbox_reset_warm(reset_type); 20379626f46SJit Loon Lim #else 204c703d752SSieu Mun Tang if (cold_reset_for_ecc_dbe()) { 205c703d752SSieu Mun Tang mailbox_reset_cold(); 206c703d752SSieu Mun Tang } 20779626f46SJit Loon Lim #endif 20879626f46SJit Loon Lim 20932cf34acSHadi Asyrafi /* disable cpuif */ 21079626f46SJit Loon Lim #ifdef GICV3_SUPPORT_GIC600 21179626f46SJit Loon Lim gicv3_cpuif_disable(plat_my_core_pos()); 21279626f46SJit Loon Lim #else 21332cf34acSHadi Asyrafi gicv2_cpuif_disable(); 21479626f46SJit Loon Lim #endif 21532cf34acSHadi Asyrafi 21632cf34acSHadi Asyrafi /* Store magic number */ 21732cf34acSHadi Asyrafi mmio_write_32(L2_RESET_DONE_REG, L2_RESET_DONE_STATUS); 21832cf34acSHadi Asyrafi 21932cf34acSHadi Asyrafi /* Increase timeout */ 220391eeeefSHadi Asyrafi mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff); 22132cf34acSHadi Asyrafi 22232cf34acSHadi Asyrafi /* Enable handshakes */ 223391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET); 22432cf34acSHadi Asyrafi 22579626f46SJit Loon Lim #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 22632cf34acSHadi Asyrafi /* Reset L2 module */ 227391eeeefSHadi Asyrafi mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100); 22879626f46SJit Loon Lim #endif 22932cf34acSHadi Asyrafi 23032cf34acSHadi Asyrafi while (1) 23132cf34acSHadi Asyrafi wfi(); 23232cf34acSHadi Asyrafi 23332cf34acSHadi Asyrafi /* Should not reach here */ 23432cf34acSHadi Asyrafi return 0; 23532cf34acSHadi Asyrafi } 23632cf34acSHadi Asyrafi 237c76d4239SHadi Asyrafi int socfpga_validate_power_state(unsigned int power_state, 238c76d4239SHadi Asyrafi psci_power_state_t *req_state) 239c76d4239SHadi Asyrafi { 240c76d4239SHadi Asyrafi VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); 241c76d4239SHadi Asyrafi 242c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 243c76d4239SHadi Asyrafi } 244c76d4239SHadi Asyrafi 245c76d4239SHadi Asyrafi int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint) 246c76d4239SHadi Asyrafi { 247c76d4239SHadi Asyrafi VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint); 248c76d4239SHadi Asyrafi return PSCI_E_SUCCESS; 249c76d4239SHadi Asyrafi } 250c76d4239SHadi Asyrafi 251c76d4239SHadi Asyrafi void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state) 252c76d4239SHadi Asyrafi { 253c76d4239SHadi Asyrafi req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; 254c76d4239SHadi Asyrafi req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; 255c76d4239SHadi Asyrafi } 256c76d4239SHadi Asyrafi 257c76d4239SHadi Asyrafi /******************************************************************************* 258c76d4239SHadi Asyrafi * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 259c76d4239SHadi Asyrafi * platform layer will take care of registering the handlers with PSCI. 260c76d4239SHadi Asyrafi ******************************************************************************/ 261c76d4239SHadi Asyrafi const plat_psci_ops_t socfpga_psci_pm_ops = { 262c76d4239SHadi Asyrafi .cpu_standby = socfpga_cpu_standby, 263c76d4239SHadi Asyrafi .pwr_domain_on = socfpga_pwr_domain_on, 264c76d4239SHadi Asyrafi .pwr_domain_off = socfpga_pwr_domain_off, 265c76d4239SHadi Asyrafi .pwr_domain_suspend = socfpga_pwr_domain_suspend, 266c76d4239SHadi Asyrafi .pwr_domain_on_finish = socfpga_pwr_domain_on_finish, 267c76d4239SHadi Asyrafi .pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish, 268c76d4239SHadi Asyrafi .system_off = socfpga_system_off, 269c76d4239SHadi Asyrafi .system_reset = socfpga_system_reset, 27032cf34acSHadi Asyrafi .system_reset2 = socfpga_system_reset2, 271c76d4239SHadi Asyrafi .validate_power_state = socfpga_validate_power_state, 272c76d4239SHadi Asyrafi .validate_ns_entrypoint = socfpga_validate_ns_entrypoint, 273c76d4239SHadi Asyrafi .get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state 274c76d4239SHadi Asyrafi }; 275c76d4239SHadi Asyrafi 276c76d4239SHadi Asyrafi /******************************************************************************* 277c76d4239SHadi Asyrafi * Export the platform specific power ops. 278c76d4239SHadi Asyrafi ******************************************************************************/ 279c76d4239SHadi Asyrafi int plat_setup_psci_ops(uintptr_t sec_entrypoint, 280c76d4239SHadi Asyrafi const struct plat_psci_ops **psci_ops) 281c76d4239SHadi Asyrafi { 282c76d4239SHadi Asyrafi /* Save warm boot entrypoint.*/ 283cf82aff0SHadi Asyrafi mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint); 284c76d4239SHadi Asyrafi *psci_ops = &socfpga_psci_pm_ops; 285cf82aff0SHadi Asyrafi 286c76d4239SHadi Asyrafi return 0; 287c76d4239SHadi Asyrafi } 288