1 /* 2 * Copyright (c) 2019-2023, ARM Limited and Contributors. All rights reserved. 3 * Copyright (c) 2019-2023, Intel Corporation. All rights reserved. 4 * Copyright (c) 2024, Altera Corporation. All rights reserved. 5 * 6 * SPDX-License-Identifier: BSD-3-Clause 7 */ 8 9 #include <arch_helpers.h> 10 #include <common/debug.h> 11 12 #ifndef GICV3_SUPPORT_GIC600 13 #include <drivers/arm/gicv2.h> 14 #else 15 #include <drivers/arm/gicv3.h> 16 #endif 17 #include <lib/mmio.h> 18 #include <lib/psci/psci.h> 19 #include <plat/common/platform.h> 20 #include "ccu/ncore_ccu.h" 21 #include "socfpga_mailbox.h" 22 #include "socfpga_plat_def.h" 23 #include "socfpga_private.h" 24 #include "socfpga_reset_manager.h" 25 #include "socfpga_sip_svc.h" 26 #include "socfpga_system_manager.h" 27 28 #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 29 void socfpga_wakeup_secondary_cpu(unsigned int cpu_id); 30 extern void plat_secondary_cold_boot_setup(void); 31 #endif 32 33 /******************************************************************************* 34 * plat handler called when a CPU is about to enter standby. 35 ******************************************************************************/ 36 void socfpga_cpu_standby(plat_local_state_t cpu_state) 37 { 38 /* 39 * Enter standby state 40 * dsb is good practice before using wfi to enter low power states 41 */ 42 VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state); 43 dsb(); 44 wfi(); 45 } 46 47 /******************************************************************************* 48 * plat handler called when a power domain is about to be turned on. The 49 * mpidr determines the CPU to be turned on. 50 ******************************************************************************/ 51 int socfpga_pwr_domain_on(u_register_t mpidr) 52 { 53 unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); 54 #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 55 /* TODO: Add in CPU FUSE from SDM */ 56 #else 57 uint32_t psci_boot = 0x00; 58 59 VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); 60 #endif 61 62 if (cpu_id == -1) 63 return PSCI_E_INTERN_FAIL; 64 65 #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 66 if (cpu_id == 0x00) { 67 psci_boot = mmio_read_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8)); 68 psci_boot |= 0x80000; /* bit 19 */ 69 mmio_write_32(SOCFPGA_SYSMGR(BOOT_SCRATCH_COLD_8), psci_boot); 70 } 71 72 mmio_write_64(PLAT_CPUID_RELEASE, cpu_id); 73 #endif 74 75 /* release core reset */ 76 #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 77 bl31_plat_set_secondary_cpu_entrypoint(cpu_id); 78 #else 79 mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 80 mmio_write_64(PLAT_CPUID_RELEASE, cpu_id); 81 #endif 82 83 return PSCI_E_SUCCESS; 84 } 85 86 /******************************************************************************* 87 * plat handler called when a power domain is about to be turned off. The 88 * target_state encodes the power state that each level should transition to. 89 ******************************************************************************/ 90 void socfpga_pwr_domain_off(const psci_power_state_t *target_state) 91 { 92 for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 93 VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 94 __func__, i, target_state->pwr_domain_state[i]); 95 96 /* Prevent interrupts from spuriously waking up this cpu */ 97 #ifdef GICV3_SUPPORT_GIC600 98 gicv3_cpuif_disable(plat_my_core_pos()); 99 #else 100 gicv2_cpuif_disable(); 101 #endif 102 103 } 104 105 /******************************************************************************* 106 * plat handler called when a power domain is about to be suspended. The 107 * target_state encodes the power state that each level should transition to. 108 ******************************************************************************/ 109 void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state) 110 { 111 #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 112 unsigned int cpu_id = plat_my_core_pos(); 113 #endif 114 115 for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 116 VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 117 __func__, i, target_state->pwr_domain_state[i]); 118 119 #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 120 /* assert core reset */ 121 mmio_setbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 122 #endif 123 } 124 125 /******************************************************************************* 126 * plat handler called when a power domain has just been powered on after 127 * being turned off earlier. The target_state encodes the low power state that 128 * each level has woken up from. 129 ******************************************************************************/ 130 void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state) 131 { 132 for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 133 VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 134 __func__, i, target_state->pwr_domain_state[i]); 135 136 /* Enable the gic cpu interface */ 137 #ifdef GICV3_SUPPORT_GIC600 138 gicv3_rdistif_init(plat_my_core_pos()); 139 gicv3_cpuif_enable(plat_my_core_pos()); 140 #else 141 /* Program the gic per-cpu distributor or re-distributor interface */ 142 gicv2_pcpu_distif_init(); 143 gicv2_set_pe_target_mask(plat_my_core_pos()); 144 145 /* Enable the gic cpu interface */ 146 gicv2_cpuif_enable(); 147 #endif 148 } 149 150 /******************************************************************************* 151 * plat handler called when a power domain has just been powered on after 152 * having been suspended earlier. The target_state encodes the low power state 153 * that each level has woken up from. 154 * TODO: At the moment we reuse the on finisher and reinitialize the secure 155 * context. Need to implement a separate suspend finisher. 156 ******************************************************************************/ 157 void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 158 { 159 #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 160 unsigned int cpu_id = plat_my_core_pos(); 161 #endif 162 163 for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) 164 VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", 165 __func__, i, target_state->pwr_domain_state[i]); 166 167 #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 168 /* release core reset */ 169 mmio_clrbits_32(SOCFPGA_RSTMGR(MPUMODRST), 1 << cpu_id); 170 #endif 171 } 172 173 /******************************************************************************* 174 * plat handlers to shutdown/reboot the system 175 ******************************************************************************/ 176 static void __dead2 socfpga_system_off(void) 177 { 178 wfi(); 179 ERROR("System Off: operation not handled.\n"); 180 panic(); 181 } 182 183 extern uint64_t intel_rsu_update_address; 184 185 static void __dead2 socfpga_system_reset(void) 186 { 187 uint32_t addr_buf[2]; 188 189 memcpy_s(addr_buf, sizeof(intel_rsu_update_address), 190 &intel_rsu_update_address, sizeof(intel_rsu_update_address)); 191 192 if (intel_rsu_update_address) { 193 mailbox_rsu_update(addr_buf); 194 } else { 195 #if CACHE_FLUSH 196 /* ATF Flush and Invalidate Cache */ 197 dcsw_op_all(DCCISW); 198 invalidate_cache_low_el(); 199 #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 200 flush_l3_dcache(); 201 #endif 202 #endif 203 mailbox_reset_cold(); 204 } 205 206 while (1) 207 wfi(); 208 } 209 210 static int socfpga_system_reset2(int is_vendor, int reset_type, 211 u_register_t cookie) 212 { 213 #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 214 mailbox_reset_warm(reset_type); 215 #else 216 if (cold_reset_for_ecc_dbe()) { 217 mailbox_reset_cold(); 218 } 219 #endif 220 221 /* disable cpuif */ 222 #ifdef GICV3_SUPPORT_GIC600 223 gicv3_cpuif_disable(plat_my_core_pos()); 224 #else 225 gicv2_cpuif_disable(); 226 #endif 227 228 /* Store magic number */ 229 mmio_write_32(L2_RESET_DONE_REG, L2_RESET_DONE_STATUS); 230 231 /* Increase timeout */ 232 mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff); 233 234 /* Enable handshakes */ 235 mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET); 236 237 #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 238 /* Reset L2 module */ 239 mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100); 240 #endif 241 242 while (1) 243 wfi(); 244 245 /* Should not reach here */ 246 return 0; 247 } 248 249 int socfpga_validate_power_state(unsigned int power_state, 250 psci_power_state_t *req_state) 251 { 252 VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); 253 254 return PSCI_E_SUCCESS; 255 } 256 257 int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint) 258 { 259 VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint); 260 return PSCI_E_SUCCESS; 261 } 262 263 void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state) 264 { 265 req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; 266 req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; 267 } 268 269 /******************************************************************************* 270 * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 271 * platform layer will take care of registering the handlers with PSCI. 272 ******************************************************************************/ 273 const plat_psci_ops_t socfpga_psci_pm_ops = { 274 .cpu_standby = socfpga_cpu_standby, 275 .pwr_domain_on = socfpga_pwr_domain_on, 276 .pwr_domain_off = socfpga_pwr_domain_off, 277 .pwr_domain_suspend = socfpga_pwr_domain_suspend, 278 .pwr_domain_on_finish = socfpga_pwr_domain_on_finish, 279 .pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish, 280 .system_off = socfpga_system_off, 281 .system_reset = socfpga_system_reset, 282 .system_reset2 = socfpga_system_reset2, 283 .validate_power_state = socfpga_validate_power_state, 284 .validate_ns_entrypoint = socfpga_validate_ns_entrypoint, 285 .get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state 286 }; 287 288 /******************************************************************************* 289 * Export the platform specific power ops. 290 ******************************************************************************/ 291 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 292 const struct plat_psci_ops **psci_ops) 293 { 294 /* Save warm boot entrypoint.*/ 295 mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint); 296 *psci_ops = &socfpga_psci_pm_ops; 297 298 return 0; 299 } 300