1 /* 2 * Copyright (c) 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 <lib/mmio.h> 13 #include <lib/psci/psci.h> 14 15 #include <gpc.h> 16 #include <imx8m_psci.h> 17 #include <plat_imx8.h> 18 19 int imx_validate_power_state(unsigned int power_state, 20 psci_power_state_t *req_state) 21 { 22 int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 23 int pwr_type = psci_get_pstate_type(power_state); 24 int state_id = psci_get_pstate_id(power_state); 25 26 if (pwr_lvl > PLAT_MAX_PWR_LVL) 27 return PSCI_E_INVALID_PARAMS; 28 29 if (pwr_type == PSTATE_TYPE_STANDBY) { 30 CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; 31 CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; 32 } 33 34 if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) { 35 CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE; 36 CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; 37 } 38 39 return PSCI_E_SUCCESS; 40 } 41 42 void imx_domain_suspend(const psci_power_state_t *target_state) 43 { 44 uint64_t base_addr = BL31_START; 45 uint64_t mpidr = read_mpidr_el1(); 46 unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); 47 48 if (is_local_state_off(CORE_PWR_STATE(target_state))) { 49 /* disable the cpu interface */ 50 plat_gic_cpuif_disable(); 51 imx_set_cpu_secure_entry(core_id, base_addr); 52 imx_set_cpu_lpm(core_id, true); 53 } else { 54 dsb(); 55 write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); 56 isb(); 57 } 58 59 if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) 60 imx_set_cluster_powerdown(core_id, true); 61 else 62 imx_set_cluster_standby(true); 63 64 if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) { 65 imx_set_sys_lpm(core_id, true); 66 } 67 } 68 69 void imx_domain_suspend_finish(const psci_power_state_t *target_state) 70 { 71 uint64_t mpidr = read_mpidr_el1(); 72 unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); 73 74 /* check the system level status */ 75 if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) { 76 imx_set_sys_lpm(core_id, false); 77 imx_clear_rbc_count(); 78 } 79 80 /* check the cluster level power status */ 81 if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) 82 imx_set_cluster_powerdown(core_id, false); 83 else 84 imx_set_cluster_standby(false); 85 86 /* check the core level power status */ 87 if (is_local_state_off(CORE_PWR_STATE(target_state))) { 88 /* clear the core lpm setting */ 89 imx_set_cpu_lpm(core_id, false); 90 /* enable the gic cpu interface */ 91 plat_gic_cpuif_enable(); 92 } else { 93 write_scr_el3(read_scr_el3() & (~0x4)); 94 isb(); 95 } 96 } 97 98 void imx_get_sys_suspend_power_state(psci_power_state_t *req_state) 99 { 100 unsigned int i; 101 102 for (i = IMX_PWR_LVL0; i < PLAT_MAX_PWR_LVL; i++) 103 req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE; 104 105 req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE; 106 } 107 108 static const plat_psci_ops_t imx_plat_psci_ops = { 109 .pwr_domain_on = imx_pwr_domain_on, 110 .pwr_domain_on_finish = imx_pwr_domain_on_finish, 111 .pwr_domain_off = imx_pwr_domain_off, 112 .validate_ns_entrypoint = imx_validate_ns_entrypoint, 113 .validate_power_state = imx_validate_power_state, 114 .cpu_standby = imx_cpu_standby, 115 .pwr_domain_suspend = imx_domain_suspend, 116 .pwr_domain_suspend_finish = imx_domain_suspend_finish, 117 .pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi, 118 .get_sys_suspend_power_state = imx_get_sys_suspend_power_state, 119 .system_reset = imx_system_reset, 120 .system_reset2 = imx_system_reset2, 121 .system_off = imx_system_off, 122 }; 123 124 /* export the platform specific psci ops */ 125 int plat_setup_psci_ops(uintptr_t sec_entrypoint, 126 const plat_psci_ops_t **psci_ops) 127 { 128 imx_mailbox_init(sec_entrypoint); 129 /* sec_entrypoint is used for warm reset */ 130 *psci_ops = &imx_plat_psci_ops; 131 132 return 0; 133 } 134