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