summaryrefslogtreecommitdiff
path: root/arch/arm/plat-mxc/dvfs_core.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-mxc/dvfs_core.c')
-rw-r--r--arch/arm/plat-mxc/dvfs_core.c74
1 files changed, 60 insertions, 14 deletions
diff --git a/arch/arm/plat-mxc/dvfs_core.c b/arch/arm/plat-mxc/dvfs_core.c
index dca974df45be..52cfc5686194 100644
--- a/arch/arm/plat-mxc/dvfs_core.c
+++ b/arch/arm/plat-mxc/dvfs_core.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2012 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -114,6 +114,7 @@ static struct delayed_work dvfs_core_handler;
*/
static struct clk *pll1_sw_clk;
static struct clk *cpu_clk;
+static struct clk *gpu_clk;
static struct clk *dvfs_clk;
static int cpu_op_nr;
@@ -189,6 +190,7 @@ static int mx5_set_cpu_freq(int op)
int podf;
int vinc = 0;
int ret = 0;
+ int retry_count = 0;
int org_cpu_rate;
unsigned long rate = 0;
int gp_volt = 0;
@@ -276,6 +278,15 @@ static int mx5_set_cpu_freq(int op)
podf = cpu_op_tbl[op].cpu_podf;
gp_volt = cpu_op_tbl[op].cpu_voltage;
+ /* Get ARM_PODF */
+ reg = __raw_readl(ccm_base + dvfs_data->ccm_cacrr_offset);
+ arm_podf = reg & 0x07;
+ if (podf == arm_podf) {
+ printk(KERN_DEBUG
+ "No need to change freq and voltage!!!!\n");
+ return 0;
+ }
+
/* Change arm_podf only */
/* set ARM_FREQ_SHIFT_DIVIDER */
reg = __raw_readl(ccm_base + dvfs_data->ccm_cdcr_offset);
@@ -290,14 +301,6 @@ static int mx5_set_cpu_freq(int op)
reg |= CCM_CDCR_ARM_FREQ_SHIFT_DIVIDER;
__raw_writel(reg, ccm_base + dvfs_data->ccm_cdcr_offset);
- /* Get ARM_PODF */
- reg = __raw_readl(ccm_base + dvfs_data->ccm_cacrr_offset);
- arm_podf = reg & 0x07;
- if (podf == arm_podf) {
- printk(KERN_DEBUG
- "No need to change freq and voltage!!!!\n");
- return 0;
- }
/* Check if FSVAI indicate freq up */
if (podf < arm_podf) {
ret = regulator_set_voltage(cpu_regulator, gp_volt,
@@ -355,7 +358,10 @@ static int mx5_set_cpu_freq(int op)
/* Wait for arm podf Enable */
while ((__raw_readl(gpc_base + dvfs_data->gpc_cntr_offset) &
MXC_GPCCNTR_STRT) == MXC_GPCCNTR_STRT) {
- printk(KERN_DEBUG "Waiting arm_podf enabled!\n");
+ if (retry_count)
+ printk(KERN_DEBUG "Waiting arm_podf enabled!\n");
+
+ retry_count++;
udelay(10);
}
spin_unlock_irqrestore(&mxc_dvfs_core_lock, flags);
@@ -577,6 +583,7 @@ static irqreturn_t dvfs_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+extern int clk_get_usecount(struct clk *clk);
static void dvfs_core_work_handler(struct work_struct *work)
{
u32 fsvai;
@@ -584,8 +591,11 @@ static void dvfs_core_work_handler(struct work_struct *work)
u32 curr_cpu = 0;
int ret = 0;
int low_freq_bus_ready = 0;
+ int disable_dvfs_irq = 0;
int bus_incr = 0, cpu_dcr = 0;
+#ifdef CONFIG_CPU_FREQ
int cpu;
+#endif
low_freq_bus_ready = low_freq_bus_used();
@@ -598,6 +608,29 @@ static void dvfs_core_work_handler(struct work_struct *work)
goto END;
}
curr_cpu = clk_get_rate(cpu_clk);
+
+ if (clk_get_usecount(gpu_clk)) {
+ maxf = 1;
+ if (curr_cpu != cpu_op_tbl[0].cpu_rate) {
+ curr_op = 0;
+ minf = 0;
+ dvfs_load_config(0);
+ if (!high_bus_freq_mode)
+ set_high_bus_freq(1);
+ set_cpu_freq(curr_op);
+ }
+ /* If we enable DVFS's irq, the irq will keep coming,
+ * and will consume about 3-40% cpu usage, we disable
+ * dvfs 's irq here, and let it check the status every
+ * 100 msecs. If gpu clk have count to 0, it will
+ * enable dvfs's irq let it do what it want.*/
+ schedule_delayed_work(&dvfs_core_handler,
+ msecs_to_jiffies(100));
+ disable_dvfs_irq = 1;
+ goto END;
+ } else
+ disable_dvfs_irq = 0;
+
/* If FSVAI indicate freq down,
check arm-clk is not in lowest frequency*/
if (fsvai == FSVAI_FREQ_DECREASE) {
@@ -687,8 +720,10 @@ END:
/* Enable DVFS interrupt */
/* FSVAIM=0 */
- reg = (reg & ~MXC_DVFSCNTR_FSVAIM);
- reg |= FSVAI_FREQ_NOCHANGE;
+ if (!disable_dvfs_irq) {
+ reg = (reg & ~MXC_DVFSCNTR_FSVAIM);
+ reg |= FSVAI_FREQ_NOCHANGE;
+ }
/* LBFL=1 */
reg = (reg & ~MXC_DVFSCNTR_LBFL);
reg |= MXC_DVFSCNTR_LBFL;
@@ -709,7 +744,10 @@ void stop_dvfs(void)
u32 reg = 0;
unsigned long flags;
u32 curr_cpu;
+ u32 old_loops_per_jiffy;
+#ifdef CONFIG_CPU_FREQ
int cpu;
+#endif
if (dvfs_core_is_active) {
@@ -736,7 +774,7 @@ void stop_dvfs(void)
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;
+ old_loops_per_jiffy = loops_per_jiffy;
loops_per_jiffy =
dvfs_cpu_jiffies(old_loops_per_jiffy,
@@ -948,9 +986,17 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev)
return PTR_ERR(cpu_clk);
}
if (!cpu_is_mx6q()) {
+ gpu_clk = clk_get(NULL, "gpu3d_clk");
+ if (IS_ERR(cpu_clk)) {
+ printk(KERN_ERR "%s: failed to get gpu clock\n",
+ __func__);
+ return PTR_ERR(gpu_clk);
+ }
+
dvfs_clk = clk_get(NULL, dvfs_data->clk2_id);
if (IS_ERR(dvfs_clk)) {
- printk(KERN_ERR "%s: failed to get dvfs clock\n", __func__);
+ printk(KERN_ERR "%s: failed to get dvfs clock\n",
+ __func__);
return PTR_ERR(dvfs_clk);
}
}