1 /*
2 * CPU frequency scaling for OMAP using OPP information
3 *
4 * Copyright (C) 2005 Nokia Corporation
5 * Written by Tony Lindgren <tony@atomide.com>
6 *
7 * Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
8 *
9 * Copyright (C) 2007-2011 Texas Instruments, Inc.
10 * - OMAP3/4 support by Rajendra Nayak, Santosh Shilimkar
11 *
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
14 * published by the Free Software Foundation.
15 */
16 #include <linux/types.h>
17 #include <linux/kernel.h>
18 #include <linux/sched.h>
19 #include <linux/cpufreq.h>
20 #include <linux/delay.h>
21 #include <linux/init.h>
22 #include <linux/err.h>
23 #include <linux/clk.h>
24 #include <linux/io.h>
25 #include <linux/opp.h>
26 #include <linux/cpu.h>
27 #include <linux/module.h>
28 #include <linux/regulator/consumer.h>
29 #include <linux/suspend.h>
31 #include <asm/system.h>
32 #include <asm/smp_plat.h>
33 #include <asm/cpu.h>
35 #include <plat/clock.h>
36 #include <plat/omap-pm.h>
37 #include <plat/common.h>
38 #include <plat/omap_device.h>
40 #include <mach/hardware.h>
42 /* Tolerance for MPU voltage is 4%, we have to pass +4% as a
43 * maximum voltage while setting the MPU regulator voltage.
44 * Which is taken from AM33XX datasheet */
45 #define MPU_TOLERANCE 4
46 #define PER_ROUND_VAL 100
48 /* Use 275MHz when entering suspend */
49 #define SLEEP_FREQ (275 * 1000)
52 #ifdef CONFIG_SMP
53 struct lpj_info {
54 unsigned long ref;
55 unsigned int freq;
56 };
58 static DEFINE_PER_CPU(struct lpj_info, lpj_ref);
59 static struct lpj_info global_lpj_ref;
60 #endif
62 static struct cpufreq_frequency_table *freq_table;
63 static atomic_t freq_table_users = ATOMIC_INIT(0);
64 static struct clk *mpu_clk;
65 static char *mpu_clk_name;
66 static struct device *mpu_dev;
67 static struct regulator *mpu_reg;
68 static DEFINE_MUTEX(omap_cpu_lock);
69 static bool is_suspended;
71 static int omap_verify_speed(struct cpufreq_policy *policy)
72 {
73 if (!freq_table)
74 return -EINVAL;
75 return cpufreq_frequency_table_verify(policy, freq_table);
76 }
78 static unsigned int omap_getspeed(unsigned int cpu)
79 {
80 unsigned long rate;
82 if (cpu >= NR_CPUS)
83 return 0;
85 rate = clk_get_rate(mpu_clk) / 1000;
86 return rate;
87 }
89 static int omap_target(struct cpufreq_policy *policy,
90 unsigned int target_freq,
91 unsigned int relation)
92 {
93 unsigned int i;
94 int ret = 0;
95 struct cpufreq_freqs freqs;
96 struct opp *opp;
97 int volt_old = 0, volt_new = 0;
99 if (is_suspended)
100 return -EBUSY;
102 if (!freq_table) {
103 dev_err(mpu_dev, "%s: cpu%d: no freq table!\n", __func__,
104 policy->cpu);
105 return -EINVAL;
106 }
108 ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
109 relation, &i);
110 if (ret) {
111 dev_dbg(mpu_dev, "%s: cpu%d: no freq match for %d(ret=%d)\n",
112 __func__, policy->cpu, target_freq, ret);
113 return ret;
114 }
115 freqs.new = freq_table[i].frequency;
116 if (!freqs.new) {
117 dev_err(mpu_dev, "%s: cpu%d: no match for freq %d\n", __func__,
118 policy->cpu, target_freq);
119 return -EINVAL;
120 }
122 freqs.old = omap_getspeed(policy->cpu);
123 freqs.cpu = policy->cpu;
125 if (freqs.old == freqs.new && policy->cur == freqs.new)
126 return ret;
128 opp = opp_find_freq_exact(mpu_dev, freqs.new * 1000, true);
129 if (IS_ERR(opp)) {
130 dev_err(mpu_dev, "%s: cpu%d: no opp match for freq %d\n",
131 __func__, policy->cpu, target_freq);
132 return -EINVAL;
133 }
135 volt_new = opp_get_voltage(opp);
136 if (!volt_new) {
137 dev_err(mpu_dev, "%s: cpu%d: no opp voltage for freq %d\n",
138 __func__, policy->cpu, target_freq);
139 return -EINVAL;
140 }
142 volt_old = regulator_get_voltage(mpu_reg);
144 #ifdef CONFIG_CPU_FREQ_DEBUG
145 pr_info("cpufreq-omap: frequency transition: %u --> %u\n",
146 freqs.old, freqs.new);
147 pr_info("cpufreq-omap: voltage transition: %d --> %d\n",
148 volt_old, volt_new);
149 #endif
151 if (freqs.new > freqs.old) {
152 ret = regulator_set_voltage(mpu_reg, volt_new,
153 volt_new + (volt_new * MPU_TOLERANCE) / PER_ROUND_VAL);
154 if (ret) {
155 dev_err(mpu_dev, "%s: unable to set voltage to %d uV (for %u MHz)\n",
156 __func__, volt_new, freqs.new/1000);
157 return ret;
158 }
159 }
161 /* notifiers */
162 for_each_cpu(i, policy->cpus) {
163 freqs.cpu = i;
164 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
165 }
167 ret = clk_set_rate(mpu_clk, freqs.new * 1000);
168 freqs.new = omap_getspeed(policy->cpu);
170 #ifdef CONFIG_SMP
171 /*
172 * Note that loops_per_jiffy is not updated on SMP systems in
173 * cpufreq driver. So, update the per-CPU loops_per_jiffy value
174 * on frequency transition. We need to update all dependent CPUs.
175 */
176 for_each_cpu(i, policy->cpus) {
177 struct lpj_info *lpj = &per_cpu(lpj_ref, i);
178 if (!lpj->freq) {
179 lpj->ref = per_cpu(cpu_data, i).loops_per_jiffy;
180 lpj->freq = freqs.old;
181 }
183 per_cpu(cpu_data, i).loops_per_jiffy =
184 cpufreq_scale(lpj->ref, lpj->freq, freqs.new);
185 }
187 /* And don't forget to adjust the global one */
188 if (!global_lpj_ref.freq) {
189 global_lpj_ref.ref = loops_per_jiffy;
190 global_lpj_ref.freq = freqs.old;
191 }
192 loops_per_jiffy = cpufreq_scale(global_lpj_ref.ref, global_lpj_ref.freq,
193 freqs.new);
194 #endif
196 /* notifiers */
197 for_each_cpu(i, policy->cpus) {
198 freqs.cpu = i;
199 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
200 }
202 if (freqs.new < freqs.old) {
203 ret = regulator_set_voltage(mpu_reg, volt_new,
204 volt_new + (volt_new * MPU_TOLERANCE) / PER_ROUND_VAL);
205 if (ret) {
206 unsigned int temp;
208 dev_err(mpu_dev, "%s: unable to set voltage to %d uV (for %u MHz)\n",
209 __func__, volt_new, freqs.new/1000);
211 if (clk_set_rate(mpu_clk, freqs.old * 1000)) {
212 dev_err(mpu_dev,
213 "%s: failed restoring clock rate to %u MHz, clock rate is %u MHz",
214 __func__,
215 freqs.old/1000, freqs.new/1000);
216 return ret;
217 }
219 temp = freqs.new;
220 freqs.new = freqs.old;
221 freqs.old = temp;
223 for_each_cpu(i, policy->cpus) {
224 freqs.cpu = i;
225 cpufreq_notify_transition(&freqs,
226 CPUFREQ_PRECHANGE);
227 cpufreq_notify_transition(&freqs,
228 CPUFREQ_POSTCHANGE);
229 }
230 return ret;
231 }
232 }
234 return ret;
235 }
237 static inline void freq_table_free(void)
238 {
239 if (atomic_dec_and_test(&freq_table_users))
240 opp_free_cpufreq_table(mpu_dev, &freq_table);
241 }
243 static int omap_pm_notify(struct notifier_block *nb, unsigned long event,
244 void *dummy)
245 {
246 struct cpufreq_policy *policy = cpufreq_cpu_get(0);
247 static unsigned int saved_frequency;
249 mutex_lock(&omap_cpu_lock);
250 switch (event) {
251 case PM_SUSPEND_PREPARE:
252 if (is_suspended)
253 goto out;
255 saved_frequency = omap_getspeed(0);
257 mutex_unlock(&omap_cpu_lock);
258 omap_target(policy, SLEEP_FREQ, CPUFREQ_RELATION_H);
259 mutex_lock(&omap_cpu_lock);
260 is_suspended = true;
261 break;
263 case PM_POST_SUSPEND:
264 is_suspended = false;
265 mutex_unlock(&omap_cpu_lock);
266 omap_target(policy, saved_frequency, CPUFREQ_RELATION_H);
267 mutex_lock(&omap_cpu_lock);
268 break;
269 }
270 out:
271 mutex_unlock(&omap_cpu_lock);
273 return NOTIFY_OK;
274 }
276 static struct notifier_block omap_cpu_pm_notifier = {
277 .notifier_call = omap_pm_notify,
278 };
280 static int __cpuinit omap_cpu_init(struct cpufreq_policy *policy)
281 {
282 int result = 0;
284 mpu_clk = clk_get(NULL, mpu_clk_name);
285 if (IS_ERR(mpu_clk))
286 return PTR_ERR(mpu_clk);
288 mpu_reg = regulator_get(NULL, "vdd_mpu");
289 if (IS_ERR(mpu_reg)) {
290 result = -EINVAL;
291 goto fail_ck;
292 }
294 /* success of regulator_get doesn't gurantee presence of driver for
295 physical regulator and presence of physical regulator (this
296 situation arises if dummy regulator is enabled),so check voltage
297 to verify that physical regulator and it's driver is present
298 */
299 if (regulator_get_voltage(mpu_reg) < 0) {
300 result = -EINVAL;
301 goto fail_reg;
302 }
304 if (policy->cpu >= NR_CPUS) {
305 result = -EINVAL;
306 goto fail_reg;
307 }
309 policy->cur = policy->min = policy->max = omap_getspeed(policy->cpu);
311 if (atomic_inc_return(&freq_table_users) == 1)
312 result = opp_init_cpufreq_table(mpu_dev, &freq_table);
314 if (result) {
315 dev_err(mpu_dev, "%s: cpu%d: failed creating freq table[%d]\n",
316 __func__, policy->cpu, result);
317 goto fail_reg;
318 }
320 result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
321 if (result)
322 goto fail_table;
324 cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
326 policy->min = policy->cpuinfo.min_freq;
327 policy->max = policy->cpuinfo.max_freq;
328 policy->cur = omap_getspeed(policy->cpu);
330 /*
331 * On OMAP SMP configuartion, both processors share the voltage
332 * and clock. So both CPUs needs to be scaled together and hence
333 * needs software co-ordination. Use cpufreq affected_cpus
334 * interface to handle this scenario. Additional is_smp() check
335 * is to keep SMP_ON_UP build working.
336 */
337 if (is_smp()) {
338 policy->shared_type = CPUFREQ_SHARED_TYPE_ANY;
339 cpumask_setall(policy->cpus);
340 }
342 /* FIXME: what's the actual transition time? */
343 policy->cpuinfo.transition_latency = 300 * 1000;
345 register_pm_notifier(&omap_cpu_pm_notifier);
347 return 0;
349 fail_table:
350 freq_table_free();
351 fail_reg:
352 regulator_put(mpu_reg);
353 fail_ck:
354 clk_put(mpu_clk);
355 return result;
356 }
358 static int omap_cpu_exit(struct cpufreq_policy *policy)
359 {
360 freq_table_free();
361 clk_put(mpu_clk);
362 return 0;
363 }
365 static struct freq_attr *omap_cpufreq_attr[] = {
366 &cpufreq_freq_attr_scaling_available_freqs,
367 NULL,
368 };
370 static struct cpufreq_driver omap_driver = {
371 .flags = CPUFREQ_STICKY,
372 .verify = omap_verify_speed,
373 .target = omap_target,
374 .get = omap_getspeed,
375 .init = omap_cpu_init,
376 .exit = omap_cpu_exit,
377 .name = "omap",
378 .attr = omap_cpufreq_attr,
379 };
381 static int __init omap_cpufreq_init(void)
382 {
383 if (cpu_is_omap24xx())
384 mpu_clk_name = "virt_prcm_set";
385 else if (cpu_is_omap34xx() && !cpu_is_am33xx())
386 mpu_clk_name = "dpll1_ck";
387 else if (cpu_is_omap44xx() || cpu_is_am33xx())
388 mpu_clk_name = "dpll_mpu_ck";
390 if (!mpu_clk_name) {
391 pr_err("%s: unsupported Silicon?\n", __func__);
392 return -EINVAL;
393 }
395 mpu_dev = omap_device_get_by_hwmod_name("mpu");
396 if (!mpu_dev) {
397 pr_warning("%s: unable to get the mpu device\n", __func__);
398 return -EINVAL;
399 }
401 return cpufreq_register_driver(&omap_driver);
402 }
404 static void __exit omap_cpufreq_exit(void)
405 {
406 cpufreq_unregister_driver(&omap_driver);
407 }
409 MODULE_DESCRIPTION("cpufreq driver for OMAP SoCs");
410 MODULE_LICENSE("GPL");
411 module_init(omap_cpufreq_init);
412 module_exit(omap_cpufreq_exit);