static int __init busfreq_init(void) { if (platform_driver_register(&busfreq_driver) != 0) { printk(KERN_ERR "busfreq_driver register failed\n"); return -ENODEV; } printk(KERN_INFO "Bus freq driver module loaded\n"); #ifdef CONFIG_MX6_VPU_352M if (cpu_is_mx6q()) bus_freq_scaling_is_active = 0;/*disable bus_freq*/ #else /* Enable busfreq by default. */ bus_freq_scaling_is_active = 1; #endif if (cpu_is_mx6q()) set_high_bus_freq(1); else if (cpu_is_mx6dl()) set_high_bus_freq(0); printk(KERN_INFO "Bus freq driver Enabled\n"); return 0; }
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 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) { bus_freq_scaling_is_active = 1; set_high_bus_freq(0); } 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 int busfreq_suspend(struct platform_device *pdev, pm_message_t message) { if (low_bus_freq_mode) set_high_bus_freq(1); busfreq_suspended = 1; return 0; }
/*! * This function disables the DVFS module. */ void stop_dvfs(void) { u32 reg = 0; unsigned long flags; u32 curr_cpu; unsigned long old_loops_per_jiffy; if (dvfs_core_is_active) { /* Mask dvfs irq, disable DVFS */ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); /* FSVAIM=1 */ reg |= MXC_DVFSCNTR_FSVAIM; __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); curr_wp = 0; if (!high_bus_freq_mode) set_high_bus_freq(1); curr_cpu = clk_get_rate(cpu_clk); if (curr_cpu != cpu_wp_tbl[curr_wp].cpu_rate) set_cpu_freq(curr_wp); if (cpufreq_trig_needed == 1) { /*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; } spin_lock_irqsave(&mxc_dvfs_core_lock, flags); reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); reg = (reg & ~MXC_DVFSCNTR_DVFEN); __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); spin_unlock_irqrestore(&mxc_dvfs_core_lock, flags); dvfs_core_is_active = 0; clk_disable(dvfs_clk); } printk(KERN_DEBUG "DVFS is stopped\n"); }
static int bus_freq_pm_notify(struct notifier_block *nb, unsigned long event, void *dummy) { mutex_lock(&bus_freq_mutex); if (event == PM_SUSPEND_PREPARE) { set_high_bus_freq(1); busfreq_suspended = 1; } else if (event == PM_POST_SUSPEND) { busfreq_suspended = 0; } mutex_unlock(&bus_freq_mutex); return NOTIFY_OK; }
/*! * This function disables the DVFS module. */ void stop_dvfs(void) { u32 reg = 0; unsigned long flags; u32 curr_cpu; if (dvfs_core_is_active) { /* Mask dvfs irq, disable DVFS */ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); /* FSVAIM=1 */ reg |= MXC_DVFSCNTR_FSVAIM; __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); curr_wp = 0; if (!high_bus_freq_mode) set_high_bus_freq(1); curr_cpu = clk_get_rate(cpu_clk); if (curr_cpu != cpu_wp_tbl[curr_wp].cpu_rate) { set_cpu_freq(curr_wp); #if defined(CONFIG_CPU_FREQ) if (cpufreq_trig_needed == 1) { cpufreq_trig_needed = 0; cpufreq_update_policy(0); } #endif } spin_lock_irqsave(&mxc_dvfs_core_lock, flags); reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); reg = (reg & ~MXC_DVFSCNTR_DVFEN); __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); spin_unlock_irqrestore(&mxc_dvfs_core_lock, flags); dvfs_core_is_active = 0; clk_disable(dvfs_clk); } printk(KERN_DEBUG "DVFS is stopped\n"); }
static ssize_t bus_freq_scaling_enable_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { u32 reg; if (strncmp(buf, "1", 1) == 0) { if (dvfs_per_active()) { printk(KERN_INFO "bus frequency scaling cannot be\ enabled when DVFS-PER is active\n"); return size; } if (!cpu_is_mx50()) { /* Initialize DVFS-PODF to 0. */ reg = __raw_readl(MXC_CCM_CDCR); reg &= ~MXC_CCM_CDCR_PERIPH_CLK_DVFS_PODF_MASK; __raw_writel(reg, MXC_CCM_CDCR); clk_set_parent(main_bus_clk, pll2); } bus_freq_scaling_is_active = 1; set_high_bus_freq(0); } else if (strncmp(buf, "0", 1) == 0) {
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; }
/*! * This function disables the DVFS module. */ void stop_dvfs(void) { u32 reg = 0; unsigned long flags; u32 curr_cpu; int cpu; #ifndef CONFIG_SMP unsigned long old_loops_per_jiffy; #endif if (dvfs_core_is_active) { /* Mask dvfs irq, disable DVFS */ reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); /* FSVAIM=1 */ reg |= MXC_DVFSCNTR_FSVAIM; __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); curr_op = 0; mutex_lock(&bus_freq_mutex); if (!high_bus_freq_mode) { mutex_unlock(&bus_freq_mutex); set_high_bus_freq(1); } else mutex_unlock(&bus_freq_mutex); curr_cpu = clk_get_rate(cpu_clk); if (curr_cpu != cpu_op_tbl[curr_op].cpu_rate) { set_cpu_freq(curr_op); /*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 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 } spin_lock_irqsave(&mxc_dvfs_core_lock, flags); reg = __raw_readl(dvfs_data->membase + MXC_DVFSCORE_CNTR); reg = (reg & ~MXC_DVFSCNTR_DVFEN); __raw_writel(reg, dvfs_data->membase + MXC_DVFSCORE_CNTR); spin_unlock_irqrestore(&mxc_dvfs_core_lock, flags); dvfs_core_is_active = 0; clk_disable(dvfs_clk); } printk(KERN_DEBUG "DVFS is stopped\n"); }
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(); }