void imx_gpcv2_set_cpu_power_gate_by_wfi(u32 cpu, bool pdn) { unsigned long flags; u32 val; spin_lock_irqsave(&gpcv2_lock, flags); val = readl_relaxed(gpc_base + GPC_LPCR_A7_AD); if (cpu == 0) { if (pdn) { imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C0); val |= BM_LPCR_A7_AD_EN_C0_WFI_PDN | BM_LPCR_A7_AD_EN_C0_IRQ_PUP; } else { imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C0); val &= ~(BM_LPCR_A7_AD_EN_C0_WFI_PDN | BM_LPCR_A7_AD_EN_C0_IRQ_PUP); } } if (cpu == 1) { if (pdn) { imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1); val |= BM_LPCR_A7_AD_EN_C1_WFI_PDN | BM_LPCR_A7_AD_EN_C1_IRQ_PUP; } else { imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1); val &= ~(BM_LPCR_A7_AD_EN_C1_WFI_PDN | BM_LPCR_A7_AD_EN_C1_IRQ_PUP); } } writel_relaxed(val, gpc_base + GPC_LPCR_A7_AD); spin_unlock_irqrestore(&gpcv2_lock, flags); }
void imx_gpcv2_set_cpu_power_gate_in_idle(bool pdn) { unsigned long flags; u32 cpu; for_each_possible_cpu(cpu) imx_gpcv2_set_cpu_power_gate_by_lpm(cpu, pdn); spin_lock_irqsave(&gpcv2_lock, flags); imx_gpcv2_set_m_core_pgc(pdn, GPC_PGC_C0); imx_gpcv2_set_m_core_pgc(pdn, GPC_PGC_C1); imx_gpcv2_set_m_core_pgc(pdn, GPC_PGC_SCU); imx_gpcv2_set_plat_power_gate_by_lpm(pdn); if (pdn) { imx_gpcv2_set_slot_ack(0, CORE0_A7, false, false); imx_gpcv2_set_slot_ack(1, CORE1_A7, false, false); imx_gpcv2_set_slot_ack(2, SCU_A7, false, true); imx_gpcv2_set_slot_ack(6, SCU_A7, true, false); imx_gpcv2_set_slot_ack(7, CORE0_A7, true, false); imx_gpcv2_set_slot_ack(8, CORE1_A7, true, true); } else { writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 0 * 0x4); writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 1 * 0x4); writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 2 * 0x4); writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 6 * 0x4); writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 7 * 0x4); writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + 8 * 0x4); writel_relaxed(BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK | BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK, gpc_base + GPC_PGC_ACK_SEL_A7); } spin_unlock_irqrestore(&gpcv2_lock, flags); }
static int imx_mipi_regulator_notify(struct notifier_block *nb, unsigned long event, void *ignored) { u32 val = 0; val = readl_relaxed(gpc_base + GPC_PGC_CPU_MAPPING); writel_relaxed(val | BIT(2), gpc_base + GPC_PGC_CPU_MAPPING); switch (event) { case REGULATOR_EVENT_PRE_ENABLE: val = readl_relaxed(gpc_base + GPC_PU_PGC_SW_PUP_REQ); writel_relaxed(val | BIT(0), gpc_base + GPC_PU_PGC_SW_PUP_REQ); while (readl_relaxed(gpc_base + GPC_PU_PGC_SW_PUP_REQ) & BIT(0)) ; break; case REGULATOR_EVENT_PRE_DISABLE: /* only disable phy need to set PGC bit, enable does NOT need */ imx_gpcv2_set_m_core_pgc(true, GPC_PGC_MIPI_PHY); val = readl_relaxed(gpc_base + GPC_PU_PGC_SW_PDN_REQ); writel_relaxed(val | BIT(0), gpc_base + GPC_PU_PGC_SW_PDN_REQ); while (readl_relaxed(gpc_base + GPC_PU_PGC_SW_PDN_REQ) & BIT(0)) ; imx_gpcv2_set_m_core_pgc(false, GPC_PGC_MIPI_PHY); break; default: break; } val = readl_relaxed(gpc_base + GPC_PGC_CPU_MAPPING); writel_relaxed(val & ~BIT(2), gpc_base + GPC_PGC_CPU_MAPPING); return NOTIFY_OK; }
void imx_gpcv2_post_resume(void) { void __iomem *reg_imr1 = gpc_base + GPC_IMR1_CORE0; int i, val; /* only external IRQs to wake up LPM and core 0/1 */ val = readl_relaxed(gpc_base + GPC_LPCR_A7_BSC); val |= BM_LPCR_A7_BSC_IRQ_SRC_A7_WAKEUP; writel_relaxed(val, gpc_base + GPC_LPCR_A7_BSC); /* mask m4 dsm trigger if M4 not enabled*/ if (!imx_src_is_m4_enabled()) writel_relaxed(readl_relaxed(gpc_base + GPC_LPCR_M4) | BM_LPCR_M4_MASK_DSM_TRIGGER, gpc_base + GPC_LPCR_M4); /* set mega/fast mix in A7 domain */ writel_relaxed(0x1, gpc_base + GPC_PGC_CPU_MAPPING); /* set SCU timing */ writel_relaxed((0x59 << 10) | 0x5B | (0x51 << 20), gpc_base + GPC_PGC_SCU_TIMING); val = readl_relaxed(gpc_base + GPC_SLPCR); val &= ~(BM_SLPCR_EN_DSM); if (!imx_src_is_m4_enabled()) val &= ~(BM_SLPCR_VSTBY | BM_SLPCR_RBC_EN | BM_SLPCR_SBYOS | BM_SLPCR_BYPASS_PMIC_READY); val |= BM_SLPCR_EN_A7_FASTWUP_WAIT_MODE; writel_relaxed(val, gpc_base + GPC_SLPCR); /* disable memory low power mode */ val = readl_relaxed(gpc_base + GPC_MLPCR); val |= BM_GPC_MLPCR_MEMLP_CTL_DIS; writel_relaxed(val, gpc_base + GPC_MLPCR); for (i = 0; i < IMR_NUM; i++) writel_relaxed(gpcv2_saved_imrs[i], reg_imr1 + i * 4); imx_gpcv2_set_lpm_mode(WAIT_CLOCKED); imx_gpcv2_set_cpu_power_gate_by_lpm(0, false); imx_gpcv2_set_plat_power_gate_by_lpm(false); imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C0); imx_gpcv2_set_m_core_pgc(false, GPC_PGC_SCU); imx_gpcv2_set_m_core_pgc(false, GPC_PGC_FM); for (i = 0; i < MAX_SLOT_NUMBER; i++) { if (i==1||i==4) /* skip slts m4 uses */ continue; writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + i * 0x4); } writel_relaxed(BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK | BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK, gpc_base + GPC_PGC_ACK_SEL_A7); }
void imx_gpcv2_set_core1_pdn_pup_by_software(bool pdn) { u32 val = readl_relaxed(gpc_base + (pdn ? GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ)); imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C1); val |= BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7; writel_relaxed(val, gpc_base + (pdn ? GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ)); while ((readl_relaxed(gpc_base + (pdn ? GPC_CPU_PGC_SW_PDN_REQ : GPC_CPU_PGC_SW_PUP_REQ)) & BM_CPU_PGC_SW_PDN_PUP_REQ_CORE1_A7) != 0) ; imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C1); }
void imx_gpcv2_pre_suspend(bool arm_power_off) { void __iomem *reg_imr1 = gpc_base + GPC_IMR1_CORE0; int i; if (arm_power_off) { imx_gpcv2_set_lpm_mode(STOP_POWER_OFF); /* enable core0 power down/up with low power mode */ imx_gpcv2_set_cpu_power_gate_by_lpm(0, true); /* enable plat power down with low power mode */ imx_gpcv2_set_plat_power_gate_by_lpm(true); /* * To avoid confuse, we use slot 0~4 for power down, * slot 5~9 for power up. * * Power down slot sequence: * Slot0 -> CORE0 * Slot1 -> Mega/Fast MIX * Slot2 -> SCU * * Power up slot sequence: * Slot5 -> Mega/Fast MIX * Slot6 -> SCU * Slot7 -> CORE0 */ imx_gpcv2_set_slot_ack(0, CORE0_A7, false, false); imx_gpcv2_set_slot_ack(2, SCU_A7, false, true); if ((!imx_src_is_m4_enabled()) || (imx_src_is_m4_enabled() && imx_mu_is_m4_in_stop())) imx_gpcv2_mf_mix_off(); imx_gpcv2_set_slot_ack(6, SCU_A7, true, false); imx_gpcv2_set_slot_ack(7, CORE0_A7, true, true); /* enable core0, scu */ imx_gpcv2_set_m_core_pgc(true, GPC_PGC_C0); imx_gpcv2_set_m_core_pgc(true, GPC_PGC_SCU); } else { imx_gpcv2_set_lpm_mode(STOP_POWER_ON); } for (i = 0; i < IMR_NUM; i++) { gpcv2_saved_imrs[i] = readl_relaxed(reg_imr1 + i * 4); writel_relaxed(~gpcv2_wake_irqs[i], reg_imr1 + i * 4); } }
void imx_gpcv2_post_resume(void) { void __iomem *reg_imr1 = gpc_base + GPC_IMR1_CORE0; int i; for (i = 0; i < IMR_NUM; i++) writel_relaxed(gpcv2_saved_imrs[i], reg_imr1 + i * 4); imx_gpcv2_set_lpm_mode(WAIT_CLOCKED); imx_gpcv2_set_cpu_power_gate_by_lpm(0, false); imx_gpcv2_set_plat_power_gate_by_lpm(false); imx_gpcv2_set_m_core_pgc(false, GPC_PGC_C0); imx_gpcv2_set_m_core_pgc(false, GPC_PGC_SCU); imx_gpcv2_set_m_core_pgc(false, GPC_PGC_FM); for (i = 0; i < MAX_SLOT_NUMBER; i++) writel_relaxed(0x0, gpc_base + GPC_SLOT0_CFG + i * 0x4); writel_relaxed(BM_GPC_PGC_ACK_SEL_A7_DUMMY_PUP_ACK | BM_GPC_PGC_ACK_SEL_A7_DUMMY_PDN_ACK, gpc_base + GPC_PGC_ACK_SEL_A7); }
static void imx_gpcv2_mf_mix_off(void) { int i; for (i = 0; i < IMR_NUM; i++) if (((gpcv2_wake_irqs[i] | gpcv2_mf_request_on[i]) & gpcv2_mf_irqs[i]) != 0) return; pr_info("Turn off Mega/Fast mix in DSM\n"); imx_gpcv2_set_mix_phy_gate_by_lpm(1, 5); imx_gpcv2_set_m_core_pgc(true, GPC_PGC_FM); }
static void imx_gpcv2_mf_mix_off(void) { int i; for (i = 0; i < IMR_NUM; i++) if (((gpcv2_wake_irqs[i] | gpcv2_mf_request_on[i]) & gpcv2_mf_irqs[i]) != 0) return; pr_info("Turn off Mega/Fast mix in DSM\n"); imx_gpcv2_set_slot_ack(1, FAST_MEGA_MIX, false, false); imx_gpcv2_set_slot_ack(5, FAST_MEGA_MIX, true, false); imx_gpcv2_set_m_core_pgc(true, GPC_PGC_FM); }