diff options
Diffstat (limited to 'arch/sh/kernel/cpufreq.c')
-rw-r--r-- | arch/sh/kernel/cpufreq.c | 121 |
1 files changed, 82 insertions, 39 deletions
diff --git a/arch/sh/kernel/cpufreq.c b/arch/sh/kernel/cpufreq.c index 0fffacea6ed9..e68b45b6f3f9 100644 --- a/arch/sh/kernel/cpufreq.c +++ b/arch/sh/kernel/cpufreq.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * cpufreq driver for the SuperH processors. | 4 | * cpufreq driver for the SuperH processors. |
5 | * | 5 | * |
6 | * Copyright (C) 2002 - 2007 Paul Mundt | 6 | * Copyright (C) 2002 - 2012 Paul Mundt |
7 | * Copyright (C) 2002 M. R. Brown | 7 | * Copyright (C) 2002 M. R. Brown |
8 | * | 8 | * |
9 | * Clock framework bits from arch/avr32/mach-at32ap/cpufreq.c | 9 | * Clock framework bits from arch/avr32/mach-at32ap/cpufreq.c |
@@ -14,6 +14,8 @@ | |||
14 | * License. See the file "COPYING" in the main directory of this archive | 14 | * License. See the file "COPYING" in the main directory of this archive |
15 | * for more details. | 15 | * for more details. |
16 | */ | 16 | */ |
17 | #define pr_fmt(fmt) "cpufreq: " fmt | ||
18 | |||
17 | #include <linux/types.h> | 19 | #include <linux/types.h> |
18 | #include <linux/cpufreq.h> | 20 | #include <linux/cpufreq.h> |
19 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
@@ -21,15 +23,18 @@ | |||
21 | #include <linux/init.h> | 23 | #include <linux/init.h> |
22 | #include <linux/err.h> | 24 | #include <linux/err.h> |
23 | #include <linux/cpumask.h> | 25 | #include <linux/cpumask.h> |
26 | #include <linux/cpu.h> | ||
24 | #include <linux/smp.h> | 27 | #include <linux/smp.h> |
25 | #include <linux/sched.h> /* set_cpus_allowed() */ | 28 | #include <linux/sched.h> /* set_cpus_allowed() */ |
26 | #include <linux/clk.h> | 29 | #include <linux/clk.h> |
30 | #include <linux/percpu.h> | ||
31 | #include <linux/sh_clk.h> | ||
27 | 32 | ||
28 | static struct clk *cpuclk; | 33 | static DEFINE_PER_CPU(struct clk, sh_cpuclk); |
29 | 34 | ||
30 | static unsigned int sh_cpufreq_get(unsigned int cpu) | 35 | static unsigned int sh_cpufreq_get(unsigned int cpu) |
31 | { | 36 | { |
32 | return (clk_get_rate(cpuclk) + 500) / 1000; | 37 | return (clk_get_rate(&per_cpu(sh_cpuclk, cpu)) + 500) / 1000; |
33 | } | 38 | } |
34 | 39 | ||
35 | /* | 40 | /* |
@@ -40,8 +45,10 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy, | |||
40 | unsigned int relation) | 45 | unsigned int relation) |
41 | { | 46 | { |
42 | unsigned int cpu = policy->cpu; | 47 | unsigned int cpu = policy->cpu; |
48 | struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu); | ||
43 | cpumask_t cpus_allowed; | 49 | cpumask_t cpus_allowed; |
44 | struct cpufreq_freqs freqs; | 50 | struct cpufreq_freqs freqs; |
51 | struct device *dev; | ||
45 | long freq; | 52 | long freq; |
46 | 53 | ||
47 | if (!cpu_online(cpu)) | 54 | if (!cpu_online(cpu)) |
@@ -52,13 +59,15 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy, | |||
52 | 59 | ||
53 | BUG_ON(smp_processor_id() != cpu); | 60 | BUG_ON(smp_processor_id() != cpu); |
54 | 61 | ||
62 | dev = get_cpu_device(cpu); | ||
63 | |||
55 | /* Convert target_freq from kHz to Hz */ | 64 | /* Convert target_freq from kHz to Hz */ |
56 | freq = clk_round_rate(cpuclk, target_freq * 1000); | 65 | freq = clk_round_rate(cpuclk, target_freq * 1000); |
57 | 66 | ||
58 | if (freq < (policy->min * 1000) || freq > (policy->max * 1000)) | 67 | if (freq < (policy->min * 1000) || freq > (policy->max * 1000)) |
59 | return -EINVAL; | 68 | return -EINVAL; |
60 | 69 | ||
61 | pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000); | 70 | dev_dbg(dev, "requested frequency %u Hz\n", target_freq * 1000); |
62 | 71 | ||
63 | freqs.cpu = cpu; | 72 | freqs.cpu = cpu; |
64 | freqs.old = sh_cpufreq_get(cpu); | 73 | freqs.old = sh_cpufreq_get(cpu); |
@@ -70,78 +79,112 @@ static int sh_cpufreq_target(struct cpufreq_policy *policy, | |||
70 | clk_set_rate(cpuclk, freq); | 79 | clk_set_rate(cpuclk, freq); |
71 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); | 80 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); |
72 | 81 | ||
73 | pr_debug("cpufreq: set frequency %lu Hz\n", freq); | 82 | dev_dbg(dev, "set frequency %lu Hz\n", freq); |
83 | |||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | static int sh_cpufreq_verify(struct cpufreq_policy *policy) | ||
88 | { | ||
89 | struct clk *cpuclk = &per_cpu(sh_cpuclk, policy->cpu); | ||
90 | struct cpufreq_frequency_table *freq_table; | ||
91 | |||
92 | freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL; | ||
93 | if (freq_table) | ||
94 | return cpufreq_frequency_table_verify(policy, freq_table); | ||
95 | |||
96 | cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, | ||
97 | policy->cpuinfo.max_freq); | ||
98 | |||
99 | policy->min = (clk_round_rate(cpuclk, 1) + 500) / 1000; | ||
100 | policy->max = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; | ||
101 | |||
102 | cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, | ||
103 | policy->cpuinfo.max_freq); | ||
74 | 104 | ||
75 | return 0; | 105 | return 0; |
76 | } | 106 | } |
77 | 107 | ||
78 | static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) | 108 | static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy) |
79 | { | 109 | { |
80 | if (!cpu_online(policy->cpu)) | 110 | unsigned int cpu = policy->cpu; |
111 | struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu); | ||
112 | struct cpufreq_frequency_table *freq_table; | ||
113 | struct device *dev; | ||
114 | |||
115 | if (!cpu_online(cpu)) | ||
81 | return -ENODEV; | 116 | return -ENODEV; |
82 | 117 | ||
83 | cpuclk = clk_get(NULL, "cpu_clk"); | 118 | dev = get_cpu_device(cpu); |
119 | |||
120 | cpuclk = clk_get(dev, "cpu_clk"); | ||
84 | if (IS_ERR(cpuclk)) { | 121 | if (IS_ERR(cpuclk)) { |
85 | printk(KERN_ERR "cpufreq: couldn't get CPU#%d clk\n", | 122 | dev_err(dev, "couldn't get CPU clk\n"); |
86 | policy->cpu); | ||
87 | return PTR_ERR(cpuclk); | 123 | return PTR_ERR(cpuclk); |
88 | } | 124 | } |
89 | 125 | ||
90 | /* cpuinfo and default policy values */ | 126 | policy->cur = policy->min = policy->max = sh_cpufreq_get(cpu); |
91 | policy->cpuinfo.min_freq = (clk_round_rate(cpuclk, 1) + 500) / 1000; | ||
92 | policy->cpuinfo.max_freq = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; | ||
93 | policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; | ||
94 | 127 | ||
95 | policy->cur = sh_cpufreq_get(policy->cpu); | 128 | freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL; |
96 | policy->min = policy->cpuinfo.min_freq; | 129 | if (freq_table) { |
97 | policy->max = policy->cpuinfo.max_freq; | 130 | int result; |
98 | 131 | ||
99 | /* | 132 | result = cpufreq_frequency_table_cpuinfo(policy, freq_table); |
100 | * Catch the cases where the clock framework hasn't been wired up | 133 | if (!result) |
101 | * properly to support scaling. | 134 | cpufreq_frequency_table_get_attr(freq_table, cpu); |
102 | */ | 135 | } else { |
103 | if (unlikely(policy->min == policy->max)) { | 136 | dev_notice(dev, "no frequency table found, falling back " |
104 | printk(KERN_ERR "cpufreq: clock framework rate rounding " | 137 | "to rate rounding.\n"); |
105 | "not supported on CPU#%d.\n", policy->cpu); | ||
106 | 138 | ||
107 | clk_put(cpuclk); | 139 | policy->cpuinfo.min_freq = |
108 | return -EINVAL; | 140 | (clk_round_rate(cpuclk, 1) + 500) / 1000; |
141 | policy->cpuinfo.max_freq = | ||
142 | (clk_round_rate(cpuclk, ~0UL) + 500) / 1000; | ||
109 | } | 143 | } |
110 | 144 | ||
111 | printk(KERN_INFO "cpufreq: CPU#%d Frequencies - Minimum %u.%03u MHz, " | 145 | policy->min = policy->cpuinfo.min_freq; |
146 | policy->max = policy->cpuinfo.max_freq; | ||
147 | |||
148 | policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL; | ||
149 | |||
150 | dev_info(dev, "CPU Frequencies - Minimum %u.%03u MHz, " | ||
112 | "Maximum %u.%03u MHz.\n", | 151 | "Maximum %u.%03u MHz.\n", |
113 | policy->cpu, policy->min / 1000, policy->min % 1000, | 152 | policy->min / 1000, policy->min % 1000, |
114 | policy->max / 1000, policy->max % 1000); | 153 | policy->max / 1000, policy->max % 1000); |
115 | 154 | ||
116 | return 0; | 155 | return 0; |
117 | } | 156 | } |
118 | 157 | ||
119 | static int sh_cpufreq_verify(struct cpufreq_policy *policy) | 158 | static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy) |
120 | { | 159 | { |
121 | cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq, | 160 | unsigned int cpu = policy->cpu; |
122 | policy->cpuinfo.max_freq); | 161 | struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu); |
123 | return 0; | ||
124 | } | ||
125 | 162 | ||
126 | static int sh_cpufreq_exit(struct cpufreq_policy *policy) | 163 | cpufreq_frequency_table_put_attr(cpu); |
127 | { | ||
128 | clk_put(cpuclk); | 164 | clk_put(cpuclk); |
165 | |||
129 | return 0; | 166 | return 0; |
130 | } | 167 | } |
131 | 168 | ||
169 | static struct freq_attr *sh_freq_attr[] = { | ||
170 | &cpufreq_freq_attr_scaling_available_freqs, | ||
171 | NULL, | ||
172 | }; | ||
173 | |||
132 | static struct cpufreq_driver sh_cpufreq_driver = { | 174 | static struct cpufreq_driver sh_cpufreq_driver = { |
133 | .owner = THIS_MODULE, | 175 | .owner = THIS_MODULE, |
134 | .name = "sh", | 176 | .name = "sh", |
135 | .init = sh_cpufreq_cpu_init, | ||
136 | .verify = sh_cpufreq_verify, | ||
137 | .target = sh_cpufreq_target, | ||
138 | .get = sh_cpufreq_get, | 177 | .get = sh_cpufreq_get, |
139 | .exit = sh_cpufreq_exit, | 178 | .target = sh_cpufreq_target, |
179 | .verify = sh_cpufreq_verify, | ||
180 | .init = sh_cpufreq_cpu_init, | ||
181 | .exit = sh_cpufreq_cpu_exit, | ||
182 | .attr = sh_freq_attr, | ||
140 | }; | 183 | }; |
141 | 184 | ||
142 | static int __init sh_cpufreq_module_init(void) | 185 | static int __init sh_cpufreq_module_init(void) |
143 | { | 186 | { |
144 | printk(KERN_INFO "cpufreq: SuperH CPU frequency driver.\n"); | 187 | pr_notice("SuperH CPU frequency driver.\n"); |
145 | return cpufreq_register_driver(&sh_cpufreq_driver); | 188 | return cpufreq_register_driver(&sh_cpufreq_driver); |
146 | } | 189 | } |
147 | 190 | ||