Root/
1 | /* |
2 | * linux/arch/arm/plat-omap/cpu-omap.c |
3 | * |
4 | * CPU frequency scaling for OMAP |
5 | * |
6 | * Copyright (C) 2005 Nokia Corporation |
7 | * Written by Tony Lindgren <tony@atomide.com> |
8 | * |
9 | * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King |
10 | * |
11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License version 2 as |
13 | * published by the Free Software Foundation. |
14 | */ |
15 | #include <linux/types.h> |
16 | #include <linux/kernel.h> |
17 | #include <linux/sched.h> |
18 | #include <linux/cpufreq.h> |
19 | #include <linux/delay.h> |
20 | #include <linux/init.h> |
21 | #include <linux/err.h> |
22 | #include <linux/clk.h> |
23 | #include <linux/io.h> |
24 | |
25 | #include <mach/hardware.h> |
26 | #include <plat/clock.h> |
27 | #include <asm/system.h> |
28 | |
29 | #define VERY_HI_RATE 900000000 |
30 | |
31 | static struct cpufreq_frequency_table *freq_table; |
32 | |
33 | #ifdef CONFIG_ARCH_OMAP1 |
34 | #define MPU_CLK "mpu" |
35 | #else |
36 | #define MPU_CLK "virt_prcm_set" |
37 | #endif |
38 | |
39 | static struct clk *mpu_clk; |
40 | |
41 | /* TODO: Add support for SDRAM timing changes */ |
42 | |
43 | static int omap_verify_speed(struct cpufreq_policy *policy) |
44 | { |
45 | if (freq_table) |
46 | return cpufreq_frequency_table_verify(policy, freq_table); |
47 | |
48 | if (policy->cpu) |
49 | return -EINVAL; |
50 | |
51 | cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, |
52 | policy->cpuinfo.max_freq); |
53 | |
54 | policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000; |
55 | policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000; |
56 | cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, |
57 | policy->cpuinfo.max_freq); |
58 | return 0; |
59 | } |
60 | |
61 | static unsigned int omap_getspeed(unsigned int cpu) |
62 | { |
63 | unsigned long rate; |
64 | |
65 | if (cpu) |
66 | return 0; |
67 | |
68 | rate = clk_get_rate(mpu_clk) / 1000; |
69 | return rate; |
70 | } |
71 | |
72 | static int omap_target(struct cpufreq_policy *policy, |
73 | unsigned int target_freq, |
74 | unsigned int relation) |
75 | { |
76 | struct cpufreq_freqs freqs; |
77 | int ret = 0; |
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->min) |
82 | target_freq = policy->min; |
83 | if (target_freq > policy->max) |
84 | target_freq = policy->max; |
85 | |
86 | freqs.old = omap_getspeed(0); |
87 | freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000; |
88 | freqs.cpu = 0; |
89 | |
90 | if (freqs.old == freqs.new) |
91 | return ret; |
92 | |
93 | cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); |
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); |
99 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); |
100 | |
101 | return ret; |
102 | } |
103 | |
104 | static int __init omap_cpu_init(struct cpufreq_policy *policy) |
105 | { |
106 | int result = 0; |
107 | |
108 | mpu_clk = clk_get(NULL, MPU_CLK); |
109 | if (IS_ERR(mpu_clk)) |
110 | return PTR_ERR(mpu_clk); |
111 | |
112 | if (policy->cpu != 0) |
113 | return -EINVAL; |
114 | |
115 | policy->cur = policy->min = policy->max = omap_getspeed(0); |
116 | |
117 | clk_init_cpufreq_table(&freq_table); |
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 = 300 * 1000; |
131 | |
132 | return 0; |
133 | } |
134 | |
135 | static int omap_cpu_exit(struct cpufreq_policy *policy) |
136 | { |
137 | clk_exit_cpufreq_table(&freq_table); |
138 | clk_put(mpu_clk); |
139 | return 0; |
140 | } |
141 | |
142 | static struct freq_attr *omap_cpufreq_attr[] = { |
143 | &cpufreq_freq_attr_scaling_available_freqs, |
144 | NULL, |
145 | }; |
146 | |
147 | static struct cpufreq_driver omap_driver = { |
148 | .flags = CPUFREQ_STICKY, |
149 | .verify = omap_verify_speed, |
150 | .target = omap_target, |
151 | .get = omap_getspeed, |
152 | .init = omap_cpu_init, |
153 | .exit = omap_cpu_exit, |
154 | .name = "omap", |
155 | .attr = omap_cpufreq_attr, |
156 | }; |
157 | |
158 | static int __init omap_cpufreq_init(void) |
159 | { |
160 | return cpufreq_register_driver(&omap_driver); |
161 | } |
162 | |
163 | arch_initcall(omap_cpufreq_init); |
164 | |
165 | /* |
166 | * if ever we want to remove this, upon cleanup call: |
167 | * |
168 | * cpufreq_unregister_driver() |
169 | * cpufreq_frequency_table_put_attr() |
170 | */ |
171 | |
172 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9