diff options
author | Nicolas Pitre <nicolas.pitre@linaro.org> | 2011-02-28 15:54:19 -0500 |
---|---|---|
committer | Nicolas Pitre <nicolas.pitre@linaro.org> | 2011-02-28 15:54:19 -0500 |
commit | 9a577aa8d55f8607e6f5ea6fb9d52780930d8373 (patch) | |
tree | c75d2b89c0affd199e0af35e86d8e664fdd34c32 | |
parent | 3b99255148bd5a40586944d0110f741c41db5f43 (diff) | |
parent | 82544ce706497e311e4d0852f221ef9c0cd897d1 (diff) |
Merge branch 'omap4_mpu_dvfs' into linaro-2.6.38
-rw-r--r-- | arch/arm/configs/omap2plus_defconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap1/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/mach-omap1/omap1-cpufreq.c | 176 | ||||
-rw-r--r-- | arch/arm/mach-omap2/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clock2420_data.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clock2430_data.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clock3xxx_data.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clock44xx_data.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/dvfs.c | 19 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap2plus-cpufreq.c | 250 | ||||
-rw-r--r-- | arch/arm/mach-omap2/omap_hwmod_44xx_data.c | 1 | ||||
-rw-r--r-- | arch/arm/mach-omap2/opp4xxx_data.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-omap2/pm.c | 25 | ||||
-rw-r--r-- | arch/arm/plat-omap/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/plat-omap/cpu-omap.c | 69 |
15 files changed, 487 insertions, 69 deletions
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig index 9f2c5bd5fbc..ccfd51cd2bc 100644 --- a/arch/arm/configs/omap2plus_defconfig +++ b/arch/arm/configs/omap2plus_defconfig @@ -58,6 +58,7 @@ CONFIG_ARM_ERRATA_411920=y CONFIG_NO_HZ=y CONFIG_HIGH_RES_TIMERS=y CONFIG_SMP=y +CONFIG_NR_CPUS=2 # CONFIG_LOCAL_TIMERS is not set CONFIG_AEABI=y CONFIG_LEDS=y diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile index ba6009f2767..cb2d3a64858 100644 --- a/arch/arm/mach-omap1/Makefile +++ b/arch/arm/mach-omap1/Makefile @@ -10,6 +10,9 @@ obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o obj-$(CONFIG_OMAP_32K_TIMER) += timer32k.o +# CPUFREQ driver +obj-$(CONFIG_CPU_FREQ) += omap1-cpufreq.o + # Power Management obj-$(CONFIG_PM) += pm.o sleep.o pm_bus.o diff --git a/arch/arm/mach-omap1/omap1-cpufreq.c b/arch/arm/mach-omap1/omap1-cpufreq.c new file mode 100644 index 00000000000..64faf3f28d9 --- /dev/null +++ b/arch/arm/mach-omap1/omap1-cpufreq.c @@ -0,0 +1,176 @@ +/* + * OMAP1 cpufreq driver + * + * CPU frequency scaling for OMAP + * + * Copyright (C) 2005 Nokia Corporation + * Written by Tony Lindgren <tony@atomide.com> + * + * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King + * + * Copyright (C) 2007-2008 Texas Instruments, Inc. + * Updated to support OMAP3 + * Rajendra Nayak <rnayak@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/opp.h> + +#include <asm/system.h> + +#include <plat/clock.h> +#include <plat/omap-pm.h> + +#include <mach/hardware.h> + +#define VERY_HI_RATE 900000000 + +static struct cpufreq_frequency_table *freq_table; +static struct clk *mpu_clk; + +static int omap_verify_speed(struct cpufreq_policy *policy) +{ + if (freq_table) + return cpufreq_frequency_table_verify(policy, freq_table); + + if (policy->cpu) + return -EINVAL; + + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + + policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000; + policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000; + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + return 0; +} + +static unsigned int omap_getspeed(unsigned int cpu) +{ + unsigned long rate; + + if (cpu) + return 0; + + rate = clk_get_rate(mpu_clk) / 1000; + return rate; +} + +static int omap_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + struct cpufreq_freqs freqs; + int ret = 0; + + /* Ensure desired rate is within allowed range. Some govenors + * (ondemand) will just pass target_freq=0 to get the minimum. */ + if (target_freq < policy->min) + target_freq = policy->min; + if (target_freq > policy->max) + target_freq = policy->max; + + freqs.old = omap_getspeed(0); + freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; + freqs.cpu = 0; + + if (freqs.old == freqs.new) + return ret; + + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + +#ifdef CONFIG_CPU_FREQ_DEBUG + pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new); +#endif + ret = clk_set_rate(mpu_clk, freqs.new * 1000); + if (!ret) + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + + return ret; +} + +static int __init omap_cpu_init(struct cpufreq_policy *policy) +{ + int result = 0; + + mpu_clk = clk_get(NULL, "mpu"); + if (IS_ERR(mpu_clk)) + return PTR_ERR(mpu_clk); + + if (policy->cpu != 0) + return -EINVAL; + + policy->cur = policy->min = policy->max = omap_getspeed(0); + + clk_init_cpufreq_table(&freq_table); + + if (freq_table) { + result = cpufreq_frequency_table_cpuinfo(policy, freq_table); + if (!result) + cpufreq_frequency_table_get_attr(freq_table, + policy->cpu); + } else { + policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000; + policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, + VERY_HI_RATE) / 1000; + } + + policy->min = policy->cpuinfo.min_freq; + policy->max = policy->cpuinfo.max_freq; + policy->cur = omap_getspeed(0); + + /* FIXME: what's the actual transition time? */ + policy->cpuinfo.transition_latency = 300 * 1000; + + return 0; +} + +static int omap_cpu_exit(struct cpufreq_policy *policy) +{ + clk_exit_cpufreq_table(&freq_table); + clk_put(mpu_clk); + return 0; +} + +static struct freq_attr *omap_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver omap_driver = { + .flags = CPUFREQ_STICKY, + .verify = omap_verify_speed, + .target = omap_target, + .get = omap_getspeed, + .init = omap_cpu_init, + .exit = omap_cpu_exit, + .name = "omap1", + .attr = omap_cpufreq_attr, +}; + +static int __init omap_cpufreq_init(void) +{ + return cpufreq_register_driver(&omap_driver); +} + +static void __exit omap_cpufreq_exit(void) +{ + cpufreq_unregister_driver(&omap_driver); +} + +MODULE_DESCRIPTION("cpufreq driver for OMAP1 SOCs"); +MODULE_LICENSE("GPL"); +module_init(omap_cpufreq_init); +module_exit(omap_cpufreq_exit); diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index f6614a6898a..86a54ca1b6e 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -56,6 +56,9 @@ obj-$(CONFIG_ARCH_OMAP3) += opp3xxx_data.o obj-$(CONFIG_ARCH_OMAP4) += opp4xxx_data.o endif +# CPUFREQ driver +obj-$(CONFIG_CPU_FREQ) += omap2plus-cpufreq.o + # Power Management ifeq ($(CONFIG_PM),y) obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o diff --git a/arch/arm/mach-omap2/clock2420_data.c b/arch/arm/mach-omap2/clock2420_data.c index 3c1712b045a..dd9fd87a731 100644 --- a/arch/arm/mach-omap2/clock2420_data.c +++ b/arch/arm/mach-omap2/clock2420_data.c @@ -1799,6 +1799,7 @@ static struct omap_clk omap2420_clks[] = { CLK(NULL, "ssi_l4_ick", &ssi_l4_ick, CK_242X), /* virtual meta-group clock */ CLK(NULL, "virt_prcm_set", &virt_prcm_set, CK_242X), + CLK(NULL, "cpu_ck", &virt_prcm_set, CK_242X), /* general l4 interface ck, multi-parent functional clk */ CLK(NULL, "gpt1_ick", &gpt1_ick, CK_242X), CLK(NULL, "gpt1_fck", &gpt1_fck, CK_242X), diff --git a/arch/arm/mach-omap2/clock2430_data.c b/arch/arm/mach-omap2/clock2430_data.c index 136171c92c6..c698c1c8778 100644 --- a/arch/arm/mach-omap2/clock2430_data.c +++ b/arch/arm/mach-omap2/clock2430_data.c @@ -1903,6 +1903,7 @@ static struct omap_clk omap2430_clks[] = { CLK(NULL, "ssi_l4_ick", &ssi_l4_ick, CK_243X), /* virtual meta-group clock */ CLK(NULL, "virt_prcm_set", &virt_prcm_set, CK_243X), + CLK(NULL, "cpu_ck", &virt_prcm_set, CK_243X), /* general l4 interface ck, multi-parent functional clk */ CLK(NULL, "gpt1_ick", &gpt1_ick, CK_243X), CLK(NULL, "gpt1_fck", &gpt1_fck, CK_243X), diff --git a/arch/arm/mach-omap2/clock3xxx_data.c b/arch/arm/mach-omap2/clock3xxx_data.c index 414de70c7a3..b1c484cd891 100644 --- a/arch/arm/mach-omap2/clock3xxx_data.c +++ b/arch/arm/mach-omap2/clock3xxx_data.c @@ -3224,6 +3224,7 @@ static struct omap_clk omap3xxx_clks[] = { CLK(NULL, "mcbsp_clks", &mcbsp_clks, CK_3XXX), CLK(NULL, "sys_clkout1", &sys_clkout1, CK_3XXX), CLK(NULL, "dpll1_ck", &dpll1_ck, CK_3XXX), + CLK(NULL, "cpu_ck", &dpll1_ck, CK_3XXX), CLK(NULL, "dpll1_x2_ck", &dpll1_x2_ck, CK_3XXX), CLK(NULL, "dpll1_x2m2_ck", &dpll1_x2m2_ck, CK_3XXX), CLK(NULL, "dpll2_ck", &dpll2_ck, CK_34XX | CK_36XX), diff --git a/arch/arm/mach-omap2/clock44xx_data.c b/arch/arm/mach-omap2/clock44xx_data.c index bfaed63690d..95f2c4c9503 100644 --- a/arch/arm/mach-omap2/clock44xx_data.c +++ b/arch/arm/mach-omap2/clock44xx_data.c @@ -3057,6 +3057,7 @@ static struct omap_clk omap44xx_clks[] = { CLK(NULL, "dpll_iva_m4x2_ck", &dpll_iva_m4x2_ck, CK_443X), CLK(NULL, "dpll_iva_m5x2_ck", &dpll_iva_m5x2_ck, CK_443X), CLK(NULL, "dpll_mpu_ck", &dpll_mpu_ck, CK_443X), + CLK(NULL, "cpu_ck", &dpll_mpu_ck, CK_443X), CLK(NULL, "dpll_mpu_m2_ck", &dpll_mpu_m2_ck, CK_443X), CLK(NULL, "per_hs_clk_div_ck", &per_hs_clk_div_ck, CK_443X), CLK(NULL, "per_hsd_byp_clk_mux_ck", &per_hsd_byp_clk_mux_ck, CK_443X), diff --git a/arch/arm/mach-omap2/dvfs.c b/arch/arm/mach-omap2/dvfs.c index 1e5492c2ecb..fb9215cb927 100644 --- a/arch/arm/mach-omap2/dvfs.c +++ b/arch/arm/mach-omap2/dvfs.c @@ -100,6 +100,19 @@ static struct voltagedomain omap3_vdd[] = { .name = "core", }, }; + +static struct voltagedomain omap4_vdd[] = { + { + .name = "mpu", + }, + { + .name = "iva", + }, + { + .name = "core", + }, +}; + static int omap_dvfs_voltage_scale(struct omap_vdd_dvfs_info *dvfs_info); static int __init omap_dvfs_init(void); @@ -723,6 +736,12 @@ static int __init omap_dvfs_init() if (cpu_is_omap34xx()) { omap_nr_vdd = 2; vdd_list = omap3_vdd; + } else if (cpu_is_omap44xx()) { + omap_nr_vdd = 3; + vdd_list = omap4_vdd; + } else { + pr_warning("DVFS not supported\n"); + return -EINVAL; } omap_dvfs_info_list = kzalloc(omap_nr_vdd * diff --git a/arch/arm/mach-omap2/omap2plus-cpufreq.c b/arch/arm/mach-omap2/omap2plus-cpufreq.c new file mode 100644 index 00000000000..e982e13f2af --- /dev/null +++ b/arch/arm/mach-omap2/omap2plus-cpufreq.c @@ -0,0 +1,250 @@ +/* + * OMAP2PLUS cpufreq driver + * + * CPU frequency scaling for OMAP + * + * Copyright (C) 2005 Nokia Corporation + * Written by Tony Lindgren <tony@atomide.com> + * + * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King + * + * Copyright (C) 2007-2008 Texas Instruments, Inc. + * Updated to support OMAP3 + * Rajendra Nayak <rnayak@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/err.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/opp.h> +#include <linux/cpu.h> + +#include <asm/system.h> +#include <asm/smp_plat.h> +#include <asm/cpu.h> + +#include <plat/clock.h> +#include <plat/omap-pm.h> +#include <plat/common.h> + +#include <mach/hardware.h> +#include <plat/dvfs.h> + +#define VERY_HI_RATE 900000000 + +static struct cpufreq_frequency_table *freq_table; +static struct clk *mpu_clk; + +static int omap_verify_speed(struct cpufreq_policy *policy) +{ + if (freq_table) + return cpufreq_frequency_table_verify(policy, freq_table); + + if (policy->cpu) + return -EINVAL; + + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + + policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000; + policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000; + cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, + policy->cpuinfo.max_freq); + return 0; +} + +static unsigned int omap_getspeed(unsigned int cpu) +{ + unsigned long rate; + + if (cpu >= NR_CPUS) + return 0; + + rate = clk_get_rate(mpu_clk) / 1000; + return rate; +} + +static int omap_target(struct cpufreq_policy *policy, + unsigned int target_freq, + unsigned int relation) +{ + int i, ret = 0; + struct cpufreq_freqs freqs; + struct device *mpu_dev = omap2_get_mpuss_device(); + + /* Wait untill all CPU's are initialized */ + if (is_smp() && (num_online_cpus() < NR_CPUS)) + return ret; + + /* Ensure desired rate is within allowed range. Some govenors + * (ondemand) will just pass target_freq=0 to get the minimum. */ + if (target_freq < policy->min) + target_freq = policy->min; + if (target_freq > policy->max) + target_freq = policy->max; + + freqs.old = omap_getspeed(policy->cpu); + freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; + freqs.cpu = policy->cpu; + + if (freqs.old == freqs.new) + return ret; + + if (!is_smp()) { + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + goto set_freq; + } + + /* notifiers */ + for_each_cpu(i, policy->cpus) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); + } + +set_freq: +#ifdef CONFIG_CPU_FREQ_DEBUG + pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new); +#endif + + ret = omap_device_scale(mpu_dev, mpu_dev, freqs.new * 1000); + if (ret) + return ret; + freqs.new = omap_getspeed(policy->cpu); + + /* + * Generic CPUFREQ driver jiffy update is under !SMP. So jiffies + * won't get updated when UP machine cpufreq build with + * CONFIG_SMP enabled. Below code is added only to manage that + * scenario + */ + if (!is_smp()) { + loops_per_jiffy = + cpufreq_scale(loops_per_jiffy, freqs.old, freqs.new); + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + goto skip_lpj; + } + +#ifdef CONFIG_SMP + /* + * Note that loops_per_jiffy is not updated on SMP systems in + * cpufreq driver. So, update the per-CPU loops_per_jiffy value + * on frequency transition. We need to update all dependent 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 + + /* notifiers */ + for_each_cpu(i, policy->cpus) { + freqs.cpu = i; + cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); + } + +skip_lpj: + return ret; +} + +static int __init omap_cpu_init(struct cpufreq_policy *policy) +{ + int result = 0; + struct device *mpu_dev; + static cpumask_var_t cpumask; + + mpu_clk = clk_get(NULL, "cpu_ck"); + if (IS_ERR(mpu_clk)) + return PTR_ERR(mpu_clk); + + if (policy->cpu >= NR_CPUS) + return -EINVAL; + + policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu); + + mpu_dev = omap2_get_mpuss_device(); + if (!mpu_dev) { + pr_warning("%s: unable to get the mpu device\n", __func__); + return -EINVAL; + } + opp_init_cpufreq_table(mpu_dev, &freq_table); + + if (freq_table) { + result = cpufreq_frequency_table_cpuinfo(policy, freq_table); + if (!result) + cpufreq_frequency_table_get_attr(freq_table, + policy->cpu); + } else { + policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000; + policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, + VERY_HI_RATE) / 1000; + } + + policy->min = policy->cpuinfo.min_freq; + policy->max = policy->cpuinfo.max_freq; + policy->cur = omap_getspeed(policy->cpu); + + /* + * On OMAP SMP configuartion, both processors share the voltage + * and clock. So both CPUs needs to be scaled together and hence + * needs software co-ordination. Use cpufreq affected_cpus + * interface to handle this scenario. Additional is_smp() check + * is to keep SMP_ON_UP builf working. + */ + if (is_smp()) { + policy->shared_type = CPUFREQ_SHARED_TYPE_ANY; + cpumask_or(cpumask, cpumask_of(policy->cpu), cpumask); + cpumask_copy(policy->cpus, cpumask); + } + + /* FIXME: what's the actual transition time? */ + policy->cpuinfo.transition_latency = 300 * 1000; + + return 0; +} + +static int omap_cpu_exit(struct cpufreq_policy *policy) +{ + clk_exit_cpufreq_table(&freq_table); + clk_put(mpu_clk); + return 0; +} + +static struct freq_attr *omap_cpufreq_attr[] = { + &cpufreq_freq_attr_scaling_available_freqs, + NULL, +}; + +static struct cpufreq_driver omap_driver = { + .flags = CPUFREQ_STICKY, + .verify = omap_verify_speed, + .target = omap_target, + .get = omap_getspeed, + .init = omap_cpu_init, + .exit = omap_cpu_exit, + .name = "omap2plus", + .attr = omap_cpufreq_attr, +}; + +static int __init omap_cpufreq_init(void) +{ + return cpufreq_register_driver(&omap_driver); +} + +static void __exit omap_cpufreq_exit(void) +{ + cpufreq_unregister_driver(&omap_driver); +} + +MODULE_DESCRIPTION("cpufreq driver for OMAP2PLUS SOCs"); +MODULE_LICENSE("GPL"); +module_init(omap_cpufreq_init); +module_exit(omap_cpufreq_exit); diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c index 0bd579e98e7..93d441798d1 100644 --- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c +++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c @@ -2058,6 +2058,7 @@ static struct omap_hwmod omap44xx_mpu_hwmod = { .mpu_irqs = omap44xx_mpu_irqs, .mpu_irqs_cnt = ARRAY_SIZE(omap44xx_mpu_irqs), .main_clk = "dpll_mpu_m2_ck", + .vdd_name = "mpu", .prcm = { .omap4 = { .clkctrl_reg = OMAP4430_CM_MPU_MPU_CLKCTRL, diff --git a/arch/arm/mach-omap2/opp4xxx_data.c b/arch/arm/mach-omap2/opp4xxx_data.c index 80d08bcd612..2e8bb8a6ba9 100644 --- a/arch/arm/mach-omap2/opp4xxx_data.c +++ b/arch/arm/mach-omap2/opp4xxx_data.c @@ -30,9 +30,9 @@ static struct omap_opp_def __initdata omap44xx_opp_def_list[] = { /* MPU OPP2 - OPP100 */ OPP_INITIALIZER("mpu", true, 600000000, OMAP4430_VDD_MPU_OPP100_UV), /* MPU OPP3 - OPP-Turbo */ - OPP_INITIALIZER("mpu", false, 800000000, OMAP4430_VDD_MPU_OPPTURBO_UV), + OPP_INITIALIZER("mpu", true, 800000000, OMAP4430_VDD_MPU_OPPTURBO_UV), /* MPU OPP4 - OPP-SB */ - OPP_INITIALIZER("mpu", false, 1008000000, OMAP4430_VDD_MPU_OPPNITRO_UV), + OPP_INITIALIZER("mpu", true, 1008000000, OMAP4430_VDD_MPU_OPPNITRO_UV), /* L3 OPP1 - OPP50 */ OPP_INITIALIZER("l3_main_1", true, 100000000, OMAP4430_VDD_CORE_OPP50_UV), /* L3 OPP2 - OPP100, OPP-Turbo, OPP-SB */ diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c index 1b94ad47b07..51b0dcdef60 100644 --- a/arch/arm/mach-omap2/pm.c +++ b/arch/arm/mach-omap2/pm.c @@ -130,6 +130,24 @@ static unsigned long omap3_l3_get_rate(struct device *dev) return dpll3_clk->rate / l3_div; } +static int omap4_mpu_set_rate(struct device *dev, unsigned long rate) +{ + int ret; + + ret = clk_set_rate(dpll1_clk, rate); + if (ret) { + dev_warn(dev, "%s: Unable to set rate to %ld\n", + __func__, rate); + return ret; + } + + return 0; +} + +static unsigned long omap4_mpu_get_rate(struct device *dev) +{ + return dpll1_clk->rate; +} /* * Build omap_devices for processors and bus. @@ -160,7 +178,14 @@ static void omap2_init_processor_devices(void) omap_device_register_dvfs_callbacks(l3_dev, omap3_l3_set_rate, omap3_l3_get_rate); + } else if (cpu_is_omap44xx()) { + dpll1_clk = clk_get(NULL, "dpll_mpu_ck"); + + if (mpu_dev) + omap_device_register_dvfs_callbacks(mpu_dev, + omap4_mpu_set_rate, omap4_mpu_get_rate); } + } /* Types of sleep_switch used in omap_set_pwrdm_state */ diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index a4a12859fdd..ec7862e9149 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -21,7 +21,6 @@ obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o obj-$(CONFIG_OMAP_IOMMU) += iommu.o iovmm.o obj-$(CONFIG_OMAP_IOMMU_DEBUG) += iommu-debug.o -obj-$(CONFIG_CPU_FREQ) += cpu-omap.o obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c index 73452c700da..11c54ec8d47 100644 --- a/arch/arm/plat-omap/cpu-omap.c +++ b/arch/arm/plat-omap/cpu-omap.c @@ -8,10 +8,6 @@ * * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King * - * Copyright (C) 2007-2008 Texas Instruments, Inc. - * Updated to support OMAP3 - * Rajendra Nayak <rnayak@ti.com> - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. @@ -25,18 +21,10 @@ #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> -#include <linux/opp.h> #include <mach/hardware.h> #include <plat/clock.h> #include <asm/system.h> -#include <asm/cpu.h> - -#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) -#include <plat/omap-pm.h> -#include <plat/common.h> -#include <plat/dvfs.h> -#endif #define VERY_HI_RATE 900000000 @@ -44,8 +32,6 @@ static struct cpufreq_frequency_table *freq_table; #ifdef CONFIG_ARCH_OMAP1 #define MPU_CLK "mpu" -#elif defined(CONFIG_ARCH_OMAP3) -#define MPU_CLK "arm_fck" #else #define MPU_CLK "virt_prcm_set" #endif @@ -88,12 +74,6 @@ static int omap_target(struct cpufreq_policy *policy, unsigned int relation) { struct cpufreq_freqs freqs; -#if defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) - unsigned long freq; - int i; - struct cpufreq_freqs freqs_notify; - struct device *mpu_dev = omap2_get_mpuss_device(); -#endif int ret = 0; /* Ensure desired rate is within allowed range. Some govenors @@ -103,13 +83,13 @@ static int omap_target(struct cpufreq_policy *policy, if (target_freq > policy->max) target_freq = policy->max; -#ifdef CONFIG_ARCH_OMAP1 freqs.old = omap_getspeed(0); freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; freqs.cpu = 0; if (freqs.old == freqs.new) return ret; + cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); #ifdef CONFIG_CPU_FREQ_DEBUG printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n", @@ -117,39 +97,7 @@ static int omap_target(struct cpufreq_policy *policy, #endif ret = clk_set_rate(mpu_clk, freqs.new * 1000); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); -#elif defined(CONFIG_ARCH_OMAP3) && !defined(CONFIG_OMAP_PM_NONE) - freqs.old = omap_getspeed(policy->cpu);; - freqs_notify.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; - freqs.cpu = policy->cpu; - if (freqs.old == freqs.new) - return ret; - - /* pre notifiers */ - for_each_cpu(i, policy->cpus) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); - } - - /* scale the frequency */ - freq = target_freq * 1000; - if (opp_find_freq_ceil(mpu_dev, &freq)) - omap_device_scale(mpu_dev, mpu_dev, freq); - -#ifdef CONFIG_SMP - /* Update loops per jiffy */ - freqs.new = omap_getspeed(policy->cpu); - 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 - /* post notifiers */ - for_each_cpu(i, policy->cpus) { - freqs.cpu = i; - cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); - } -#endif return ret; } @@ -166,14 +114,7 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy) policy->cur = policy->min = policy->max = omap_getspeed(0); - if (!cpu_is_omap34xx()) { - clk_init_cpufreq_table(&freq_table); - } else { - struct device *mpu_dev = omap2_get_mpuss_device(); - - opp_init_cpufreq_table(mpu_dev, &freq_table); - } - + clk_init_cpufreq_table(&freq_table); if (freq_table) { result = cpufreq_frequency_table_cpuinfo(policy, freq_table); if (!result) @@ -185,10 +126,6 @@ static int __init omap_cpu_init(struct cpufreq_policy *policy) VERY_HI_RATE) / 1000; } - policy->min = policy->cpuinfo.min_freq; - policy->max = policy->cpuinfo.max_freq; - policy->cur = omap_getspeed(0); - /* FIXME: what's the actual transition time? */ policy->cpuinfo.transition_latency = 300 * 1000; @@ -223,7 +160,7 @@ static int __init omap_cpufreq_init(void) return cpufreq_register_driver(&omap_driver); } -late_initcall(omap_cpufreq_init); +arch_initcall(omap_cpufreq_init); /* * if ever we want to remove this, upon cleanup call: |