예제 #1
0
void arch_idle(void)
{
	if (enable_wait_mode) {
		mxc_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
		if (mem_clk_on_in_wait) {
			u32 reg;
			/*
			  * MX6SL, MX6Q (TO1.2 or later) and
			  * MX6DL (TO1.1 or later) have a bit in CCM_CGPR that
			  * when cleared keeps the clocks to memories ON
			  * when ARM is in WFI. This mode can be used when
			  * IPG clock is very low (12MHz) and the ARM:IPG ratio
			  * perhaps cannot be maintained.
			  */
			reg = __raw_readl(MXC_CCM_CGPR);
			reg &= ~MXC_CCM_CGPR_MEM_IPG_STOP_MASK;
			__raw_writel(reg, MXC_CCM_CGPR);

			ca9_do_idle();
		} else if (num_possible_cpus() == 1)
			/* iMX6SL or iMX6DLS */
			arch_idle_single_core();
		else
			arch_idle_multi_core();
	} else {
		mxc_cpu_lp_set(WAIT_CLOCKED);
		ca9_do_idle();
	}
}
예제 #2
0
void arch_idle(void)
{
	int cpu = smp_processor_id();

	if (enable_wait_mode) {
#ifdef CONFIG_LOCAL_TIMERS
		if (!tick_broadcast_oneshot_active()
			|| !tick_oneshot_mode_active())
			return;

		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
#endif
		if (enet_is_active)
			/* Don't allow the chip to enter WAIT mode if enet is active
			  * and the GPIO workaround for ENET interrupts is not used,
			  * since all ENET interrupts donot wake up the SOC.
			  */
			mxc_cpu_lp_set(WAIT_CLOCKED);
		else
			mxc_cpu_lp_set(WAIT_UNCLOCKED_POWER_OFF);
		if (mem_clk_on_in_wait) {
			u32 reg;
			/*
			  * MX6SL, MX6Q (TO1.2 or later) and
			  * MX6DL (TO1.1 or later) have a bit in
			  * CCM_CGPR that when cleared keeps the
			  * clocks to memories ON when ARM is in WFI.
			  * This mode can be used when IPG clock is
			  * very low (12MHz) and the ARM:IPG ratio
			  * perhaps cannot be maintained.
			  */
			reg = __raw_readl(MXC_CCM_CGPR);
			reg &= ~MXC_CCM_CGPR_MEM_IPG_STOP_MASK;
			__raw_writel(reg, MXC_CCM_CGPR);

			ca9_do_idle();
		} else if (num_possible_cpus() == 1)
			/* iMX6SL or iMX6DLS */
			arch_idle_single_core();
		else
			arch_idle_multi_core(cpu);
#ifdef CONFIG_LOCAL_TIMERS
		clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
#endif
	}  else {
		mxc_cpu_lp_set(WAIT_CLOCKED);
		ca9_do_idle();
	}
}
예제 #3
0
void arch_idle_multi_core(void)
{
	u32 reg;
	int cpu = smp_processor_id();

#ifdef CONFIG_LOCAL_TIMERS
	if (!tick_broadcast_oneshot_active()
		|| !tick_oneshot_mode_active())
		return;

	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
#endif
	/* iMX6Q and iMX6DL */
	if ((cpu_is_mx6q() && chip_rev >= IMX_CHIP_REVISION_1_2) ||
		(cpu_is_mx6dl() && chip_rev >= IMX_CHIP_REVISION_1_1)) {
		/*
		  * This code should only be executed on MX6QTO1.2 or later
		  * and MX6DL TO1.1 or later.
		  * These chips have the HW fix for the WAIT mode issue.
		  * Ensure that the CGPR bit 17 is set to enable the fix.
		  */

		reg = __raw_readl(MXC_CCM_CGPR);
		reg |= MXC_CCM_CGPR_WAIT_MODE_FIX;
		__raw_writel(reg, MXC_CCM_CGPR);

		ca9_do_idle();
	} else
		arch_idle_with_workaround(cpu);
#ifdef CONFIG_LOCAL_TIMERS
	clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
#endif

}
예제 #4
0
void arch_idle_multi_core(int cpu)
{
	u32 reg;

	/* iMX6Q and iMX6DL */
	if ((cpu_is_mx6q() && chip_rev >= IMX_CHIP_REVISION_1_2) ||
		(cpu_is_mx6dl() && chip_rev >= IMX_CHIP_REVISION_1_1)) {
		/*
		  * This code should only be executed on MX6QTO1.2 or later
		  * and MX6DL TO1.1 or later.
		  * These chips have the HW fix for the WAIT mode issue.
		  * Ensure that the CGPR bit 17 is set to enable the fix.
		  */

		reg = __raw_readl(MXC_CCM_CGPR);
		reg |= MXC_CCM_CGPR_WAIT_MODE_FIX;
		__raw_writel(reg, MXC_CCM_CGPR);

		ca9_do_idle();
	} else
		arch_idle_with_workaround(cpu);
}
예제 #5
0
void arch_idle_single_core(void)
{
	u32 reg;

	if (cpu_is_mx6dl() && chip_rev > IMX_CHIP_REVISION_1_0) {
		/*
		  * MX6DLS TO1.1 has the HW fix for the WAIT mode issue.
		  * Ensure that the CGPR bit 17 is set to enable the fix.
		  */
		reg = __raw_readl(MXC_CCM_CGPR);
		reg |= MXC_CCM_CGPR_WAIT_MODE_FIX;
		__raw_writel(reg, MXC_CCM_CGPR);

		ca9_do_idle();
	} else {
		if (low_bus_freq_mode || audio_bus_freq_mode) {
			int ddr_usecount = 0;
			if ((mmdc_ch0_axi != NULL))
				ddr_usecount = clk_get_usecount(mmdc_ch0_axi);

			if (cpu_is_mx6sl() && low_bus_freq_mode
				&& ddr_usecount == 1) {
				/* In this mode PLL2 i already in bypass,
				  * ARM is sourced from PLL1. The code in IRAM
				  * will set ARM to be sourced from STEP_CLK
				  * at 24MHz. It will also set DDR to 1MHz to
				  * reduce power.
				  */
				u32 org_arm_podf = __raw_readl(MXC_CCM_CACRR);

				/* Need to run WFI code from IRAM so that
				  * we can lower DDR freq.
				  */
				mx6sl_wfi_iram(org_arm_podf,
					(unsigned long)mx6sl_wfi_iram_base);
			} else {
				/* Need to set ARM to run at 24MHz since IPG
				  * is at 12MHz. This is valid for audio mode on
				  * MX6SL, and all low power modes on MX6DLS.
				  */
				if (cpu_is_mx6sl() && low_bus_freq_mode) {
					/* ARM is from PLL1, need to switch to
					  * STEP_CLK sourced from 24MHz.
					  */
					/* Swtich STEP_CLK to 24MHz. */
					reg = __raw_readl(MXC_CCM_CCSR);
					reg &= ~MXC_CCM_CCSR_STEP_SEL;
					__raw_writel(reg, MXC_CCM_CCSR);
					/* Set PLL1_SW_CLK to be from
					  *STEP_CLK.
					  */
					reg = __raw_readl(MXC_CCM_CCSR);
					reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL;
					__raw_writel(reg, MXC_CCM_CCSR);

				} else {
					/* PLL1_SW_CLK is sourced from
					  * PLL2_PFD2_400MHz at this point.
					  * Move it to bypassed PLL1.
					  */
					reg = __raw_readl(MXC_CCM_CCSR);
					reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL;
					__raw_writel(reg, MXC_CCM_CCSR);
				}
				ca9_do_idle();

				if (cpu_is_mx6sl() && low_bus_freq_mode) {
					/* Set PLL1_SW_CLK to be from PLL1 */
					reg = __raw_readl(MXC_CCM_CCSR);
					reg &= ~MXC_CCM_CCSR_PLL1_SW_CLK_SEL;
					__raw_writel(reg, MXC_CCM_CCSR);
				} else {
					reg |= MXC_CCM_CCSR_PLL1_SW_CLK_SEL;
					__raw_writel(reg, MXC_CCM_CCSR);
				}
			}
		} else {
			/*
			  * Implement the 12:5 ARM:IPG_CLK ratio
			  * workaround for the WAIT mode issue.
			  * We can directly use the divider to drop the ARM
			  * core freq in a single core environment.
			  *  Set the ARM_PODF to get the max freq possible
			  * to avoid the WAIT mode issue when IPG is at 66MHz.
			  */
			__raw_writel(wait_mode_arm_podf, MXC_CCM_CACRR);
			while (__raw_readl(MXC_CCM_CDHIPR))
				;
			ca9_do_idle();

			__raw_writel(cur_arm_podf - 1, MXC_CCM_CACRR);
		}
	}
}