From patchwork Thu Mar 12 18:27:55 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kevin Hilman X-Patchwork-Id: 11476 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n2CIW7Td013278 for ; Thu, 12 Mar 2009 18:32:07 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756702AbZCLScF (ORCPT ); Thu, 12 Mar 2009 14:32:05 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1756723AbZCLScE (ORCPT ); Thu, 12 Mar 2009 14:32:04 -0400 Received: from qw-out-2122.google.com ([74.125.92.27]:41257 "EHLO qw-out-2122.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753052AbZCLScB (ORCPT ); Thu, 12 Mar 2009 14:32:01 -0400 Received: by qw-out-2122.google.com with SMTP id 5so1102985qwi.37 for ; Thu, 12 Mar 2009 11:31:58 -0700 (PDT) Received: by 10.142.173.8 with SMTP id v8mr116300wfe.181.1236882718226; Thu, 12 Mar 2009 11:31:58 -0700 (PDT) Received: from localhost ([216.254.16.51]) by mx.google.com with ESMTPS id 28sm1980619wfg.31.2009.03.12.11.31.55 (version=TLSv1/SSLv3 cipher=RC4-MD5); Thu, 12 Mar 2009 11:31:57 -0700 (PDT) From: Kevin Hilman To: linux-omap@vger.kernel.org Subject: [PATCH 45/86] [ARM] OMAP2: Implement CPUfreq frequency table based on PRCM table Date: Thu, 12 Mar 2009 11:27:55 -0700 Message-Id: <1236882516-29403-46-git-send-email-khilman@deeprootsystems.com> X-Mailer: git-send-email 1.6.1.2 In-Reply-To: <1236882516-29403-45-git-send-email-khilman@deeprootsystems.com> References: <1236882516-29403-1-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-2-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-3-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-4-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-5-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-6-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-7-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-8-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-9-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-10-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-11-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-12-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-13-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-14-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-15-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-16-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-17-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-18-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-19-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-20-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-21-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-22-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-23-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-24-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-25-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-26-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-27-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-28-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-29-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-30-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-31-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-32-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-33-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-34-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-35-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-36-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-37-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-38-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-39-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-40-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-41-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-42-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-43-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-44-git-send-email-khilman@deeprootsystems.com> <1236882516-29403-45-git-send-email-khilman@deeprootsystems.com> Sender: linux-omap-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-omap@vger.kernel.org From: Kevin Hilman This patch adds a CPUfreq frequency-table implementation for OMAP2 by walking the PRCM rate-table for available entries and adding them to a CPUfreq table. CPUfreq can then be used to manage switching between all the available entries in the PRCM rate table. Either use the CPUfreq sysfs interface directly, (see Section 3 of Documentation/cpu-freq/user-guide.txt) or use the cpufrequtils package: http://www.kernel.org/pub/linux/utils/kernel/cpufreq/cpufrequtils.html Signed-off-by: Kevin Hilman Updated to try to use cpufreq_table if it exists. linux-omap source commit is 77ce544fa48deb7a2003f454624e3ca10d37ab87. Signed-off-by: Tony Lindgren Signed-off-by: Paul Walmsley Signed-off-by: Russell King --- arch/arm/mach-omap2/clock24xx.c | 42 ++++++++++++++++++++++ arch/arm/plat-omap/cpu-omap.c | 57 ++++++++++++++++++++++++++++-- arch/arm/plat-omap/include/mach/clock.h | 3 ++ 3 files changed, 98 insertions(+), 4 deletions(-) diff --git a/arch/arm/mach-omap2/clock24xx.c b/arch/arm/mach-omap2/clock24xx.c index 421728a..b990266 100644 --- a/arch/arm/mach-omap2/clock24xx.c +++ b/arch/arm/mach-omap2/clock24xx.c @@ -574,6 +574,45 @@ static int omap2_select_table_rate(struct clk *clk, unsigned long rate) return 0; } +#ifdef CONFIG_CPU_FREQ +/* + * Walk PRCM rate table and fillout cpufreq freq_table + */ +static struct cpufreq_frequency_table freq_table[ARRAY_SIZE(rate_table)]; + +void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table) +{ + struct prcm_config *prcm; + int i = 0; + + for (prcm = rate_table; prcm->mpu_speed; prcm++) { + if (!(prcm->flags & cpu_mask)) + continue; + if (prcm->xtal_speed != sys_ck.rate) + continue; + + /* don't put bypass rates in table */ + if (prcm->dpll_speed == prcm->xtal_speed) + continue; + + freq_table[i].index = i; + freq_table[i].frequency = prcm->mpu_speed / 1000; + i++; + } + + if (i == 0) { + printk(KERN_WARNING "%s: failed to initialize frequency " + "table\n", __func__); + return; + } + + freq_table[i].index = i; + freq_table[i].frequency = CPUFREQ_TABLE_END; + + *table = &freq_table[0]; +} +#endif + static struct clk_functions omap2_clk_functions = { .clk_enable = omap2_clk_enable, .clk_disable = omap2_clk_disable, @@ -581,6 +620,9 @@ static struct clk_functions omap2_clk_functions = { .clk_set_rate = omap2_clk_set_rate, .clk_set_parent = omap2_clk_set_parent, .clk_disable_unused = omap2_clk_disable_unused, +#ifdef CONFIG_CPU_FREQ + .clk_init_cpufreq_table = omap2_clk_init_cpufreq_table, +#endif }; static u32 omap2_get_apll_clkin(void) diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c index b269024..843e8af 100644 --- a/arch/arm/plat-omap/cpu-omap.c +++ b/arch/arm/plat-omap/cpu-omap.c @@ -23,10 +23,13 @@ #include #include +#include #include #define VERY_HI_RATE 900000000 +static struct cpufreq_frequency_table *freq_table; + #ifdef CONFIG_ARCH_OMAP1 #define MPU_CLK "mpu" #else @@ -39,6 +42,9 @@ static struct clk *mpu_clk; int omap_verify_speed(struct cpufreq_policy *policy) { + if (freq_table) + return cpufreq_frequency_table_verify(policy, freq_table); + if (policy->cpu) return -EINVAL; @@ -70,12 +76,26 @@ static int omap_target(struct cpufreq_policy *policy, 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->cpuinfo.min_freq) + target_freq = policy->cpuinfo.min_freq; + if (target_freq > policy->cpuinfo.max_freq) + target_freq = policy->cpuinfo.max_freq; + 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); - ret = clk_set_rate(mpu_clk, target_freq * 1000); +#ifdef CONFIG_CPU_FREQ_DEBUG + printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n", + freqs.old, freqs.new); +#endif + ret = clk_set_rate(mpu_clk, freqs.new * 1000); cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); return ret; @@ -83,16 +103,31 @@ static int omap_target(struct cpufreq_policy *policy, static int __init omap_cpu_init(struct cpufreq_policy *policy) { + int result = 0; + mpu_clk = clk_get(NULL, MPU_CLK); 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); - 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->cpuinfo.transition_latency = CPUFREQ_ETERNAL; + + 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; + } + + /* FIXME: what's the actual transition time? */ + policy->cpuinfo.transition_latency = 10 * 1000 * 1000; return 0; } @@ -103,6 +138,11 @@ static int omap_cpu_exit(struct cpufreq_policy *policy) 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, @@ -111,6 +151,7 @@ static struct cpufreq_driver omap_driver = { .init = omap_cpu_init, .exit = omap_cpu_exit, .name = "omap", + .attr = omap_cpufreq_attr, }; static int __init omap_cpufreq_init(void) @@ -119,3 +160,11 @@ static int __init omap_cpufreq_init(void) } arch_initcall(omap_cpufreq_init); + +/* + * if ever we want to remove this, upon cleanup call: + * + * cpufreq_unregister_driver() + * cpufreq_frequency_table_put_attr() + */ + diff --git a/arch/arm/plat-omap/include/mach/clock.h b/arch/arm/plat-omap/include/mach/clock.h index 6f49a33..681c651 100644 --- a/arch/arm/plat-omap/include/mach/clock.h +++ b/arch/arm/plat-omap/include/mach/clock.h @@ -121,6 +121,9 @@ extern void recalculate_root_clocks(void); extern void followparent_recalc(struct clk *clk); extern int clk_get_usecount(struct clk *clk); extern void clk_enable_init_clocks(void); +#ifdef CONFIG_CPU_FREQ +extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table); +#endif extern const struct clkops clkops_null;