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