Commit c79589dc5e467705757d4a03345738c583308976

Authored by Nishanth Menon
Committed by Afzal Mohammed
1 parent f3b5c894fd
Exists in master

cpufreq: OMAP: only supports OPP library

OMAP2 is the only family using clk_[init|exit]_cpufreq_table, however,
the cpufreq code does not currently use clk_init_cpufreq_table. As a
result, it is unusuable for OMAP2 and only usable only on platforms
using OPP library.

Remove the unbalanced clk_exit_cpufreq_table().  Any platforms where
OPPs are not availble will fail on init because a freq table will not
be properly initialized.

Signed-off-by: Nishanth Menon <nm@ti.com>
[khilman@ti.com: changelog edits, and graceful failure mode changes]
Signed-off-by: Kevin Hilman <khilman@ti.com>
[vaibhav.bedia@ti.com: Pull in for AM33xx]
Signed-off-by: Vaibhav Bedia <vaibhav.bedia@ti.com>

Showing 1 changed file with 1 additions and 2 deletions Inline Diff

drivers/cpufreq/omap-cpufreq.c
1 /* 1 /*
2 * CPU frequency scaling for OMAP 2 * CPU frequency scaling for OMAP using OPP information
3 * 3 *
4 * Copyright (C) 2005 Nokia Corporation 4 * Copyright (C) 2005 Nokia Corporation
5 * Written by Tony Lindgren <tony@atomide.com> 5 * Written by Tony Lindgren <tony@atomide.com>
6 * 6 *
7 * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King 7 * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
8 * 8 *
9 * Copyright (C) 2007-2011 Texas Instruments, Inc. 9 * Copyright (C) 2007-2011 Texas Instruments, Inc.
10 * - OMAP3/4 support by Rajendra Nayak, Santosh Shilimkar 10 * - OMAP3/4 support by Rajendra Nayak, Santosh Shilimkar
11 * 11 *
12 * This program is free software; you can redistribute it and/or modify 12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as 13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation. 14 * published by the Free Software Foundation.
15 */ 15 */
16 #include <linux/types.h> 16 #include <linux/types.h>
17 #include <linux/kernel.h> 17 #include <linux/kernel.h>
18 #include <linux/sched.h> 18 #include <linux/sched.h>
19 #include <linux/cpufreq.h> 19 #include <linux/cpufreq.h>
20 #include <linux/delay.h> 20 #include <linux/delay.h>
21 #include <linux/init.h> 21 #include <linux/init.h>
22 #include <linux/err.h> 22 #include <linux/err.h>
23 #include <linux/clk.h> 23 #include <linux/clk.h>
24 #include <linux/io.h> 24 #include <linux/io.h>
25 #include <linux/opp.h> 25 #include <linux/opp.h>
26 #include <linux/cpu.h> 26 #include <linux/cpu.h>
27 27
28 #include <asm/system.h> 28 #include <asm/system.h>
29 #include <asm/smp_plat.h> 29 #include <asm/smp_plat.h>
30 #include <asm/cpu.h> 30 #include <asm/cpu.h>
31 31
32 #include <plat/clock.h> 32 #include <plat/clock.h>
33 #include <plat/omap-pm.h> 33 #include <plat/omap-pm.h>
34 #include <plat/omap_device.h> 34 #include <plat/omap_device.h>
35 #include <plat/common.h> 35 #include <plat/common.h>
36 36
37 #include <mach/hardware.h> 37 #include <mach/hardware.h>
38 38
39 #ifdef CONFIG_SMP 39 #ifdef CONFIG_SMP
40 struct lpj_info { 40 struct lpj_info {
41 unsigned long ref; 41 unsigned long ref;
42 unsigned int freq; 42 unsigned int freq;
43 }; 43 };
44 44
45 static DEFINE_PER_CPU(struct lpj_info, lpj_ref); 45 static DEFINE_PER_CPU(struct lpj_info, lpj_ref);
46 static struct lpj_info global_lpj_ref; 46 static struct lpj_info global_lpj_ref;
47 #endif 47 #endif
48 48
49 static struct cpufreq_frequency_table *freq_table; 49 static struct cpufreq_frequency_table *freq_table;
50 static struct clk *mpu_clk; 50 static struct clk *mpu_clk;
51 static char *mpu_clk_name; 51 static char *mpu_clk_name;
52 static struct device *mpu_dev; 52 static struct device *mpu_dev;
53 53
54 static int omap_verify_speed(struct cpufreq_policy *policy) 54 static int omap_verify_speed(struct cpufreq_policy *policy)
55 { 55 {
56 if (!freq_table) 56 if (!freq_table)
57 return -EINVAL; 57 return -EINVAL;
58 return cpufreq_frequency_table_verify(policy, freq_table); 58 return cpufreq_frequency_table_verify(policy, freq_table);
59 } 59 }
60 60
61 static unsigned int omap_getspeed(unsigned int cpu) 61 static unsigned int omap_getspeed(unsigned int cpu)
62 { 62 {
63 unsigned long rate; 63 unsigned long rate;
64 64
65 if (cpu >= NR_CPUS) 65 if (cpu >= NR_CPUS)
66 return 0; 66 return 0;
67 67
68 rate = clk_get_rate(mpu_clk) / 1000; 68 rate = clk_get_rate(mpu_clk) / 1000;
69 return rate; 69 return rate;
70 } 70 }
71 71
72 static int omap_target(struct cpufreq_policy *policy, 72 static int omap_target(struct cpufreq_policy *policy,
73 unsigned int target_freq, 73 unsigned int target_freq,
74 unsigned int relation) 74 unsigned int relation)
75 { 75 {
76 unsigned int i; 76 unsigned int i;
77 int ret = 0; 77 int ret = 0;
78 struct cpufreq_freqs freqs; 78 struct cpufreq_freqs freqs;
79 79
80 if (!freq_table) { 80 if (!freq_table) {
81 dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__, 81 dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__,
82 policy->cpu); 82 policy->cpu);
83 return -EINVAL; 83 return -EINVAL;
84 } 84 }
85 85
86 ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, 86 ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
87 relation, &i); 87 relation, &i);
88 if (ret) { 88 if (ret) {
89 dev_dbg(mpu_dev, "%s: cpu%d: no freq match for %d(ret=%d)\n", 89 dev_dbg(mpu_dev, "%s: cpu%d: no freq match for %d(ret=%d)\n",
90 __func__, policy->cpu, target_freq, ret); 90 __func__, policy->cpu, target_freq, ret);
91 return ret; 91 return ret;
92 } 92 }
93 freqs.new = freq_table[i].frequency; 93 freqs.new = freq_table[i].frequency;
94 if (!freqs.new) { 94 if (!freqs.new) {
95 dev_err(mpu_dev, "%s: cpu%d: no match for freq %d\n", __func__, 95 dev_err(mpu_dev, "%s: cpu%d: no match for freq %d\n", __func__,
96 policy->cpu, target_freq); 96 policy->cpu, target_freq);
97 return -EINVAL; 97 return -EINVAL;
98 } 98 }
99 99
100 freqs.old = omap_getspeed(policy->cpu); 100 freqs.old = omap_getspeed(policy->cpu);
101 freqs.cpu = policy->cpu; 101 freqs.cpu = policy->cpu;
102 102
103 if (freqs.old == freqs.new && policy->cur == freqs.new) 103 if (freqs.old == freqs.new && policy->cur == freqs.new)
104 return ret; 104 return ret;
105 105
106 /* notifiers */ 106 /* notifiers */
107 for_each_cpu(i, policy->cpus) { 107 for_each_cpu(i, policy->cpus) {
108 freqs.cpu = i; 108 freqs.cpu = i;
109 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 109 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
110 } 110 }
111 111
112 #ifdef CONFIG_CPU_FREQ_DEBUG 112 #ifdef CONFIG_CPU_FREQ_DEBUG
113 pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new); 113 pr_info("cpufreq-omap: transition: %u --> %u\n", freqs.old, freqs.new);
114 #endif 114 #endif
115 115
116 ret = clk_set_rate(mpu_clk, freqs.new * 1000); 116 ret = clk_set_rate(mpu_clk, freqs.new * 1000);
117 freqs.new = omap_getspeed(policy->cpu); 117 freqs.new = omap_getspeed(policy->cpu);
118 118
119 #ifdef CONFIG_SMP 119 #ifdef CONFIG_SMP
120 /* 120 /*
121 * Note that loops_per_jiffy is not updated on SMP systems in 121 * Note that loops_per_jiffy is not updated on SMP systems in
122 * cpufreq driver. So, update the per-CPU loops_per_jiffy value 122 * cpufreq driver. So, update the per-CPU loops_per_jiffy value
123 * on frequency transition. We need to update all dependent CPUs. 123 * on frequency transition. We need to update all dependent CPUs.
124 */ 124 */
125 for_each_cpu(i, policy->cpus) { 125 for_each_cpu(i, policy->cpus) {
126 struct lpj_info *lpj = &per_cpu(lpj_ref, i); 126 struct lpj_info *lpj = &per_cpu(lpj_ref, i);
127 if (!lpj->freq) { 127 if (!lpj->freq) {
128 lpj->ref = per_cpu(cpu_data, i).loops_per_jiffy; 128 lpj->ref = per_cpu(cpu_data, i).loops_per_jiffy;
129 lpj->freq = freqs.old; 129 lpj->freq = freqs.old;
130 } 130 }
131 131
132 per_cpu(cpu_data, i).loops_per_jiffy = 132 per_cpu(cpu_data, i).loops_per_jiffy =
133 cpufreq_scale(lpj->ref, lpj->freq, freqs.new); 133 cpufreq_scale(lpj->ref, lpj->freq, freqs.new);
134 } 134 }
135 135
136 /* And don't forget to adjust the global one */ 136 /* And don't forget to adjust the global one */
137 if (!global_lpj_ref.freq) { 137 if (!global_lpj_ref.freq) {
138 global_lpj_ref.ref = loops_per_jiffy; 138 global_lpj_ref.ref = loops_per_jiffy;
139 global_lpj_ref.freq = freqs.old; 139 global_lpj_ref.freq = freqs.old;
140 } 140 }
141 loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq, 141 loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq,
142 freqs.new); 142 freqs.new);
143 #endif 143 #endif
144 144
145 /* notifiers */ 145 /* notifiers */
146 for_each_cpu(i, policy->cpus) { 146 for_each_cpu(i, policy->cpus) {
147 freqs.cpu = i; 147 freqs.cpu = i;
148 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 148 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
149 } 149 }
150 150
151 return ret; 151 return ret;
152 } 152 }
153 153
154 static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy) 154 static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
155 { 155 {
156 int result = 0; 156 int result = 0;
157 157
158 mpu_clk = clk_get(NULL, mpu_clk_name); 158 mpu_clk = clk_get(NULL, mpu_clk_name);
159 if (IS_ERR(mpu_clk)) 159 if (IS_ERR(mpu_clk))
160 return PTR_ERR(mpu_clk); 160 return PTR_ERR(mpu_clk);
161 161
162 if (policy->cpu >= NR_CPUS) 162 if (policy->cpu >= NR_CPUS)
163 return -EINVAL; 163 return -EINVAL;
164 164
165 policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu); 165 policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu);
166 result = opp_init_cpufreq_table(mpu_dev, &freq_table); 166 result = opp_init_cpufreq_table(mpu_dev, &freq_table);
167 167
168 if (result) { 168 if (result) {
169 dev_err(mpu_dev, "%s: cpu%d: failed creating freq table[%d]\n", 169 dev_err(mpu_dev, "%s: cpu%d: failed creating freq table[%d]\n",
170 __func__, policy->cpu, result); 170 __func__, policy->cpu, result);
171 return result; 171 return result;
172 } 172 }
173 173
174 result = cpufreq_frequency_table_cpuinfo(policy, freq_table); 174 result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
175 if (!result) 175 if (!result)
176 cpufreq_frequency_table_get_attr(freq_table, policy->cpu); 176 cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
177 177
178 policy->min = policy->cpuinfo.min_freq; 178 policy->min = policy->cpuinfo.min_freq;
179 policy->max = policy->cpuinfo.max_freq; 179 policy->max = policy->cpuinfo.max_freq;
180 policy->cur = omap_getspeed(policy->cpu); 180 policy->cur = omap_getspeed(policy->cpu);
181 181
182 /* 182 /*
183 * On OMAP SMP configuartion, both processors share the voltage 183 * On OMAP SMP configuartion, both processors share the voltage
184 * and clock. So both CPUs needs to be scaled together and hence 184 * and clock. So both CPUs needs to be scaled together and hence
185 * needs software co-ordination. Use cpufreq affected_cpus 185 * needs software co-ordination. Use cpufreq affected_cpus
186 * interface to handle this scenario. Additional is_smp() check 186 * interface to handle this scenario. Additional is_smp() check
187 * is to keep SMP_ON_UP build working. 187 * is to keep SMP_ON_UP build working.
188 */ 188 */
189 if (is_smp()) { 189 if (is_smp()) {
190 policy->shared_type = CPUFREQ_SHARED_TYPE_ANY; 190 policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
191 cpumask_setall(policy->cpus); 191 cpumask_setall(policy->cpus);
192 } 192 }
193 193
194 /* FIXME: what's the actual transition time? */ 194 /* FIXME: what's the actual transition time? */
195 policy->cpuinfo.transition_latency = 300 * 1000; 195 policy->cpuinfo.transition_latency = 300 * 1000;
196 196
197 return 0; 197 return 0;
198 } 198 }
199 199
200 static int omap_cpu_exit(struct cpufreq_policy *policy) 200 static int omap_cpu_exit(struct cpufreq_policy *policy)
201 { 201 {
202 clk_exit_cpufreq_table(&freq_table);
203 clk_put(mpu_clk); 202 clk_put(mpu_clk);
204 return 0; 203 return 0;
205 } 204 }
206 205
207 static struct freq_attr *omap_cpufreq_attr[] = { 206 static struct freq_attr *omap_cpufreq_attr[] = {
208 &cpufreq_freq_attr_scaling_available_freqs, 207 &cpufreq_freq_attr_scaling_available_freqs,
209 NULL, 208 NULL,
210 }; 209 };
211 210
212 static struct cpufreq_driver omap_driver = { 211 static struct cpufreq_driver omap_driver = {
213 .flags = CPUFREQ_STICKY, 212 .flags = CPUFREQ_STICKY,
214 .verify = omap_verify_speed, 213 .verify = omap_verify_speed,
215 .target = omap_target, 214 .target = omap_target,
216 .get = omap_getspeed, 215 .get = omap_getspeed,
217 .init = omap_cpu_init, 216 .init = omap_cpu_init,
218 .exit = omap_cpu_exit, 217 .exit = omap_cpu_exit,
219 .name = "omap", 218 .name = "omap",
220 .attr = omap_cpufreq_attr, 219 .attr = omap_cpufreq_attr,
221 }; 220 };
222 221
223 static int __init omap_cpufreq_init(void) 222 static int __init omap_cpufreq_init(void)
224 { 223 {
225 if (cpu_is_omap24xx()) 224 if (cpu_is_omap24xx())
226 mpu_clk_name = "virt_prcm_set"; 225 mpu_clk_name = "virt_prcm_set";
227 else if (cpu_is_omap34xx()) 226 else if (cpu_is_omap34xx())
228 mpu_clk_name = "dpll1_ck"; 227 mpu_clk_name = "dpll1_ck";
229 else if (cpu_is_omap44xx()) 228 else if (cpu_is_omap44xx())
230 mpu_clk_name = "dpll_mpu_ck"; 229 mpu_clk_name = "dpll_mpu_ck";
231 230
232 if (!mpu_clk_name) { 231 if (!mpu_clk_name) {
233 pr_err("%s: unsupported Silicon?\n", __func__); 232 pr_err("%s: unsupported Silicon?\n", __func__);
234 return -EINVAL; 233 return -EINVAL;
235 } 234 }
236 235
237 mpu_dev = omap_device_get_by_hwmod_name("mpu"); 236 mpu_dev = omap_device_get_by_hwmod_name("mpu");
238 if (!mpu_dev) { 237 if (!mpu_dev) {
239 pr_warning("%s: unable to get the mpu device\n", __func__); 238 pr_warning("%s: unable to get the mpu device\n", __func__);
240 return -EINVAL; 239 return -EINVAL;
241 } 240 }
242 241
243 return cpufreq_register_driver(&omap_driver); 242 return cpufreq_register_driver(&omap_driver);
244 } 243 }
245 244
246 static void __exit omap_cpufreq_exit(void) 245 static void __exit omap_cpufreq_exit(void)
247 { 246 {
248 cpufreq_unregister_driver(&omap_driver); 247 cpufreq_unregister_driver(&omap_driver);
249 } 248 }
250 249
251 MODULE_DESCRIPTION("cpufreq driver for OMAP SoCs"); 250 MODULE_DESCRIPTION("cpufreq driver for OMAP SoCs");
252 MODULE_LICENSE("GPL"); 251 MODULE_LICENSE("GPL");
253 module_init(omap_cpufreq_init); 252 module_init(omap_cpufreq_init);
254 module_exit(omap_cpufreq_exit); 253 module_exit(omap_cpufreq_exit);
255 254