static void reduce_bus_freq_handler(struct work_struct *work) { unsigned long reg; if (low_bus_freq_mode || !low_freq_bus_used()) return; if (audio_bus_freq_mode && lp_audio_freq) return; while (!mutex_trylock(&bus_freq_mutex)) msleep(1); /* PLL3 is used in the DDR freq change process, enable it. */ if (low_bus_freq_mode || !low_freq_bus_used()) { mutex_unlock(&bus_freq_mutex); return; } if (audio_bus_freq_mode && lp_audio_freq) { mutex_unlock(&bus_freq_mutex); return; } clk_enable(pll3); if (lp_audio_freq) { /* Need to ensure that PLL2_PFD_400M is kept ON. */ clk_enable(pll2_400); update_ddr_freq(50000000); audio_bus_freq_mode = 1; low_bus_freq_mode = 0; } else { update_ddr_freq(24000000); if (audio_bus_freq_mode) clk_disable(pll2_400); low_bus_freq_mode = 1; audio_bus_freq_mode = 0; } if (med_bus_freq_mode) clk_disable(pll2_400); high_bus_freq_mode = 0; med_bus_freq_mode = 0; if (cpu_is_mx6q()) { /* Power gate the PU LDO. */ org_ldo = reg = __raw_readl(ANADIG_REG_CORE); reg &= ~(ANADIG_REG_TARGET_MASK << ANADIG_REG1_PU_TARGET_OFFSET); __raw_writel(reg, ANADIG_REG_CORE); } clk_disable(pll3); mutex_unlock(&bus_freq_mutex); }
/* Set the DDR to either 528MHz or 400MHz for MX6q * or 400MHz for MX6DL. */ int set_high_bus_freq(int high_bus_freq) { if (busfreq_suspended) return 0; if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active) return 0; if (high_bus_freq_mode && high_bus_freq) return 0; if (med_bus_freq_mode && !high_bus_freq) return 0; while (!mutex_trylock(&bus_freq_mutex)) msleep(1); if ((high_bus_freq_mode && (high_bus_freq || lp_high_freq)) || (med_bus_freq_mode && !high_bus_freq && lp_med_freq && !lp_high_freq)) { mutex_unlock(&bus_freq_mutex); return 0; } clk_enable(pll3); /* Enable the PU LDO */ if (cpu_is_mx6q() && low_bus_freq_mode) __raw_writel(org_ldo, ANADIG_REG_CORE); if (high_bus_freq) { update_ddr_freq(ddr_normal_rate); if (med_bus_freq_mode) clk_disable(pll2_400); high_bus_freq_mode = 1; med_bus_freq_mode = 0; } else { clk_enable(pll2_400); update_ddr_freq(ddr_med_rate); high_bus_freq_mode = 0; med_bus_freq_mode = 1; } if (audio_bus_freq_mode) clk_disable(pll2_400); low_bus_freq_mode = 0; audio_bus_freq_mode = 0; low_bus_freq_mode = 0; clk_disable(pll3); mutex_unlock(&bus_freq_mutex); return 0; }
void set_ddr_freq(int ddr_rate) { unsigned long flags; unsigned int ret = 0; spin_lock_irqsave(&ddr_freq_lock, flags); if (cpu_is_mx50()) ret = update_ddr_freq(ddr_rate); #if 1 { unsigned int reg; printk(KERN_NOTICE "set_ddr_freq ddr_rate =%d ret = %d \n",ddr_rate, ret); reg = __raw_readl(MXC_CCM_CLK_DDR); printk(KERN_NOTICE "after ddr divider = 0x%x \n",reg&0x3f); } #endif spin_unlock_irqrestore(&ddr_freq_lock, flags); if (!ret) cur_ddr_rate = ddr_rate; udelay(100); }
void set_ddr_freq(int ddr_rate) { unsigned long flags; unsigned int ret = 0; spin_lock_irqsave(&ddr_freq_lock, flags); if (cpu_is_mx50()) ret = update_ddr_freq(ddr_rate); spin_unlock_irqrestore(&ddr_freq_lock, flags); if (!ret) cur_ddr_rate = ddr_rate; udelay(100); }
/* Set the DDR to either 528MHz or 400MHz for MX6q * or 400MHz for MX6DL. */ int set_high_bus_freq(int high_bus_freq) { if (bus_freq_scaling_initialized && bus_freq_scaling_is_active) cancel_delayed_work_sync(&low_bus_freq_handler); if (busfreq_suspended) return 0; if (!bus_freq_scaling_initialized || !bus_freq_scaling_is_active) return 0; if (cpu_is_mx6sl()) high_bus_freq = 1; if (high_bus_freq_mode && high_bus_freq) return 0; /* medium bus freq is only supported for MX6DQ */ if (cpu_is_mx6q() && med_bus_freq_mode && !high_bus_freq) return 0; if (cpu_is_mx6dl() && high_bus_freq) high_bus_freq = 0; if (cpu_is_mx6dl() && med_bus_freq_mode) return 0; if ((high_bus_freq_mode && (high_bus_freq || lp_high_freq)) || (med_bus_freq_mode && !high_bus_freq && lp_med_freq && !lp_high_freq)) return 0; if (cpu_is_mx6sl()) { u32 reg; unsigned long flags; u32 ttbr1; spin_lock_irqsave(&freq_lock, flags); /* sync the outer cache. */ outer_sync(); ttbr1 = save_ttbr1(); /* Change DDR freq in IRAM. */ mx6sl_ddr_freq_change_iram(ddr_normal_rate, low_bus_freq_mode); restore_ttbr1(ttbr1); spin_unlock_irqrestore(&freq_lock, flags); /* Set periph_clk to be sourced from pll2_pfd2_400M */ /* First need to set the divider before changing the */ /* parent if parent clock is larger than previous one */ clk_set_rate(ahb_clk, clk_round_rate(ahb_clk, LPAPM_CLK / 3)); clk_set_rate(axi_clk, clk_round_rate(axi_clk, LPAPM_CLK / 2)); clk_set_parent(periph_clk, pll2_400); if (low_bus_freq_mode) { /* Now move ARM to be sourced from PLL2_400 too. */ clk_set_parent(pll1_sw_clk, pll2_400); /* Ensure that the clock will be at original speed. */ reg = __raw_writel(org_arm_podf, MXC_CCM_CACRR); while (__raw_readl(MXC_CCM_CDHIPR)) ; clk_disable(pll1); } high_bus_freq_mode = 1; low_bus_freq_mode = 0; audio_bus_freq_mode = 0; } else { clk_enable(pll3); if (high_bus_freq) { update_ddr_freq(ddr_normal_rate); /* Make sure periph clk's parent also got updated */ clk_set_parent(periph_clk, pll2); if (med_bus_freq_mode) clk_disable(pll2_400); high_bus_freq_mode = 1; med_bus_freq_mode = 0; } else { clk_enable(pll2_400); update_ddr_freq(ddr_med_rate); /* Make sure periph clk's parent also got updated */ clk_set_parent(periph_clk, pll2_400); high_bus_freq_mode = 0; med_bus_freq_mode = 1; } if (audio_bus_freq_mode) clk_disable(pll2_400); /* AXI_CLK is sourced from PLL3_PFD_540 on MX6DL */ if (cpu_is_mx6dl() && clk_get_parent(axi_clk) != pll3_540) clk_set_parent(axi_clk, pll3_540); low_bus_freq_mode = 0; audio_bus_freq_mode = 0; clk_disable(pll3); } return 0; }
void reduce_bus_freq(void) { if (!cpu_is_mx6sl()) { if (cpu_is_mx6dl() && (clk_get_parent(axi_clk) != periph_clk)) /* Set the axi_clk to be sourced from the periph_clk. * So that its frequency can be lowered down to 50MHz * or 24MHz as the case may be. */ clk_set_parent(axi_clk, periph_clk); clk_enable(pll3); if (lp_audio_freq) { /* Need to ensure that PLL2_PFD_400M is kept ON. */ clk_enable(pll2_400); update_ddr_freq(DDR_AUDIO_CLK); /* Make sure periph clk's parent also got updated */ clk_set_parent(periph_clk, pll2_200); audio_bus_freq_mode = 1; low_bus_freq_mode = 0; } else { update_ddr_freq(LPAPM_CLK); /* Make sure periph clk's parent also got updated */ clk_set_parent(periph_clk, osc_clk); if (audio_bus_freq_mode) clk_disable(pll2_400); low_bus_freq_mode = 1; audio_bus_freq_mode = 0; } if (med_bus_freq_mode) clk_disable(pll2_400); clk_disable(pll3); med_bus_freq_mode = 0; } else { u32 reg; u32 div; unsigned long flags; if (high_bus_freq_mode) { /* Set periph_clk to be sourced from OSC_CLK */ /* Set AXI to 24MHz. */ clk_set_parent(periph_clk, osc_clk); clk_set_rate(axi_clk, clk_round_rate(axi_clk, LPAPM_CLK)); /* Set AHB to 24MHz. */ clk_set_rate(ahb_clk, clk_round_rate(ahb_clk, LPAPM_CLK)); } if (lp_audio_freq) { u32 ttbr1; /* PLL2 is on in this mode, as DDR is at 100MHz. */ /* Now change DDR freq while running from IRAM. */ /* Set AHB to 24MHz. */ clk_set_rate(ahb_clk, clk_round_rate(ahb_clk, LPAPM_CLK / 3)); spin_lock_irqsave(&freq_lock, flags); /* sync the outer cache. */ outer_sync(); /* Save TTBR1 */ ttbr1 = save_ttbr1(); mx6sl_ddr_freq_change_iram(DDR_AUDIO_CLK, low_bus_freq_mode); restore_ttbr1(ttbr1); spin_unlock_irqrestore(&freq_lock, flags); if (low_bus_freq_mode) { /* Swtich ARM to run off PLL2_PFD2_400MHz * since DDR is anyway at 100MHz. */ clk_set_parent(pll1_sw_clk, pll2_400); /* Ensure that the clock will be * at original speed. */ reg = __raw_writel(org_arm_podf, MXC_CCM_CACRR); while (__raw_readl(MXC_CCM_CDHIPR)) ; /* We have enabled PLL1 in the code below when * ARM is from PLL1, so disable it here. */ clk_disable(pll1); } low_bus_freq_mode = 0; audio_bus_freq_mode = 1; } else { u32 ttbr1; /* Set MMDC clk to 24MHz. */ /* Since we are going to set PLL2 in bypass mode, * move the CPU clock off PLL2. */ /* Ensure that the clock will be at * lowest possible freq. */ org_arm_podf = __raw_readl(MXC_CCM_CACRR); /* Need to enable PLL1 before setting its rate. */ clk_enable(pll1); clk_set_rate(pll1, cpu_op_tbl[cpu_op_nr - 1].pll_lpm_rate); div = clk_get_rate(pll1) / cpu_op_tbl[cpu_op_nr - 1].cpu_rate; reg = __raw_writel(div - 1, MXC_CCM_CACRR); while (__raw_readl(MXC_CCM_CDHIPR)) ; clk_set_parent(pll1_sw_clk, pll1); spin_lock_irqsave(&freq_lock, flags); /* sync the outer cache. */ outer_sync(); ttbr1 = save_ttbr1(); /* Now change DDR freq while running from IRAM. */ mx6sl_ddr_freq_change_iram(LPAPM_CLK, low_bus_freq_mode); restore_ttbr1(ttbr1); spin_unlock_irqrestore(&freq_lock, flags); low_bus_freq_mode = 1; audio_bus_freq_mode = 0; } } high_bus_freq_mode = 0; }