1e8837b0aSJacky Bai /* 2e8837b0aSJacky Bai * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. 3e8837b0aSJacky Bai * 4e8837b0aSJacky Bai * SPDX-License-Identifier: BSD-3-Clause 5e8837b0aSJacky Bai */ 6e8837b0aSJacky Bai 7e8837b0aSJacky Bai #include <stdbool.h> 8e8837b0aSJacky Bai 9e8837b0aSJacky Bai #include <arch.h> 10e8837b0aSJacky Bai #include <arch_helpers.h> 11e8837b0aSJacky Bai #include <common/debug.h> 12e8837b0aSJacky Bai #include <drivers/delay_timer.h> 13e8837b0aSJacky Bai #include <lib/mmio.h> 14e8837b0aSJacky Bai #include <lib/psci/psci.h> 15e8837b0aSJacky Bai 16e8837b0aSJacky Bai #include <gpc.h> 17e8837b0aSJacky Bai #include <imx8m_psci.h> 18e8837b0aSJacky Bai #include <plat_imx8.h> 19e8837b0aSJacky Bai 20e8837b0aSJacky Bai /* 21e8837b0aSJacky Bai * below callback functions need to be override by i.mx8mq, 22e8837b0aSJacky Bai * for other i.mx8m soc, if no special requirement, 23e8837b0aSJacky Bai * reuse below ones. 24e8837b0aSJacky Bai */ 25e8837b0aSJacky Bai #pragma weak imx_validate_power_state 26e8837b0aSJacky Bai #pragma weak imx_domain_suspend 27e8837b0aSJacky Bai #pragma weak imx_domain_suspend_finish 28e8837b0aSJacky Bai #pragma weak imx_get_sys_suspend_power_state 29e8837b0aSJacky Bai 30e8837b0aSJacky Bai int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) 31e8837b0aSJacky Bai { 32e8837b0aSJacky Bai /* The non-secure entrypoint should be in RAM space */ 33e8837b0aSJacky Bai if (ns_entrypoint < PLAT_NS_IMAGE_OFFSET) 34e8837b0aSJacky Bai return PSCI_E_INVALID_PARAMS; 35e8837b0aSJacky Bai 36e8837b0aSJacky Bai return PSCI_E_SUCCESS; 37e8837b0aSJacky Bai } 38e8837b0aSJacky Bai 39e8837b0aSJacky Bai int imx_pwr_domain_on(u_register_t mpidr) 40e8837b0aSJacky Bai { 41e8837b0aSJacky Bai unsigned int core_id; 42e8837b0aSJacky Bai uint64_t base_addr = BL31_BASE; 43e8837b0aSJacky Bai 44e8837b0aSJacky Bai core_id = MPIDR_AFFLVL0_VAL(mpidr); 45e8837b0aSJacky Bai 46e8837b0aSJacky Bai imx_set_cpu_secure_entry(core_id, base_addr); 47e8837b0aSJacky Bai imx_set_cpu_pwr_on(core_id); 48e8837b0aSJacky Bai 49e8837b0aSJacky Bai return PSCI_E_SUCCESS; 50e8837b0aSJacky Bai } 51e8837b0aSJacky Bai 52e8837b0aSJacky Bai void imx_pwr_domain_on_finish(const psci_power_state_t *target_state) 53e8837b0aSJacky Bai { 54e8837b0aSJacky Bai plat_gic_pcpu_init(); 55e8837b0aSJacky Bai plat_gic_cpuif_enable(); 56e8837b0aSJacky Bai } 57e8837b0aSJacky Bai 58e8837b0aSJacky Bai void imx_pwr_domain_off(const psci_power_state_t *target_state) 59e8837b0aSJacky Bai { 60e8837b0aSJacky Bai uint64_t mpidr = read_mpidr_el1(); 61e8837b0aSJacky Bai unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); 62e8837b0aSJacky Bai 63e8837b0aSJacky Bai plat_gic_cpuif_disable(); 64e8837b0aSJacky Bai imx_set_cpu_pwr_off(core_id); 65e8837b0aSJacky Bai } 66e8837b0aSJacky Bai 67e8837b0aSJacky Bai int imx_validate_power_state(unsigned int power_state, 68e8837b0aSJacky Bai psci_power_state_t *req_state) 69e8837b0aSJacky Bai { 70e8837b0aSJacky Bai int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 71e8837b0aSJacky Bai int pwr_type = psci_get_pstate_type(power_state); 72e8837b0aSJacky Bai int state_id = psci_get_pstate_id(power_state); 73e8837b0aSJacky Bai 74e8837b0aSJacky Bai if (pwr_lvl > PLAT_MAX_PWR_LVL) 75e8837b0aSJacky Bai return PSCI_E_INVALID_PARAMS; 76e8837b0aSJacky Bai 77e8837b0aSJacky Bai if (pwr_type == PSTATE_TYPE_STANDBY) { 78e8837b0aSJacky Bai CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; 79e8837b0aSJacky Bai CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; 80e8837b0aSJacky Bai } 81e8837b0aSJacky Bai 82e8837b0aSJacky Bai if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) { 83e8837b0aSJacky Bai CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE; 84e8837b0aSJacky Bai CLUSTER_PWR_STATE(req_state) = PLAT_WAIT_RET_STATE; 85e8837b0aSJacky Bai } 86e8837b0aSJacky Bai 87e8837b0aSJacky Bai return PSCI_E_SUCCESS; 88e8837b0aSJacky Bai } 89e8837b0aSJacky Bai 90e8837b0aSJacky Bai void imx_cpu_standby(plat_local_state_t cpu_state) 91e8837b0aSJacky Bai { 92e8837b0aSJacky Bai dsb(); 93e8837b0aSJacky Bai write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); 94e8837b0aSJacky Bai isb(); 95e8837b0aSJacky Bai 96e8837b0aSJacky Bai wfi(); 97e8837b0aSJacky Bai 98e8837b0aSJacky Bai write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); 99e8837b0aSJacky Bai isb(); 100e8837b0aSJacky Bai } 101e8837b0aSJacky Bai 102e8837b0aSJacky Bai void imx_domain_suspend(const psci_power_state_t *target_state) 103e8837b0aSJacky Bai { 104e8837b0aSJacky Bai uint64_t base_addr = BL31_BASE; 105e8837b0aSJacky Bai uint64_t mpidr = read_mpidr_el1(); 106e8837b0aSJacky Bai unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); 107e8837b0aSJacky Bai 108e8837b0aSJacky Bai if (is_local_state_off(CORE_PWR_STATE(target_state))) { 109e8837b0aSJacky Bai plat_gic_cpuif_disable(); 110e8837b0aSJacky Bai imx_set_cpu_secure_entry(core_id, base_addr); 111e8837b0aSJacky Bai imx_set_cpu_lpm(core_id, true); 112e8837b0aSJacky Bai } else { 113e8837b0aSJacky Bai dsb(); 114e8837b0aSJacky Bai write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); 115e8837b0aSJacky Bai isb(); 116e8837b0aSJacky Bai } 117e8837b0aSJacky Bai 118e8837b0aSJacky Bai if (!is_local_state_run(CLUSTER_PWR_STATE(target_state))) 119e8837b0aSJacky Bai imx_set_cluster_powerdown(core_id, CLUSTER_PWR_STATE(target_state)); 120e8837b0aSJacky Bai 121e8837b0aSJacky Bai if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) 122e8837b0aSJacky Bai imx_set_sys_lpm(core_id, true); 123e8837b0aSJacky Bai } 124e8837b0aSJacky Bai 125e8837b0aSJacky Bai void imx_domain_suspend_finish(const psci_power_state_t *target_state) 126e8837b0aSJacky Bai { 127e8837b0aSJacky Bai uint64_t mpidr = read_mpidr_el1(); 128e8837b0aSJacky Bai unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); 129e8837b0aSJacky Bai 130e8837b0aSJacky Bai if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) 131e8837b0aSJacky Bai imx_set_sys_lpm(core_id, false); 132e8837b0aSJacky Bai 133e8837b0aSJacky Bai if (!is_local_state_run(CLUSTER_PWR_STATE(target_state))) { 134e8837b0aSJacky Bai imx_clear_rbc_count(); 135e8837b0aSJacky Bai imx_set_cluster_powerdown(core_id, PSCI_LOCAL_STATE_RUN); 136e8837b0aSJacky Bai } 137e8837b0aSJacky Bai 138e8837b0aSJacky Bai if (is_local_state_off(CORE_PWR_STATE(target_state))) { 139e8837b0aSJacky Bai imx_set_cpu_lpm(core_id, false); 140e8837b0aSJacky Bai plat_gic_cpuif_enable(); 141e8837b0aSJacky Bai } else { 142e8837b0aSJacky Bai write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); 143e8837b0aSJacky Bai isb(); 144e8837b0aSJacky Bai } 145e8837b0aSJacky Bai } 146e8837b0aSJacky Bai 147e8837b0aSJacky Bai void imx_get_sys_suspend_power_state(psci_power_state_t *req_state) 148e8837b0aSJacky Bai { 149e8837b0aSJacky Bai unsigned int i; 150e8837b0aSJacky Bai 151e8837b0aSJacky Bai for (i = IMX_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) 152e8837b0aSJacky Bai req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE; 153e8837b0aSJacky Bai } 154e8837b0aSJacky Bai 155e8837b0aSJacky Bai void __dead2 imx_system_reset(void) 156e8837b0aSJacky Bai { 157e8837b0aSJacky Bai uintptr_t wdog_base = IMX_WDOG_BASE; 158e8837b0aSJacky Bai unsigned int val; 159e8837b0aSJacky Bai 160e8837b0aSJacky Bai /* WDOG_B reset */ 161e8837b0aSJacky Bai val = mmio_read_16(wdog_base); 162e8837b0aSJacky Bai #ifdef IMX_WDOG_B_RESET 163e8837b0aSJacky Bai val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_WDE | 164e8837b0aSJacky Bai WDOG_WCR_WDT | WDOG_WCR_SRS; 165e8837b0aSJacky Bai #else 166e8837b0aSJacky Bai val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_SRS; 167e8837b0aSJacky Bai #endif 168e8837b0aSJacky Bai mmio_write_16(wdog_base, val); 169e8837b0aSJacky Bai 170e8837b0aSJacky Bai mmio_write_16(wdog_base + WDOG_WSR, 0x5555); 171e8837b0aSJacky Bai mmio_write_16(wdog_base + WDOG_WSR, 0xaaaa); 172e8837b0aSJacky Bai while (1) 173e8837b0aSJacky Bai ; 174e8837b0aSJacky Bai } 175e8837b0aSJacky Bai 176e8837b0aSJacky Bai void __dead2 imx_system_off(void) 177e8837b0aSJacky Bai { 178e8837b0aSJacky Bai mmio_write_32(IMX_SNVS_BASE + SNVS_LPCR, SNVS_LPCR_SRTC_ENV | 179e8837b0aSJacky Bai SNVS_LPCR_DP_EN | SNVS_LPCR_TOP); 180e8837b0aSJacky Bai 181e8837b0aSJacky Bai while (1) 182e8837b0aSJacky Bai ; 183e8837b0aSJacky Bai } 184e8837b0aSJacky Bai 185e8837b0aSJacky Bai void __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state) 186e8837b0aSJacky Bai { 187e8837b0aSJacky Bai /* 188e8837b0aSJacky Bai * before enter WAIT or STOP mode with PLAT(SCU) power down, 189e8837b0aSJacky Bai * rbc count need to be enabled to make sure PLAT is 190e8837b0aSJacky Bai * power down successfully even if the the wakeup IRQ is pending 191e8837b0aSJacky Bai * early before the power down sequence. the RBC counter is 192e8837b0aSJacky Bai * drived by the 32K OSC, so delay 30us to make sure the counter 193e8837b0aSJacky Bai * is really running. 194e8837b0aSJacky Bai */ 195*9eb1bb63SJacky Bai if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) { 196e8837b0aSJacky Bai imx_set_rbc_count(); 197e8837b0aSJacky Bai udelay(30); 198e8837b0aSJacky Bai } 199e8837b0aSJacky Bai 200e8837b0aSJacky Bai while (1) 201e8837b0aSJacky Bai wfi(); 202e8837b0aSJacky Bai } 203