summaryrefslogtreecommitdiff
path: root/arch/arm/plat-mxc
diff options
context:
space:
mode:
authorRanjani Vaidyanathan <ra5478@freescale.com>2011-07-29 14:30:19 -0500
committerRanjani Vaidyanathan <ra5478@freescale.com>2011-08-30 17:26:39 -0500
commit2ecbb95c0d3e6fcefae3a0bf9800f9149adec824 (patch)
tree08becb3e913b5d919c5de3f808d8b213ba970615 /arch/arm/plat-mxc
parent9fb2acc5b76620f9207a609dd02dc762a72de95c (diff)
ENGR00139280: MX6: Add CPUFREQ support
Add support for CPUFREQ for SMP system. Added support for 1GHz, 800MHz, 400MHz and 160MHz. Added support for scaling the voltage along with frequency. Signed-off-by: Ranjani Vaidyanathan <ra5478@freescale.com>
Diffstat (limited to 'arch/arm/plat-mxc')
-rw-r--r--arch/arm/plat-mxc/cpu.c4
-rw-r--r--arch/arm/plat-mxc/cpufreq.c96
-rw-r--r--arch/arm/plat-mxc/dvfs_core.c30
3 files changed, 86 insertions, 44 deletions
diff --git a/arch/arm/plat-mxc/cpu.c b/arch/arm/plat-mxc/cpu.c
index f69d07bd7289..3b35f55dea84 100644
--- a/arch/arm/plat-mxc/cpu.c
+++ b/arch/arm/plat-mxc/cpu.c
@@ -22,8 +22,8 @@
unsigned int __mxc_cpu_type;
EXPORT_SYMBOL(__mxc_cpu_type);
extern int mxc_early_serial_console_init(unsigned long base, struct clk *clk);
-struct regulator *(*get_cpu_regulator)(void);
-void (*put_cpu_regulator)(void);
+int (*set_cpu_voltage)(u32 volt);
+void (*set_num_cpu_op)(int num);
void mxc_set_cpu_type(unsigned int type)
{
diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c
index c2492426a2ed..3630f95e723b 100644
--- a/arch/arm/plat-mxc/cpufreq.c
+++ b/arch/arm/plat-mxc/cpufreq.c
@@ -21,14 +21,17 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+
+#include <asm/smp_plat.h>
+#include <asm/cpu.h>
+
#include <mach/hardware.h>
#include <mach/clock.h>
#define CLK32_FREQ 32768
#define NANOSECOND (1000 * 1000 * 1000)
-struct cpu_op *(*get_cpu_op)(int *op);
-char *gp_reg_id;
int cpufreq_trig_needed;
static int cpu_freq_khz_min;
@@ -40,10 +43,11 @@ static struct cpufreq_frequency_table *imx_freq_table;
static int cpu_op_nr;
static struct cpu_op *cpu_op_tbl;
static struct regulator *gp_regulator;
+static u32 pre_suspend_rate;
extern int dvfs_core_is_active;
-extern struct regulator *(*get_cpu_regulator)(void);
-extern void (*put_cpu_regulator)(void);
+extern struct cpu_op *(*get_cpu_op)(int *op);
+extern int (*set_cpu_voltage)(u32 cpu_volt);
int set_cpu_freq(int freq)
{
@@ -65,11 +69,12 @@ int set_cpu_freq(int freq)
/*Set the voltage for the GP domain. */
if (freq > org_cpu_rate) {
- ret = regulator_set_voltage(gp_regulator, gp_volt, gp_volt);
+ ret = set_cpu_voltage(gp_volt);
if (ret < 0) {
printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!!\n");
return ret;
}
+ udelay(50);
}
ret = clk_set_rate(cpu_clk, freq);
@@ -79,7 +84,7 @@ int set_cpu_freq(int freq)
}
if (freq < org_cpu_rate) {
- ret = regulator_set_voltage(gp_regulator, gp_volt, gp_volt);
+ ret = set_cpu_voltage(gp_volt);
if (ret < 0) {
printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE!!!!\n");
return ret;
@@ -91,7 +96,7 @@ int set_cpu_freq(int freq)
static int mxc_verify_speed(struct cpufreq_policy *policy)
{
- if (policy->cpu != 0)
+ if (policy->cpu > num_possible_cpus())
return -EINVAL;
return cpufreq_frequency_table_verify(policy, imx_freq_table);
@@ -99,7 +104,7 @@ static int mxc_verify_speed(struct cpufreq_policy *policy)
static unsigned int mxc_get_speed(unsigned int cpu)
{
- if (cpu)
+ if (cpu > num_possible_cpus())
return 0;
return clk_get_rate(cpu_clk) / 1000;
@@ -112,11 +117,18 @@ static int mxc_set_target(struct cpufreq_policy *policy,
int freq_Hz;
int ret = 0;
unsigned int index;
+ int i, num_cpus;
+
+ num_cpus = num_possible_cpus();
+ if (policy->cpu > num_cpus)
+ return 0;
+#ifdef CONFIG_ARCH_MX5
if (dvfs_core_is_active) {
printk(KERN_DEBUG"DVFS-CORE is active, cannot change frequency using CPUFREQ\n");
return ret;
}
+#endif
cpufreq_frequency_table_target(policy, imx_freq_table,
target_freq, relation, &index);
@@ -124,17 +136,59 @@ static int mxc_set_target(struct cpufreq_policy *policy,
freqs.old = clk_get_rate(cpu_clk) / 1000;
freqs.new = freq_Hz / 1000;
- freqs.cpu = 0;
+ freqs.cpu = policy->cpu;
freqs.flags = 0;
- cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+ for (i = 0; i < num_cpus; i++) {
+ freqs.cpu = i;
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ }
ret = set_cpu_freq(freq_Hz);
- cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+#ifdef CONFIG_SMP
+ /* Loops per jiffy is not updated by the CPUFREQ driver for SMP systems.
+ * So update it for all CPUs.
+ */
+
+ for_each_cpu(i, policy->cpus)
+ per_cpu(cpu_data, i).loops_per_jiffy =
+ cpufreq_scale(per_cpu(cpu_data, i).loops_per_jiffy,
+ freqs.old, freqs.new);
+#endif
+ for (i = 0; i < num_cpus; i++) {
+ freqs.cpu = i;
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ }
+
return ret;
}
+static int mxc_cpufreq_suspend(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct cpufreq_policy *policy = pdev;
+
+ pre_suspend_rate = clk_get_rate(cpu_clk);
+ /* Set to max freq and voltage */
+ if (pre_suspend_rate != (imx_freq_table[0].frequency * 1000))
+ set_cpu_freq(imx_freq_table[0].frequency);
+
+ return 0;
+}
+
+static int mxc_cpufreq_resume(struct platform_device *pdev,
+ pm_message_t state)
+{
+ struct cpufreq_policy *policy = pdev;
+
+ if (clk_get_rate(cpu_clk) != pre_suspend_rate)
+ set_cpu_freq(pre_suspend_rate);
+
+ return 0;
+}
+
static int __devinit mxc_cpufreq_init(struct cpufreq_policy *policy)
{
int ret;
@@ -142,7 +196,7 @@ static int __devinit mxc_cpufreq_init(struct cpufreq_policy *policy)
printk(KERN_INFO "i.MXC CPU frequency driver\n");
- if (policy->cpu != 0)
+ if (policy->cpu >= num_possible_cpus())
return -EINVAL;
if (!get_cpu_op)
@@ -154,14 +208,6 @@ static int __devinit mxc_cpufreq_init(struct cpufreq_policy *policy)
return PTR_ERR(cpu_clk);
}
- gp_regulator = get_cpu_regulator();
-
- if (IS_ERR(gp_regulator)) {
- clk_put(cpu_clk);
- printk(KERN_ERR "%s: failed to get gp regulator\n", __func__);
- return PTR_ERR(gp_regulator);
- }
-
cpu_op_tbl = get_cpu_op(&cpu_op_nr);
cpu_freq_khz_min = cpu_op_tbl[0].cpu_rate / 1000;
@@ -193,6 +239,14 @@ static int __devinit mxc_cpufreq_init(struct cpufreq_policy *policy)
policy->min = policy->cpuinfo.min_freq = cpu_freq_khz_min;
policy->max = policy->cpuinfo.max_freq = cpu_freq_khz_max;
+ /* All processors share the same frequency and voltage.
+ * So all frequencies need to be scaled together.
+ */
+ if (is_smp()) {
+ policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
+ cpumask_setall(policy->cpus);
+ }
+
/* Manual states, that PLL stabilizes in two CLK32 periods */
policy->cpuinfo.transition_latency = 2 * NANOSECOND / CLK32_FREQ;
@@ -230,6 +284,8 @@ static struct cpufreq_driver mxc_driver = {
.get = mxc_get_speed,
.init = mxc_cpufreq_init,
.exit = mxc_cpufreq_exit,
+ .suspend = mxc_cpufreq_suspend,
+ .resume = mxc_cpufreq_resume,
.name = "imx",
};
diff --git a/arch/arm/plat-mxc/dvfs_core.c b/arch/arm/plat-mxc/dvfs_core.c
index 846fee95b713..954ca8684090 100644
--- a/arch/arm/plat-mxc/dvfs_core.c
+++ b/arch/arm/plat-mxc/dvfs_core.c
@@ -97,6 +97,8 @@ static int minf;
extern void setup_pll(void);
extern int cpufreq_trig_needed;
+extern int (*set_cpu_voltage)(u32 cpu_volt);
+
struct timeval core_prev_intr;
void dump_dvfs_core_regs(void);
@@ -112,13 +114,10 @@ static struct clk *pll1_sw_clk;
static struct clk *cpu_clk;
static struct clk *dvfs_clk;
static struct regulator *core_regulator;
-extern struct regulator *(*get_cpu_regulator)(void);
-extern void*(*put_cpu_regulator)(void);
static int cpu_op_nr;
-#ifdef CONFIG_ARCH_MX5
extern struct cpu_op *(*get_cpu_op)(int *op);
-#endif
+extern int (*set_cpu_voltage)(u32 cpu_volt);
enum {
FSVAI_FREQ_NOCHANGE = 0x0,
@@ -194,8 +193,7 @@ static int set_cpu_freq(int op)
/*Set the voltage for the GP domain. */
if (rate > org_cpu_rate) {
- ret = regulator_set_voltage(core_regulator, gp_volt,
- gp_volt);
+ ret = set_cpu_voltage(gp_volt);
if (ret < 0) {
printk(KERN_DEBUG "COULD NOT SET GP VOLTAGE\n");
return ret;
@@ -242,8 +240,7 @@ static int set_cpu_freq(int op)
spin_unlock_irqrestore(&mxc_dvfs_core_lock, flags);
if (rate < org_cpu_rate) {
- ret = regulator_set_voltage(core_regulator,
- gp_volt, gp_volt);
+ ret = set_cpu_voltage(gp_volt);
if (ret < 0) {
printk(KERN_DEBUG
"COULD NOT SET GP VOLTAGE!!!!\n");
@@ -284,8 +281,7 @@ static int set_cpu_freq(int op)
}
/* Check if FSVAI indicate freq up */
if (podf < arm_podf) {
- ret = regulator_set_voltage(core_regulator,
- gp_volt, gp_volt);
+ ret = set_cpu_voltage(gp_volt);
if (ret < 0) {
printk(KERN_DEBUG
"COULD NOT SET GP VOLTAGE!!!!\n");
@@ -345,8 +341,7 @@ static int set_cpu_freq(int op)
spin_unlock_irqrestore(&mxc_dvfs_core_lock, flags);
if (vinc == 0) {
- ret = regulator_set_voltage(core_regulator,
- gp_volt, gp_volt);
+ ret = set_cpu_voltage(gp_volt);
if (ret < 0) {
printk(KERN_DEBUG
"COULD NOT SET GP VOLTAGE\n!!!");
@@ -497,7 +492,7 @@ static void dvfs_core_work_handler(struct work_struct *work)
{
u32 fsvai;
u32 reg;
- u32 curr_cpu;
+ u32 curr_cpu = 0;
int ret = 0;
int low_freq_bus_ready = 0;
int bus_incr = 0, cpu_dcr = 0;
@@ -853,15 +848,6 @@ static int __devinit mxc_dvfs_core_probe(struct platform_device *pdev)
return PTR_ERR(dvfs_clk);
}
- core_regulator = get_cpu_regulator();
- if (IS_ERR(core_regulator)) {
- clk_put(cpu_clk);
- clk_put(dvfs_clk);
- printk(KERN_ERR "%s: failed to get gp regulator %s\n",
- __func__, dvfs_data->reg_id);
- return PTR_ERR(core_regulator);
- }
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
err = -ENODEV;