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