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/gicv3.h> 13 #include <lib/mmio.h> 14 #include <lib/psci/psci.h> 15 16 #include <plat_imx8.h> 17 #include <sci/sci.h> 18 19 #include "../../common/sci/imx8_mu.h" 20 21 const static int ap_core_index[PLATFORM_CORE_COUNT] = { 22 SC_R_A35_0, SC_R_A35_1, SC_R_A35_2, SC_R_A35_3 23 }; 24 25 /* save gic dist/redist context when GIC is power down */ 26 static struct plat_gic_ctx imx_gicv3_ctx; 27 static unsigned int gpt_lpcg, gpt_reg[2]; 28 29 static void imx_enable_irqstr_wakeup(void) 30 { 31 uint32_t irq_mask; 32 gicv3_dist_ctx_t *dist_ctx = &imx_gicv3_ctx.dist_ctx; 33 34 /* put IRQSTR into ON mode */ 35 sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON); 36 37 /* enable the irqsteer to handle wakeup irq */ 38 mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x1); 39 for (int i = 0; i < 15; i++) { 40 irq_mask = dist_ctx->gicd_isenabler[i]; 41 mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 0x4 * i, irq_mask); 42 } 43 44 /* set IRQSTR low power mode */ 45 if (imx_is_wakeup_src_irqsteer()) 46 sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY); 47 else 48 sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF); 49 } 50 51 static void imx_disable_irqstr_wakeup(void) 52 { 53 /* Put IRQSTEER back to ON mode */ 54 sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON); 55 56 /* disable the irqsteer */ 57 mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x0); 58 for (int i = 0; i < 16; i++) 59 mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x4 + 0x4 * i, 0x0); 60 61 /* Put IRQSTEER into OFF mode */ 62 sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF); 63 } 64 65 int imx_pwr_domain_on(u_register_t mpidr) 66 { 67 int ret = PSCI_E_SUCCESS; 68 unsigned int cpu_id; 69 70 cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 71 72 printf("imx_pwr_domain_on cpu_id %d\n", cpu_id); 73 74 if (sc_pm_set_resource_power_mode(ipc_handle, ap_core_index[cpu_id], 75 SC_PM_PW_MODE_ON) != SC_ERR_NONE) { 76 ERROR("core %d power on failed!\n", cpu_id); 77 ret = PSCI_E_INTERN_FAIL; 78 } 79 80 if (sc_pm_cpu_start(ipc_handle, ap_core_index[cpu_id], 81 true, BL31_BASE) != SC_ERR_NONE) { 82 ERROR("boot core %d failed!\n", cpu_id); 83 ret = PSCI_E_INTERN_FAIL; 84 } 85 86 return ret; 87 } 88 89 void imx_pwr_domain_on_finish(const psci_power_state_t *target_state) 90 { 91 plat_gic_pcpu_init(); 92 plat_gic_cpuif_enable(); 93 } 94 95 int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) 96 { 97 return PSCI_E_SUCCESS; 98 } 99 100 void imx_pwr_domain_off(const psci_power_state_t *target_state) 101 { 102 u_register_t mpidr = read_mpidr_el1(); 103 unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 104 105 plat_gic_cpuif_disable(); 106 sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], 107 SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_NONE); 108 printf("turn off core:%d\n", cpu_id); 109 } 110 111 void imx_domain_suspend(const psci_power_state_t *target_state) 112 { 113 u_register_t mpidr = read_mpidr_el1(); 114 unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 115 116 if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL0])) { 117 plat_gic_cpuif_disable(); 118 sc_pm_set_cpu_resume(ipc_handle, ap_core_index[cpu_id], true, BL31_BASE); 119 sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], 120 SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC); 121 } else { 122 dsb(); 123 write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); 124 isb(); 125 } 126 127 if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL1])) 128 sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF); 129 130 if (is_local_state_retn(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL])) { 131 plat_gic_cpuif_disable(); 132 133 /* save gic context */ 134 plat_gic_save(cpu_id, &imx_gicv3_ctx); 135 /* enable the irqsteer for wakeup */ 136 imx_enable_irqstr_wakeup(); 137 138 /* Save GPT clock and registers, then turn off its power */ 139 gpt_lpcg = mmio_read_32(IMX_GPT0_LPCG_BASE); 140 gpt_reg[0] = mmio_read_32(IMX_GPT0_BASE); 141 gpt_reg[1] = mmio_read_32(IMX_GPT0_BASE + 0x4); 142 sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_OFF); 143 144 sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF); 145 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_DDR, 146 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); 147 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_MU, 148 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); 149 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_INTERCONNECT, 150 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); 151 152 /* Put GIC in OFF mode. */ 153 sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_OFF); 154 sc_pm_set_cpu_resume(ipc_handle, ap_core_index[cpu_id], true, BL31_BASE); 155 if (imx_is_wakeup_src_irqsteer()) 156 sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], 157 SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER); 158 else 159 sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], 160 SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU); 161 } 162 } 163 164 void imx_domain_suspend_finish(const psci_power_state_t *target_state) 165 { 166 u_register_t mpidr = read_mpidr_el1(); 167 unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); 168 169 if (is_local_state_retn(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL])) { 170 MU_Resume(SC_IPC_BASE); 171 172 sc_pm_req_low_power_mode(ipc_handle, ap_core_index[cpu_id], SC_PM_PW_MODE_ON); 173 sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], 174 SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC); 175 176 /* Put GIC back to high power mode. */ 177 sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_ON); 178 179 /* restore gic context */ 180 plat_gic_restore(cpu_id, &imx_gicv3_ctx); 181 182 /* Turn on GPT power and restore its clock and registers */ 183 sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON); 184 sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0); 185 mmio_write_32(IMX_GPT0_BASE, gpt_reg[0]); 186 mmio_write_32(IMX_GPT0_BASE + 0x4, gpt_reg[1]); 187 mmio_write_32(IMX_GPT0_LPCG_BASE, gpt_lpcg); 188 189 sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON); 190 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_DDR, 191 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 192 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_MU, 193 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 194 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_INTERCONNECT, 195 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 196 197 /* disable the irqsteer wakeup */ 198 imx_disable_irqstr_wakeup(); 199 200 plat_gic_cpuif_enable(); 201 } 202 203 if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL1])) 204 sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON); 205 206 if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL0])) { 207 sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], 208 SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC); 209 plat_gic_cpuif_enable(); 210 } else { 211 write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); 212 isb(); 213 } 214 } 215 216 static const plat_psci_ops_t imx_plat_psci_ops = { 217 .pwr_domain_on = imx_pwr_domain_on, 218 .pwr_domain_on_finish = imx_pwr_domain_on_finish, 219 .validate_ns_entrypoint = imx_validate_ns_entrypoint, 220 .system_off = imx_system_off, 221 .system_reset = imx_system_reset, 222 .pwr_domain_off = imx_pwr_domain_off, 223 .pwr_domain_suspend = imx_domain_suspend, 224 .pwr_domain_suspend_finish = imx_domain_suspend_finish, 225 .get_sys_suspend_power_state = imx_get_sys_suspend_power_state, 226 .validate_power_state = imx_validate_power_state, 227 }; 228 229 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 230 const plat_psci_ops_t **psci_ops) 231 { 232 imx_mailbox_init(sec_entrypoint); 233 *psci_ops = &imx_plat_psci_ops; 234 235 /* make sure system sources power ON in low power mode by default */ 236 sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON); 237 238 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_DDR, 239 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 240 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_MU, 241 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 242 sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_INTERCONNECT, 243 SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); 244 245 return 0; 246 } 247