1baa7650bSAnson Huang /* 2baa7650bSAnson Huang * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. 3baa7650bSAnson Huang * 4baa7650bSAnson Huang * SPDX-License-Identifier: BSD-3-Clause 5baa7650bSAnson Huang */ 6baa7650bSAnson Huang 7baa7650bSAnson Huang #include <arch.h> 8baa7650bSAnson Huang #include <arch_helpers.h> 9baa7650bSAnson Huang #include <cci.h> 10baa7650bSAnson Huang #include <debug.h> 11baa7650bSAnson Huang #include <gicv3.h> 12baa7650bSAnson Huang #include <mmio.h> 13baa7650bSAnson Huang #include <plat_imx8.h> 14baa7650bSAnson Huang #include <psci.h> 15baa7650bSAnson Huang #include <sci/sci.h> 16baa7650bSAnson Huang #include <stdbool.h> 17baa7650bSAnson Huang 188ef9f860SAnson Huang #define CORE_PWR_STATE(state) \ 198ef9f860SAnson Huang ((state)->pwr_domain_state[MPIDR_AFFLVL0]) 208ef9f860SAnson Huang #define CLUSTER_PWR_STATE(state) \ 218ef9f860SAnson Huang ((state)->pwr_domain_state[MPIDR_AFFLVL1]) 228ef9f860SAnson Huang #define SYSTEM_PWR_STATE(state) \ 238ef9f860SAnson Huang ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) 248ef9f860SAnson Huang 25baa7650bSAnson Huang const static int ap_core_index[PLATFORM_CORE_COUNT] = { 26baa7650bSAnson Huang SC_R_A53_0, SC_R_A53_1, SC_R_A53_2, 27baa7650bSAnson Huang SC_R_A53_3, SC_R_A72_0, SC_R_A72_1, 28baa7650bSAnson Huang }; 29baa7650bSAnson Huang 30baa7650bSAnson Huang int imx_pwr_domain_on(u_register_t mpidr) 31baa7650bSAnson Huang { 32baa7650bSAnson Huang int ret = PSCI_E_SUCCESS; 33baa7650bSAnson Huang unsigned int cluster_id, cpu_id; 34baa7650bSAnson Huang 35baa7650bSAnson Huang cluster_id = MPIDR_AFFLVL1_VAL(mpidr); 36baa7650bSAnson Huang cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 37baa7650bSAnson Huang 38*39b6cc66SAntonio Nino Diaz printf("imx_pwr_domain_on cluster_id %d, cpu_id %d\n", cluster_id, cpu_id); 39baa7650bSAnson Huang 40baa7650bSAnson Huang if (cluster_id == 0) { 418ef9f860SAnson Huang sc_pm_set_resource_power_mode(ipc_handle, SC_R_A53, 428ef9f860SAnson Huang SC_PM_PW_MODE_ON); 43baa7650bSAnson Huang if (sc_pm_set_resource_power_mode(ipc_handle, ap_core_index[cpu_id], 44baa7650bSAnson Huang SC_PM_PW_MODE_ON) != SC_ERR_NONE) { 45baa7650bSAnson Huang ERROR("cluster0 core %d power on failed!\n", cpu_id); 46baa7650bSAnson Huang ret = PSCI_E_INTERN_FAIL; 47baa7650bSAnson Huang } 48baa7650bSAnson Huang 49baa7650bSAnson Huang if (sc_pm_cpu_start(ipc_handle, ap_core_index[cpu_id], 50baa7650bSAnson Huang true, BL31_BASE) != SC_ERR_NONE) { 51baa7650bSAnson Huang ERROR("boot cluster0 core %d failed!\n", cpu_id); 52baa7650bSAnson Huang ret = PSCI_E_INTERN_FAIL; 53baa7650bSAnson Huang } 54baa7650bSAnson Huang } else { 558ef9f860SAnson Huang sc_pm_set_resource_power_mode(ipc_handle, SC_R_A72, 568ef9f860SAnson Huang SC_PM_PW_MODE_ON); 57baa7650bSAnson Huang if (sc_pm_set_resource_power_mode(ipc_handle, ap_core_index[cpu_id + 4], 58baa7650bSAnson Huang SC_PM_PW_MODE_ON) != SC_ERR_NONE) { 59baa7650bSAnson Huang ERROR(" cluster1 core %d power on failed!\n", cpu_id); 60baa7650bSAnson Huang ret = PSCI_E_INTERN_FAIL; 61baa7650bSAnson Huang } 62baa7650bSAnson Huang 63baa7650bSAnson Huang if (sc_pm_cpu_start(ipc_handle, ap_core_index[cpu_id + 4], 64baa7650bSAnson Huang true, BL31_BASE) != SC_ERR_NONE) { 65baa7650bSAnson Huang ERROR("boot cluster1 core %d failed!\n", cpu_id); 66baa7650bSAnson Huang ret = PSCI_E_INTERN_FAIL; 67baa7650bSAnson Huang } 68baa7650bSAnson Huang } 69baa7650bSAnson Huang 70baa7650bSAnson Huang return ret; 71baa7650bSAnson Huang } 72baa7650bSAnson Huang 73baa7650bSAnson Huang void imx_pwr_domain_on_finish(const psci_power_state_t *target_state) 74baa7650bSAnson Huang { 75baa7650bSAnson Huang uint64_t mpidr = read_mpidr_el1(); 76baa7650bSAnson Huang 778ef9f860SAnson Huang if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 788ef9f860SAnson Huang cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 79baa7650bSAnson Huang 80baa7650bSAnson Huang plat_gic_pcpu_init(); 81baa7650bSAnson Huang plat_gic_cpuif_enable(); 82baa7650bSAnson Huang } 83baa7650bSAnson Huang 840f53bca0SAnson Huang void imx_pwr_domain_off(const psci_power_state_t *target_state) 850f53bca0SAnson Huang { 860f53bca0SAnson Huang u_register_t mpidr = read_mpidr_el1(); 870f53bca0SAnson Huang unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); 880f53bca0SAnson Huang unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 890f53bca0SAnson Huang 900f53bca0SAnson Huang plat_gic_cpuif_disable(); 910f53bca0SAnson Huang sc_pm_req_cpu_low_power_mode(ipc_handle, 928ef9f860SAnson Huang ap_core_index[cpu_id + cluster_id * 4], 930f53bca0SAnson Huang SC_PM_PW_MODE_OFF, 940f53bca0SAnson Huang SC_PM_WAKE_SRC_NONE); 958ef9f860SAnson Huang if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 968ef9f860SAnson Huang cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 97*39b6cc66SAntonio Nino Diaz printf("turn off cluster:%d core:%d\n", cluster_id, cpu_id); 980f53bca0SAnson Huang } 990f53bca0SAnson Huang 1008ef9f860SAnson Huang void imx_domain_suspend(const psci_power_state_t *target_state) 1018ef9f860SAnson Huang { 1028ef9f860SAnson Huang u_register_t mpidr = read_mpidr_el1(); 1038ef9f860SAnson Huang unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); 1048ef9f860SAnson Huang unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 1058ef9f860SAnson Huang 1068ef9f860SAnson Huang plat_gic_cpuif_disable(); 1078ef9f860SAnson Huang 1088ef9f860SAnson Huang cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 1098ef9f860SAnson Huang 1108ef9f860SAnson Huang sc_pm_set_cpu_resume_addr(ipc_handle, 1118ef9f860SAnson Huang ap_core_index[cpu_id + cluster_id * 4], BL31_BASE); 1128ef9f860SAnson Huang sc_pm_req_cpu_low_power_mode(ipc_handle, 1138ef9f860SAnson Huang ap_core_index[cpu_id + cluster_id * 4], 1148ef9f860SAnson Huang SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC); 1158ef9f860SAnson Huang } 1168ef9f860SAnson Huang 1178ef9f860SAnson Huang void imx_domain_suspend_finish(const psci_power_state_t *target_state) 1188ef9f860SAnson Huang { 1198ef9f860SAnson Huang u_register_t mpidr = read_mpidr_el1(); 1208ef9f860SAnson Huang 1218ef9f860SAnson Huang cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 1228ef9f860SAnson Huang 1238ef9f860SAnson Huang plat_gic_cpuif_enable(); 1248ef9f860SAnson Huang } 1258ef9f860SAnson Huang 126baa7650bSAnson Huang int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) 127baa7650bSAnson Huang { 128baa7650bSAnson Huang return PSCI_E_SUCCESS; 129baa7650bSAnson Huang } 130baa7650bSAnson Huang 131baa7650bSAnson Huang static const plat_psci_ops_t imx_plat_psci_ops = { 132baa7650bSAnson Huang .pwr_domain_on = imx_pwr_domain_on, 133baa7650bSAnson Huang .pwr_domain_on_finish = imx_pwr_domain_on_finish, 1340f53bca0SAnson Huang .pwr_domain_off = imx_pwr_domain_off, 1358ef9f860SAnson Huang .pwr_domain_suspend = imx_domain_suspend, 1368ef9f860SAnson Huang .pwr_domain_suspend_finish = imx_domain_suspend_finish, 1378ef9f860SAnson Huang .get_sys_suspend_power_state = imx_get_sys_suspend_power_state, 1388ef9f860SAnson Huang .validate_power_state = imx_validate_power_state, 139baa7650bSAnson Huang .validate_ns_entrypoint = imx_validate_ns_entrypoint, 140db81c592SAnson Huang .system_off = imx_system_off, 141d31ffcf0SAnson Huang .system_reset = imx_system_reset, 142baa7650bSAnson Huang }; 143baa7650bSAnson Huang 144baa7650bSAnson Huang int plat_setup_psci_ops(uintptr_t sec_entrypoint, 145baa7650bSAnson Huang const plat_psci_ops_t **psci_ops) 146baa7650bSAnson Huang { 147baa7650bSAnson Huang imx_mailbox_init(sec_entrypoint); 148baa7650bSAnson Huang *psci_ops = &imx_plat_psci_ops; 149baa7650bSAnson Huang 1508ef9f860SAnson Huang /* Request low power mode for cluster/cci, only need to do once */ 1518ef9f860SAnson Huang sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF); 1528ef9f860SAnson Huang sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_OFF); 1538ef9f860SAnson Huang sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF); 1548ef9f860SAnson Huang 1558ef9f860SAnson Huang /* Request RUN and LP modes for DDR, system interconnect etc. */ 1568ef9f860SAnson Huang sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, 1578ef9f860SAnson Huang SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY); 1588ef9f860SAnson Huang sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, 1598ef9f860SAnson Huang SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY); 1608ef9f860SAnson Huang sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, 1618ef9f860SAnson Huang SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY); 1628ef9f860SAnson Huang sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, 1638ef9f860SAnson Huang SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY); 1648ef9f860SAnson Huang sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, 1658ef9f860SAnson Huang SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, 1668ef9f860SAnson Huang SC_PM_PW_MODE_STBY); 1678ef9f860SAnson Huang sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, 1688ef9f860SAnson Huang SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, 1698ef9f860SAnson Huang SC_PM_PW_MODE_STBY); 170baa7650bSAnson Huang 171baa7650bSAnson Huang return 0; 172baa7650bSAnson Huang } 173