1 /* 2 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <stdlib.h> 8 #include <stdint.h> 9 #include <stdbool.h> 10 11 #include <common/debug.h> 12 #include <lib/mmio.h> 13 #include <lib/psci/psci.h> 14 #include <platform_def.h> 15 #include <services/std_svc.h> 16 17 #include <gpc.h> 18 19 void imx_set_cpu_secure_entry(unsigned int core_id, uintptr_t sec_entrypoint) 20 { 21 uint64_t temp_base; 22 23 temp_base = (uint64_t) sec_entrypoint; 24 temp_base >>= 2; 25 26 mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3), 27 ((uint32_t)(temp_base >> 22) & 0xffff)); 28 mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3) + 4, 29 ((uint32_t)temp_base & 0x003fffff)); 30 } 31 32 /* use wfi power down the core */ 33 void imx_set_cpu_pwr_off(unsigned int core_id) 34 { 35 /* enable the wfi power down of the core */ 36 mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | 37 (1 << (core_id + 20))); 38 /* assert the pcg pcr bit of the core */ 39 mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 40 }; 41 42 /* use the sw method to power up the core */ 43 void imx_set_cpu_pwr_on(unsigned int core_id) 44 { 45 /* clear the wfi power down bit of the core */ 46 mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id)); 47 /* assert the ncpuporeset */ 48 mmio_clrbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id)); 49 /* assert the pcg pcr bit of the core */ 50 mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 51 /* sw power up the core */ 52 mmio_setbits_32(IMX_GPC_BASE + CPU_PGC_UP_TRG, (1 << core_id)); 53 54 /* wait for the power up finished */ 55 while ((mmio_read_32(IMX_GPC_BASE + CPU_PGC_UP_TRG) & (1 << core_id)) != 0) 56 ; 57 58 /* deassert the pcg pcr bit of the core */ 59 mmio_clrbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 60 /* deassert the ncpuporeset */ 61 mmio_setbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id)); 62 } 63 64 /* if out of lpm, we need to do reverse steps */ 65 void imx_set_cpu_lpm(unsigned int core_id, bool pdn) 66 { 67 if (pdn) { 68 /* enable the core WFI PDN & IRQ PUP */ 69 mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | 70 (1 << (core_id + 20)) | COREx_IRQ_WUP(core_id)); 71 /* assert the pcg pcr bit of the core */ 72 mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 73 } else { 74 /* disable CORE WFI PDN & IRQ PUP */ 75 mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | 76 COREx_IRQ_WUP(core_id)); 77 /* deassert the pcg pcr bit of the core */ 78 mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 79 } 80 } 81 82 void imx_set_sys_wakeup(unsigned int last_core, bool pdn) 83 { 84 /* TODO */ 85 } 86 87 void imx_pup_pdn_slot_config(int last_core, bool pdn) 88 { 89 if (pdn) { 90 /* SLOT0 for A53 PLAT power down */ 91 mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(0), SLT_PLAT_PDN); 92 /* SLOT1 for A53 PLAT power up */ 93 mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(1), SLT_PLAT_PUP); 94 /* SLOT2 for A53 primary core power up */ 95 mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(2), SLT_COREx_PUP(last_core)); 96 /* ACK setting: PLAT ACK for PDN, CORE ACK for PUP */ 97 mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF, 98 A53_PLAT_PDN_ACK | A53_PLAT_PUP_ACK); 99 } else { 100 mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(0), 0xFFFFFFFF); 101 mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(1), 0xFFFFFFFF); 102 mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(2), 0xFFFFFFFF); 103 mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF, 104 A53_DUMMY_PDN_ACK | A53_DUMMY_PUP_ACK); 105 } 106 } 107 108 void imx_set_cluster_standby(bool retention) 109 { 110 /* 111 * Enable BIT 6 of A53 AD register to make sure system 112 * don't enter LPM mode. 113 */ 114 if (retention) 115 mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6)); 116 else 117 mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6)); 118 } 119 120 void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state) 121 { 122 uint32_t val; 123 124 if (is_local_state_off(power_state)) { 125 val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); 126 val |= A53_LPM_STOP; /* enable C0-C1's STOP mode */ 127 val &= ~CPU_CLOCK_ON_LPM; /* disable CPU clock in LPM mode */ 128 mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); 129 130 /* enable C2-3's STOP mode */ 131 mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_STOP); 132 133 /* enable PLAT/SCU power down */ 134 val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD); 135 val &= ~EN_L2_WFI_PDN; 136 val |= L2PGE | EN_PLAT_PDN; 137 val &= ~COREx_IRQ_WUP(last_core); /* disable IRQ PUP for last core */ 138 val |= COREx_LPM_PUP(last_core); /* enable LPM PUP for last core */ 139 mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); 140 141 imx_pup_pdn_slot_config(last_core, true); 142 143 /* enable PLAT PGC */ 144 mmio_setbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1); 145 } else { 146 /* clear PLAT PGC */ 147 mmio_clrbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1); 148 149 /* clear the slot and ack for cluster power down */ 150 imx_pup_pdn_slot_config(last_core, false); 151 152 val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); 153 val &= ~A53_LPM_MASK; /* clear the C0~1 LPM */ 154 val |= CPU_CLOCK_ON_LPM; /* disable cpu clock in LPM */ 155 mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); 156 157 /* set A53 LPM to RUN mode */ 158 mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_MASK); 159 160 /* clear PLAT/SCU power down */ 161 val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD); 162 val |= EN_L2_WFI_PDN; 163 val &= ~(L2PGE | EN_PLAT_PDN); 164 val &= ~COREx_LPM_PUP(last_core); /* disable C0's LPM PUP */ 165 mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); 166 } 167 } 168 169 /* config the system level power mode */ 170 void imx_set_sys_lpm(bool retention) 171 { 172 uint32_t val; 173 174 /* set system DSM mode SLPCR(0x14) */ 175 val = mmio_read_32(IMX_GPC_BASE + SLPCR); 176 val &= ~(SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS | 177 SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN); 178 179 if (retention) 180 val |= (SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS | 181 SLPCR_BYPASS_PMIC_READY | SLPCR_RBC_EN | 182 SLPCR_A53_FASTWUP_STOP_MODE); 183 184 mmio_write_32(IMX_GPC_BASE + SLPCR, val); 185 } 186 187 void imx_set_rbc_count(void) 188 { 189 mmio_setbits_32(IMX_GPC_BASE + SLPCR, 0x3f << SLPCR_RBC_COUNT_SHIFT); 190 } 191 192 void imx_clear_rbc_count(void) 193 { 194 mmio_clrbits_32(IMX_GPC_BASE + SLPCR, 0x3f << SLPCR_RBC_COUNT_SHIFT); 195 } 196 197 void imx_gpc_init(void) 198 { 199 uint32_t val; 200 int i; 201 /* mask all the interrupt by default */ 202 /* Due to the hardware design requirement, need to make 203 * sure GPR interrupt(#32) is unmasked during RUN mode to 204 * avoid entering DSM mode by mistake. 205 */ 206 for (i = 0; i < 4; i++) { 207 mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_A53 + i * 4, 0xFFFFFFFE); 208 mmio_write_32(IMX_GPC_BASE + IMR1_CORE1_A53 + i * 4, 0xFFFFFFFE); 209 mmio_write_32(IMX_GPC_BASE + IMR1_CORE2_A53 + i * 4, 0xFFFFFFFE); 210 mmio_write_32(IMX_GPC_BASE + IMR1_CORE3_A53 + i * 4, 0xFFFFFFFE); 211 mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_M4 + i * 4, ~0x0); 212 } 213 214 /* use external IRQs to wakeup C0~C3 from LPM */ 215 val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); 216 val |= IRQ_SRC_A53_WUP; 217 /* clear the MASTER0 LPM handshake */ 218 val &= ~MASTER0_LPM_HSK; 219 mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); 220 221 /* mask M4 DSM trigger if M4 is NOT enabled */ 222 mmio_setbits_32(IMX_GPC_BASE + LPCR_M4, DSM_MODE_MASK); 223 224 /* set all mix/PU in A53 domain */ 225 mmio_write_32(IMX_GPC_BASE + PGC_CPU_0_1_MAPPING, 0xfffd); 226 227 /* set SCU timming */ 228 mmio_write_32(IMX_GPC_BASE + PGC_SCU_TIMING, 229 (0x59 << 10) | 0x5B | (0x2 << 20)); 230 231 /* set DUMMY PDN/PUP ACK by default for A53 domain */ 232 mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_DUMMY_PUP_ACK | 233 A53_DUMMY_PDN_ACK); 234 235 /* disable DSM mode by default */ 236 mmio_clrbits_32(IMX_GPC_BASE + SLPCR, DSM_MODE_MASK); 237 238 /* 239 * USB PHY power up needs to make sure RESET bit in SRC is clear, 240 * otherwise, the PU power up bit in GPC will NOT self-cleared. 241 * only need to do it once. 242 */ 243 mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG1PHY_SCR, 0x1); 244 mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG2PHY_SCR, 0x1); 245 } 246