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 #if PLATFORM_MODEL == PLAT_SOCFPGA_AGILEX5 217 mailbox_reset_warm(reset_type); 218 #else 219 if (cold_reset_for_ecc_dbe()) { 220 mailbox_reset_cold(); 221 } 222 #endif 223 224 /* disable cpuif */ 225 #ifdef GICV3_SUPPORT_GIC600 226 gicv3_cpuif_disable(plat_my_core_pos()); 227 #else 228 gicv2_cpuif_disable(); 229 #endif 230 231 /* Store magic number */ 232 mmio_write_32(L2_RESET_DONE_REG, L2_RESET_DONE_STATUS); 233 234 /* Increase timeout */ 235 mmio_write_32(SOCFPGA_RSTMGR(HDSKTIMEOUT), 0xffffff); 236 237 /* Enable handshakes */ 238 mmio_setbits_32(SOCFPGA_RSTMGR(HDSKEN), RSTMGR_HDSKEN_SET); 239 240 #if PLATFORM_MODEL != PLAT_SOCFPGA_AGILEX5 241 /* Reset L2 module */ 242 mmio_setbits_32(SOCFPGA_RSTMGR(COLDMODRST), 0x100); 243 #endif 244 245 while (1) 246 wfi(); 247 248 /* Should not reach here */ 249 return 0; 250 } 251 252 int socfpga_validate_power_state(unsigned int power_state, 253 psci_power_state_t *req_state) 254 { 255 VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); 256 257 return PSCI_E_SUCCESS; 258 } 259 260 int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint) 261 { 262 VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint); 263 return PSCI_E_SUCCESS; 264 } 265 266 void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state) 267 { 268 req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; 269 req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; 270 } 271 272 /******************************************************************************* 273 * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard 274 * platform layer will take care of registering the handlers with PSCI. 275 ******************************************************************************/ 276 const plat_psci_ops_t socfpga_psci_pm_ops = { 277 .cpu_standby = socfpga_cpu_standby, 278 .pwr_domain_on = socfpga_pwr_domain_on, 279 .pwr_domain_off = socfpga_pwr_domain_off, 280 .pwr_domain_suspend = socfpga_pwr_domain_suspend, 281 .pwr_domain_on_finish = socfpga_pwr_domain_on_finish, 282 .pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish, 283 .system_off = socfpga_system_off, 284 .system_reset = socfpga_system_reset, 285 .system_reset2 = socfpga_system_reset2, 286 .validate_power_state = socfpga_validate_power_state, 287 .validate_ns_entrypoint = socfpga_validate_ns_entrypoint, 288 .get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state 289 }; 290 291 /******************************************************************************* 292 * Export the platform specific power ops. 293 ******************************************************************************/ 294 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 295 const struct plat_psci_ops **psci_ops) 296 { 297 /* Save warm boot entrypoint.*/ 298 mmio_write_64(PLAT_SEC_ENTRY, sec_entrypoint); 299 *psci_ops = &socfpga_psci_pm_ops; 300 301 return 0; 302 } 303