1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2018-2023, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <stdbool.h> 8*91f16700Schasinglulu 9*91f16700Schasinglulu #include <arch.h> 10*91f16700Schasinglulu #include <arch_helpers.h> 11*91f16700Schasinglulu #include <common/debug.h> 12*91f16700Schasinglulu #include <common/runtime_svc.h> 13*91f16700Schasinglulu #include <lib/mmio.h> 14*91f16700Schasinglulu #include <lib/psci/psci.h> 15*91f16700Schasinglulu 16*91f16700Schasinglulu #include <gpc.h> 17*91f16700Schasinglulu #include <imx8m_psci.h> 18*91f16700Schasinglulu #include <plat_imx8.h> 19*91f16700Schasinglulu 20*91f16700Schasinglulu #define MAX_PLL_NUM U(10) 21*91f16700Schasinglulu 22*91f16700Schasinglulu static uint32_t gpc_imr_offset[] = { IMR1_CORE0_A53, IMR1_CORE1_A53, IMR1_CORE2_A53, IMR1_CORE3_A53, }; 23*91f16700Schasinglulu 24*91f16700Schasinglulu DEFINE_BAKERY_LOCK(gpc_lock); 25*91f16700Schasinglulu 26*91f16700Schasinglulu #define FSL_SIP_CONFIG_GPC_PM_DOMAIN 0x03 27*91f16700Schasinglulu 28*91f16700Schasinglulu #pragma weak imx_set_cpu_pwr_off 29*91f16700Schasinglulu #pragma weak imx_set_cpu_pwr_on 30*91f16700Schasinglulu #pragma weak imx_set_cpu_lpm 31*91f16700Schasinglulu #pragma weak imx_set_cluster_powerdown 32*91f16700Schasinglulu #pragma weak imx_set_sys_wakeup 33*91f16700Schasinglulu #pragma weak imx_noc_slot_config 34*91f16700Schasinglulu #pragma weak imx_gpc_handler 35*91f16700Schasinglulu #pragma weak imx_anamix_override 36*91f16700Schasinglulu 37*91f16700Schasinglulu void imx_set_cpu_secure_entry(unsigned int core_id, uintptr_t sec_entrypoint) 38*91f16700Schasinglulu { 39*91f16700Schasinglulu uint64_t temp_base; 40*91f16700Schasinglulu 41*91f16700Schasinglulu temp_base = (uint64_t) sec_entrypoint; 42*91f16700Schasinglulu temp_base >>= 2; 43*91f16700Schasinglulu 44*91f16700Schasinglulu mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3), 45*91f16700Schasinglulu ((uint32_t)(temp_base >> 22) & 0xffff)); 46*91f16700Schasinglulu mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3) + 4, 47*91f16700Schasinglulu ((uint32_t)temp_base & 0x003fffff)); 48*91f16700Schasinglulu } 49*91f16700Schasinglulu 50*91f16700Schasinglulu void imx_set_cpu_pwr_off(unsigned int core_id) 51*91f16700Schasinglulu { 52*91f16700Schasinglulu 53*91f16700Schasinglulu bakery_lock_get(&gpc_lock); 54*91f16700Schasinglulu 55*91f16700Schasinglulu /* enable the wfi power down of the core */ 56*91f16700Schasinglulu mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id)); 57*91f16700Schasinglulu 58*91f16700Schasinglulu bakery_lock_release(&gpc_lock); 59*91f16700Schasinglulu 60*91f16700Schasinglulu /* assert the pcg pcr bit of the core */ 61*91f16700Schasinglulu mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 62*91f16700Schasinglulu } 63*91f16700Schasinglulu 64*91f16700Schasinglulu void imx_set_cpu_pwr_on(unsigned int core_id) 65*91f16700Schasinglulu { 66*91f16700Schasinglulu bakery_lock_get(&gpc_lock); 67*91f16700Schasinglulu 68*91f16700Schasinglulu /* clear the wfi power down bit of the core */ 69*91f16700Schasinglulu mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id)); 70*91f16700Schasinglulu 71*91f16700Schasinglulu bakery_lock_release(&gpc_lock); 72*91f16700Schasinglulu 73*91f16700Schasinglulu /* assert the ncpuporeset */ 74*91f16700Schasinglulu mmio_clrbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id)); 75*91f16700Schasinglulu /* assert the pcg pcr bit of the core */ 76*91f16700Schasinglulu mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 77*91f16700Schasinglulu /* sw power up the core */ 78*91f16700Schasinglulu mmio_setbits_32(IMX_GPC_BASE + CPU_PGC_UP_TRG, (1 << core_id)); 79*91f16700Schasinglulu 80*91f16700Schasinglulu /* wait for the power up finished */ 81*91f16700Schasinglulu while ((mmio_read_32(IMX_GPC_BASE + CPU_PGC_UP_TRG) & (1 << core_id)) != 0) 82*91f16700Schasinglulu ; 83*91f16700Schasinglulu 84*91f16700Schasinglulu /* deassert the pcg pcr bit of the core */ 85*91f16700Schasinglulu mmio_clrbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 86*91f16700Schasinglulu /* deassert the ncpuporeset */ 87*91f16700Schasinglulu mmio_setbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id)); 88*91f16700Schasinglulu } 89*91f16700Schasinglulu 90*91f16700Schasinglulu void imx_set_cpu_lpm(unsigned int core_id, bool pdn) 91*91f16700Schasinglulu { 92*91f16700Schasinglulu bakery_lock_get(&gpc_lock); 93*91f16700Schasinglulu 94*91f16700Schasinglulu if (pdn) { 95*91f16700Schasinglulu /* enable the core WFI PDN & IRQ PUP */ 96*91f16700Schasinglulu mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | 97*91f16700Schasinglulu COREx_IRQ_WUP(core_id)); 98*91f16700Schasinglulu /* assert the pcg pcr bit of the core */ 99*91f16700Schasinglulu mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 100*91f16700Schasinglulu } else { 101*91f16700Schasinglulu /* disable CORE WFI PDN & IRQ PUP */ 102*91f16700Schasinglulu mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | 103*91f16700Schasinglulu COREx_IRQ_WUP(core_id)); 104*91f16700Schasinglulu /* deassert the pcg pcr bit of the core */ 105*91f16700Schasinglulu mmio_clrbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); 106*91f16700Schasinglulu } 107*91f16700Schasinglulu 108*91f16700Schasinglulu bakery_lock_release(&gpc_lock); 109*91f16700Schasinglulu } 110*91f16700Schasinglulu 111*91f16700Schasinglulu /* 112*91f16700Schasinglulu * the plat and noc can only be power up & down by slot method, 113*91f16700Schasinglulu * slot0: plat power down; slot1: noc power down; slot2: noc power up; 114*91f16700Schasinglulu * slot3: plat power up. plat's pup&pdn ack is used by default. if 115*91f16700Schasinglulu * noc is config to power down, then noc's pdn ack should be used. 116*91f16700Schasinglulu */ 117*91f16700Schasinglulu static void imx_a53_plat_slot_config(bool pdn) 118*91f16700Schasinglulu { 119*91f16700Schasinglulu if (pdn) { 120*91f16700Schasinglulu mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(0), PLAT_PDN_SLT_CTRL); 121*91f16700Schasinglulu mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(3), PLAT_PUP_SLT_CTRL); 122*91f16700Schasinglulu mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_PLAT_PDN_ACK | 123*91f16700Schasinglulu A53_PLAT_PUP_ACK); 124*91f16700Schasinglulu mmio_setbits_32(IMX_GPC_BASE + PLAT_PGC_PCR, 0x1); 125*91f16700Schasinglulu } else { 126*91f16700Schasinglulu mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(0), PLAT_PDN_SLT_CTRL); 127*91f16700Schasinglulu mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(3), PLAT_PUP_SLT_CTRL); 128*91f16700Schasinglulu mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_DUMMY_PUP_ACK | 129*91f16700Schasinglulu A53_DUMMY_PDN_ACK); 130*91f16700Schasinglulu mmio_clrbits_32(IMX_GPC_BASE + PLAT_PGC_PCR, 0x1); 131*91f16700Schasinglulu } 132*91f16700Schasinglulu } 133*91f16700Schasinglulu 134*91f16700Schasinglulu void imx_set_cluster_standby(bool enter) 135*91f16700Schasinglulu { 136*91f16700Schasinglulu /* 137*91f16700Schasinglulu * Enable BIT 6 of A53 AD register to make sure system 138*91f16700Schasinglulu * don't enter LPM mode. 139*91f16700Schasinglulu */ 140*91f16700Schasinglulu if (enter) 141*91f16700Schasinglulu mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6)); 142*91f16700Schasinglulu else 143*91f16700Schasinglulu mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6)); 144*91f16700Schasinglulu } 145*91f16700Schasinglulu 146*91f16700Schasinglulu /* i.mx8mq need to override it */ 147*91f16700Schasinglulu void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state) 148*91f16700Schasinglulu { 149*91f16700Schasinglulu uint32_t val; 150*91f16700Schasinglulu 151*91f16700Schasinglulu if (!is_local_state_run(power_state)) { 152*91f16700Schasinglulu /* config C0~1's LPM, enable a53 clock off in LPM */ 153*91f16700Schasinglulu mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, A53_CLK_ON_LPM, 154*91f16700Schasinglulu LPM_MODE(power_state)); 155*91f16700Schasinglulu /* config C2-3's LPM */ 156*91f16700Schasinglulu mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, LPM_MODE(power_state)); 157*91f16700Schasinglulu 158*91f16700Schasinglulu /* enable PLAT/SCU power down */ 159*91f16700Schasinglulu val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD); 160*91f16700Schasinglulu val &= ~EN_L2_WFI_PDN; 161*91f16700Schasinglulu /* L2 cache memory is on in WAIT mode */ 162*91f16700Schasinglulu if (is_local_state_off(power_state)) { 163*91f16700Schasinglulu val |= (L2PGE | EN_PLAT_PDN); 164*91f16700Schasinglulu imx_a53_plat_slot_config(true); 165*91f16700Schasinglulu } 166*91f16700Schasinglulu 167*91f16700Schasinglulu mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); 168*91f16700Schasinglulu } else { 169*91f16700Schasinglulu /* clear the slot and ack for cluster power down */ 170*91f16700Schasinglulu imx_a53_plat_slot_config(false); 171*91f16700Schasinglulu /* reverse the cluster level setting */ 172*91f16700Schasinglulu mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, 0xf, A53_CLK_ON_LPM); 173*91f16700Schasinglulu mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, 0xf); 174*91f16700Schasinglulu 175*91f16700Schasinglulu /* clear PLAT/SCU power down */ 176*91f16700Schasinglulu mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_AD, (L2PGE | EN_PLAT_PDN), 177*91f16700Schasinglulu EN_L2_WFI_PDN); 178*91f16700Schasinglulu } 179*91f16700Schasinglulu } 180*91f16700Schasinglulu 181*91f16700Schasinglulu static unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id) 182*91f16700Schasinglulu { 183*91f16700Schasinglulu unsigned int n = id >> ISENABLER_SHIFT; 184*91f16700Schasinglulu 185*91f16700Schasinglulu return mmio_read_32(base + GICD_ISENABLER + (n << 2)); 186*91f16700Schasinglulu } 187*91f16700Schasinglulu 188*91f16700Schasinglulu /* 189*91f16700Schasinglulu * gic's clock will be gated in system suspend, so gic has no ability to 190*91f16700Schasinglulu * to wakeup the system, we need to config the imr based on the irq 191*91f16700Schasinglulu * enable status in gic, then gpc will monitor the wakeup irq 192*91f16700Schasinglulu */ 193*91f16700Schasinglulu void imx_set_sys_wakeup(unsigned int last_core, bool pdn) 194*91f16700Schasinglulu { 195*91f16700Schasinglulu uint32_t irq_mask; 196*91f16700Schasinglulu uintptr_t gicd_base = PLAT_GICD_BASE; 197*91f16700Schasinglulu 198*91f16700Schasinglulu if (pdn) 199*91f16700Schasinglulu mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, A53_CORE_WUP_SRC(last_core), 200*91f16700Schasinglulu IRQ_SRC_A53_WUP); 201*91f16700Schasinglulu else 202*91f16700Schasinglulu mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, IRQ_SRC_A53_WUP, 203*91f16700Schasinglulu A53_CORE_WUP_SRC(last_core)); 204*91f16700Schasinglulu 205*91f16700Schasinglulu /* clear last core's IMR based on GIC's mask setting */ 206*91f16700Schasinglulu for (int i = 0; i < IRQ_IMR_NUM; i++) { 207*91f16700Schasinglulu if (pdn) 208*91f16700Schasinglulu /* set the wakeup irq base GIC */ 209*91f16700Schasinglulu irq_mask = ~gicd_read_isenabler(gicd_base, 32 * (i + 1)); 210*91f16700Schasinglulu else 211*91f16700Schasinglulu irq_mask = IMR_MASK_ALL; 212*91f16700Schasinglulu 213*91f16700Schasinglulu mmio_write_32(IMX_GPC_BASE + gpc_imr_offset[last_core] + i * 4, 214*91f16700Schasinglulu irq_mask); 215*91f16700Schasinglulu } 216*91f16700Schasinglulu } 217*91f16700Schasinglulu 218*91f16700Schasinglulu /* 219*91f16700Schasinglulu * this function only need to be override by platform 220*91f16700Schasinglulu * that support noc power down, for example: imx8mm. 221*91f16700Schasinglulu * otherwize, keep it empty. 222*91f16700Schasinglulu */ 223*91f16700Schasinglulu void imx_noc_slot_config(bool pdn) 224*91f16700Schasinglulu { 225*91f16700Schasinglulu 226*91f16700Schasinglulu } 227*91f16700Schasinglulu 228*91f16700Schasinglulu /* this is common for all imx8m soc */ 229*91f16700Schasinglulu void imx_set_sys_lpm(unsigned int last_core, bool retention) 230*91f16700Schasinglulu { 231*91f16700Schasinglulu uint32_t val; 232*91f16700Schasinglulu 233*91f16700Schasinglulu val = mmio_read_32(IMX_GPC_BASE + SLPCR); 234*91f16700Schasinglulu val &= ~(SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS | 235*91f16700Schasinglulu SLPCR_BYPASS_PMIC_READY | SLPCR_A53_FASTWUP_STOP_MODE); 236*91f16700Schasinglulu 237*91f16700Schasinglulu if (retention) 238*91f16700Schasinglulu val |= (SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS | 239*91f16700Schasinglulu SLPCR_BYPASS_PMIC_READY); 240*91f16700Schasinglulu 241*91f16700Schasinglulu mmio_write_32(IMX_GPC_BASE + SLPCR, val); 242*91f16700Schasinglulu 243*91f16700Schasinglulu /* config the noc power down */ 244*91f16700Schasinglulu imx_noc_slot_config(retention); 245*91f16700Schasinglulu 246*91f16700Schasinglulu /* config wakeup irqs' mask in gpc */ 247*91f16700Schasinglulu imx_set_sys_wakeup(last_core, retention); 248*91f16700Schasinglulu } 249*91f16700Schasinglulu 250*91f16700Schasinglulu void imx_set_rbc_count(void) 251*91f16700Schasinglulu { 252*91f16700Schasinglulu mmio_setbits_32(IMX_GPC_BASE + SLPCR, SLPCR_RBC_EN | 253*91f16700Schasinglulu (0x8 << SLPCR_RBC_COUNT_SHIFT)); 254*91f16700Schasinglulu } 255*91f16700Schasinglulu 256*91f16700Schasinglulu void imx_clear_rbc_count(void) 257*91f16700Schasinglulu { 258*91f16700Schasinglulu mmio_clrbits_32(IMX_GPC_BASE + SLPCR, SLPCR_RBC_EN | 259*91f16700Schasinglulu (0x3f << SLPCR_RBC_COUNT_SHIFT)); 260*91f16700Schasinglulu } 261*91f16700Schasinglulu 262*91f16700Schasinglulu struct pll_override pll[MAX_PLL_NUM] = { 263*91f16700Schasinglulu {.reg = 0x0, .override_mask = (1 << 12) | (1 << 8), }, 264*91f16700Schasinglulu {.reg = 0x14, .override_mask = (1 << 12) | (1 << 8), }, 265*91f16700Schasinglulu {.reg = 0x28, .override_mask = (1 << 12) | (1 << 8), }, 266*91f16700Schasinglulu {.reg = 0x50, .override_mask = (1 << 12) | (1 << 8), }, 267*91f16700Schasinglulu {.reg = 0x64, .override_mask = (1 << 10) | (1 << 8), }, 268*91f16700Schasinglulu {.reg = 0x74, .override_mask = (1 << 10) | (1 << 8), }, 269*91f16700Schasinglulu {.reg = 0x84, .override_mask = (1 << 10) | (1 << 8), }, 270*91f16700Schasinglulu {.reg = 0x94, .override_mask = 0x5555500, }, 271*91f16700Schasinglulu {.reg = 0x104, .override_mask = 0x5555500, }, 272*91f16700Schasinglulu {.reg = 0x114, .override_mask = 0x500, }, 273*91f16700Schasinglulu }; 274*91f16700Schasinglulu 275*91f16700Schasinglulu #define PLL_BYPASS BIT(4) 276*91f16700Schasinglulu void imx_anamix_override(bool enter) 277*91f16700Schasinglulu { 278*91f16700Schasinglulu unsigned int i; 279*91f16700Schasinglulu 280*91f16700Schasinglulu /* 281*91f16700Schasinglulu * bypass all the plls & enable the override bit before 282*91f16700Schasinglulu * entering DSM mode. 283*91f16700Schasinglulu */ 284*91f16700Schasinglulu for (i = 0U; i < MAX_PLL_NUM; i++) { 285*91f16700Schasinglulu if (enter) { 286*91f16700Schasinglulu mmio_setbits_32(IMX_ANAMIX_BASE + pll[i].reg, PLL_BYPASS); 287*91f16700Schasinglulu mmio_setbits_32(IMX_ANAMIX_BASE + pll[i].reg, pll[i].override_mask); 288*91f16700Schasinglulu } else { 289*91f16700Schasinglulu mmio_clrbits_32(IMX_ANAMIX_BASE + pll[i].reg, PLL_BYPASS); 290*91f16700Schasinglulu mmio_clrbits_32(IMX_ANAMIX_BASE + pll[i].reg, pll[i].override_mask); 291*91f16700Schasinglulu } 292*91f16700Schasinglulu } 293*91f16700Schasinglulu } 294*91f16700Schasinglulu 295*91f16700Schasinglulu int imx_gpc_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3) 296*91f16700Schasinglulu { 297*91f16700Schasinglulu switch (x1) { 298*91f16700Schasinglulu case FSL_SIP_CONFIG_GPC_PM_DOMAIN: 299*91f16700Schasinglulu imx_gpc_pm_domain_enable(x2, x3); 300*91f16700Schasinglulu break; 301*91f16700Schasinglulu default: 302*91f16700Schasinglulu return SMC_UNK; 303*91f16700Schasinglulu } 304*91f16700Schasinglulu 305*91f16700Schasinglulu return 0; 306*91f16700Schasinglulu } 307