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