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); }
static ssize_t bus_freq_scaling_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { if (strncmp(buf, "1", 1) == 0) { #ifdef CONFIG_MX6_VPU_352M if (cpu_is_mx6q()) /*do not enable bus freq*/ bus_freq_scaling_is_active = 0; printk(KERN_WARNING "Bus frequency can't be enabled if using VPU 352M!\n"); return size; #else bus_freq_scaling_is_active = 1; #endif set_high_bus_freq(0); /* Make sure system can enter low bus mode if it should be in low bus mode */ if (low_freq_bus_used() && !low_bus_freq_mode) set_low_bus_freq(); } else if (strncmp(buf, "0", 1) == 0) { if (bus_freq_scaling_is_active) set_high_bus_freq(1); bus_freq_scaling_is_active = 0; } return size; }
static void reduce_bus_freq_handler(struct work_struct *work) { mutex_lock(&bus_freq_mutex); if (!low_freq_bus_used()) { mutex_unlock(&bus_freq_mutex); return; } /* If we are already in audio bus freq mode, * just return if lp_audio_freq is true. */ if (audio_bus_freq_mode && lp_audio_freq) { mutex_unlock(&bus_freq_mutex); return; } /* If we dont want to transition from low bus to * audio bus mode and are already in *low bus mode, then return. */ if (!lp_audio_freq && low_bus_freq_mode) { mutex_unlock(&bus_freq_mutex); return; } reduce_bus_freq(); mutex_unlock(&bus_freq_mutex); }
static void dvfs_core_work_handler(struct work_struct *work) { u32 fsvai; u32 reg; u32 curr_cpu; int ret = 0; int maxf = 0, minf = 0; int low_freq_bus_ready = 0; int bus_incr = 0, cpu_dcr = 0; low_freq_bus_ready = low_freq_bus_used(); /* Check DVFS frequency adjustment interrupt status */ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); fsvai = (reg & MXC_DVFSCNTR_FSVAI_MASK) >> MXC_DVFSCNTR_FSVAI_OFFSET; /* Check FSVAI, FSVAI=0 is error */ if (fsvai == FSVAI_FREQ_NOCHANGE) { /* Do nothing. Freq change is not required */ goto END; } curr_cpu = clk_get_rate(cpu_clk); /* If FSVAI indicate freq down, check arm-clk is not in lowest frequency 200 MHz */ if (fsvai == FSVAI_FREQ_DECREASE) { if (curr_cpu == cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate) { minf = 1; if (low_bus_freq_mode) goto END; } else { /* freq down */ curr_wp++; if (curr_wp >= cpu_wp_nr) { curr_wp = cpu_wp_nr - 1; goto END; } if (curr_wp == cpu_wp_nr - 1 && !low_freq_bus_ready) { minf = 1; dvfs_load_config(1); } else { cpu_dcr = 1; } } } else { if (curr_cpu == cpu_wp_tbl[0].cpu_rate) { maxf = 1; goto END; } else { if (!high_bus_freq_mode) { /* bump up LP freq first. */ bus_incr = 1; dvfs_load_config(2); } else { /* freq up */ curr_wp = 0; maxf = 1; dvfs_load_config(0); } } } low_freq_bus_ready = low_freq_bus_used(); if ((curr_wp == cpu_wp_nr - 1) && (!low_bus_freq_mode) && (low_freq_bus_ready) && !bus_incr) { if (cpu_dcr) ret = set_cpu_freq(curr_wp); if (!cpu_dcr) { set_low_bus_freq(); dvfs_load_config(3); } else { dvfs_load_config(2); cpu_dcr = 0; } } else { if (!high_bus_freq_mode) set_high_bus_freq(1); if (!bus_incr) ret = set_cpu_freq(curr_wp); bus_incr = 0; } END: /* Set MAXF, MINF */ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); reg = (reg & ~(MXC_DVFSCNTR_MAXF_MASK | MXC_DVFSCNTR_MINF_MASK)); reg |= maxf << MXC_DVFSCNTR_MAXF_OFFSET; reg |= minf << MXC_DVFSCNTR_MINF_OFFSET; /* Enable DVFS interrupt */ /* FSVAIM=0 */ reg = (reg & ~MXC_DVFSCNTR_FSVAIM); reg |= FSVAI_FREQ_NOCHANGE; /* LBFL=1 */ reg = (reg & ~MXC_DVFSCNTR_LBFL); reg |= MXC_DVFSCNTR_LBFL; __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); /*Unmask GPC1 IRQ */ reg = __raw_readl(dvfs_data->gpc_cntr_reg_addr); reg &= ~MXC_GPCCNTR_GPCIRQM; __raw_writel(reg, dvfs_data->gpc_cntr_reg_addr); #if defined(CONFIG_CPU_FREQ) if (cpufreq_trig_needed == 1) { cpufreq_trig_needed = 0; cpufreq_update_policy(0); } #endif }
void bus_freq_update(struct clk *clk, bool flag) { mutex_lock(&bus_freq_mutex); if (flag) { if (clk == cpu_clk) { /* The CPU freq is being increased. * check if we need to increase the bus freq */ high_cpu_freq = 1; if (low_bus_freq_mode || audio_bus_freq_mode) set_high_bus_freq(0); } else { /* Update count */ if (clk->flags & AHB_HIGH_SET_POINT) lp_high_freq++; else if (clk->flags & AHB_MED_SET_POINT) lp_med_freq++; else if (clk->flags & AHB_AUDIO_SET_POINT) lp_audio_freq++; /* Update bus freq */ if ((clk->flags & CPU_FREQ_TRIG_UPDATE) && (clk_get_usecount(clk) == 0)) { if (!(clk->flags & (AHB_HIGH_SET_POINT | AHB_MED_SET_POINT))) { if (low_freq_bus_used()) set_low_bus_freq(); } else { if ((clk->flags & AHB_MED_SET_POINT) && !med_bus_freq_mode) { /* Set to Medium setpoint */ set_high_bus_freq(0); } else if ((clk->flags & AHB_HIGH_SET_POINT) && !high_bus_freq_mode) { /* Currently at low or medium * set point, need to set to * high setpoint */ set_high_bus_freq(1); } } } } } else { if (clk == cpu_clk) { /* CPU freq is dropped, check if we can * lower the bus freq. */ high_cpu_freq = 0; if (low_freq_bus_used() && !(low_bus_freq_mode || audio_bus_freq_mode)) set_low_bus_freq(); } else { /* Update count */ if (clk->flags & AHB_HIGH_SET_POINT) lp_high_freq--; else if (clk->flags & AHB_MED_SET_POINT) lp_med_freq--; else if (clk->flags & AHB_AUDIO_SET_POINT) lp_audio_freq--; /* Update bus freq */ if ((clk->flags & CPU_FREQ_TRIG_UPDATE) && (clk_get_usecount(clk) == 0)) { if (low_freq_bus_used()) set_low_bus_freq(); else { /* Set to either high or * medium setpoint. */ set_high_bus_freq(0); } } } } mutex_unlock(&bus_freq_mutex); return; }
static void dvfs_core_work_handler(struct work_struct *work) { u32 fsvai; u32 reg; u32 curr_cpu = 0; int ret = 0; int low_freq_bus_ready = 0; int bus_incr = 0, cpu_dcr = 0; #ifdef CONFIG_ARCH_MX5 int disable_dvfs_irq = 0; #endif int cpu; low_freq_bus_ready = low_freq_bus_used(); /* Check DVFS frequency adjustment interrupt status */ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); fsvai = (reg & MXC_DVFSCNTR_FSVAI_MASK) >> MXC_DVFSCNTR_FSVAI_OFFSET; /* Check FSVAI, FSVAI=0 is error */ if (fsvai == FSVAI_FREQ_NOCHANGE) { /* Do nothing. Freq change is not required */ goto END; } curr_cpu = clk_get_rate(cpu_clk); /* If FSVAI indicate freq down, check arm-clk is not in lowest frequency*/ if (fsvai == FSVAI_FREQ_DECREASE) { if (curr_cpu <= cpu_op_tbl[cpu_op_nr - 1].cpu_rate) { minf = 1; mutex_lock(&bus_freq_mutex); if (low_bus_freq_mode) { mutex_unlock(&bus_freq_mutex); goto END; } else mutex_unlock(&bus_freq_mutex); } else { /* freq down */ curr_op++; maxf = 0; if (curr_op >= cpu_op_nr) { curr_op = cpu_op_nr - 1; goto END; } cpu_dcr = 1; dvfs_load_config(curr_op); } } else { if (curr_cpu == cpu_op_tbl[0].cpu_rate) { maxf = 1; goto END; } else { mutex_lock(&bus_freq_mutex); if (!high_bus_freq_mode && dvfs_config_setpoint == (cpu_op_nr + 1)) { /* bump up LP freq first. */ bus_incr = 1; dvfs_load_config(cpu_op_nr); } else { /* freq up */ curr_op = 0; maxf = 1; minf = 0; dvfs_load_config(0); } mutex_unlock(&bus_freq_mutex); } } low_freq_bus_ready = low_freq_bus_used(); mutex_lock(&bus_freq_mutex); if ((curr_op == cpu_op_nr - 1) && (!low_bus_freq_mode) && (low_freq_bus_ready) && !bus_incr) { if (!minf) set_cpu_freq(curr_op); /* If dvfs_core_op is greater than cpu_op_nr, it implies * we support LPAPM mode for this platform. */ if (dvfs_core_op > cpu_op_nr) { set_low_bus_freq(); dvfs_load_config(cpu_op_nr + 1); } mutex_unlock(&bus_freq_mutex); } else { if (!high_bus_freq_mode) { mutex_unlock(&bus_freq_mutex); set_high_bus_freq(1); } else mutex_unlock(&bus_freq_mutex); if (!bus_incr) ret = set_cpu_freq(curr_op); bus_incr = 0; } END: if (cpufreq_trig_needed == 1) { /*Fix loops-per-jiffy */ #ifdef CONFIG_SMP for_each_online_cpu(cpu) per_cpu(cpu_data, cpu).loops_per_jiffy = dvfs_cpu_jiffies(per_cpu(cpu_data, cpu).loops_per_jiffy, curr_cpu / 1000, clk_get_rate(cpu_clk) / 1000); #else u32 old_loops_per_jiffy = loops_per_jiffy; loops_per_jiffy = dvfs_cpu_jiffies(old_loops_per_jiffy, curr_cpu/1000, clk_get_rate(cpu_clk) / 1000); #endif #if defined (CONFIG_CPU_FREQ) /* Fix CPU frequency for CPUFREQ. */ for (cpu = 0; cpu < num_online_cpus(); cpu++) cpufreq_get(cpu); #endif cpufreq_trig_needed = 0; } /* Set MAXF, MINF */ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); reg = (reg & ~(MXC_DVFSCNTR_MAXF_MASK | MXC_DVFSCNTR_MINF_MASK)); reg |= maxf << MXC_DVFSCNTR_MAXF_OFFSET; reg |= minf << MXC_DVFSCNTR_MINF_OFFSET; /* Enable DVFS interrupt */ /* FSVAIM=0 */ reg = (reg & ~MXC_DVFSCNTR_FSVAIM); reg |= FSVAI_FREQ_NOCHANGE; /* LBFL=1 */ reg = (reg & ~MXC_DVFSCNTR_LBFL); reg |= MXC_DVFSCNTR_LBFL; __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); /*Unmask GPC1 IRQ */ reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset); reg &= ~MXC_GPCCNTR_GPCIRQM; __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset); }
static void dvfs_core_work_handler(struct work_struct *work) { u32 fsvai; u32 reg; u32 curr_cpu; int ret = 0; int low_freq_bus_ready = 0; int bus_incr = 0, cpu_dcr = 0; unsigned long old_loops_per_jiffy; GALLEN_DBGLOCAL_BEGIN(); low_freq_bus_ready = low_freq_bus_used(); curr_cpu = clk_get_rate(cpu_clk); /* Check DVFS frequency adjustment interrupt status */ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); fsvai = (reg & MXC_DVFSCNTR_FSVAI_MASK) >> MXC_DVFSCNTR_FSVAI_OFFSET; /* Check FSVAI, FSVAI=0 is error */ if (fsvai == FSVAI_FREQ_NOCHANGE) { GALLEN_DBGLOCAL_RUNLOG(0); /* Do nothing. Freq change is not required */ goto END; } curr_cpu = clk_get_rate(cpu_clk); /* If FSVAI indicate freq down, check arm-clk is not in lowest frequency*/ if (fsvai == FSVAI_FREQ_DECREASE) { GALLEN_DBGLOCAL_RUNLOG(1); if (curr_cpu == cpu_wp_tbl[cpu_wp_nr - 1].cpu_rate) { GALLEN_DBGLOCAL_RUNLOG(2); minf = 1; if (low_bus_freq_mode) { GALLEN_DBGLOCAL_RUNLOG(3); goto END; } } else { GALLEN_DBGLOCAL_RUNLOG(4); /* freq down */ curr_wp++; maxf = 0; if (curr_wp >= cpu_wp_nr) { GALLEN_DBGLOCAL_RUNLOG(5); curr_wp = cpu_wp_nr - 1; goto END; } cpu_dcr = 1; dvfs_load_config(curr_wp); } } else { GALLEN_DBGLOCAL_RUNLOG(6); if (curr_cpu == cpu_wp_tbl[0].cpu_rate) { GALLEN_DBGLOCAL_RUNLOG(7); maxf = 1; goto END; } else { GALLEN_DBGLOCAL_RUNLOG(8); if (!high_bus_freq_mode && dvfs_config_setpoint == (cpu_wp_nr + 1)) { GALLEN_DBGLOCAL_RUNLOG(9); /* bump up LP freq first. */ bus_incr = 1; dvfs_load_config(cpu_wp_nr); } else { GALLEN_DBGLOCAL_RUNLOG(10); /* freq up */ curr_wp = 0; maxf = 1; minf = 0; dvfs_load_config(0); } } } low_freq_bus_ready = low_freq_bus_used(); if ((curr_wp == cpu_wp_nr - 1) && (!low_bus_freq_mode) && (low_freq_bus_ready) && !bus_incr) { GALLEN_DBGLOCAL_RUNLOG(11); if (!minf) { GALLEN_DBGLOCAL_RUNLOG(12); set_cpu_freq(curr_wp); } /* If dvfs_core_wp is greater than cpu_wp_nr, it implies * we support LPAPM mode for this platform. */ if (dvfs_core_wp > cpu_wp_nr) { GALLEN_DBGLOCAL_RUNLOG(13); set_low_bus_freq(); dvfs_load_config(cpu_wp_nr + 1); } } else { GALLEN_DBGLOCAL_RUNLOG(14); if (!high_bus_freq_mode) { GALLEN_DBGLOCAL_RUNLOG(15); set_high_bus_freq(1); } if (!bus_incr) { GALLEN_DBGLOCAL_RUNLOG(16); ret = set_cpu_freq(curr_wp); } bus_incr = 0; } printk("current wp=%d\n",curr_wp); if (cpufreq_trig_needed == 1) { GALLEN_DBGLOCAL_RUNLOG(17); /*Fix loops-per-jiffy */ old_loops_per_jiffy = loops_per_jiffy; loops_per_jiffy = dvfs_cpu_jiffies(old_loops_per_jiffy, curr_cpu/1000, clk_get_rate(cpu_clk) / 1000); #if defined(CONFIG_CPU_FREQ) /* Fix CPU frequency for CPUFREQ. */ cpufreq_get(0); #endif cpufreq_trig_needed = 0; } END: /* Set MAXF, MINF */ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); reg = (reg & ~(MXC_DVFSCNTR_MAXF_MASK | MXC_DVFSCNTR_MINF_MASK)); reg |= maxf << MXC_DVFSCNTR_MAXF_OFFSET; reg |= minf << MXC_DVFSCNTR_MINF_OFFSET; /* Enable DVFS interrupt */ /* FSVAIM=0 */ reg = (reg & ~MXC_DVFSCNTR_FSVAIM); reg |= FSVAI_FREQ_NOCHANGE; /* LBFL=1 */ reg = (reg & ~MXC_DVFSCNTR_LBFL); reg |= MXC_DVFSCNTR_LBFL; __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); /*Unmask GPC1 IRQ */ reg = __raw_readl(gpc_base + dvfs_data->gpc_cntr_offset); reg &= ~MXC_GPCCNTR_GPCIRQM; __raw_writel(reg, gpc_base + dvfs_data->gpc_cntr_offset); GALLEN_DBGLOCAL_END(); }