diff options
author | Ranjani Vaidyanathan <ra5478@freescale.com> | 2011-07-29 14:30:19 -0500 |
---|---|---|
committer | Ranjani Vaidyanathan <ra5478@freescale.com> | 2011-08-30 17:26:39 -0500 |
commit | 2ecbb95c0d3e6fcefae3a0bf9800f9149adec824 (patch) | |
tree | 08becb3e913b5d919c5de3f808d8b213ba970615 /arch/arm/plat-mxc | |
parent | 9fb2acc5b76620f9207a609dd02dc762a72de95c (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.c | 4 | ||||
-rw-r--r-- | arch/arm/plat-mxc/cpufreq.c | 96 | ||||
-rw-r--r-- | arch/arm/plat-mxc/dvfs_core.c | 30 |
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; |