aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorKevin Hilman <khilman@mvista.com>2009-01-27 21:13:38 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-02-08 12:50:28 -0500
commitaeec299011da8c3f07a47fe5d988f0eafda53906 (patch)
tree8661476adf90325972e5feab723f1272ab04fc6b /arch
parentae8578c0194695bd37435249dfed720769a6bbf3 (diff)
[ARM] OMAP2: Implement CPUfreq frequency table based on PRCM table
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 <khilman@mvista.com> Updated to try to use cpufreq_table if it exists. linux-omap source commit is 77ce544fa48deb7a2003f454624e3ca10d37ab87. Signed-off-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Paul Walmsley <paul@pwsan.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-omap2/clock24xx.c42
-rw-r--r--arch/arm/plat-omap/cpu-omap.c57
-rw-r--r--arch/arm/plat-omap/include/mach/clock.h3
3 files changed, 98 insertions, 4 deletions
diff --git a/arch/arm/mach-omap2/clock24xx.c b/arch/arm/mach-omap2/clock24xx.c
index 421728a7f90..b9902666e4b 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)
574 return 0; 574 return 0;
575} 575}
576 576
577#ifdef CONFIG_CPU_FREQ
578/*
579 * Walk PRCM rate table and fillout cpufreq freq_table
580 */
581static struct cpufreq_frequency_table freq_table[ARRAY_SIZE(rate_table)];
582
583void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table)
584{
585 struct prcm_config *prcm;
586 int i = 0;
587
588 for (prcm = rate_table; prcm->mpu_speed; prcm++) {
589 if (!(prcm->flags & cpu_mask))
590 continue;
591 if (prcm->xtal_speed != sys_ck.rate)
592 continue;
593
594 /* don't put bypass rates in table */
595 if (prcm->dpll_speed == prcm->xtal_speed)
596 continue;
597
598 freq_table[i].index = i;
599 freq_table[i].frequency = prcm->mpu_speed / 1000;
600 i++;
601 }
602
603 if (i == 0) {
604 printk(KERN_WARNING "%s: failed to initialize frequency "
605 "table\n", __func__);
606 return;
607 }
608
609 freq_table[i].index = i;
610 freq_table[i].frequency = CPUFREQ_TABLE_END;
611
612 *table = &freq_table[0];
613}
614#endif
615
577static struct clk_functions omap2_clk_functions = { 616static struct clk_functions omap2_clk_functions = {
578 .clk_enable = omap2_clk_enable, 617 .clk_enable = omap2_clk_enable,
579 .clk_disable = omap2_clk_disable, 618 .clk_disable = omap2_clk_disable,
@@ -581,6 +620,9 @@ static struct clk_functions omap2_clk_functions = {
581 .clk_set_rate = omap2_clk_set_rate, 620 .clk_set_rate = omap2_clk_set_rate,
582 .clk_set_parent = omap2_clk_set_parent, 621 .clk_set_parent = omap2_clk_set_parent,
583 .clk_disable_unused = omap2_clk_disable_unused, 622 .clk_disable_unused = omap2_clk_disable_unused,
623#ifdef CONFIG_CPU_FREQ
624 .clk_init_cpufreq_table = omap2_clk_init_cpufreq_table,
625#endif
584}; 626};
585 627
586static u32 omap2_get_apll_clkin(void) 628static 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 b2690242a39..843e8af6406 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -23,10 +23,13 @@
23#include <linux/io.h> 23#include <linux/io.h>
24 24
25#include <mach/hardware.h> 25#include <mach/hardware.h>
26#include <mach/clock.h>
26#include <asm/system.h> 27#include <asm/system.h>
27 28
28#define VERY_HI_RATE 900000000 29#define VERY_HI_RATE 900000000
29 30
31static struct cpufreq_frequency_table *freq_table;
32
30#ifdef CONFIG_ARCH_OMAP1 33#ifdef CONFIG_ARCH_OMAP1
31#define MPU_CLK "mpu" 34#define MPU_CLK "mpu"
32#else 35#else
@@ -39,6 +42,9 @@ static struct clk *mpu_clk;
39 42
40int omap_verify_speed(struct cpufreq_policy *policy) 43int omap_verify_speed(struct cpufreq_policy *policy)
41{ 44{
45 if (freq_table)
46 return cpufreq_frequency_table_verify(policy, freq_table);
47
42 if (policy->cpu) 48 if (policy->cpu)
43 return -EINVAL; 49 return -EINVAL;
44 50
@@ -70,12 +76,26 @@ static int omap_target(struct cpufreq_policy *policy,
70 struct cpufreq_freqs freqs; 76 struct cpufreq_freqs freqs;
71 int ret = 0; 77 int ret = 0;
72 78
79 /* Ensure desired rate is within allowed range. Some govenors
80 * (ondemand) will just pass target_freq=0 to get the minimum. */
81 if (target_freq < policy->cpuinfo.min_freq)
82 target_freq = policy->cpuinfo.min_freq;
83 if (target_freq > policy->cpuinfo.max_freq)
84 target_freq = policy->cpuinfo.max_freq;
85
73 freqs.old = omap_getspeed(0); 86 freqs.old = omap_getspeed(0);
74 freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; 87 freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
75 freqs.cpu = 0; 88 freqs.cpu = 0;
76 89
90 if (freqs.old == freqs.new)
91 return ret;
92
77 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 93 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
78 ret = clk_set_rate(mpu_clk, target_freq * 1000); 94#ifdef CONFIG_CPU_FREQ_DEBUG
95 printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n",
96 freqs.old, freqs.new);
97#endif
98 ret = clk_set_rate(mpu_clk, freqs.new * 1000);
79 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 99 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
80 100
81 return ret; 101 return ret;
@@ -83,16 +103,31 @@ static int omap_target(struct cpufreq_policy *policy,
83 103
84static int __init omap_cpu_init(struct cpufreq_policy *policy) 104static int __init omap_cpu_init(struct cpufreq_policy *policy)
85{ 105{
106 int result = 0;
107
86 mpu_clk = clk_get(NULL, MPU_CLK); 108 mpu_clk = clk_get(NULL, MPU_CLK);
87 if (IS_ERR(mpu_clk)) 109 if (IS_ERR(mpu_clk))
88 return PTR_ERR(mpu_clk); 110 return PTR_ERR(mpu_clk);
89 111
90 if (policy->cpu != 0) 112 if (policy->cpu != 0)
91 return -EINVAL; 113 return -EINVAL;
114
92 policy->cur = policy->min = policy->max = omap_getspeed(0); 115 policy->cur = policy->min = policy->max = omap_getspeed(0);
93 policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000; 116
94 policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, VERY_HI_RATE) / 1000; 117 clk_init_cpufreq_table(&freq_table);
95 policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; 118 if (freq_table) {
119 result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
120 if (!result)
121 cpufreq_frequency_table_get_attr(freq_table,
122 policy->cpu);
123 } else {
124 policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
125 policy->cpuinfo.max_freq = clk_round_rate(mpu_clk,
126 VERY_HI_RATE) / 1000;
127 }
128
129 /* FIXME: what's the actual transition time? */
130 policy->cpuinfo.transition_latency = 10 * 1000 * 1000;
96 131
97 return 0; 132 return 0;
98} 133}
@@ -103,6 +138,11 @@ static int omap_cpu_exit(struct cpufreq_policy *policy)
103 return 0; 138 return 0;
104} 139}
105 140
141static struct freq_attr *omap_cpufreq_attr[] = {
142 &cpufreq_freq_attr_scaling_available_freqs,
143 NULL,
144};
145
106static struct cpufreq_driver omap_driver = { 146static struct cpufreq_driver omap_driver = {
107 .flags = CPUFREQ_STICKY, 147 .flags = CPUFREQ_STICKY,
108 .verify = omap_verify_speed, 148 .verify = omap_verify_speed,
@@ -111,6 +151,7 @@ static struct cpufreq_driver omap_driver = {
111 .init = omap_cpu_init, 151 .init = omap_cpu_init,
112 .exit = omap_cpu_exit, 152 .exit = omap_cpu_exit,
113 .name = "omap", 153 .name = "omap",
154 .attr = omap_cpufreq_attr,
114}; 155};
115 156
116static int __init omap_cpufreq_init(void) 157static int __init omap_cpufreq_init(void)
@@ -119,3 +160,11 @@ static int __init omap_cpufreq_init(void)
119} 160}
120 161
121arch_initcall(omap_cpufreq_init); 162arch_initcall(omap_cpufreq_init);
163
164/*
165 * if ever we want to remove this, upon cleanup call:
166 *
167 * cpufreq_unregister_driver()
168 * cpufreq_frequency_table_put_attr()
169 */
170
diff --git a/arch/arm/plat-omap/include/mach/clock.h b/arch/arm/plat-omap/include/mach/clock.h
index 6f49a333289..681c65105e2 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);
121extern void followparent_recalc(struct clk *clk); 121extern void followparent_recalc(struct clk *clk);
122extern int clk_get_usecount(struct clk *clk); 122extern int clk_get_usecount(struct clk *clk);
123extern void clk_enable_init_clocks(void); 123extern void clk_enable_init_clocks(void);
124#ifdef CONFIG_CPU_FREQ
125extern void clk_init_cpufreq_table(struct cpufreq_frequency_table **table);
126#endif
124 127
125extern const struct clkops clkops_null; 128extern const struct clkops clkops_null;
126 129