コード例 #1
0
/* set cpu low power mode before WFI instruction */
void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
{

	int stop_mode = 0;
	void __iomem *anatop_base = IO_ADDRESS(ANATOP_BASE_ADDR);
	u32 ccm_clpcr, anatop_val;

	ccm_clpcr = __raw_readl(MXC_CCM_CLPCR) & ~(MXC_CCM_CLPCR_LPM_MASK);

	switch (mode) {
	case WAIT_CLOCKED:
		break;
	case WAIT_UNCLOCKED:
		ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
		break;
	case WAIT_UNCLOCKED_POWER_OFF:
	case STOP_POWER_OFF:
	case ARM_POWER_OFF:
		if (mode == WAIT_UNCLOCKED_POWER_OFF) {
			ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY;
			ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS;
			ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
			if (cpu_is_mx6sl()) {
				ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH0_LPM_HS;
				ccm_clpcr |= MXC_CCM_CLPCR_BYPASS_PMIC_VFUNC_READY;
			} else
				ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS;
			stop_mode = 0;
		} else if (mode == STOP_POWER_OFF) {
			ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
			ccm_clpcr |= 0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET;
			ccm_clpcr |= MXC_CCM_CLPCR_VSTBY;
			ccm_clpcr |= MXC_CCM_CLPCR_SBYOS;
			if (cpu_is_mx6sl()) {
				ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH0_LPM_HS;
				ccm_clpcr |= MXC_CCM_CLPCR_BYPASS_PMIC_VFUNC_READY;
			} else
				ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS;
			stop_mode = 1;
		} else {
			ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
			ccm_clpcr |= 0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET;
			ccm_clpcr |= MXC_CCM_CLPCR_VSTBY;
			ccm_clpcr |= MXC_CCM_CLPCR_SBYOS;
			if (cpu_is_mx6sl()) {
				ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH0_LPM_HS;
				ccm_clpcr |= MXC_CCM_CLPCR_BYPASS_PMIC_VFUNC_READY;
			} else
				ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS;
			stop_mode = 2;
		}
		break;
	case STOP_XTAL_ON:
		ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
		ccm_clpcr |= MXC_CCM_CLPCR_VSTBY;
		ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS;
		if (cpu_is_mx6sl()) {
			ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH0_LPM_HS;
			ccm_clpcr |= MXC_CCM_CLPCR_BYPASS_PMIC_VFUNC_READY;
		} else
			ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS;
		stop_mode = 3;

		break;
	default:
		printk(KERN_WARNING "UNKNOWN cpu power mode: %d\n", mode);
		return;
	}

	if (stop_mode > 0) {
		gpc_set_wakeup(gpc_wake_irq);
		/* Power down and power up sequence */
		/* The PUPSCR counter counts in terms of CLKIL (32KHz) cycles.
		   * The PUPSCR should include the time it takes for the ARM LDO to
		   * ramp up.
		   */
		__raw_writel(0x202, gpc_base + GPC_PGC_CPU_PUPSCR_OFFSET);
		/* The PDNSCR is a counter that counts in IPG_CLK cycles. This counter
		  * can be set to minimum values to power down faster.
		  */
		__raw_writel(0x101, gpc_base + GPC_PGC_CPU_PDNSCR_OFFSET);
		if (stop_mode >= 2) {
			/* dormant mode, need to power off the arm core */
			__raw_writel(0x1, gpc_base + GPC_PGC_CPU_PDN_OFFSET);
			if (cpu_is_mx6q() || cpu_is_mx6dl()) {
				/* If stop_mode_config is clear, then 2P5 will be off,
				need to enable weak 2P5, as DDR IO need 2P5 as
				pre-driver */
				if ((__raw_readl(anatop_base + HW_ANADIG_ANA_MISC0)
					& BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG) == 0) {
					/* Enable weak 2P5 linear regulator */
					anatop_val = __raw_readl(anatop_base +
						HW_ANADIG_REG_2P5);
					anatop_val |= BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG;
					__raw_writel(anatop_val, anatop_base +
						HW_ANADIG_REG_2P5);
				}
				if (mx6q_revision() != IMX_CHIP_REVISION_1_0) {
					/* Enable fet_odrive */
					anatop_val = __raw_readl(anatop_base +
						HW_ANADIG_REG_CORE);
					anatop_val |= BM_ANADIG_REG_CORE_FET_ODRIVE;
					__raw_writel(anatop_val, anatop_base +
						HW_ANADIG_REG_CORE);
				}
			} else {
				if (stop_mode == 2) {
					/* Disable VDDHIGH_IN to VDDSNVS_IN
					  * power path, only used when VDDSNVS_IN
					  * is powered by dedicated
					 * power rail */
					anatop_val = __raw_readl(anatop_base +
						HW_ANADIG_ANA_MISC0);
					anatop_val |= BM_ANADIG_ANA_MISC0_RTC_RINGOSC_EN;
					__raw_writel(anatop_val, anatop_base +
						HW_ANADIG_ANA_MISC0);
					/* Need to enable pull down if 2P5 is disabled */
					anatop_val = __raw_readl(anatop_base +
						HW_ANADIG_REG_2P5);
					anatop_val |= BM_ANADIG_REG_2P5_ENABLE_PULLDOWN;
					__raw_writel(anatop_val, anatop_base +
						HW_ANADIG_REG_2P5);
				}
			}
			if (stop_mode != 3) {
				/* Make sure we clear WB_COUNT
				  * and re-config it.
				  */
				__raw_writel(__raw_readl(MXC_CCM_CCR) &
					(~MXC_CCM_CCR_WB_COUNT_MASK),
					MXC_CCM_CCR);
				/* Reconfigure WB, need to set WB counter
				 * to 0x7 to make sure it work normally */
				__raw_writel(__raw_readl(MXC_CCM_CCR) |
					(0x7 << MXC_CCM_CCR_WB_COUNT_OFFSET),
					MXC_CCM_CCR);

				/* Set WB_PER enable */
				ccm_clpcr |= MXC_CCM_CLPCR_WB_PER_AT_LPM;
			}
		}
		if (cpu_is_mx6sl() ||
			(mx6q_revision() > IMX_CHIP_REVISION_1_1) ||
			(mx6dl_revision() > IMX_CHIP_REVISION_1_0)) {
			u32 reg;
			/* We need to allow the memories to be clock gated
			  * in STOP mode, else the power consumption will
			  * be very high.
			  */
			reg = __raw_readl(MXC_CCM_CGPR);
			reg |= MXC_CCM_CGPR_MEM_IPG_STOP_MASK;
			if (!cpu_is_mx6sl()) {
				/*
				  * For MX6QTO1.2 or later and MX6DLTO1.1 or later,
				  * ensure that the CCM_CGPR bit 17 is cleared before
				  * dormant mode is entered.
				  */
				reg &= ~MXC_CCM_CGPR_WAIT_MODE_FIX;
			}
			__raw_writel(reg, MXC_CCM_CGPR);
		}
	}
	__raw_writel(ccm_clpcr, MXC_CCM_CLPCR);
}
コード例 #2
0
/* set cpu low power mode before WFI instruction */
void mxc_cpu_lp_set(enum mxc_cpu_pwr_mode mode)
{

	int stop_mode = 0;
	void __iomem *anatop_base = IO_ADDRESS(ANATOP_BASE_ADDR);
	u32 ccm_clpcr, anatop_val;

	ccm_clpcr = __raw_readl(MXC_CCM_CLPCR) & ~(MXC_CCM_CLPCR_LPM_MASK);

	switch (mode) {
	case WAIT_CLOCKED:
		break;
	case WAIT_UNCLOCKED:
		ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
		break;
	case WAIT_UNCLOCKED_POWER_OFF:
	case STOP_POWER_OFF:
	case ARM_POWER_OFF:
		if (mode == WAIT_UNCLOCKED_POWER_OFF) {
			ccm_clpcr &= ~MXC_CCM_CLPCR_VSTBY;
			ccm_clpcr &= ~MXC_CCM_CLPCR_SBYOS;
			ccm_clpcr |= 0x1 << MXC_CCM_CLPCR_LPM_OFFSET;
			ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS;
			stop_mode = 0;
		} else if (mode == STOP_POWER_OFF) {
			ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
			ccm_clpcr |= 0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET;
			ccm_clpcr |= MXC_CCM_CLPCR_VSTBY;
			ccm_clpcr |= MXC_CCM_CLPCR_SBYOS;
			ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS;
			stop_mode = 1;
		} else {
			ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;
			ccm_clpcr |= 0x3 << MXC_CCM_CLPCR_STBY_COUNT_OFFSET;
			ccm_clpcr |= MXC_CCM_CLPCR_VSTBY;
			ccm_clpcr |= MXC_CCM_CLPCR_SBYOS;
			ccm_clpcr |= MXC_CCM_CLPCR_BYP_MMDC_CH1_LPM_HS;
			stop_mode = 2;
		}
		break;
	case STOP_POWER_ON:
		ccm_clpcr |= 0x2 << MXC_CCM_CLPCR_LPM_OFFSET;

		break;
	default:
		printk(KERN_WARNING "UNKNOWN cpu power mode: %d\n", mode);
		return;
	}

	if (stop_mode > 0) {
		gpc_set_wakeup(gpc_wake_irq);
		/* Power down and power up sequence */
		__raw_writel(0xFFFFFFFF, gpc_base + GPC_PGC_CPU_PUPSCR_OFFSET);
		__raw_writel(0xFFFFFFFF, gpc_base + GPC_PGC_CPU_PDNSCR_OFFSET);

		/* dormant mode, need to power off the arm core */
		if (stop_mode == 2) {
			__raw_writel(0x1, gpc_base + GPC_PGC_CPU_PDN_OFFSET);
			__raw_writel(0x1, gpc_base + GPC_PGC_GPU_PGCR_OFFSET);
			__raw_writel(0x1, gpc_base + GPC_CNTR_OFFSET);
			/* Enable weak 2P5 linear regulator */
			anatop_val = __raw_readl(anatop_base + ANATOP_REG_2P5_OFFSET);
			anatop_val |= 1 << 18;
			__raw_writel(anatop_val, anatop_base + ANATOP_REG_2P5_OFFSET);
			/* Make sure ARM and SOC domain has same voltage and PU domain off */
			anatop_val = __raw_readl(anatop_base + ANATOP_REG_CORE_OFFSET);
			anatop_val &= 0xff83001f;
			anatop_val |= (anatop_val & 0x1f) << 18;
			__raw_writel(anatop_val, anatop_base + ANATOP_REG_CORE_OFFSET);
			__raw_writel(__raw_readl(MXC_CCM_CCR) | MXC_CCM_CCR_RBC_EN, MXC_CCM_CCR);
			ccm_clpcr |= MXC_CCM_CLPCR_WB_PER_AT_LPM;
		}
	}
	__raw_writel(ccm_clpcr, MXC_CCM_CLPCR);
}