1e8837b0aSJacky Bai /* 2*b7abf485SJacky Bai * Copyright (c) 2018-2022, 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 16*b7abf485SJacky Bai #include <dram.h> 17e8837b0aSJacky Bai #include <gpc.h> 18e8837b0aSJacky Bai #include <imx8m_psci.h> 19e8837b0aSJacky Bai #include <plat_imx8.h> 20e8837b0aSJacky Bai 21e8837b0aSJacky Bai /* 22e8837b0aSJacky Bai * below callback functions need to be override by i.mx8mq, 23e8837b0aSJacky Bai * for other i.mx8m soc, if no special requirement, 24e8837b0aSJacky Bai * reuse below ones. 25e8837b0aSJacky Bai */ 26e8837b0aSJacky Bai #pragma weak imx_validate_power_state 27e8837b0aSJacky Bai #pragma weak imx_domain_suspend 28e8837b0aSJacky Bai #pragma weak imx_domain_suspend_finish 29e8837b0aSJacky Bai #pragma weak imx_get_sys_suspend_power_state 30e8837b0aSJacky Bai 31e8837b0aSJacky Bai int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) 32e8837b0aSJacky Bai { 33e8837b0aSJacky Bai /* The non-secure entrypoint should be in RAM space */ 34e8837b0aSJacky Bai if (ns_entrypoint < PLAT_NS_IMAGE_OFFSET) 35e8837b0aSJacky Bai return PSCI_E_INVALID_PARAMS; 36e8837b0aSJacky Bai 37e8837b0aSJacky Bai return PSCI_E_SUCCESS; 38e8837b0aSJacky Bai } 39e8837b0aSJacky Bai 40e8837b0aSJacky Bai int imx_pwr_domain_on(u_register_t mpidr) 41e8837b0aSJacky Bai { 42e8837b0aSJacky Bai unsigned int core_id; 43e8837b0aSJacky Bai uint64_t base_addr = BL31_BASE; 44e8837b0aSJacky Bai 45e8837b0aSJacky Bai core_id = MPIDR_AFFLVL0_VAL(mpidr); 46e8837b0aSJacky Bai 47e8837b0aSJacky Bai imx_set_cpu_secure_entry(core_id, base_addr); 48e8837b0aSJacky Bai imx_set_cpu_pwr_on(core_id); 49e8837b0aSJacky Bai 50e8837b0aSJacky Bai return PSCI_E_SUCCESS; 51e8837b0aSJacky Bai } 52e8837b0aSJacky Bai 53e8837b0aSJacky Bai void imx_pwr_domain_on_finish(const psci_power_state_t *target_state) 54e8837b0aSJacky Bai { 55e8837b0aSJacky Bai plat_gic_pcpu_init(); 56e8837b0aSJacky Bai plat_gic_cpuif_enable(); 57e8837b0aSJacky Bai } 58e8837b0aSJacky Bai 59e8837b0aSJacky Bai void imx_pwr_domain_off(const psci_power_state_t *target_state) 60e8837b0aSJacky Bai { 61e8837b0aSJacky Bai uint64_t mpidr = read_mpidr_el1(); 62e8837b0aSJacky Bai unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); 63e8837b0aSJacky Bai 64e8837b0aSJacky Bai plat_gic_cpuif_disable(); 65e8837b0aSJacky Bai imx_set_cpu_pwr_off(core_id); 66e8837b0aSJacky Bai } 67e8837b0aSJacky Bai 68e8837b0aSJacky Bai int imx_validate_power_state(unsigned int power_state, 69e8837b0aSJacky Bai psci_power_state_t *req_state) 70e8837b0aSJacky Bai { 71e8837b0aSJacky Bai int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 72e8837b0aSJacky Bai int pwr_type = psci_get_pstate_type(power_state); 73e8837b0aSJacky Bai int state_id = psci_get_pstate_id(power_state); 74e8837b0aSJacky Bai 75e8837b0aSJacky Bai if (pwr_lvl > PLAT_MAX_PWR_LVL) 76e8837b0aSJacky Bai return PSCI_E_INVALID_PARAMS; 77e8837b0aSJacky Bai 78e8837b0aSJacky Bai if (pwr_type == PSTATE_TYPE_STANDBY) { 79e8837b0aSJacky Bai CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; 80e8837b0aSJacky Bai CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; 81e8837b0aSJacky Bai } 82e8837b0aSJacky Bai 83e8837b0aSJacky Bai if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) { 84e8837b0aSJacky Bai CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE; 85e8837b0aSJacky Bai CLUSTER_PWR_STATE(req_state) = PLAT_WAIT_RET_STATE; 86e8837b0aSJacky Bai } 87e8837b0aSJacky Bai 88e8837b0aSJacky Bai return PSCI_E_SUCCESS; 89e8837b0aSJacky Bai } 90e8837b0aSJacky Bai 91e8837b0aSJacky Bai void imx_cpu_standby(plat_local_state_t cpu_state) 92e8837b0aSJacky Bai { 93e8837b0aSJacky Bai dsb(); 94e8837b0aSJacky Bai write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); 95e8837b0aSJacky Bai isb(); 96e8837b0aSJacky Bai 97e8837b0aSJacky Bai wfi(); 98e8837b0aSJacky Bai 99e8837b0aSJacky Bai write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); 100e8837b0aSJacky Bai isb(); 101e8837b0aSJacky Bai } 102e8837b0aSJacky Bai 103e8837b0aSJacky Bai void imx_domain_suspend(const psci_power_state_t *target_state) 104e8837b0aSJacky Bai { 105e8837b0aSJacky Bai uint64_t base_addr = BL31_BASE; 106e8837b0aSJacky Bai uint64_t mpidr = read_mpidr_el1(); 107e8837b0aSJacky Bai unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); 108e8837b0aSJacky Bai 109e8837b0aSJacky Bai if (is_local_state_off(CORE_PWR_STATE(target_state))) { 110e8837b0aSJacky Bai plat_gic_cpuif_disable(); 111e8837b0aSJacky Bai imx_set_cpu_secure_entry(core_id, base_addr); 112e8837b0aSJacky Bai imx_set_cpu_lpm(core_id, true); 113e8837b0aSJacky Bai } else { 114e8837b0aSJacky Bai dsb(); 115e8837b0aSJacky Bai write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); 116e8837b0aSJacky Bai isb(); 117e8837b0aSJacky Bai } 118e8837b0aSJacky Bai 119e8837b0aSJacky Bai if (!is_local_state_run(CLUSTER_PWR_STATE(target_state))) 120e8837b0aSJacky Bai imx_set_cluster_powerdown(core_id, CLUSTER_PWR_STATE(target_state)); 121e8837b0aSJacky Bai 122*b7abf485SJacky Bai if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) { 123e8837b0aSJacky Bai imx_set_sys_lpm(core_id, true); 124*b7abf485SJacky Bai dram_enter_retention(); 125*b7abf485SJacky Bai } 126e8837b0aSJacky Bai } 127e8837b0aSJacky Bai 128e8837b0aSJacky Bai void imx_domain_suspend_finish(const psci_power_state_t *target_state) 129e8837b0aSJacky Bai { 130e8837b0aSJacky Bai uint64_t mpidr = read_mpidr_el1(); 131e8837b0aSJacky Bai unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); 132e8837b0aSJacky Bai 133*b7abf485SJacky Bai if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) { 134*b7abf485SJacky Bai dram_exit_retention(); 135e8837b0aSJacky Bai imx_set_sys_lpm(core_id, false); 136*b7abf485SJacky Bai } 137e8837b0aSJacky Bai 138e8837b0aSJacky Bai if (!is_local_state_run(CLUSTER_PWR_STATE(target_state))) { 139e8837b0aSJacky Bai imx_clear_rbc_count(); 140e8837b0aSJacky Bai imx_set_cluster_powerdown(core_id, PSCI_LOCAL_STATE_RUN); 141e8837b0aSJacky Bai } 142e8837b0aSJacky Bai 143e8837b0aSJacky Bai if (is_local_state_off(CORE_PWR_STATE(target_state))) { 144e8837b0aSJacky Bai imx_set_cpu_lpm(core_id, false); 145e8837b0aSJacky Bai plat_gic_cpuif_enable(); 146e8837b0aSJacky Bai } else { 147e8837b0aSJacky Bai write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); 148e8837b0aSJacky Bai isb(); 149e8837b0aSJacky Bai } 150e8837b0aSJacky Bai } 151e8837b0aSJacky Bai 152e8837b0aSJacky Bai void imx_get_sys_suspend_power_state(psci_power_state_t *req_state) 153e8837b0aSJacky Bai { 154e8837b0aSJacky Bai unsigned int i; 155e8837b0aSJacky Bai 156e8837b0aSJacky Bai for (i = IMX_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) 157e8837b0aSJacky Bai req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE; 158e8837b0aSJacky Bai } 159e8837b0aSJacky Bai 16060a0dde9SIgor Opaniuk static void __dead2 imx_wdog_restart(bool external_reset) 161e8837b0aSJacky Bai { 162e8837b0aSJacky Bai uintptr_t wdog_base = IMX_WDOG_BASE; 163e8837b0aSJacky Bai unsigned int val; 164e8837b0aSJacky Bai 165e8837b0aSJacky Bai val = mmio_read_16(wdog_base); 16660a0dde9SIgor Opaniuk /* 16760a0dde9SIgor Opaniuk * Common watchdog init flags, for additional details check 16860a0dde9SIgor Opaniuk * 6.6.4.1 Watchdog Control Register (WDOGx_WCR) 16960a0dde9SIgor Opaniuk * 17060a0dde9SIgor Opaniuk * Initial bit selection: 17160a0dde9SIgor Opaniuk * WDOG_WCR_WDE - Enable the watchdog. 17260a0dde9SIgor Opaniuk * 17360a0dde9SIgor Opaniuk * 0x000E mask is used to keep previous values (that could be set 17460a0dde9SIgor Opaniuk * in SPL) of WDBG and WDE/WDT (both are write-one once-only bits). 17560a0dde9SIgor Opaniuk */ 17660a0dde9SIgor Opaniuk val = (val & 0x000E) | WDOG_WCR_WDE; 17760a0dde9SIgor Opaniuk if (external_reset) { 17860a0dde9SIgor Opaniuk /* 17960a0dde9SIgor Opaniuk * To assert WDOG_B (external reset) we have 18060a0dde9SIgor Opaniuk * to set WDA bit 0 (already set in previous step). 18160a0dde9SIgor Opaniuk * SRS bits are required to be set to 1 (no effect on the 18260a0dde9SIgor Opaniuk * system). 18360a0dde9SIgor Opaniuk */ 18460a0dde9SIgor Opaniuk val |= WDOG_WCR_SRS; 18560a0dde9SIgor Opaniuk } else { 18660a0dde9SIgor Opaniuk /* 18760a0dde9SIgor Opaniuk * To assert Software Reset Signal (internal reset) we have 18860a0dde9SIgor Opaniuk * to set SRS bit to 0 (already set in previous step). 18960a0dde9SIgor Opaniuk * SRE bit is required to be set to 1 when used in 19060a0dde9SIgor Opaniuk * conjunction with the Software Reset Signal before 19160a0dde9SIgor Opaniuk * SRS asserton, otherwise SRS bit will just automatically 19260a0dde9SIgor Opaniuk * reset to 1. 19360a0dde9SIgor Opaniuk * 19460a0dde9SIgor Opaniuk * Also we set WDA to 1 (no effect on system). 19560a0dde9SIgor Opaniuk */ 19660a0dde9SIgor Opaniuk val |= WDOG_WCR_SRE | WDOG_WCR_WDA; 19760a0dde9SIgor Opaniuk } 19860a0dde9SIgor Opaniuk 199e8837b0aSJacky Bai mmio_write_16(wdog_base, val); 200e8837b0aSJacky Bai 201e8837b0aSJacky Bai mmio_write_16(wdog_base + WDOG_WSR, 0x5555); 202e8837b0aSJacky Bai mmio_write_16(wdog_base + WDOG_WSR, 0xaaaa); 203e8837b0aSJacky Bai while (1) 204e8837b0aSJacky Bai ; 205e8837b0aSJacky Bai } 206e8837b0aSJacky Bai 20760a0dde9SIgor Opaniuk void __dead2 imx_system_reset(void) 20860a0dde9SIgor Opaniuk { 20960a0dde9SIgor Opaniuk #ifdef IMX_WDOG_B_RESET 21060a0dde9SIgor Opaniuk imx_wdog_restart(true); 21160a0dde9SIgor Opaniuk #else 21260a0dde9SIgor Opaniuk imx_wdog_restart(false); 21360a0dde9SIgor Opaniuk #endif 21460a0dde9SIgor Opaniuk } 21560a0dde9SIgor Opaniuk 21660a0dde9SIgor Opaniuk int imx_system_reset2(int is_vendor, int reset_type, u_register_t cookie) 21760a0dde9SIgor Opaniuk { 21860a0dde9SIgor Opaniuk imx_wdog_restart(false); 21960a0dde9SIgor Opaniuk 22060a0dde9SIgor Opaniuk /* 22160a0dde9SIgor Opaniuk * imx_wdog_restart cannot return (as it's a __dead function), 22260a0dde9SIgor Opaniuk * however imx_system_reset2 has to return some value according 22360a0dde9SIgor Opaniuk * to PSCI v1.1 spec. 22460a0dde9SIgor Opaniuk */ 22560a0dde9SIgor Opaniuk return 0; 22660a0dde9SIgor Opaniuk } 22760a0dde9SIgor Opaniuk 228e8837b0aSJacky Bai void __dead2 imx_system_off(void) 229e8837b0aSJacky Bai { 230e8837b0aSJacky Bai mmio_write_32(IMX_SNVS_BASE + SNVS_LPCR, SNVS_LPCR_SRTC_ENV | 231e8837b0aSJacky Bai SNVS_LPCR_DP_EN | SNVS_LPCR_TOP); 232e8837b0aSJacky Bai 233e8837b0aSJacky Bai while (1) 234e8837b0aSJacky Bai ; 235e8837b0aSJacky Bai } 236e8837b0aSJacky Bai 237e8837b0aSJacky Bai void __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state) 238e8837b0aSJacky Bai { 239e8837b0aSJacky Bai /* 240e8837b0aSJacky Bai * before enter WAIT or STOP mode with PLAT(SCU) power down, 241e8837b0aSJacky Bai * rbc count need to be enabled to make sure PLAT is 242e8837b0aSJacky Bai * power down successfully even if the the wakeup IRQ is pending 243e8837b0aSJacky Bai * early before the power down sequence. the RBC counter is 244e8837b0aSJacky Bai * drived by the 32K OSC, so delay 30us to make sure the counter 245e8837b0aSJacky Bai * is really running. 246e8837b0aSJacky Bai */ 2479eb1bb63SJacky Bai if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) { 248e8837b0aSJacky Bai imx_set_rbc_count(); 249e8837b0aSJacky Bai udelay(30); 250e8837b0aSJacky Bai } 251e8837b0aSJacky Bai 252e8837b0aSJacky Bai while (1) 253e8837b0aSJacky Bai wfi(); 254e8837b0aSJacky Bai } 255