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(); } }
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(); } }
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 }
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); }
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); } } }