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 #define CORE_PWR_STATE(state) \ 21 ((state)->pwr_domain_state[MPIDR_AFFLVL0]) 22 #define CLUSTER_PWR_STATE(state) \ 23 ((state)->pwr_domain_state[MPIDR_AFFLVL1]) 24 #define SYSTEM_PWR_STATE(state) \ 25 ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) 26 27 const static int ap_core_index[PLATFORM_CORE_COUNT] = { 28 SC_R_A53_0, SC_R_A53_1, SC_R_A53_2, 29 SC_R_A53_3, SC_R_A72_0, SC_R_A72_1, 30 }; 31 32 int imx_pwr_domain_on(u_register_t mpidr) 33 { 34 int ret = PSCI_E_SUCCESS; 35 unsigned int cluster_id, cpu_id; 36 37 cluster_id = MPIDR_AFFLVL1_VAL(mpidr); 38 cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 39 40 printf("imx_pwr_domain_on cluster_id %d, cpu_id %d\n", cluster_id, cpu_id); 41 42 if (cluster_id == 0) { 43 sc_pm_set_resource_power_mode(ipc_handle, SC_R_A53, 44 SC_PM_PW_MODE_ON); 45 if (sc_pm_set_resource_power_mode(ipc_handle, ap_core_index[cpu_id], 46 SC_PM_PW_MODE_ON) != SC_ERR_NONE) { 47 ERROR("cluster0 core %d power on failed!\n", cpu_id); 48 ret = PSCI_E_INTERN_FAIL; 49 } 50 51 if (sc_pm_cpu_start(ipc_handle, ap_core_index[cpu_id], 52 true, BL31_BASE) != SC_ERR_NONE) { 53 ERROR("boot cluster0 core %d failed!\n", cpu_id); 54 ret = PSCI_E_INTERN_FAIL; 55 } 56 } else { 57 sc_pm_set_resource_power_mode(ipc_handle, SC_R_A72, 58 SC_PM_PW_MODE_ON); 59 if (sc_pm_set_resource_power_mode(ipc_handle, ap_core_index[cpu_id + 4], 60 SC_PM_PW_MODE_ON) != SC_ERR_NONE) { 61 ERROR(" cluster1 core %d power on failed!\n", cpu_id); 62 ret = PSCI_E_INTERN_FAIL; 63 } 64 65 if (sc_pm_cpu_start(ipc_handle, ap_core_index[cpu_id + 4], 66 true, BL31_BASE) != SC_ERR_NONE) { 67 ERROR("boot cluster1 core %d failed!\n", cpu_id); 68 ret = PSCI_E_INTERN_FAIL; 69 } 70 } 71 72 return ret; 73 } 74 75 void imx_pwr_domain_on_finish(const psci_power_state_t *target_state) 76 { 77 uint64_t mpidr = read_mpidr_el1(); 78 79 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 80 cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 81 82 plat_gic_pcpu_init(); 83 plat_gic_cpuif_enable(); 84 } 85 86 void imx_pwr_domain_off(const psci_power_state_t *target_state) 87 { 88 u_register_t mpidr = read_mpidr_el1(); 89 unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); 90 unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 91 92 plat_gic_cpuif_disable(); 93 sc_pm_req_cpu_low_power_mode(ipc_handle, 94 ap_core_index[cpu_id + cluster_id * 4], 95 SC_PM_PW_MODE_OFF, 96 SC_PM_WAKE_SRC_NONE); 97 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) 98 cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 99 printf("turn off cluster:%d core:%d\n", cluster_id, cpu_id); 100 } 101 102 void imx_domain_suspend(const psci_power_state_t *target_state) 103 { 104 u_register_t mpidr = read_mpidr_el1(); 105 unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); 106 unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 107 108 plat_gic_cpuif_disable(); 109 110 cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 111 112 sc_pm_set_cpu_resume_addr(ipc_handle, 113 ap_core_index[cpu_id + cluster_id * 4], BL31_BASE); 114 sc_pm_req_cpu_low_power_mode(ipc_handle, 115 ap_core_index[cpu_id + cluster_id * 4], 116 SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC); 117 } 118 119 void imx_domain_suspend_finish(const psci_power_state_t *target_state) 120 { 121 u_register_t mpidr = read_mpidr_el1(); 122 123 cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); 124 125 plat_gic_cpuif_enable(); 126 } 127 128 int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) 129 { 130 return PSCI_E_SUCCESS; 131 } 132 133 static const plat_psci_ops_t imx_plat_psci_ops = { 134 .pwr_domain_on = imx_pwr_domain_on, 135 .pwr_domain_on_finish = imx_pwr_domain_on_finish, 136 .pwr_domain_off = imx_pwr_domain_off, 137 .pwr_domain_suspend = imx_domain_suspend, 138 .pwr_domain_suspend_finish = imx_domain_suspend_finish, 139 .get_sys_suspend_power_state = imx_get_sys_suspend_power_state, 140 .validate_power_state = imx_validate_power_state, 141 .validate_ns_entrypoint = imx_validate_ns_entrypoint, 142 .system_off = imx_system_off, 143 .system_reset = imx_system_reset, 144 }; 145 146 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 147 const plat_psci_ops_t **psci_ops) 148 { 149 imx_mailbox_init(sec_entrypoint); 150 *psci_ops = &imx_plat_psci_ops; 151 152 /* Request low power mode for cluster/cci, only need to do once */ 153 sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF); 154 sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_OFF); 155 sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF); 156 157 /* Request RUN and LP modes for DDR, system interconnect etc. */ 158 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, 159 SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY); 160 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, 161 SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY); 162 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, 163 SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY); 164 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, 165 SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_STBY); 166 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, 167 SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, 168 SC_PM_PW_MODE_STBY); 169 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, 170 SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, 171 SC_PM_PW_MODE_STBY); 172 173 return 0; 174 } 175