1*fcd41e86SJacky Bai /* 2*fcd41e86SJacky Bai * Copyright 2021-2024 NXP 3*fcd41e86SJacky Bai * 4*fcd41e86SJacky Bai * SPDX-License-Identifier: BSD-3-Clause 5*fcd41e86SJacky Bai */ 6*fcd41e86SJacky Bai 7*fcd41e86SJacky Bai #include <stdbool.h> 8*fcd41e86SJacky Bai 9*fcd41e86SJacky Bai #include <arch.h> 10*fcd41e86SJacky Bai #include <arch_helpers.h> 11*fcd41e86SJacky Bai #include <common/debug.h> 12*fcd41e86SJacky Bai #include <drivers/arm/gicv3.h> 13*fcd41e86SJacky Bai #include <lib/mmio.h> 14*fcd41e86SJacky Bai #include <lib/psci/psci.h> 15*fcd41e86SJacky Bai 16*fcd41e86SJacky Bai #include <plat_imx8.h> 17*fcd41e86SJacky Bai 18*fcd41e86SJacky Bai static uintptr_t secure_entrypoint; 19*fcd41e86SJacky Bai 20*fcd41e86SJacky Bai #define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0]) 21*fcd41e86SJacky Bai #define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1]) 22*fcd41e86SJacky Bai #define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) 23*fcd41e86SJacky Bai 24*fcd41e86SJacky Bai #define RVBARADDRx(c) (IMX_SIM1_BASE + 0x5c + 0x4 * (c)) 25*fcd41e86SJacky Bai #define WKPUx(c) (IMX_SIM1_BASE + 0x3c + 0x4 * (c)) 26*fcd41e86SJacky Bai #define AD_COREx_LPMODE(c) (IMX_CMC1_BASE + 0x50 + 0x4 * (c)) 27*fcd41e86SJacky Bai 28*fcd41e86SJacky Bai static int imx_pwr_set_cpu_entry(unsigned int cpu, unsigned int entry) 29*fcd41e86SJacky Bai { 30*fcd41e86SJacky Bai mmio_write_32(RVBARADDRx(cpu), entry); 31*fcd41e86SJacky Bai 32*fcd41e86SJacky Bai /* set update bit */ 33*fcd41e86SJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(24 + cpu)); 34*fcd41e86SJacky Bai /* wait for ack */ 35*fcd41e86SJacky Bai while (!(mmio_read_32(IMX_SIM1_BASE + 0x8) & BIT_32(26 + cpu))) { 36*fcd41e86SJacky Bai } 37*fcd41e86SJacky Bai 38*fcd41e86SJacky Bai /* clear update bit */ 39*fcd41e86SJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) & ~BIT_32(24 + cpu)); 40*fcd41e86SJacky Bai /* clear ack bit */ 41*fcd41e86SJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x8, mmio_read_32(IMX_SIM1_BASE + 0x8) | BIT_32(26 + cpu)); 42*fcd41e86SJacky Bai 43*fcd41e86SJacky Bai return 0; 44*fcd41e86SJacky Bai } 45*fcd41e86SJacky Bai 46*fcd41e86SJacky Bai int imx_pwr_domain_on(u_register_t mpidr) 47*fcd41e86SJacky Bai { 48*fcd41e86SJacky Bai unsigned int cpu = MPIDR_AFFLVL0_VAL(mpidr); 49*fcd41e86SJacky Bai 50*fcd41e86SJacky Bai imx_pwr_set_cpu_entry(cpu, secure_entrypoint); 51*fcd41e86SJacky Bai 52*fcd41e86SJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f); 53*fcd41e86SJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x50 + 0x4 * cpu, 0); 54*fcd41e86SJacky Bai 55*fcd41e86SJacky Bai /* enable wku wakeup for idle */ 56*fcd41e86SJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x3c + 0x4 * cpu, 0xffffffff); 57*fcd41e86SJacky Bai 58*fcd41e86SJacky Bai return PSCI_E_SUCCESS; 59*fcd41e86SJacky Bai } 60*fcd41e86SJacky Bai 61*fcd41e86SJacky Bai void imx_pwr_domain_on_finish(const psci_power_state_t *target_state) 62*fcd41e86SJacky Bai { 63*fcd41e86SJacky Bai imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY); 64*fcd41e86SJacky Bai plat_gic_pcpu_init(); 65*fcd41e86SJacky Bai plat_gic_cpuif_enable(); 66*fcd41e86SJacky Bai } 67*fcd41e86SJacky Bai 68*fcd41e86SJacky Bai int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) 69*fcd41e86SJacky Bai { 70*fcd41e86SJacky Bai return PSCI_E_SUCCESS; 71*fcd41e86SJacky Bai } 72*fcd41e86SJacky Bai 73*fcd41e86SJacky Bai void imx_pwr_domain_off(const psci_power_state_t *target_state) 74*fcd41e86SJacky Bai { 75*fcd41e86SJacky Bai unsigned int cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1()); 76*fcd41e86SJacky Bai 77*fcd41e86SJacky Bai plat_gic_cpuif_disable(); 78*fcd41e86SJacky Bai 79*fcd41e86SJacky Bai /* disable wakeup */ 80*fcd41e86SJacky Bai mmio_write_32(WKPUx(cpu), 0); 81*fcd41e86SJacky Bai 82*fcd41e86SJacky Bai mmio_write_32(AD_COREx_LPMODE(cpu), 0x3); 83*fcd41e86SJacky Bai } 84*fcd41e86SJacky Bai 85*fcd41e86SJacky Bai void __dead2 imx8ulp_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state) 86*fcd41e86SJacky Bai { 87*fcd41e86SJacky Bai while (1) { 88*fcd41e86SJacky Bai wfi(); 89*fcd41e86SJacky Bai } 90*fcd41e86SJacky Bai } 91*fcd41e86SJacky Bai 92*fcd41e86SJacky Bai void __dead2 imx8ulp_system_reset(void) 93*fcd41e86SJacky Bai { 94*fcd41e86SJacky Bai imx_pwr_set_cpu_entry(0, IMX_ROM_ENTRY); 95*fcd41e86SJacky Bai 96*fcd41e86SJacky Bai /* Write invalid command to WDOG CNT to trigger reset */ 97*fcd41e86SJacky Bai mmio_write_32(IMX_WDOG3_BASE + 0x4, 0x12345678); 98*fcd41e86SJacky Bai 99*fcd41e86SJacky Bai while (true) { 100*fcd41e86SJacky Bai wfi(); 101*fcd41e86SJacky Bai } 102*fcd41e86SJacky Bai } 103*fcd41e86SJacky Bai 104*fcd41e86SJacky Bai static const plat_psci_ops_t imx_plat_psci_ops = { 105*fcd41e86SJacky Bai .pwr_domain_on = imx_pwr_domain_on, 106*fcd41e86SJacky Bai .pwr_domain_on_finish = imx_pwr_domain_on_finish, 107*fcd41e86SJacky Bai .validate_ns_entrypoint = imx_validate_ns_entrypoint, 108*fcd41e86SJacky Bai .system_reset = imx8ulp_system_reset, 109*fcd41e86SJacky Bai .pwr_domain_off = imx_pwr_domain_off, 110*fcd41e86SJacky Bai .pwr_domain_pwr_down_wfi = imx8ulp_pwr_domain_pwr_down_wfi, 111*fcd41e86SJacky Bai }; 112*fcd41e86SJacky Bai 113*fcd41e86SJacky Bai int plat_setup_psci_ops(uintptr_t sec_entrypoint, 114*fcd41e86SJacky Bai const plat_psci_ops_t **psci_ops) 115*fcd41e86SJacky Bai { 116*fcd41e86SJacky Bai secure_entrypoint = sec_entrypoint; 117*fcd41e86SJacky Bai imx_pwr_set_cpu_entry(0, sec_entrypoint); 118*fcd41e86SJacky Bai *psci_ops = &imx_plat_psci_ops; 119*fcd41e86SJacky Bai 120*fcd41e86SJacky Bai mmio_write_32(IMX_CMC1_BASE + 0x18, 0x3f); 121*fcd41e86SJacky Bai mmio_write_32(IMX_SIM1_BASE + 0x3c, 0xffffffff); 122*fcd41e86SJacky Bai 123*fcd41e86SJacky Bai return 0; 124*fcd41e86SJacky Bai } 125