181136819SBai Ping /* 281136819SBai Ping * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. 381136819SBai Ping * 481136819SBai Ping * SPDX-License-Identifier: BSD-3-Clause 581136819SBai Ping */ 681136819SBai Ping 781136819SBai Ping #include <stdlib.h> 881136819SBai Ping #include <stdint.h> 981136819SBai Ping #include <stdbool.h> 10*09d40e0eSAntonio Nino Diaz 11*09d40e0eSAntonio Nino Diaz #include <common/debug.h> 12*09d40e0eSAntonio Nino Diaz #include <lib/mmio.h> 13*09d40e0eSAntonio Nino Diaz #include <lib/psci/psci.h> 14*09d40e0eSAntonio Nino Diaz #include <platform_def.h> 15*09d40e0eSAntonio Nino Diaz #include <services/std_svc.h> 16*09d40e0eSAntonio Nino Diaz 17*09d40e0eSAntonio Nino Diaz #include <gpc.h> 1881136819SBai Ping 1981136819SBai Ping void imx_set_cpu_secure_entry(unsigned int core_id, uintptr_t sec_entrypoint) 2081136819SBai Ping { 2181136819SBai Ping uint64_t temp_base; 2281136819SBai Ping 2381136819SBai Ping temp_base = (uint64_t) sec_entrypoint; 2481136819SBai Ping temp_base >>= 2; 2581136819SBai Ping 2681136819SBai Ping mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3), 2781136819SBai Ping ((uint32_t)(temp_base >> 22) & 0xffff)); 2881136819SBai Ping mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3) + 4, 2981136819SBai Ping ((uint32_t)temp_base & 0x003fffff)); 3081136819SBai Ping } 3181136819SBai Ping 3281136819SBai Ping /* use wfi power down the core */ 3381136819SBai Ping void imx_set_cpu_pwr_off(unsigned int core_id) 3481136819SBai Ping { 3581136819SBai Ping /* enable the wfi power down of the core */ 3681136819SBai Ping mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | 3781136819SBai Ping (1 << (core_id + 20))); 3881136819SBai Ping /* assert the pcg pcr bit of the core */ 3981136819SBai Ping mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 4081136819SBai Ping }; 4181136819SBai Ping 4281136819SBai Ping /* use the sw method to power up the core */ 4381136819SBai Ping void imx_set_cpu_pwr_on(unsigned int core_id) 4481136819SBai Ping { 4581136819SBai Ping /* clear the wfi power down bit of the core */ 4681136819SBai Ping mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id)); 4781136819SBai Ping /* assert the ncpuporeset */ 4881136819SBai Ping mmio_clrbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id)); 4981136819SBai Ping /* assert the pcg pcr bit of the core */ 5081136819SBai Ping mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 5181136819SBai Ping /* sw power up the core */ 5281136819SBai Ping mmio_setbits_32(IMX_GPC_BASE + CPU_PGC_UP_TRG, (1 << core_id)); 5381136819SBai Ping 5481136819SBai Ping /* wait for the power up finished */ 5581136819SBai Ping while ((mmio_read_32(IMX_GPC_BASE + CPU_PGC_UP_TRG) & (1 << core_id)) != 0) 5681136819SBai Ping ; 5781136819SBai Ping 5881136819SBai Ping /* deassert the pcg pcr bit of the core */ 5981136819SBai Ping mmio_clrbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 6081136819SBai Ping /* deassert the ncpuporeset */ 6181136819SBai Ping mmio_setbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id)); 6281136819SBai Ping } 6381136819SBai Ping 6481136819SBai Ping /* if out of lpm, we need to do reverse steps */ 6581136819SBai Ping void imx_set_cpu_lpm(unsigned int core_id, bool pdn) 6681136819SBai Ping { 6781136819SBai Ping if (pdn) { 6881136819SBai Ping /* enable the core WFI PDN & IRQ PUP */ 6981136819SBai Ping mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | 7081136819SBai Ping (1 << (core_id + 20)) | COREx_IRQ_WUP(core_id)); 7181136819SBai Ping /* assert the pcg pcr bit of the core */ 7281136819SBai Ping mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 7381136819SBai Ping } else { 7481136819SBai Ping /* disable CORE WFI PDN & IRQ PUP */ 7581136819SBai Ping mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | 7681136819SBai Ping COREx_IRQ_WUP(core_id)); 7781136819SBai Ping /* deassert the pcg pcr bit of the core */ 7881136819SBai Ping mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 7981136819SBai Ping } 8081136819SBai Ping } 8181136819SBai Ping 8281136819SBai Ping void imx_set_sys_wakeup(unsigned int last_core, bool pdn) 8381136819SBai Ping { 8481136819SBai Ping /* TODO */ 8581136819SBai Ping } 8681136819SBai Ping 8781136819SBai Ping void imx_pup_pdn_slot_config(int last_core, bool pdn) 8881136819SBai Ping { 8981136819SBai Ping if (pdn) { 9081136819SBai Ping /* SLOT0 for A53 PLAT power down */ 9181136819SBai Ping mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(0), SLT_PLAT_PDN); 9281136819SBai Ping /* SLOT1 for A53 PLAT power up */ 9381136819SBai Ping mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(1), SLT_PLAT_PUP); 9481136819SBai Ping /* SLOT2 for A53 primary core power up */ 9581136819SBai Ping mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(2), SLT_COREx_PUP(last_core)); 9681136819SBai Ping /* ACK setting: PLAT ACK for PDN, CORE ACK for PUP */ 9781136819SBai Ping mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF, 9881136819SBai Ping A53_PLAT_PDN_ACK | A53_PLAT_PUP_ACK); 9981136819SBai Ping } else { 10081136819SBai Ping mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(0), 0xFFFFFFFF); 10181136819SBai Ping mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(1), 0xFFFFFFFF); 10281136819SBai Ping mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(2), 0xFFFFFFFF); 10381136819SBai Ping mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF, 10481136819SBai Ping A53_DUMMY_PDN_ACK | A53_DUMMY_PUP_ACK); 10581136819SBai Ping } 10681136819SBai Ping } 10781136819SBai Ping 10881136819SBai Ping void imx_set_cluster_standby(bool retention) 10981136819SBai Ping { 11081136819SBai Ping /* 11181136819SBai Ping * Enable BIT 6 of A53 AD register to make sure system 11281136819SBai Ping * don't enter LPM mode. 11381136819SBai Ping */ 11481136819SBai Ping if (retention) 11581136819SBai Ping mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6)); 11681136819SBai Ping else 11781136819SBai Ping mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6)); 11881136819SBai Ping } 11981136819SBai Ping 12081136819SBai Ping void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state) 12181136819SBai Ping { 12281136819SBai Ping uint32_t val; 12381136819SBai Ping 12481136819SBai Ping if (is_local_state_off(power_state)) { 12581136819SBai Ping val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); 12681136819SBai Ping val |= A53_LPM_STOP; /* enable C0-C1's STOP mode */ 12781136819SBai Ping val &= ~CPU_CLOCK_ON_LPM; /* disable CPU clock in LPM mode */ 12881136819SBai Ping mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); 12981136819SBai Ping 13081136819SBai Ping /* enable C2-3's STOP mode */ 13181136819SBai Ping mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_STOP); 13281136819SBai Ping 13381136819SBai Ping /* enable PLAT/SCU power down */ 13481136819SBai Ping val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD); 13581136819SBai Ping val &= ~EN_L2_WFI_PDN; 13681136819SBai Ping val |= L2PGE | EN_PLAT_PDN; 13781136819SBai Ping val &= ~COREx_IRQ_WUP(last_core); /* disable IRQ PUP for last core */ 13881136819SBai Ping val |= COREx_LPM_PUP(last_core); /* enable LPM PUP for last core */ 13981136819SBai Ping mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); 14081136819SBai Ping 14181136819SBai Ping imx_pup_pdn_slot_config(last_core, true); 14281136819SBai Ping 14381136819SBai Ping /* enable PLAT PGC */ 14481136819SBai Ping mmio_setbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1); 14581136819SBai Ping } else { 14681136819SBai Ping /* clear PLAT PGC */ 14781136819SBai Ping mmio_clrbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1); 14881136819SBai Ping 14981136819SBai Ping /* clear the slot and ack for cluster power down */ 15081136819SBai Ping imx_pup_pdn_slot_config(last_core, false); 15181136819SBai Ping 15281136819SBai Ping val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); 15381136819SBai Ping val &= ~A53_LPM_MASK; /* clear the C0~1 LPM */ 15481136819SBai Ping val |= CPU_CLOCK_ON_LPM; /* disable cpu clock in LPM */ 15581136819SBai Ping mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); 15681136819SBai Ping 15781136819SBai Ping /* set A53 LPM to RUN mode */ 15881136819SBai Ping mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_MASK); 15981136819SBai Ping 16081136819SBai Ping /* clear PLAT/SCU power down */ 16181136819SBai Ping val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD); 16281136819SBai Ping val |= EN_L2_WFI_PDN; 16381136819SBai Ping val &= ~(L2PGE | EN_PLAT_PDN); 16481136819SBai Ping val &= ~COREx_LPM_PUP(last_core); /* disable C0's LPM PUP */ 16581136819SBai Ping mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); 16681136819SBai Ping } 16781136819SBai Ping } 16881136819SBai Ping 16981136819SBai Ping /* config the system level power mode */ 17081136819SBai Ping void imx_set_sys_lpm(bool retention) 17181136819SBai Ping { 17281136819SBai Ping uint32_t val; 17381136819SBai Ping 17481136819SBai Ping /* set system DSM mode SLPCR(0x14) */ 17581136819SBai Ping val = mmio_read_32(IMX_GPC_BASE + SLPCR); 17681136819SBai Ping val &= ~(SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS | 17781136819SBai Ping SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN); 17881136819SBai Ping 17981136819SBai Ping if (retention) 18081136819SBai Ping val |= (SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS | 18181136819SBai Ping SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN | 18281136819SBai Ping SLPCR_A53_FASTWUP_STOP_MODE); 18381136819SBai Ping 18481136819SBai Ping mmio_write_32(IMX_GPC_BASE + SLPCR, val); 18581136819SBai Ping } 18681136819SBai Ping 18781136819SBai Ping void imx_set_rbc_count(void) 18881136819SBai Ping { 18981136819SBai Ping mmio_setbits_32(IMX_GPC_BASE + SLPCR, 0x3f << SLPCR_RBC_COUNT_SHIFT); 19081136819SBai Ping } 19181136819SBai Ping 19281136819SBai Ping void imx_clear_rbc_count(void) 19381136819SBai Ping { 19481136819SBai Ping mmio_clrbits_32(IMX_GPC_BASE + SLPCR, 0x3f << SLPCR_RBC_COUNT_SHIFT); 19581136819SBai Ping } 19681136819SBai Ping 19781136819SBai Ping void imx_gpc_init(void) 19881136819SBai Ping { 19981136819SBai Ping uint32_t val; 20081136819SBai Ping int i; 20181136819SBai Ping /* mask all the interrupt by default */ 20281136819SBai Ping /* Due to the hardware design requirement, need to make 20381136819SBai Ping * sure GPR interrupt(#32) is unmasked during RUN mode to 20481136819SBai Ping * avoid entering DSM mode by mistake. 20581136819SBai Ping */ 20681136819SBai Ping for (i = 0; i < 4; i++) { 20781136819SBai Ping mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_A53 + i * 4, 0xFFFFFFFE); 20881136819SBai Ping mmio_write_32(IMX_GPC_BASE + IMR1_CORE1_A53 + i * 4, 0xFFFFFFFE); 20981136819SBai Ping mmio_write_32(IMX_GPC_BASE + IMR1_CORE2_A53 + i * 4, 0xFFFFFFFE); 21081136819SBai Ping mmio_write_32(IMX_GPC_BASE + IMR1_CORE3_A53 + i * 4, 0xFFFFFFFE); 21181136819SBai Ping mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_M4 + i * 4, ~0x0); 21281136819SBai Ping } 21381136819SBai Ping 21481136819SBai Ping /* use external IRQs to wakeup C0~C3 from LPM */ 21581136819SBai Ping val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); 21681136819SBai Ping val |= IRQ_SRC_A53_WUP; 21781136819SBai Ping /* clear the MASTER0 LPM handshake */ 21881136819SBai Ping val &= ~MASTER0_LPM_HSK; 21981136819SBai Ping mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); 22081136819SBai Ping 22181136819SBai Ping /* mask M4 DSM trigger if M4 is NOT enabled */ 22281136819SBai Ping mmio_setbits_32(IMX_GPC_BASE + LPCR_M4, DSM_MODE_MASK); 22381136819SBai Ping 22481136819SBai Ping /* set all mix/PU in A53 domain */ 22581136819SBai Ping mmio_write_32(IMX_GPC_BASE + PGC_CPU_0_1_MAPPING, 0xfffd); 22681136819SBai Ping 22781136819SBai Ping /* set SCU timming */ 22881136819SBai Ping mmio_write_32(IMX_GPC_BASE + PGC_SCU_TIMING, 22981136819SBai Ping (0x59 << 10) | 0x5B | (0x2 << 20)); 23081136819SBai Ping 23181136819SBai Ping /* set DUMMY PDN/PUP ACK by default for A53 domain */ 23281136819SBai Ping mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_DUMMY_PUP_ACK | 23381136819SBai Ping A53_DUMMY_PDN_ACK); 23481136819SBai Ping 23581136819SBai Ping /* disable DSM mode by default */ 23681136819SBai Ping mmio_clrbits_32(IMX_GPC_BASE + SLPCR, DSM_MODE_MASK); 23781136819SBai Ping 23881136819SBai Ping /* 23981136819SBai Ping * USB PHY power up needs to make sure RESET bit in SRC is clear, 24081136819SBai Ping * otherwise, the PU power up bit in GPC will NOT self-cleared. 24181136819SBai Ping * only need to do it once. 24281136819SBai Ping */ 24381136819SBai Ping mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG1PHY_SCR, 0x1); 24481136819SBai Ping mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG2PHY_SCR, 0x1); 24581136819SBai Ping } 246