1*81136819SBai Ping /* 2*81136819SBai Ping * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. 3*81136819SBai Ping * 4*81136819SBai Ping * SPDX-License-Identifier: BSD-3-Clause 5*81136819SBai Ping */ 6*81136819SBai Ping 7*81136819SBai Ping #include <arch.h> 8*81136819SBai Ping #include <arch_helpers.h> 9*81136819SBai Ping #include <debug.h> 10*81136819SBai Ping #include <gpc.h> 11*81136819SBai Ping #include <stdbool.h> 12*81136819SBai Ping #include <plat_imx8.h> 13*81136819SBai Ping #include <psci.h> 14*81136819SBai Ping #include <mmio.h> 15*81136819SBai Ping 16*81136819SBai Ping #define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0]) 17*81136819SBai Ping #define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1]) 18*81136819SBai Ping #define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) 19*81136819SBai Ping 20*81136819SBai Ping int imx_pwr_domain_on(u_register_t mpidr) 21*81136819SBai Ping { 22*81136819SBai Ping unsigned int core_id; 23*81136819SBai Ping uint64_t base_addr = BL31_BASE; 24*81136819SBai Ping 25*81136819SBai Ping core_id = MPIDR_AFFLVL0_VAL(mpidr); 26*81136819SBai Ping 27*81136819SBai Ping /* set the secure entrypoint */ 28*81136819SBai Ping imx_set_cpu_secure_entry(core_id, base_addr); 29*81136819SBai Ping /* power up the core */ 30*81136819SBai Ping imx_set_cpu_pwr_on(core_id); 31*81136819SBai Ping 32*81136819SBai Ping return PSCI_E_SUCCESS; 33*81136819SBai Ping } 34*81136819SBai Ping 35*81136819SBai Ping void imx_pwr_domain_on_finish(const psci_power_state_t *target_state) 36*81136819SBai Ping { 37*81136819SBai Ping /* program the GIC per cpu dist and rdist interface */ 38*81136819SBai Ping plat_gic_pcpu_init(); 39*81136819SBai Ping /* enable the GICv3 cpu interface */ 40*81136819SBai Ping plat_gic_cpuif_enable(); 41*81136819SBai Ping } 42*81136819SBai Ping 43*81136819SBai Ping void imx_pwr_domain_off(const psci_power_state_t *target_state) 44*81136819SBai Ping { 45*81136819SBai Ping uint64_t mpidr = read_mpidr_el1(); 46*81136819SBai Ping unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); 47*81136819SBai Ping 48*81136819SBai Ping /* disable the GIC cpu interface first */ 49*81136819SBai Ping plat_gic_cpuif_disable(); 50*81136819SBai Ping /* config the core for power down */ 51*81136819SBai Ping imx_set_cpu_pwr_off(core_id); 52*81136819SBai Ping } 53*81136819SBai Ping 54*81136819SBai Ping int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) 55*81136819SBai Ping { 56*81136819SBai Ping /* The non-secure entrypoint should be in RAM space */ 57*81136819SBai Ping if (ns_entrypoint < PLAT_NS_IMAGE_OFFSET) 58*81136819SBai Ping return PSCI_E_INVALID_PARAMS; 59*81136819SBai Ping 60*81136819SBai Ping return PSCI_E_SUCCESS; 61*81136819SBai Ping } 62*81136819SBai Ping 63*81136819SBai Ping int imx_validate_power_state(unsigned int power_state, 64*81136819SBai Ping psci_power_state_t *req_state) 65*81136819SBai Ping { 66*81136819SBai Ping int pwr_lvl = psci_get_pstate_pwrlvl(power_state); 67*81136819SBai Ping int pwr_type = psci_get_pstate_type(power_state); 68*81136819SBai Ping int state_id = psci_get_pstate_id(power_state); 69*81136819SBai Ping 70*81136819SBai Ping if (pwr_lvl > PLAT_MAX_PWR_LVL) 71*81136819SBai Ping return PSCI_E_INVALID_PARAMS; 72*81136819SBai Ping 73*81136819SBai Ping if (pwr_type == PSTATE_TYPE_STANDBY) { 74*81136819SBai Ping CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; 75*81136819SBai Ping CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; 76*81136819SBai Ping } 77*81136819SBai Ping 78*81136819SBai Ping if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) { 79*81136819SBai Ping CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE; 80*81136819SBai Ping CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; 81*81136819SBai Ping } 82*81136819SBai Ping 83*81136819SBai Ping return PSCI_E_SUCCESS; 84*81136819SBai Ping } 85*81136819SBai Ping 86*81136819SBai Ping void imx_cpu_standby(plat_local_state_t cpu_state) 87*81136819SBai Ping { 88*81136819SBai Ping dsb(); 89*81136819SBai Ping write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); 90*81136819SBai Ping isb(); 91*81136819SBai Ping 92*81136819SBai Ping wfi(); 93*81136819SBai Ping 94*81136819SBai Ping write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); 95*81136819SBai Ping isb(); 96*81136819SBai Ping } 97*81136819SBai Ping 98*81136819SBai Ping void imx_domain_suspend(const psci_power_state_t *target_state) 99*81136819SBai Ping { 100*81136819SBai Ping uint64_t base_addr = BL31_BASE; 101*81136819SBai Ping uint64_t mpidr = read_mpidr_el1(); 102*81136819SBai Ping unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); 103*81136819SBai Ping 104*81136819SBai Ping if (is_local_state_off(CORE_PWR_STATE(target_state))) { 105*81136819SBai Ping /* disable the cpu interface */ 106*81136819SBai Ping plat_gic_cpuif_disable(); 107*81136819SBai Ping imx_set_cpu_secure_entry(core_id, base_addr); 108*81136819SBai Ping imx_set_cpu_lpm(core_id, true); 109*81136819SBai Ping } else { 110*81136819SBai Ping dsb(); 111*81136819SBai Ping write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); 112*81136819SBai Ping isb(); 113*81136819SBai Ping } 114*81136819SBai Ping 115*81136819SBai Ping if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) 116*81136819SBai Ping imx_set_cluster_powerdown(core_id, true); 117*81136819SBai Ping else 118*81136819SBai Ping imx_set_cluster_standby(true); 119*81136819SBai Ping 120*81136819SBai Ping if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) { 121*81136819SBai Ping imx_set_sys_lpm(true); 122*81136819SBai Ping } 123*81136819SBai Ping } 124*81136819SBai Ping 125*81136819SBai Ping void imx_domain_suspend_finish(const psci_power_state_t *target_state) 126*81136819SBai Ping { 127*81136819SBai Ping uint64_t mpidr = read_mpidr_el1(); 128*81136819SBai Ping unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); 129*81136819SBai Ping 130*81136819SBai Ping /* check the system level status */ 131*81136819SBai Ping if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) { 132*81136819SBai Ping imx_set_sys_lpm(false); 133*81136819SBai Ping imx_clear_rbc_count(); 134*81136819SBai Ping } 135*81136819SBai Ping 136*81136819SBai Ping /* check the cluster level power status */ 137*81136819SBai Ping if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) 138*81136819SBai Ping imx_set_cluster_powerdown(core_id, false); 139*81136819SBai Ping else 140*81136819SBai Ping imx_set_cluster_standby(false); 141*81136819SBai Ping 142*81136819SBai Ping /* check the core level power status */ 143*81136819SBai Ping if (is_local_state_off(CORE_PWR_STATE(target_state))) { 144*81136819SBai Ping /* clear the core lpm setting */ 145*81136819SBai Ping imx_set_cpu_lpm(core_id, false); 146*81136819SBai Ping /* enable the gic cpu interface */ 147*81136819SBai Ping plat_gic_cpuif_enable(); 148*81136819SBai Ping } else { 149*81136819SBai Ping write_scr_el3(read_scr_el3() & (~0x4)); 150*81136819SBai Ping isb(); 151*81136819SBai Ping } 152*81136819SBai Ping } 153*81136819SBai Ping 154*81136819SBai Ping void imx_get_sys_suspend_power_state(psci_power_state_t *req_state) 155*81136819SBai Ping { 156*81136819SBai Ping unsigned int i; 157*81136819SBai Ping 158*81136819SBai Ping for (i = IMX_PWR_LVL0; i < PLAT_MAX_PWR_LVL; i++) 159*81136819SBai Ping req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE; 160*81136819SBai Ping 161*81136819SBai Ping req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE; 162*81136819SBai Ping } 163*81136819SBai Ping 164*81136819SBai Ping void __dead2 imx_system_reset(void) 165*81136819SBai Ping { 166*81136819SBai Ping uintptr_t wdog_base = IMX_WDOG_BASE; 167*81136819SBai Ping unsigned int val; 168*81136819SBai Ping 169*81136819SBai Ping /* WDOG_B reset */ 170*81136819SBai Ping val = mmio_read_16(wdog_base); 171*81136819SBai Ping #ifdef IMX_WDOG_B_RESET 172*81136819SBai Ping val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_WDE | 173*81136819SBai Ping WDOG_WCR_WDT | WDOG_WCR_SRS; 174*81136819SBai Ping #else 175*81136819SBai Ping val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_SRS; 176*81136819SBai Ping #endif 177*81136819SBai Ping mmio_write_16(wdog_base, val); 178*81136819SBai Ping 179*81136819SBai Ping mmio_write_16(wdog_base + WDOG_WSR, 0x5555); 180*81136819SBai Ping mmio_write_16(wdog_base + WDOG_WSR, 0xaaaa); 181*81136819SBai Ping while (1) 182*81136819SBai Ping ; 183*81136819SBai Ping } 184*81136819SBai Ping 185*81136819SBai Ping 186*81136819SBai Ping 187*81136819SBai Ping void __dead2 imx_system_off(void) 188*81136819SBai Ping { 189*81136819SBai Ping mmio_write_32(IMX_SNVS_BASE + SNVS_LPCR, SNVS_LPCR_SRTC_ENV | 190*81136819SBai Ping SNVS_LPCR_DP_EN | SNVS_LPCR_TOP); 191*81136819SBai Ping 192*81136819SBai Ping while (1) 193*81136819SBai Ping ; 194*81136819SBai Ping } 195*81136819SBai Ping 196*81136819SBai Ping void __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state) 197*81136819SBai Ping { 198*81136819SBai Ping if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) 199*81136819SBai Ping imx_set_rbc_count(); 200*81136819SBai Ping 201*81136819SBai Ping while (1) 202*81136819SBai Ping wfi(); 203*81136819SBai Ping } 204*81136819SBai Ping 205*81136819SBai Ping static const plat_psci_ops_t imx_plat_psci_ops = { 206*81136819SBai Ping .pwr_domain_on = imx_pwr_domain_on, 207*81136819SBai Ping .pwr_domain_on_finish = imx_pwr_domain_on_finish, 208*81136819SBai Ping .pwr_domain_off = imx_pwr_domain_off, 209*81136819SBai Ping .validate_ns_entrypoint = imx_validate_ns_entrypoint, 210*81136819SBai Ping .validate_power_state = imx_validate_power_state, 211*81136819SBai Ping .cpu_standby = imx_cpu_standby, 212*81136819SBai Ping .pwr_domain_suspend = imx_domain_suspend, 213*81136819SBai Ping .pwr_domain_suspend_finish = imx_domain_suspend_finish, 214*81136819SBai Ping .pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi, 215*81136819SBai Ping .get_sys_suspend_power_state = imx_get_sys_suspend_power_state, 216*81136819SBai Ping .system_reset = imx_system_reset, 217*81136819SBai Ping .system_off = imx_system_off, 218*81136819SBai Ping }; 219*81136819SBai Ping 220*81136819SBai Ping /* export the platform specific psci ops */ 221*81136819SBai Ping int plat_setup_psci_ops(uintptr_t sec_entrypoint, 222*81136819SBai Ping const plat_psci_ops_t **psci_ops) 223*81136819SBai Ping { 224*81136819SBai Ping imx_mailbox_init(sec_entrypoint); 225*81136819SBai Ping /* sec_entrypoint is used for warm reset */ 226*81136819SBai Ping *psci_ops = &imx_plat_psci_ops; 227*81136819SBai Ping 228*81136819SBai Ping return 0; 229*81136819SBai Ping } 230