15 #include <linux/module.h>
23 #include <linux/device.h>
25 #include <linux/slab.h>
31 #include <plat/clock.h>
34 #include <mach/regs-clock.h>
42 static unsigned int last_target = ~0;
43 static unsigned int ftab_size;
46 static struct clk *_clk_mpll;
47 static struct clk *_clk_xtal;
48 static struct clk *clk_fclk;
49 static struct clk *clk_hclk;
50 static struct clk *clk_pclk;
53 #ifdef CONFIG_CPU_FREQ_S3C24XX_DEBUGFS
61 return &s3c24xx_iotiming;
67 unsigned long fclk, pclk,
hclk, armclk;
77 cfg->
freq.hclk_tns = 1000000000 / (cfg->
freq.hclk / 10);
80 cfg->
divs.p_divisor = fclk / pclk;
85 unsigned long pll = cfg->
pll.frequency;
88 cfg->
freq.hclk = pll / cfg->
divs.h_divisor;
89 cfg->
freq.pclk = pll / cfg->
divs.p_divisor;
92 cfg->
freq.hclk_tns = 1000000000 / (cfg->
freq.hclk / 10);
95 static inline int closer(
unsigned int target,
unsigned int n,
unsigned int c)
97 int diff_cur =
abs(target - c);
98 int diff_new =
abs(target - n);
100 return (diff_new < diff_cur);
103 static void s3c_cpufreq_show(
const char *pfx,
106 s3c_freq_dbg(
"%s: Fvco=%u, F=%lu, A=%lu, H=%lu (%u), P=%lu (%u)\n",
107 pfx, cfg->
pll.frequency, cfg->
freq.fclk, cfg->
freq.armclk,
108 cfg->
freq.hclk, cfg->
divs.h_divisor,
109 cfg->
freq.pclk, cfg->
divs.p_divisor);
116 if (cfg->
info->set_iotiming)
117 (cfg->
info->set_iotiming)(cfg, &s3c24xx_iotiming);
122 if (cfg->
info->calc_iotiming)
123 return (cfg->
info->calc_iotiming)(
cfg, &s3c24xx_iotiming);
130 (cfg->
info->set_refresh)(cfg);
135 (cfg->
info->set_divs)(cfg);
140 return (cfg->
info->calc_divs)(
cfg);
145 (cfg->
info->set_fvco)(cfg);
148 static inline void s3c_cpufreq_resume_clocks(
void)
150 cpu_cur.info->resume_clocks();
153 static inline void s3c_cpufreq_updateclk(
struct clk *
clk,
160 unsigned int target_freq,
169 s3c_cpufreq_show(
"cur", &cpu_cur);
173 cpu_new.pll = pll ? *pll : cpu_cur.pll;
176 freqs.pll_changing = 1;
180 cpu_new.freq.armclk = target_freq;
181 cpu_new.freq.fclk = cpu_new.pll.frequency;
183 if (s3c_cpufreq_calcdivs(&cpu_new) < 0) {
185 goto err_notpossible;
190 s3c_cpufreq_calc(&cpu_new);
192 s3c_freq_dbg(
"%s: calculated frequencies for new\n", __func__);
194 if (cpu_new.freq.hclk != cpu_cur.freq.hclk) {
195 if (s3c_cpufreq_calcio(&cpu_new) < 0) {
197 goto err_notpossible;
201 s3c_cpufreq_show(
"new", &cpu_new);
205 freqs.old = cpu_cur.freq;
206 freqs.new = cpu_new.freq;
209 freqs.freqs.old = cpu_cur.freq.armclk / 1000;
210 freqs.freqs.new = cpu_new.freq.armclk / 1000;
216 s3c_cpufreq_updateclk(_clk_mpll, cpu_new.pll.frequency);
217 s3c_cpufreq_updateclk(clk_fclk, cpu_new.freq.fclk);
218 s3c_cpufreq_updateclk(clk_hclk, cpu_new.freq.hclk);
219 s3c_cpufreq_updateclk(clk_pclk, cpu_new.freq.pclk);
233 if (cpu_new.freq.hclk < cpu_cur.freq.hclk) {
234 s3c_cpufreq_setrefresh(&cpu_new);
235 s3c_cpufreq_setio(&cpu_new);
238 if (cpu_new.freq.fclk == cpu_cur.freq.fclk) {
241 s3c_cpufreq_setdivs(&cpu_new);
243 if (cpu_new.freq.fclk < cpu_cur.freq.fclk) {
246 s3c_cpufreq_setfvco(&cpu_new);
247 s3c_cpufreq_setdivs(&cpu_new);
251 s3c_cpufreq_setdivs(&cpu_new);
252 s3c_cpufreq_setfvco(&cpu_new);
257 if (cpu_new.freq.hclk > cpu_cur.freq.hclk) {
258 s3c_cpufreq_setrefresh(&cpu_new);
259 s3c_cpufreq_setio(&cpu_new);
286 unsigned int target_freq,
287 unsigned int relation)
295 if (target_freq == last_target)
298 last_target = target_freq;
301 __func__, policy, target_freq, relation);
305 target_freq, relation,
311 s3c_freq_dbg(
"%s: adjust %d to entry %d (%u)\n", __func__,
312 target_freq, index, ftab[index].
frequency);
320 if (!pll_reg || cpu_cur.lock_pll) {
331 tmp_policy.min = policy->
min * 1000;
332 tmp_policy.max = policy->
max * 1000;
333 tmp_policy.cpu = policy->
cpu;
340 target_freq, relation,
345 goto err_notpossible;
348 pll = pll_reg +
index;
356 return s3c_cpufreq_settarget(policy, target_freq, pll);
363 static unsigned int s3c_cpufreq_get(
unsigned int cpu)
383 if (policy->
cpu != 0)
386 policy->
cur = s3c_cpufreq_get(0);
388 policy->
max = policy->
cpuinfo.max_freq = cpu_cur.info->max.fclk / 1000;
389 policy->
governor = CPUFREQ_DEFAULT_GOVERNOR;
392 policy->
cpuinfo.transition_latency = cpu_cur.info->latency;
400 static __init int s3c_cpufreq_initclks(
void)
409 if (IS_ERR(clk_fclk) || IS_ERR(clk_hclk) || IS_ERR(clk_pclk) ||
410 IS_ERR(_clk_mpll) || IS_ERR(clk_arm) || IS_ERR(_clk_xtal)) {
426 if (policy->
cpu != 0)
434 static unsigned int suspend_freq;
440 suspend_freq = s3c_cpufreq_get(0) * 1000;
449 s3c_freq_dbg(
"%s: resuming with policy %p\n", __func__, policy);
454 s3c_cpufreq_resume_clocks();
466 ret = s3c_cpufreq_settarget(
NULL, suspend_freq, &suspend_pll);
475 #define s3c_cpufreq_resume NULL
476 #define s3c_cpufreq_suspend NULL
481 .verify = s3c_cpufreq_verify,
482 .target = s3c_cpufreq_target,
483 .get = s3c_cpufreq_get,
484 .init = s3c_cpufreq_init,
493 if (!info || !info->
name) {
537 cpu_cur.board = ours;
546 if (!cpu_cur.info->get_iotiming) {
553 ret = (cpu_cur.info->get_iotiming)(&cpu_cur, &s3c24xx_iotiming);
561 #define do_min(_a, _b) ((_a) == 0 ? (_b) : (_b) == 0 ? (_a) : min(_a, _b))
573 static void s3c_cpufreq_freq_min(
struct s3c_freq *
dst,
586 result = freq * time_us;
592 static void s3c_cpufreq_update_loctkime(
void)
594 unsigned int bits = cpu_cur.info->locktime_bits;
603 val = calc_locktime(rate, cpu_cur.info->locktime_u) <<
bits;
604 val |= calc_locktime(rate, cpu_cur.info->locktime_m);
610 static int s3c_cpufreq_build_freq(
void)
614 if (!cpu_cur.info->calc_freqtable)
620 size = cpu_cur.info->calc_freqtable(&cpu_cur,
NULL, 0);
631 ret = cpu_cur.info->calc_freqtable(&cpu_cur, ftab, size);
637 static int __init s3c_cpufreq_initcall(
void)
641 if (cpu_cur.info && cpu_cur.board) {
642 ret = s3c_cpufreq_initclks();
647 s3c_cpufreq_getcur(&cpu_cur);
648 s3c_cpufreq_show(
"cur", &cpu_cur);
650 if (cpu_cur.board->auto_io) {
659 if (cpu_cur.board->need_io && !cpu_cur.info->set_iotiming) {
666 if (!cpu_cur.info->need_pll)
667 cpu_cur.lock_pll = 1;
669 s3c_cpufreq_update_loctkime();
671 s3c_cpufreq_freq_min(&cpu_cur.max, &cpu_cur.board->max,
674 if (cpu_cur.info->calc_freqtable)
675 s3c_cpufreq_build_freq();
694 unsigned int plls_no)
715 return vals ? 0 : -
ENOMEM;