1 /* 2 * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <stdbool.h> 8 9 #include <arch.h> 10 #include <arch_helpers.h> 11 #include <common/debug.h> 12 #include <drivers/arm/cci.h> 13 #include <drivers/arm/gicv3.h> 14 #include <lib/mmio.h> 15 #include <lib/psci/psci.h> 16 17 #include <plat_imx8.h> 18 #include <sci/sci.h> 19 20 #include "../../common/sci/imx8_mu.h" 21 22 #define CORE_PWR_STATE(state) \ 23 ((state)->pwr_domain_state[MPIDR_AFFLVL0]) 24 #define CLUSTER_PWR_STATE(state) \ 25 ((state)->pwr_domain_state[MPIDR_AFFLVL1]) 26 #define SYSTEM_PWR_STATE(state) \ 27 ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) 28 29 const static int ap_core_index[PLATFORM_CORE_COUNT] = { 30 SC_R_A53_0, SC_R_A53_1, SC_R_A53_2, 31 SC_R_A53_3, SC_R_A72_0, SC_R_A72_1, 32 }; 33 34 /* save gic dist/redist context when GIC is poewr down */ 35 static struct plat_gic_ctx imx_gicv3_ctx; 36 static unsigned int gpt_lpcg, gpt_reg[2]; 37 38 static void imx_enable_irqstr_wakeup(void) 39 { 40 uint32_t irq_mask; 41 gicv3_dist_ctx_t *dist_ctx = &imx_gicv3_ctx.dist_ctx; 42 43 /* put IRQSTR into ON mode */ 44 sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON); 45 46 /* enable the irqsteer to handle wakeup irq */ 47 mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x1); 48 for (int i = 0; i < 15; i++) { 49 irq_mask = dist_ctx->gicd_isenabler[i]; 50 mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 0x4 * i, irq_mask); 51 } 52 53 /* set IRQSTR low power mode */ 54 if (imx_is_wakeup_src_irqsteer()) 55 sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY); 56 else 57 sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF); 58 } 59 60 static void imx_disable_irqstr_wakeup(void) 61 { 62 /* put IRQSTR into ON from STBY mode */ 63 sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON); 64 65 /* disable the irqsteer */ 66 mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x0); 67 for (int i = 0; i < 16; i++) 68 mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x4 + 0x4 * i, 0x0); 69 70 /* put IRQSTR into OFF mode */ 71 sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF); 72 } 73 74 int imx_pwr_domain_on(u_register_t mpidr) 75 { 76 int ret = PSCI_E_SUCCESS; 77 unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); 78 unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 79 80 sc_pm_set_resource_power_mode(ipc_handle, cluster_id == 0 ? 81 SC_R_A53 : SC_R_A72, SC_PM_PW_MODE_ON); 82 83 if (cluster_id == 1) 84 sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON); 85 86 if (sc_pm_set_resource_power_mode(ipc_handle, 87 ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], 88 SC_PM_PW_MODE_ON) != SC_ERR_NONE) { 89 ERROR("core %d power on failed!\n", cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id); 90 ret = PSCI_E_INTERN_FAIL; 91 } 92 93 if (sc_pm_cpu_start(ipc_handle, 94 ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], 95 true, BL31_BASE) != SC_ERR_NONE) { 96 ERROR("boot core %d failed!\n", cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id); 97 ret = PSCI_E_INTERN_FAIL; 98 } 99 100 return ret; 101 } 102 103 void imx_pwr_domain_on_finish(const psci_power_state_t *target_state) 104 { 105 uint64_t mpidr = read_mpidr_el1(); 106 107 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 108 cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 109 110 plat_gic_pcpu_init(); 111 plat_gic_cpuif_enable(); 112 } 113 114 void imx_pwr_domain_off(const psci_power_state_t *target_state) 115 { 116 u_register_t mpidr = read_mpidr_el1(); 117 unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); 118 unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 119 120 plat_gic_cpuif_disable(); 121 sc_pm_req_cpu_low_power_mode(ipc_handle, 122 ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], 123 SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_NONE); 124 125 if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) { 126 cci_disable_snoop_dvm_reqs(cluster_id); 127 if (cluster_id == 1) 128 sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF); 129 } 130 printf("turn off cluster:%d core:%d\n", cluster_id, cpu_id); 131 } 132 133 void imx_domain_suspend(const psci_power_state_t *target_state) 134 { 135 u_register_t mpidr = read_mpidr_el1(); 136 unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); 137 unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 138 139 if (is_local_state_off(CORE_PWR_STATE(target_state))) { 140 plat_gic_cpuif_disable(); 141 sc_pm_set_cpu_resume(ipc_handle, 142 ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], 143 true, BL31_BASE); 144 sc_pm_req_cpu_low_power_mode(ipc_handle, 145 ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], 146 SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC); 147 } else { 148 dsb(); 149 write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); 150 isb(); 151 } 152 153 if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) { 154 cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 155 if (cluster_id == 1) 156 sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF); 157 } 158 159 if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) { 160 plat_gic_cpuif_disable(); 161 162 /* save gic context */ 163 plat_gic_save(cpu_id, &imx_gicv3_ctx); 164 /* enable the irqsteer for wakeup */ 165 imx_enable_irqstr_wakeup(); 166 167 cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 168 169 /* Put GIC in LP mode. */ 170 sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_OFF); 171 /* Save GPT clock and registers, then turn off its power */ 172 gpt_lpcg = mmio_read_32(IMX_GPT_LPCG_BASE); 173 gpt_reg[0] = mmio_read_32(IMX_GPT_BASE); 174 gpt_reg[1] = mmio_read_32(IMX_GPT_BASE + 0x4); 175 sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_OFF); 176 177 sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_OFF); 178 sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF); 179 sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF); 180 181 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_DDR, 182 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); 183 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_DDR, 184 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); 185 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_MU, 186 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); 187 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_MU, 188 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); 189 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_INTERCONNECT, 190 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); 191 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_INTERCONNECT, 192 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); 193 sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF); 194 195 sc_pm_set_cpu_resume(ipc_handle, 196 ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], 197 true, BL31_BASE); 198 if (imx_is_wakeup_src_irqsteer()) 199 sc_pm_req_cpu_low_power_mode(ipc_handle, 200 ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], 201 SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER); 202 else 203 sc_pm_req_cpu_low_power_mode(ipc_handle, 204 ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], 205 SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU); 206 } 207 } 208 209 void imx_domain_suspend_finish(const psci_power_state_t *target_state) 210 { 211 u_register_t mpidr = read_mpidr_el1(); 212 unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); 213 unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 214 215 /* check the system level status */ 216 if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) { 217 MU_Resume(SC_IPC_BASE); 218 219 sc_pm_req_cpu_low_power_mode(ipc_handle, 220 ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], 221 SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC); 222 223 /* Put GIC/IRQSTR back to high power mode. */ 224 sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_ON); 225 226 /* Turn GPT power and restore its clock and registers */ 227 sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON); 228 sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0); 229 mmio_write_32(IMX_GPT_BASE, gpt_reg[0]); 230 mmio_write_32(IMX_GPT_BASE + 0x4, gpt_reg[1]); 231 mmio_write_32(IMX_GPT_LPCG_BASE, gpt_lpcg); 232 233 sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_ON); 234 sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON); 235 sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON); 236 237 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_DDR, 238 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 239 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_DDR, 240 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 241 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_MU, 242 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 243 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_MU, 244 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 245 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_INTERCONNECT, 246 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 247 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_INTERCONNECT, 248 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 249 sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON); 250 251 cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 252 253 /* restore gic context */ 254 plat_gic_restore(cpu_id, &imx_gicv3_ctx); 255 /* disable the irqsteer wakeup */ 256 imx_disable_irqstr_wakeup(); 257 258 plat_gic_cpuif_enable(); 259 } 260 261 /* check the cluster level power status */ 262 if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) { 263 cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 264 if (cluster_id == 1) 265 sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON); 266 } 267 268 /* check the core level power status */ 269 if (is_local_state_off(CORE_PWR_STATE(target_state))) { 270 sc_pm_set_cpu_resume(ipc_handle, 271 ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], 272 false, BL31_BASE); 273 sc_pm_req_cpu_low_power_mode(ipc_handle, 274 ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], 275 SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC); 276 plat_gic_cpuif_enable(); 277 } else { 278 write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); 279 isb(); 280 } 281 } 282 283 int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) 284 { 285 return PSCI_E_SUCCESS; 286 } 287 288 static const plat_psci_ops_t imx_plat_psci_ops = { 289 .pwr_domain_on = imx_pwr_domain_on, 290 .pwr_domain_on_finish = imx_pwr_domain_on_finish, 291 .pwr_domain_off = imx_pwr_domain_off, 292 .pwr_domain_suspend = imx_domain_suspend, 293 .pwr_domain_suspend_finish = imx_domain_suspend_finish, 294 .get_sys_suspend_power_state = imx_get_sys_suspend_power_state, 295 .validate_power_state = imx_validate_power_state, 296 .validate_ns_entrypoint = imx_validate_ns_entrypoint, 297 .system_off = imx_system_off, 298 .system_reset = imx_system_reset, 299 }; 300 301 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 302 const plat_psci_ops_t **psci_ops) 303 { 304 imx_mailbox_init(sec_entrypoint); 305 *psci_ops = &imx_plat_psci_ops; 306 307 /* make sure system sources power ON in low power mode by default */ 308 sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_ON); 309 sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON); 310 sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON); 311 312 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_DDR, 313 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 314 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_DDR, 315 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 316 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_MU, 317 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 318 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_MU, 319 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 320 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_INTERCONNECT, 321 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 322 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_INTERCONNECT, 323 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 324 325 return 0; 326 } 327