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