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 <lib/mmio.h> 13*e8837b0aSJacky Bai #include <lib/psci/psci.h> 14*e8837b0aSJacky Bai 15*e8837b0aSJacky Bai #include <gpc.h> 16*e8837b0aSJacky Bai #include <imx8m_psci.h> 17*e8837b0aSJacky Bai #include <plat_imx8.h> 18*e8837b0aSJacky Bai 19*e8837b0aSJacky Bai static uint32_t gpc_imr_offset[] = { 0x30, 0x40, 0x1c0, 0x1d0, }; 20*e8837b0aSJacky Bai 21*e8837b0aSJacky Bai #pragma weak imx_set_cpu_pwr_off 22*e8837b0aSJacky Bai #pragma weak imx_set_cpu_pwr_on 23*e8837b0aSJacky Bai #pragma weak imx_set_cpu_lpm 24*e8837b0aSJacky Bai #pragma weak imx_set_cluster_powerdown 25*e8837b0aSJacky Bai 26*e8837b0aSJacky Bai void imx_set_cpu_secure_entry(unsigned int core_id, uintptr_t sec_entrypoint) 27*e8837b0aSJacky Bai { 28*e8837b0aSJacky Bai uint64_t temp_base; 29*e8837b0aSJacky Bai 30*e8837b0aSJacky Bai temp_base = (uint64_t) sec_entrypoint; 31*e8837b0aSJacky Bai temp_base >>= 2; 32*e8837b0aSJacky Bai 33*e8837b0aSJacky Bai mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3), 34*e8837b0aSJacky Bai ((uint32_t)(temp_base >> 22) & 0xffff)); 35*e8837b0aSJacky Bai mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3) + 4, 36*e8837b0aSJacky Bai ((uint32_t)temp_base & 0x003fffff)); 37*e8837b0aSJacky Bai } 38*e8837b0aSJacky Bai 39*e8837b0aSJacky Bai void imx_set_cpu_pwr_off(unsigned int core_id) 40*e8837b0aSJacky Bai { 41*e8837b0aSJacky Bai /* enable the wfi power down of the core */ 42*e8837b0aSJacky Bai mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id)); 43*e8837b0aSJacky Bai /* assert the pcg pcr bit of the core */ 44*e8837b0aSJacky Bai mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 45*e8837b0aSJacky Bai } 46*e8837b0aSJacky Bai 47*e8837b0aSJacky Bai void imx_set_cpu_pwr_on(unsigned int core_id) 48*e8837b0aSJacky Bai { 49*e8837b0aSJacky Bai /* clear the wfi power down bit of the core */ 50*e8837b0aSJacky Bai mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id)); 51*e8837b0aSJacky Bai /* assert the ncpuporeset */ 52*e8837b0aSJacky Bai mmio_clrbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id)); 53*e8837b0aSJacky Bai /* assert the pcg pcr bit of the core */ 54*e8837b0aSJacky Bai mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 55*e8837b0aSJacky Bai /* sw power up the core */ 56*e8837b0aSJacky Bai mmio_setbits_32(IMX_GPC_BASE + CPU_PGC_UP_TRG, (1 << core_id)); 57*e8837b0aSJacky Bai 58*e8837b0aSJacky Bai /* wait for the power up finished */ 59*e8837b0aSJacky Bai while ((mmio_read_32(IMX_GPC_BASE + CPU_PGC_UP_TRG) & (1 << core_id)) != 0) 60*e8837b0aSJacky Bai ; 61*e8837b0aSJacky Bai 62*e8837b0aSJacky Bai /* deassert the pcg pcr bit of the core */ 63*e8837b0aSJacky Bai mmio_clrbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 64*e8837b0aSJacky Bai /* deassert the ncpuporeset */ 65*e8837b0aSJacky Bai mmio_setbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id)); 66*e8837b0aSJacky Bai } 67*e8837b0aSJacky Bai 68*e8837b0aSJacky Bai void imx_set_cpu_lpm(unsigned int core_id, bool pdn) 69*e8837b0aSJacky Bai { 70*e8837b0aSJacky Bai if (pdn) { 71*e8837b0aSJacky Bai /* enable the core WFI PDN & IRQ PUP */ 72*e8837b0aSJacky Bai mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | 73*e8837b0aSJacky Bai COREx_IRQ_WUP(core_id)); 74*e8837b0aSJacky Bai /* assert the pcg pcr bit of the core */ 75*e8837b0aSJacky Bai mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 76*e8837b0aSJacky Bai } else { 77*e8837b0aSJacky Bai /* disbale CORE WFI PDN & IRQ PUP */ 78*e8837b0aSJacky Bai mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | 79*e8837b0aSJacky Bai COREx_IRQ_WUP(core_id)); 80*e8837b0aSJacky Bai /* deassert the pcg pcr bit of the core */ 81*e8837b0aSJacky Bai mmio_clrbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 82*e8837b0aSJacky Bai } 83*e8837b0aSJacky Bai } 84*e8837b0aSJacky Bai 85*e8837b0aSJacky Bai /* 86*e8837b0aSJacky Bai * the plat and noc can only be power up & down by slot method, 87*e8837b0aSJacky Bai * slot0: plat power down; slot1: noc power down; slot2: noc power up; 88*e8837b0aSJacky Bai * slot3: plat power up. plat's pup&pdn ack is used by default. if 89*e8837b0aSJacky Bai * noc is config to power down, then noc's pdn ack should be used. 90*e8837b0aSJacky Bai */ 91*e8837b0aSJacky Bai static void imx_a53_plat_slot_config(bool pdn) 92*e8837b0aSJacky Bai { 93*e8837b0aSJacky Bai if (pdn) { 94*e8837b0aSJacky Bai mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(0), PLAT_PDN_SLT_CTRL); 95*e8837b0aSJacky Bai mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(3), PLAT_PUP_SLT_CTRL); 96*e8837b0aSJacky Bai mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_PLAT_PDN_ACK | 97*e8837b0aSJacky Bai A53_PLAT_PUP_ACK); 98*e8837b0aSJacky Bai mmio_setbits_32(IMX_GPC_BASE + PLAT_PGC_PCR, 0x1); 99*e8837b0aSJacky Bai } else { 100*e8837b0aSJacky Bai mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(0), PLAT_PDN_SLT_CTRL); 101*e8837b0aSJacky Bai mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(3), PLAT_PUP_SLT_CTRL); 102*e8837b0aSJacky Bai mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_DUMMY_PUP_ACK | 103*e8837b0aSJacky Bai A53_DUMMY_PDN_ACK); 104*e8837b0aSJacky Bai mmio_clrbits_32(IMX_GPC_BASE + PLAT_PGC_PCR, 0x1); 105*e8837b0aSJacky Bai } 106*e8837b0aSJacky Bai } 107*e8837b0aSJacky Bai 108*e8837b0aSJacky Bai void imx_set_cluster_standby(bool enter) 109*e8837b0aSJacky Bai { 110*e8837b0aSJacky Bai /* 111*e8837b0aSJacky Bai * Enable BIT 6 of A53 AD register to make sure system 112*e8837b0aSJacky Bai * don't enter LPM mode. 113*e8837b0aSJacky Bai */ 114*e8837b0aSJacky Bai if (enter) 115*e8837b0aSJacky Bai mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6)); 116*e8837b0aSJacky Bai else 117*e8837b0aSJacky Bai mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6)); 118*e8837b0aSJacky Bai } 119*e8837b0aSJacky Bai 120*e8837b0aSJacky Bai /* i.mx8mq need to override it */ 121*e8837b0aSJacky Bai void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state) 122*e8837b0aSJacky Bai { 123*e8837b0aSJacky Bai uint32_t val; 124*e8837b0aSJacky Bai 125*e8837b0aSJacky Bai if (!is_local_state_run(power_state)) { 126*e8837b0aSJacky Bai /* config C0~1's LPM, enable a53 clock off in LPM */ 127*e8837b0aSJacky Bai mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, A53_CLK_ON_LPM, 128*e8837b0aSJacky Bai LPM_MODE(power_state)); 129*e8837b0aSJacky Bai /* config C2-3's LPM */ 130*e8837b0aSJacky Bai mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, LPM_MODE(power_state)); 131*e8837b0aSJacky Bai 132*e8837b0aSJacky Bai /* enable PLAT/SCU power down */ 133*e8837b0aSJacky Bai val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD); 134*e8837b0aSJacky Bai val &= ~EN_L2_WFI_PDN; 135*e8837b0aSJacky Bai /* L2 cache memory is on in WAIT mode */ 136*e8837b0aSJacky Bai if (is_local_state_off(power_state)) 137*e8837b0aSJacky Bai val |= (L2PGE | EN_PLAT_PDN); 138*e8837b0aSJacky Bai else 139*e8837b0aSJacky Bai val |= EN_PLAT_PDN; 140*e8837b0aSJacky Bai 141*e8837b0aSJacky Bai mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); 142*e8837b0aSJacky Bai 143*e8837b0aSJacky Bai imx_a53_plat_slot_config(true); 144*e8837b0aSJacky Bai } else { 145*e8837b0aSJacky Bai /* clear the slot and ack for cluster power down */ 146*e8837b0aSJacky Bai imx_a53_plat_slot_config(false); 147*e8837b0aSJacky Bai /* reverse the cluster level setting */ 148*e8837b0aSJacky Bai mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, 0xf, A53_CLK_ON_LPM); 149*e8837b0aSJacky Bai mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, 0xf); 150*e8837b0aSJacky Bai 151*e8837b0aSJacky Bai /* clear PLAT/SCU power down */ 152*e8837b0aSJacky Bai mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_AD, (L2PGE | EN_PLAT_PDN), 153*e8837b0aSJacky Bai EN_L2_WFI_PDN); 154*e8837b0aSJacky Bai } 155*e8837b0aSJacky Bai } 156*e8837b0aSJacky Bai 157*e8837b0aSJacky Bai static unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id) 158*e8837b0aSJacky Bai { 159*e8837b0aSJacky Bai unsigned int n = id >> ISENABLER_SHIFT; 160*e8837b0aSJacky Bai 161*e8837b0aSJacky Bai return mmio_read_32(base + GICD_ISENABLER + (n << 2)); 162*e8837b0aSJacky Bai } 163*e8837b0aSJacky Bai 164*e8837b0aSJacky Bai /* 165*e8837b0aSJacky Bai * gic's clock will be gated in system suspend, so gic has no ability to 166*e8837b0aSJacky Bai * to wakeup the system, we need to config the imr based on the irq 167*e8837b0aSJacky Bai * enable status in gic, then gpc will monitor the wakeup irq 168*e8837b0aSJacky Bai */ 169*e8837b0aSJacky Bai void imx_set_sys_wakeup(unsigned int last_core, bool pdn) 170*e8837b0aSJacky Bai { 171*e8837b0aSJacky Bai uint32_t irq_mask; 172*e8837b0aSJacky Bai uintptr_t gicd_base = PLAT_GICD_BASE; 173*e8837b0aSJacky Bai 174*e8837b0aSJacky Bai if (pdn) 175*e8837b0aSJacky Bai mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, A53_CORE_WUP_SRC(last_core), 176*e8837b0aSJacky Bai IRQ_SRC_A53_WUP); 177*e8837b0aSJacky Bai else 178*e8837b0aSJacky Bai mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, IRQ_SRC_A53_WUP, 179*e8837b0aSJacky Bai A53_CORE_WUP_SRC(last_core)); 180*e8837b0aSJacky Bai 181*e8837b0aSJacky Bai /* clear last core's IMR based on GIC's mask setting */ 182*e8837b0aSJacky Bai for (int i = 0; i < IRQ_IMR_NUM; i++) { 183*e8837b0aSJacky Bai if (pdn) 184*e8837b0aSJacky Bai /* set the wakeup irq base GIC */ 185*e8837b0aSJacky Bai irq_mask = ~gicd_read_isenabler(gicd_base, 32 * (i + 1)); 186*e8837b0aSJacky Bai else 187*e8837b0aSJacky Bai irq_mask = IMR_MASK_ALL; 188*e8837b0aSJacky Bai 189*e8837b0aSJacky Bai mmio_write_32(IMX_GPC_BASE + gpc_imr_offset[last_core] + i * 4, 190*e8837b0aSJacky Bai irq_mask); 191*e8837b0aSJacky Bai } 192*e8837b0aSJacky Bai } 193*e8837b0aSJacky Bai 194*e8837b0aSJacky Bai #pragma weak imx_noc_slot_config 195*e8837b0aSJacky Bai /* 196*e8837b0aSJacky Bai * this function only need to be override by platform 197*e8837b0aSJacky Bai * that support noc power down, for example: imx8mm. 198*e8837b0aSJacky Bai * otherwize, keep it empty. 199*e8837b0aSJacky Bai */ 200*e8837b0aSJacky Bai void imx_noc_slot_config(bool pdn) 201*e8837b0aSJacky Bai { 202*e8837b0aSJacky Bai 203*e8837b0aSJacky Bai } 204*e8837b0aSJacky Bai 205*e8837b0aSJacky Bai /* this is common for all imx8m soc */ 206*e8837b0aSJacky Bai void imx_set_sys_lpm(unsigned int last_core, bool retention) 207*e8837b0aSJacky Bai { 208*e8837b0aSJacky Bai uint32_t val; 209*e8837b0aSJacky Bai 210*e8837b0aSJacky Bai val = mmio_read_32(IMX_GPC_BASE + SLPCR); 211*e8837b0aSJacky Bai val &= ~(SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS | 212*e8837b0aSJacky Bai SLPCR_BYPASS_PMIC_READY | SLPCR_A53_FASTWUP_STOP_MODE); 213*e8837b0aSJacky Bai 214*e8837b0aSJacky Bai if (retention) 215*e8837b0aSJacky Bai val |= (SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS | 216*e8837b0aSJacky Bai SLPCR_BYPASS_PMIC_READY | SLPCR_A53_FASTWUP_STOP_MODE); 217*e8837b0aSJacky Bai 218*e8837b0aSJacky Bai mmio_write_32(IMX_GPC_BASE + SLPCR, val); 219*e8837b0aSJacky Bai 220*e8837b0aSJacky Bai /* config the noc power down */ 221*e8837b0aSJacky Bai imx_noc_slot_config(retention); 222*e8837b0aSJacky Bai 223*e8837b0aSJacky Bai /* config wakeup irqs' mask in gpc */ 224*e8837b0aSJacky Bai imx_set_sys_wakeup(last_core, retention); 225*e8837b0aSJacky Bai } 226*e8837b0aSJacky Bai 227*e8837b0aSJacky Bai void imx_set_rbc_count(void) 228*e8837b0aSJacky Bai { 229*e8837b0aSJacky Bai mmio_setbits_32(IMX_GPC_BASE + SLPCR, SLPCR_RBC_EN | 230*e8837b0aSJacky Bai (0x8 << SLPCR_RBC_COUNT_SHIFT)); 231*e8837b0aSJacky Bai } 232*e8837b0aSJacky Bai 233*e8837b0aSJacky Bai void imx_clear_rbc_count(void) 234*e8837b0aSJacky Bai { 235*e8837b0aSJacky Bai mmio_clrbits_32(IMX_GPC_BASE + SLPCR, SLPCR_RBC_EN | 236*e8837b0aSJacky Bai (0x3f << SLPCR_RBC_COUNT_SHIFT)); 237*e8837b0aSJacky Bai } 238