1 /* 2 * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <assert.h> 8 #include <stdbool.h> 9 10 #include <arch_helpers.h> 11 #include <common/debug.h> 12 #include <lib/el3_runtime/cpu_data.h> 13 #include <lib/psci/psci.h> 14 #include <plat/common/platform.h> 15 16 #include <ti_sci_protocol.h> 17 #include <k3_gicv3.h> 18 #include <ti_sci.h> 19 20 #define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0]) 21 #define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1]) 22 #define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) 23 24 uintptr_t k3_sec_entrypoint; 25 26 static void k3_cpu_standby(plat_local_state_t cpu_state) 27 { 28 u_register_t scr; 29 30 scr = read_scr_el3(); 31 /* Enable the Non secure interrupt to wake the CPU */ 32 write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT); 33 isb(); 34 /* dsb is good practice before using wfi to enter low power states */ 35 dsb(); 36 /* Enter standby state */ 37 wfi(); 38 /* Restore SCR */ 39 write_scr_el3(scr); 40 } 41 42 static int k3_pwr_domain_on(u_register_t mpidr) 43 { 44 int core, proc_id, device_id, ret; 45 46 core = plat_core_pos_by_mpidr(mpidr); 47 if (core < 0) { 48 ERROR("Could not get target core id: %d\n", core); 49 return PSCI_E_INTERN_FAIL; 50 } 51 52 proc_id = PLAT_PROC_START_ID + core; 53 device_id = PLAT_PROC_DEVICE_START_ID + core; 54 55 ret = ti_sci_proc_request(proc_id); 56 if (ret) { 57 ERROR("Request for processor failed: %d\n", ret); 58 return PSCI_E_INTERN_FAIL; 59 } 60 61 ret = ti_sci_proc_set_boot_cfg(proc_id, k3_sec_entrypoint, 0, 0); 62 if (ret) { 63 ERROR("Request to set core boot address failed: %d\n", ret); 64 return PSCI_E_INTERN_FAIL; 65 } 66 67 /* sanity check these are off before starting a core */ 68 ret = ti_sci_proc_set_boot_ctrl(proc_id, 69 0, PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ | 70 PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS | 71 PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM); 72 if (ret) { 73 ERROR("Request to clear boot configuration failed: %d\n", ret); 74 return PSCI_E_INTERN_FAIL; 75 } 76 77 ret = ti_sci_device_get(device_id); 78 if (ret) { 79 ERROR("Request to start core failed: %d\n", ret); 80 return PSCI_E_INTERN_FAIL; 81 } 82 83 return PSCI_E_SUCCESS; 84 } 85 86 void k3_pwr_domain_off(const psci_power_state_t *target_state) 87 { 88 int core, cluster, proc_id, device_id, cluster_id, ret; 89 90 /* At very least the local core should be powering down */ 91 assert(CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE); 92 93 /* Prevent interrupts from spuriously waking up this cpu */ 94 k3_gic_cpuif_disable(); 95 96 core = plat_my_core_pos(); 97 cluster = MPIDR_AFFLVL1_VAL(read_mpidr_el1()); 98 proc_id = PLAT_PROC_START_ID + core; 99 device_id = PLAT_PROC_DEVICE_START_ID + core; 100 cluster_id = PLAT_CLUSTER_DEVICE_START_ID + (cluster * 2); 101 102 /* 103 * If we are the last core in the cluster then we take a reference to 104 * the cluster device so that it does not get shutdown before we 105 * execute the entire cluster L2 cleaning sequence below. 106 */ 107 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { 108 ret = ti_sci_device_get(cluster_id); 109 if (ret) { 110 ERROR("Request to get cluster failed: %d\n", ret); 111 return; 112 } 113 } 114 115 /* Start by sending wait for WFI command */ 116 ret = ti_sci_proc_wait_boot_status_no_wait(proc_id, 117 /* 118 * Wait maximum time to give us the best chance to get 119 * to WFI before this command timeouts 120 */ 121 UINT8_MAX, 100, UINT8_MAX, UINT8_MAX, 122 /* Wait for WFI */ 123 PROC_BOOT_STATUS_FLAG_ARMV8_WFI, 0, 0, 0); 124 if (ret) { 125 ERROR("Sending wait for WFI failed (%d)\n", ret); 126 return; 127 } 128 129 /* Now queue up the core shutdown request */ 130 ret = ti_sci_device_put_no_wait(device_id); 131 if (ret) { 132 ERROR("Sending core shutdown message failed (%d)\n", ret); 133 return; 134 } 135 136 /* If our cluster is not going down we stop here */ 137 if (CLUSTER_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) 138 return; 139 140 /* set AINACTS */ 141 ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id, 142 PROC_BOOT_CTRL_FLAG_ARMV8_AINACTS, 0); 143 if (ret) { 144 ERROR("Sending set control message failed (%d)\n", ret); 145 return; 146 } 147 148 /* set L2FLUSHREQ */ 149 ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id, 150 PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ, 0); 151 if (ret) { 152 ERROR("Sending set control message failed (%d)\n", ret); 153 return; 154 } 155 156 /* wait for L2FLUSHDONE*/ 157 ret = ti_sci_proc_wait_boot_status_no_wait(proc_id, 158 UINT8_MAX, 2, UINT8_MAX, UINT8_MAX, 159 PROC_BOOT_STATUS_FLAG_ARMV8_L2F_DONE, 0, 0, 0); 160 if (ret) { 161 ERROR("Sending wait message failed (%d)\n", ret); 162 return; 163 } 164 165 /* clear L2FLUSHREQ */ 166 ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id, 167 0, PROC_BOOT_CTRL_FLAG_ARMV8_L2FLUSHREQ); 168 if (ret) { 169 ERROR("Sending set control message failed (%d)\n", ret); 170 return; 171 } 172 173 /* set ACINACTM */ 174 ret = ti_sci_proc_set_boot_ctrl_no_wait(proc_id, 175 PROC_BOOT_CTRL_FLAG_ARMV8_ACINACTM, 0); 176 if (ret) { 177 ERROR("Sending set control message failed (%d)\n", ret); 178 return; 179 } 180 181 /* wait for STANDBYWFIL2 */ 182 ret = ti_sci_proc_wait_boot_status_no_wait(proc_id, 183 UINT8_MAX, 2, UINT8_MAX, UINT8_MAX, 184 PROC_BOOT_STATUS_FLAG_ARMV8_STANDBYWFIL2, 0, 0, 0); 185 if (ret) { 186 ERROR("Sending wait message failed (%d)\n", ret); 187 return; 188 } 189 190 /* Now queue up the cluster shutdown request */ 191 ret = ti_sci_device_put_no_wait(cluster_id); 192 if (ret) { 193 ERROR("Sending cluster shutdown message failed (%d)\n", ret); 194 return; 195 } 196 } 197 198 void k3_pwr_domain_on_finish(const psci_power_state_t *target_state) 199 { 200 /* TODO: Indicate to System firmware about completion */ 201 202 k3_gic_pcpu_init(); 203 k3_gic_cpuif_enable(); 204 } 205 206 static void __dead2 k3_system_off(void) 207 { 208 int ret; 209 210 /* Queue up the system shutdown request */ 211 ret = ti_sci_device_put_no_wait(PLAT_BOARD_DEVICE_ID); 212 if (ret != 0) { 213 ERROR("Sending system shutdown message failed (%d)\n", ret); 214 } 215 216 while (true) 217 wfi(); 218 } 219 220 static void __dead2 k3_system_reset(void) 221 { 222 /* Send the system reset request to system firmware */ 223 ti_sci_core_reboot(); 224 225 while (true) 226 wfi(); 227 } 228 229 static int k3_validate_power_state(unsigned int power_state, 230 psci_power_state_t *req_state) 231 { 232 /* TODO: perform the proper validation */ 233 234 return PSCI_E_SUCCESS; 235 } 236 237 #if K3_PM_SYSTEM_SUSPEND 238 static void k3_pwr_domain_suspend(const psci_power_state_t *target_state) 239 { 240 unsigned int core, proc_id; 241 242 core = plat_my_core_pos(); 243 proc_id = PLAT_PROC_START_ID + core; 244 245 /* Prevent interrupts from spuriously waking up this cpu */ 246 k3_gic_cpuif_disable(); 247 k3_gic_save_context(); 248 249 k3_pwr_domain_off(target_state); 250 251 ti_sci_enter_sleep(proc_id, 0, k3_sec_entrypoint); 252 } 253 254 static void k3_pwr_domain_suspend_finish(const psci_power_state_t *target_state) 255 { 256 k3_gic_restore_context(); 257 k3_gic_cpuif_enable(); 258 } 259 260 static void k3_get_sys_suspend_power_state(psci_power_state_t *req_state) 261 { 262 unsigned int i; 263 264 /* CPU & cluster off, system in retention */ 265 for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) { 266 req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; 267 } 268 } 269 #endif 270 271 static const plat_psci_ops_t k3_plat_psci_ops = { 272 .cpu_standby = k3_cpu_standby, 273 .pwr_domain_on = k3_pwr_domain_on, 274 .pwr_domain_off = k3_pwr_domain_off, 275 .pwr_domain_on_finish = k3_pwr_domain_on_finish, 276 #if K3_PM_SYSTEM_SUSPEND 277 .pwr_domain_suspend = k3_pwr_domain_suspend, 278 .pwr_domain_suspend_finish = k3_pwr_domain_suspend_finish, 279 .get_sys_suspend_power_state = k3_get_sys_suspend_power_state, 280 #endif 281 .system_off = k3_system_off, 282 .system_reset = k3_system_reset, 283 .validate_power_state = k3_validate_power_state, 284 }; 285 286 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 287 const plat_psci_ops_t **psci_ops) 288 { 289 k3_sec_entrypoint = sec_entrypoint; 290 291 *psci_ops = &k3_plat_psci_ops; 292 293 return 0; 294 } 295