[PATCH 38/133] [Jaunty SRU] ARM.imx51 Freescale:ENGR00109146 DVFS: System can not go to APM if DVFS core is enabled

Brad Figg brad.figg at canonical.com
Thu Jul 9 16:48:28 UTC 2009


DVFS: System can not go to Audio playback mode if DVFS core is enabled.

Signed-off-by: Nancy Chen <Nancy.Chen at freescale.com>
Signed-off-by: Brad Figg <brad.figg at canonical.com>
---
 arch/arm/mach-mx51/Makefile   |    2 +-
 arch/arm/mach-mx51/clock.c    |    5 +
 arch/arm/mach-mx51/devices.c  |   14 ++
 arch/arm/plat-mxc/clock.c     |   35 ++++-
 arch/arm/plat-mxc/cpufreq.c   |  336 +++--------------------------------------
 arch/arm/plat-mxc/dvfs_core.c |  188 +++++++++++++++--------
 6 files changed, 199 insertions(+), 381 deletions(-)

diff --git a/arch/arm/mach-mx51/Makefile b/arch/arm/mach-mx51/Makefile
index 8ff16da..37f49ea 100644
--- a/arch/arm/mach-mx51/Makefile
+++ b/arch/arm/mach-mx51/Makefile
@@ -5,7 +5,7 @@
 # Object file lists.
 
 
-obj-y   := system.o iomux.o cpu.o mm.o clock.o devices.o serial.o dma.o lpmodes.o pm.o
+obj-y   := system.o iomux.o cpu.o mm.o clock.o devices.o serial.o dma.o lpmodes.o pm.o bus_freq.o
 
 obj-y += dummy_gpio.o
 
diff --git a/arch/arm/mach-mx51/clock.c b/arch/arm/mach-mx51/clock.c
index 375224e..878d413 100644
--- a/arch/arm/mach-mx51/clock.c
+++ b/arch/arm/mach-mx51/clock.c
@@ -50,6 +50,7 @@ static struct cpu_wp *cpu_wp_tbl;
 int cpu_wp_nr;
 
 extern int mxc_jtag_enabled;
+extern int cpufreq_trig_needed;
 
 static int cpu_clk_set_wp(int wp);
 extern void propagate_rate(struct clk *tclk);
@@ -3103,6 +3104,10 @@ static int cpu_clk_set_wp(int wp)
 		pll1_main_clk.rate = pll1_sw_clk.rate;
 		cpu_clk.rate = pll1_sw_clk.rate;
 	}
+
+#if defined(CONFIG_CPU_FREQ)
+	cpufreq_trig_needed = 1;
+#endif
 	return 0;
 }
 
diff --git a/arch/arm/mach-mx51/devices.c b/arch/arm/mach-mx51/devices.c
index f882174..ab86d1f 100644
--- a/arch/arm/mach-mx51/devices.c
+++ b/arch/arm/mach-mx51/devices.c
@@ -896,6 +896,19 @@ static inline void mx51_init_lpmode(void)
 	(void)platform_device_register(&mx51_lpmode_device);
 }
 
+static struct platform_device busfreq_device = {
+	.name = "busfreq",
+	.id = 0,
+	.dev = {
+		.release = mxc_nop_release,
+		},
+};
+
+static inline void mxc_init_busfreq(void)
+{
+	(void)platform_device_register(&busfreq_device);
+}
+
 #if defined(CONFIG_MXC_IIM) || defined(CONFIG_MXC_IIM_MODULE)
 static struct resource mxc_iim_resources[] = {
 	{
@@ -942,6 +955,7 @@ int __init mxc_init_devices(void)
 	mxc_init_spdif();
 	mxc_init_tve();
 	mx51_init_lpmode();
+	mxc_init_busfreq();
 	mxc_init_dvfs();
 	mxc_init_iim();
 	return 0;
diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c
index b55a03f..c15386c 100644
--- a/arch/arm/plat-mxc/clock.c
+++ b/arch/arm/plat-mxc/clock.c
@@ -41,6 +41,16 @@
 
 #include <mach/clock.h>
 
+#if (defined(CONFIG_ARCH_MX51) || defined(CONFIG_ARCH_MX37))
+extern int dvfs_core_is_active;
+extern void dvfs_core_set_bus_freq(void);
+#else
+int dvfs_core_is_active;
+void dvfs_core_set_bus_freq(void)
+{
+};
+#endif
+
 static LIST_HEAD(clocks);
 static DEFINE_MUTEX(clocks_mutex);
 static DEFINE_SPINLOCK(clockfw_lock);
@@ -159,11 +169,18 @@ int clk_enable(struct clk *clk)
 
 	spin_unlock_irqrestore(&clockfw_lock, flags);
 
-#if defined(CONFIG_CPU_FREQ)
 	if ((clk->flags & CPU_FREQ_TRIG_UPDATE)
-	    && (clk_get_usecount(clk) == 1))
-		cpufreq_update_policy(0);
+	    && (clk_get_usecount(clk) == 1)) {
+#if defined(CONFIG_CPU_FREQ)
+		if (dvfs_core_is_active)
+			dvfs_core_set_bus_freq();
+		else
+			cpufreq_update_policy(0);
+#else
+		if (dvfs_core_is_active)
+			dvfs_core_set_bus_freq();
 #endif
+	}
 	return ret;
 }
 EXPORT_SYMBOL(clk_enable);
@@ -185,12 +202,20 @@ void clk_disable(struct clk *clk)
 
 	spin_unlock_irqrestore(&clockfw_lock, flags);
 
-#if defined(CONFIG_CPU_FREQ)
 	if ((clk->flags & CPU_FREQ_TRIG_UPDATE)
-	    && (clk_get_usecount(clk) == 0))
+	    && (clk_get_usecount(clk) == 0)) {
+#if defined(CONFIG_CPU_FREQ)
+		if (dvfs_core_is_active)
+			dvfs_core_set_bus_freq();
+		else
 		cpufreq_update_policy(0);
+#else
+		if (dvfs_core_is_active)
+			dvfs_core_set_bus_freq();
 #endif
+	}
 }
+
 EXPORT_SYMBOL(clk_disable);
 
 /*!
diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c
index 5e8f977..656622a 100644
--- a/arch/arm/plat-mxc/cpufreq.c
+++ b/arch/arm/plat-mxc/cpufreq.c
@@ -36,40 +36,23 @@
 #include <mach/clock.h>
 #include <asm/cacheflush.h>
 
-int low_bus_freq_mode;
-int high_bus_freq_mode;
 int cpu_freq_khz_min;
 int cpu_freq_khz_max;
 int arm_lpm_clk;
 int arm_normal_clk;
-char *gp_reg_id = "SW1";
-char *lp_reg_id = "SW2";
-int axi_c_clk_support;
 
 static struct clk *cpu_clk;
-static struct clk *main_bus_clk;
-static struct clk *pll2;
-static struct clk *axi_a_clk;
-static struct clk *axi_b_clk;
-static struct clk *axi_c_clk;
-static struct clk *emi_core_clk;
-static struct clk *nfc_clk;
-static struct clk *ahb_clk;
-static struct clk *vpu_clk;
-static struct clk *vpu_core_clk;
-static struct clk *arm_axi_clk;
-static struct clk *ddr_clk;
-static struct clk *ipu_clk;
-static struct clk *periph_apm_clk;
-static struct clk *lp_apm;
-static struct clk *osc;
 static struct regulator *gp_regulator;
-static struct regulator *lp_regulator;
 static struct cpu_wp *cpu_wp_tbl;
 static struct cpufreq_frequency_table imx_freq_table[4];
-
+extern int low_bus_freq_mode;
+extern int high_bus_freq_mode;
 extern int dvfs_core_is_active;
 extern int cpu_wp_nr;
+extern char *gp_reg_id;
+extern int set_low_bus_freq(void);
+extern int set_high_bus_freq(void);
+extern int low_freq_bus_used(void);
 #ifdef CONFIG_ARCH_MX51
 extern struct cpu_wp *(*get_cpu_wp)(int *wp);
 #endif
@@ -120,117 +103,6 @@ static int set_cpu_freq(int freq)
 	return ret;
 }
 
-static int set_low_bus_freq(void)
-{
-	int ret = 0;
-	unsigned long lp_lpm_clk;
-
-	struct clk *p_clk;
-	struct clk *amode_parent_clk;
-
-	if (axi_c_clk_support == 0)
-		return 0;
-
-	lp_lpm_clk = clk_get_rate(lp_apm);
-	amode_parent_clk = lp_apm;
-	p_clk = clk_get_parent(periph_apm_clk);
-
-	/* Make sure osc_clk is the parent of lp_apm. */
-	if (clk_get_parent(amode_parent_clk) != osc)
-		clk_set_parent(amode_parent_clk, osc);
-
-	/* Set the parent of periph_apm_clk to be lp_apm */
-	clk_set_parent(periph_apm_clk, amode_parent_clk);
-	amode_parent_clk = periph_apm_clk;
-
-	p_clk = clk_get_parent(main_bus_clk);
-	/* Set the parent of main_bus_clk to be periph_apm_clk */
-	clk_set_parent(main_bus_clk, amode_parent_clk);
-
-	clk_set_rate(axi_a_clk, lp_lpm_clk);
-	clk_set_rate(axi_b_clk, lp_lpm_clk);
-	clk_set_rate(axi_c_clk, lp_lpm_clk);
-	clk_set_rate(emi_core_clk, lp_lpm_clk);
-	clk_set_rate(nfc_clk, 4800000);
-	clk_set_rate(ahb_clk, lp_lpm_clk);
-
-	amode_parent_clk = emi_core_clk;
-
-	p_clk = clk_get_parent(arm_axi_clk);
-	if (p_clk != amode_parent_clk)
-		clk_set_parent(arm_axi_clk, amode_parent_clk);
-
-	p_clk = clk_get_parent(vpu_clk);
-	if (p_clk != amode_parent_clk)
-		clk_set_parent(vpu_clk, amode_parent_clk);
-
-	p_clk = clk_get_parent(vpu_core_clk);
-	if (p_clk != amode_parent_clk)
-		clk_set_parent(vpu_core_clk, amode_parent_clk);
-
-	/* Set the voltage to 1.0v for the LP domain. */
-	ret = regulator_set_voltage(lp_regulator, 1000000, 1000000);
-	if (ret < 0) {
-		printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!!!!\n");
-		return ret;
-	}
-
-	low_bus_freq_mode = 1;
-	high_bus_freq_mode = 0;
-	return ret;
-}
-
-static int set_high_bus_freq(void)
-{
-	struct clk *p_clk;
-	struct clk *rmode_parent_clk;
-	int ret = 0;
-
-	if (axi_c_clk_support == 0)
-		return 0;
-
-	if (!low_bus_freq_mode)
-		return ret;
-
-	low_bus_freq_mode = 0;
-
-	/* Set the voltage to 1.2v for the LP domain. */
-	ret = regulator_set_voltage(lp_regulator, 1200000, 1200000);
-	if (ret < 0) {
-		printk(KERN_DEBUG "COULD NOT SET LP VOLTAGE!!!!!!\n");
-		return ret;
-	}
-
-	rmode_parent_clk = pll2;
-
-	/* Set the dividers before setting the parent clock. */
-	clk_set_rate(axi_a_clk, 4800000);
-	clk_set_rate(axi_b_clk, 4000000);
-	clk_set_rate(axi_c_clk, 6000000);
-
-	clk_set_rate(emi_core_clk, 4800000);
-	clk_set_rate(ahb_clk, 4800000);
-
-	/* Set the parent of main_bus_clk to be pll2 */
-	p_clk = clk_get_parent(main_bus_clk);
-	clk_set_parent(main_bus_clk, rmode_parent_clk);
-	udelay(5);
-	high_bus_freq_mode = 1;
-	return ret;
-}
-
-static int low_freq_bus_used(void)
-{
-	if (axi_c_clk_support == 0)
-		return 0;
-
-	if ((clk_get_usecount(ipu_clk) == 0)
-	    && (clk_get_usecount(vpu_clk) == 0))
-		return 1;
-	else
-		return 0;
-}
-
 static int mxc_verify_speed(struct cpufreq_policy *policy)
 {
 	if (policy->cpu != 0)
@@ -274,6 +146,9 @@ static int mxc_set_target(struct cpufreq_policy *policy,
 	int low_freq_bus_ready = 0;
 	int ret = 0;
 
+	if (dvfs_core_is_active)
+		target_freq = clk_get_rate(cpu_clk) / 1000;
+
 	/*
 	 * Some governors do not respects CPU and policy lower limits
 	 * which leads to bad things (division by zero etc), ensure
@@ -299,20 +174,22 @@ static int mxc_set_target(struct cpufreq_policy *policy,
 
 	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
 
-	if ((freq_Hz == arm_lpm_clk) && (!low_bus_freq_mode)
-	    && (low_freq_bus_ready)) {
-		set_low_bus_freq();
-		if (!dvfs_core_is_active)
-			ret = set_cpu_freq(freq_Hz);
-	} else {
-		if (!high_bus_freq_mode)
-			set_high_bus_freq();
-
-		if (!dvfs_core_is_active)
-			ret = set_cpu_freq(freq_Hz);
-		if (low_bus_freq_mode) {
-			if (ret == 0)
+	if (!dvfs_core_is_active) {
+		if ((freq_Hz == arm_lpm_clk) && (!low_bus_freq_mode)
+		    && (low_freq_bus_ready)) {
+			set_low_bus_freq();
+			if (!dvfs_core_is_active)
+				ret = set_cpu_freq(freq_Hz);
+		} else {
+			if (!high_bus_freq_mode)
 				set_high_bus_freq();
+
+			if (!dvfs_core_is_active)
+				ret = set_cpu_freq(freq_Hz);
+			if (low_bus_freq_mode) {
+				if (ret == 0)
+					set_high_bus_freq();
+			}
 		}
 	}
 
@@ -337,115 +214,6 @@ static int __init mxc_cpufreq_driver_init(struct cpufreq_policy *policy)
 		return PTR_ERR(cpu_clk);
 	}
 
-	axi_c_clk = clk_get(NULL, "axi_c_clk");
-	if (IS_ERR(axi_c_clk)) {
-		axi_c_clk_support = 0;
-		printk(KERN_ERR "%s: failed to get axi_c_clk\n", __func__);
-	} else {
-		axi_c_clk_support = 1;
-		main_bus_clk = clk_get(NULL, "main_bus_clk");
-		if (IS_ERR(main_bus_clk)) {
-			printk(KERN_ERR "%s: failed to get main_bus_clk\n",
-			       __func__);
-			return PTR_ERR(main_bus_clk);
-		}
-
-		pll2 = clk_get(NULL, "pll2");
-		if (IS_ERR(pll2)) {
-			printk(KERN_ERR "%s: failed to get pll2\n", __func__);
-			return PTR_ERR(pll2);
-		}
-
-		axi_a_clk = clk_get(NULL, "axi_a_clk");
-		if (IS_ERR(axi_a_clk)) {
-			printk(KERN_ERR "%s: failed to get axi_a_clk\n",
-			       __func__);
-			return PTR_ERR(axi_a_clk);
-		}
-
-		axi_b_clk = clk_get(NULL, "axi_b_clk");
-		if (IS_ERR(axi_b_clk)) {
-			printk(KERN_ERR "%s: failed to get axi_b_clk\n",
-			       __func__);
-			return PTR_ERR(axi_b_clk);
-		}
-
-		emi_core_clk = clk_get(NULL, "emi_core_clk");
-		if (IS_ERR(emi_core_clk)) {
-			printk(KERN_ERR "%s: failed to get emi_core_clk\n",
-			       __func__);
-			return PTR_ERR(emi_core_clk);
-		}
-
-		nfc_clk = clk_get(NULL, "nfc_clk");
-		if (IS_ERR(nfc_clk)) {
-			printk(KERN_ERR "%s: failed to get nfc_clk\n",
-			       __func__);
-			return PTR_ERR(nfc_clk);
-		}
-
-		ahb_clk = clk_get(NULL, "ahb_clk");
-		if (IS_ERR(ahb_clk)) {
-			printk(KERN_ERR "%s: failed to get ahb_clk\n",
-			       __func__);
-			return PTR_ERR(ahb_clk);
-		}
-
-		vpu_core_clk = clk_get(NULL, "vpu_core_clk");
-		if (IS_ERR(vpu_core_clk)) {
-			printk(KERN_ERR "%s: failed to get vpu_core_clk\n",
-			       __func__);
-			return PTR_ERR(vpu_core_clk);
-		}
-
-		arm_axi_clk = clk_get(NULL, "arm_axi_clk");
-		if (IS_ERR(arm_axi_clk)) {
-			printk(KERN_ERR "%s: failed to get arm_axi_clk\n",
-			       __func__);
-			return PTR_ERR(arm_axi_clk);
-		}
-
-		ddr_clk = clk_get(NULL, "ddr_clk");
-		if (IS_ERR(ddr_clk)) {
-			printk(KERN_ERR "%s: failed to get ddr_clk\n",
-			       __func__);
-			return PTR_ERR(ddr_clk);
-		}
-
-		ipu_clk = clk_get(NULL, "ipu_clk");
-		if (IS_ERR(ipu_clk)) {
-			printk(KERN_ERR "%s: failed to get ipu_clk\n",
-			       __func__);
-			return PTR_ERR(ipu_clk);
-		}
-
-		vpu_clk = clk_get(NULL, "vpu_clk");
-		if (IS_ERR(vpu_clk)) {
-			printk(KERN_ERR "%s: failed to get vpu_clk\n",
-			       __func__);
-			return PTR_ERR(vpu_clk);
-		}
-
-		periph_apm_clk = clk_get(NULL, "periph_apm_clk");
-		if (IS_ERR(periph_apm_clk)) {
-			printk(KERN_ERR "%s: failed to get periph_apm_clk\n",
-			       __func__);
-			return PTR_ERR(periph_apm_clk);
-		}
-
-		lp_apm = clk_get(NULL, "lp_apm");
-		if (IS_ERR(lp_apm)) {
-			printk(KERN_ERR "%s: failed to get lp_apm\n", __func__);
-			return PTR_ERR(lp_apm);
-		}
-
-		osc = clk_get(NULL, "osc");
-		if (IS_ERR(osc)) {
-			printk(KERN_ERR "%s: failed to get osc\n", __func__);
-			return PTR_ERR(osc);
-		}
-	}
-
 	gp_regulator = regulator_get(NULL, gp_reg_id);
 	if (IS_ERR(gp_regulator)) {
 		clk_put(cpu_clk);
@@ -453,13 +221,6 @@ static int __init mxc_cpufreq_driver_init(struct cpufreq_policy *policy)
 		return PTR_ERR(gp_regulator);
 	}
 
-	lp_regulator = regulator_get(NULL, lp_reg_id);
-	if (IS_ERR(lp_regulator)) {
-		clk_put(ahb_clk);
-		printk(KERN_ERR "%s: failed to get lp regulator\n", __func__);
-		return PTR_ERR(lp_regulator);
-	}
-
 	/* Set the current working point. */
 	cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr);
 
@@ -478,15 +239,6 @@ static int __init mxc_cpufreq_driver_init(struct cpufreq_policy *policy)
 			cpu_freq_khz_max = cpu_wp_tbl[i].cpu_rate / 1000;
 	}
 
-	imx_freq_table[i].index = i + 1;
-	imx_freq_table[i].frequency = cpu_wp_tbl[i].cpu_rate / 1000;
-
-	if ((cpu_wp_tbl[i].cpu_rate / 1000) < cpu_freq_khz_min)
-		cpu_freq_khz_min = cpu_wp_tbl[i].cpu_rate / 1000;
-
-	if ((cpu_wp_tbl[i].cpu_rate / 1000) > cpu_freq_khz_max)
-		cpu_freq_khz_max = cpu_wp_tbl[i].cpu_rate / 1000;
-
 	imx_freq_table[i].index = 0;
 	imx_freq_table[i].frequency = CPUFREQ_TABLE_END;
 
@@ -504,35 +256,13 @@ static int __init mxc_cpufreq_driver_init(struct cpufreq_policy *policy)
 	ret = cpufreq_frequency_table_cpuinfo(policy, imx_freq_table);
 	if (ret < 0) {
 		clk_put(cpu_clk);
-		if (axi_c_clk_support != 0) {
-			clk_put(main_bus_clk);
-			clk_put(pll2);
-			clk_put(axi_a_clk);
-			clk_put(axi_b_clk);
-			clk_put(axi_c_clk);
-			clk_put(emi_core_clk);
-			clk_put(nfc_clk);
-			clk_put(ahb_clk);
-			clk_put(vpu_core_clk);
-			clk_put(arm_axi_clk);
-			clk_put(ddr_clk);
-			clk_put(ipu_clk);
-			clk_put(vpu_clk);
-			clk_put(periph_apm_clk);
-			clk_put(lp_apm);
-			clk_put(osc);
-		}
-
 		regulator_put(gp_regulator);
-		regulator_put(lp_regulator);
 		printk(KERN_ERR "%s: failed to register i.MXC CPUfreq\n",
 		       __func__);
 		return ret;
 	}
 	cpufreq_frequency_table_get_attr(imx_freq_table, policy->cpu);
 
-	low_bus_freq_mode = 0;
-	high_bus_freq_mode = 0;
 	return 0;
 }
 
@@ -548,25 +278,7 @@ static int mxc_cpufreq_driver_exit(struct cpufreq_policy *policy)
 		set_high_bus_freq();
 
 	clk_put(cpu_clk);
-	if (axi_c_clk_support != 0) {
-		clk_put(main_bus_clk);
-		clk_put(pll2);
-		clk_put(axi_a_clk);
-		clk_put(axi_b_clk);
-		clk_put(axi_c_clk);
-		clk_put(emi_core_clk);
-		clk_put(nfc_clk);
-		clk_put(ahb_clk);
-		clk_put(vpu_core_clk);
-		clk_put(arm_axi_clk);
-		clk_put(ddr_clk);
-		clk_put(ipu_clk);
-		clk_put(periph_apm_clk);
-		clk_put(lp_apm);
-		clk_put(osc);
-	}
 	regulator_put(gp_regulator);
-	regulator_put(lp_regulator);
 	return 0;
 }
 
diff --git a/arch/arm/plat-mxc/dvfs_core.c b/arch/arm/plat-mxc/dvfs_core.c
index d246324..52b5db6 100644
--- a/arch/arm/plat-mxc/dvfs_core.c
+++ b/arch/arm/plat-mxc/dvfs_core.c
@@ -40,6 +40,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/input.h>
 #include <linux/platform_device.h>
+#include <linux/cpufreq.h>
 
 #define MXC_DVFSTHRS_UPTHR_MASK               0x0FC00000
 #define MXC_DVFSTHRS_UPTHR_OFFSET             22
@@ -95,6 +96,7 @@ static struct cpu_wp *cpu_wp_tbl;
 int dvfs_core_resume;
 int curr_wp;
 int dvfs_core_is_active;
+int cpufreq_trig_needed;
 
 /*
  * Clock structures
@@ -119,8 +121,43 @@ enum {
  */
 #define DVFS_LTBRSR		(2 << MXC_DVFSCNTR_LTBRSR_OFFSET)
 
+extern int low_bus_freq_mode;
+extern int high_bus_freq_mode;
+extern int set_low_bus_freq(void);
+extern int set_high_bus_freq(void);
+extern int low_freq_bus_used(void);
+
 DEFINE_SPINLOCK(mxc_dvfs_core_lock);
 
+void dvfs_core_set_bus_freq(void)
+{
+	u32 reg;
+	int low_freq_bus_ready = 0;
+
+	/* Mask DVFS irq */
+	reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr);
+	/* FSVAIM=1 */
+	reg |= MXC_DVFSCNTR_FSVAIM;
+	__raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr);
+
+	low_freq_bus_ready = low_freq_bus_used();
+
+	if ((curr_wp == dvfs_data->num_wp - 1) && (!low_bus_freq_mode)
+	    && (low_freq_bus_ready))
+		set_low_bus_freq();
+	else if ((curr_wp == dvfs_data->num_wp - 1) && (low_bus_freq_mode)
+		 && (!low_freq_bus_ready))
+		set_high_bus_freq();
+
+	/* Enable DVFS interrupt */
+	/* FSVAIM=0 */
+	reg = (reg & ~MXC_DVFSCNTR_FSVAIM);
+	/* LBFL=1 */
+	reg = (reg & ~MXC_DVFSCNTR_LBFL);
+	reg |= MXC_DVFSCNTR_LBFL;
+	__raw_writel(reg, dvfs_data->dvfs_cntr_reg_addr);
+}
+
 static void dvfs_load_config(void)
 {
 	u32 reg;
@@ -137,6 +174,64 @@ static void dvfs_load_config(void)
 	__raw_writel(reg, dvfs_data->dvfs_coun_reg_addr);
 }
 
+static int set_cpu_freq(int wp)
+{
+	int ret = 0;
+	int org_cpu_rate;
+	unsigned long rate = 0;
+	int gp_volt = 0;
+	u32 reg;
+
+	org_cpu_rate = clk_get_rate(cpu_clk);
+	rate = cpu_wp_tbl[wp].cpu_rate;
+
+	if (org_cpu_rate == rate)
+		return ret;
+
+	gp_volt = cpu_wp_tbl[wp].cpu_voltage;
+
+	if (gp_volt == 0)
+		return ret;
+
+	/*Set the voltage for the GP domain. */
+	if (rate > org_cpu_rate) {
+		ret = regulator_set_voltage(core_regulator, gp_volt, gp_volt);
+		if (ret < 0) {
+			printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!!\n");
+			return ret;
+		}
+		udelay(dvfs_data->delay_time);
+	}
+
+	ret = clk_set_rate(cpu_clk, rate);
+	if (ret != 0) {
+		printk(KERN_DEBUG "cannot set CPU clock rate\n");
+		return ret;
+	}
+
+	/* START the GPC main control FSM */
+	/* set VINC */
+	reg = __raw_readl(dvfs_data->gpc_vcr_reg_addr);
+	reg &=
+	    ~(MXC_GPCVCR_VINC_MASK | MXC_GPCVCR_VCNTU_MASK |
+	      MXC_GPCVCR_VCNT_MASK);
+	reg |=
+	    (1 << MXC_GPCVCR_VCNTU_OFFSET) |
+	    (100 << MXC_GPCVCR_VCNT_OFFSET);
+	__raw_writel(reg, dvfs_data->gpc_vcr_reg_addr);
+
+	if (rate < org_cpu_rate) {
+		ret = regulator_set_voltage(core_regulator, gp_volt, gp_volt);
+		if (ret < 0) {
+			printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!!\n");
+			return ret;
+		}
+		udelay(dvfs_data->delay_time);
+	}
+
+	return ret;
+}
+
 static int start_dvfs(void)
 {
 	u32 reg;
@@ -236,10 +331,9 @@ static void dvfs_core_workqueue_handler(struct work_struct *work)
 	u32 fsvai;
 	u32 reg;
 	u32 curr_cpu;
-	unsigned long rate = 0;
 	int ret = 0;
-	int uvol;
 	int maxf = 0, minf = 0;
+	int low_freq_bus_ready = 0;
 
 	/* Check DVFS frequency adjustment interrupt status */
 	reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr);
@@ -267,37 +361,8 @@ static void dvfs_core_workqueue_handler(struct work_struct *work)
 				goto END;
 			}
 
-			rate = cpu_wp_tbl[curr_wp].cpu_rate;
-			uvol = cpu_wp_tbl[curr_wp].cpu_voltage;
 			if (curr_wp == dvfs_data->num_wp - 1)
 				minf = 1;
-
-			ret = clk_set_rate(cpu_clk, rate);
-			if (ret != 0) {
-				printk(KERN_DEBUG
-				       "cannot set CPU clock rate\n");
-				goto END;
-			}
-
-			/* START the GPC main control FSM */
-			/* set VINC */
-			reg = __raw_readl(dvfs_data->gpc_vcr_reg_addr);
-			reg &=
-			    ~(MXC_GPCVCR_VINC_MASK | MXC_GPCVCR_VCNTU_MASK |
-			      MXC_GPCVCR_VCNT_MASK);
-			reg |=
-			    (1 << MXC_GPCVCR_VCNTU_OFFSET) |
-			    (100 << MXC_GPCVCR_VCNT_OFFSET);
-			__raw_writel(reg, dvfs_data->gpc_vcr_reg_addr);
-
-			/* Set the voltage for the GP domain. */
-			ret = regulator_set_voltage(core_regulator, uvol, uvol);
-			if (ret < 0) {
-				printk(KERN_DEBUG
-				       "COULD NOT SET CORE VOLTAGE!!!!!\n");
-				goto END;
-			}
-			udelay(dvfs_data->delay_time);
 		}
 	} else {
 		if (curr_cpu == cpu_wp_tbl[0].cpu_rate) {
@@ -306,37 +371,34 @@ static void dvfs_core_workqueue_handler(struct work_struct *work)
 		} else {
 			/* freq up */
 			curr_wp = 0;
-			rate = cpu_wp_tbl[curr_wp].cpu_rate;
-			/* START the GPC main control FSM */
-			/* set VINC */
-			reg = __raw_readl(dvfs_data->gpc_vcr_reg_addr);
-			reg &=
-			    ~(MXC_GPCVCR_VINC_MASK | MXC_GPCVCR_VCNTU_MASK |
-			      MXC_GPCVCR_VCNT_MASK);
-			reg |=
-			    (1 << MXC_GPCVCR_VCNTU_OFFSET) |
-			    (100 << MXC_GPCVCR_VCNT_OFFSET);
-			__raw_writel(reg, dvfs_data->gpc_vcr_reg_addr);
-
-			ret = regulator_set_voltage(core_regulator,
-						cpu_wp_tbl[curr_wp].cpu_voltage,
-						cpu_wp_tbl[curr_wp].cpu_voltage);
-			if (ret < 0) {
-				printk(KERN_DEBUG
-				       "COULD NOT SET CORE VOLTAGE!!!!\n");
-				goto END;
-			}
-			udelay(dvfs_data->delay_time);
-
-			ret =
-			    clk_set_rate(cpu_clk, cpu_wp_tbl[curr_wp].cpu_rate);
-			if (ret != 0)
-				printk(KERN_DEBUG
-				       "cannot set CPU clock rate\n");
 			maxf = 1;
 		}
 	}
 
+	low_freq_bus_ready = low_freq_bus_used();
+	if ((curr_wp == dvfs_data->num_wp - 1) && (!low_bus_freq_mode)
+	    && (low_freq_bus_ready)) {
+		set_low_bus_freq();
+		ret = set_cpu_freq(curr_wp);
+	} else {
+		if (!high_bus_freq_mode)
+			set_high_bus_freq();
+
+		ret = set_cpu_freq(curr_wp);
+
+		if (low_bus_freq_mode) {
+			if (ret == 0)
+				set_high_bus_freq();
+		}
+			}
+
+#if defined(CONFIG_CPU_FREQ)
+	if (cpufreq_trig_needed == 1) {
+		cpufreq_trig_needed = 0;
+		cpufreq_update_policy(0);
+	}
+#endif
+
 END:			/* Set MAXF, MINF */
 	reg = __raw_readl(dvfs_data->dvfs_cntr_reg_addr);
 	reg = (reg & ~(MXC_DVFSCNTR_MAXF_MASK | MXC_DVFSCNTR_MINF_MASK));
@@ -377,11 +439,10 @@ static void stop_dvfs(void)
 		curr_wp = 0;
 		curr_cpu = clk_get_rate(cpu_clk);
 		if (curr_cpu != cpu_wp_tbl[curr_wp].cpu_rate) {
-			if (regulator_set_voltage(core_regulator,
-					cpu_wp_tbl[curr_wp].cpu_voltage,
-					cpu_wp_tbl[curr_wp].cpu_voltage) == 0)
-				clk_set_rate(cpu_clk,
-					     cpu_wp_tbl[curr_wp].cpu_rate);
+			if (!high_bus_freq_mode)
+				set_high_bus_freq();
+
+			set_cpu_freq(curr_wp);
 		}
 
 		clk_disable(dvfs_clk);
@@ -496,6 +557,7 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev)
 	cpu_wp_tbl = get_cpu_wp(&cpu_wp_nr);
 	curr_wp = 0;
 	dvfs_core_resume = 0;
+	cpufreq_trig_needed = 0;
 
 	return err;
 
-- 
1.6.0.4





More information about the kernel-team mailing list