diff options
author | Viresh Kumar <viresh.kumar@linaro.org> | 2013-04-04 08:54:21 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-04-10 07:19:25 -0400 |
commit | 7a9989356b23fa2c7731632d3b575c53c1ac8bce (patch) | |
tree | e4fa7384b7dfc08173a82b4e45bce0c91fdc4021 /drivers/cpufreq | |
parent | ab423e435f1eafdb9a071fe8a9942b2522d09d2d (diff) |
cpufreq: mips: move cpufreq driver to drivers/cpufreq
This patch moves cpufreq driver of MIPS architecture to drivers/cpufreq.
Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
Acked-by: John Crispin <blogic@openwrt.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r-- | drivers/cpufreq/Kconfig | 18 | ||||
-rw-r--r-- | drivers/cpufreq/Makefile | 1 | ||||
-rw-r--r-- | drivers/cpufreq/loongson2_cpufreq.c | 248 |
3 files changed, 267 insertions, 0 deletions
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index a2f1600c78f8..5030df5cd3eb 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig | |||
@@ -235,6 +235,24 @@ config IA64_ACPI_CPUFREQ | |||
235 | 235 | ||
236 | endmenu | 236 | endmenu |
237 | 237 | ||
238 | menu "MIPS CPUFreq processor drivers" | ||
239 | depends on MIPS | ||
240 | |||
241 | config LOONGSON2_CPUFREQ | ||
242 | tristate "Loongson2 CPUFreq Driver" | ||
243 | select CPU_FREQ_TABLE | ||
244 | help | ||
245 | This option adds a CPUFreq driver for loongson processors which | ||
246 | support software configurable cpu frequency. | ||
247 | |||
248 | Loongson2F and it's successors support this feature. | ||
249 | |||
250 | For details, take a look at <file:Documentation/cpu-freq/>. | ||
251 | |||
252 | If in doubt, say N. | ||
253 | |||
254 | endmenu | ||
255 | |||
238 | menu "PowerPC CPU frequency scaling drivers" | 256 | menu "PowerPC CPU frequency scaling drivers" |
239 | depends on PPC32 || PPC64 | 257 | depends on PPC32 || PPC64 |
240 | source "drivers/cpufreq/Kconfig.powerpc" | 258 | source "drivers/cpufreq/Kconfig.powerpc" |
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index ab681337e6d4..9659cbbad25e 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile | |||
@@ -82,3 +82,4 @@ obj-$(CONFIG_BLACKFIN) += blackfin-cpufreq.o | |||
82 | obj-$(CONFIG_CRIS_MACH_ARTPEC3) += cris-artpec3-cpufreq.o | 82 | obj-$(CONFIG_CRIS_MACH_ARTPEC3) += cris-artpec3-cpufreq.o |
83 | obj-$(CONFIG_ETRAXFS) += cris-etraxfs-cpufreq.o | 83 | obj-$(CONFIG_ETRAXFS) += cris-etraxfs-cpufreq.o |
84 | obj-$(CONFIG_IA64_ACPI_CPUFREQ) += ia64-acpi-cpufreq.o | 84 | obj-$(CONFIG_IA64_ACPI_CPUFREQ) += ia64-acpi-cpufreq.o |
85 | obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o | ||
diff --git a/drivers/cpufreq/loongson2_cpufreq.c b/drivers/cpufreq/loongson2_cpufreq.c new file mode 100644 index 000000000000..84889573b566 --- /dev/null +++ b/drivers/cpufreq/loongson2_cpufreq.c | |||
@@ -0,0 +1,248 @@ | |||
1 | /* | ||
2 | * Cpufreq driver for the loongson-2 processors | ||
3 | * | ||
4 | * The 2E revision of loongson processor not support this feature. | ||
5 | * | ||
6 | * Copyright (C) 2006 - 2008 Lemote Inc. & Insititute of Computing Technology | ||
7 | * Author: Yanhua, yanh@lemote.com | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file "COPYING" in the main directory of this archive | ||
11 | * for more details. | ||
12 | */ | ||
13 | #include <linux/cpufreq.h> | ||
14 | #include <linux/module.h> | ||
15 | #include <linux/err.h> | ||
16 | #include <linux/sched.h> /* set_cpus_allowed() */ | ||
17 | #include <linux/delay.h> | ||
18 | #include <linux/platform_device.h> | ||
19 | |||
20 | #include <asm/clock.h> | ||
21 | |||
22 | #include <asm/mach-loongson/loongson.h> | ||
23 | |||
24 | static uint nowait; | ||
25 | |||
26 | static struct clk *cpuclk; | ||
27 | |||
28 | static void (*saved_cpu_wait) (void); | ||
29 | |||
30 | static int loongson2_cpu_freq_notifier(struct notifier_block *nb, | ||
31 | unsigned long val, void *data); | ||
32 | |||
33 | static struct notifier_block loongson2_cpufreq_notifier_block = { | ||
34 | .notifier_call = loongson2_cpu_freq_notifier | ||
35 | }; | ||
36 | |||
37 | static int loongson2_cpu_freq_notifier(struct notifier_block *nb, | ||
38 | unsigned long val, void *data) | ||
39 | { | ||
40 | if (val == CPUFREQ_POSTCHANGE) | ||
41 | current_cpu_data.udelay_val = loops_per_jiffy; | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | static unsigned int loongson2_cpufreq_get(unsigned int cpu) | ||
47 | { | ||
48 | return clk_get_rate(cpuclk); | ||
49 | } | ||
50 | |||
51 | /* | ||
52 | * Here we notify other drivers of the proposed change and the final change. | ||
53 | */ | ||
54 | static int loongson2_cpufreq_target(struct cpufreq_policy *policy, | ||
55 | unsigned int target_freq, | ||
56 | unsigned int relation) | ||
57 | { | ||
58 | unsigned int cpu = policy->cpu; | ||
59 | unsigned int newstate = 0; | ||
60 | cpumask_t cpus_allowed; | ||
61 | struct cpufreq_freqs freqs; | ||
62 | unsigned int freq; | ||
63 | |||
64 | cpus_allowed = current->cpus_allowed; | ||
65 | set_cpus_allowed_ptr(current, cpumask_of(cpu)); | ||
66 | |||
67 | if (cpufreq_frequency_table_target | ||
68 | (policy, &loongson2_clockmod_table[0], target_freq, relation, | ||
69 | &newstate)) | ||
70 | return -EINVAL; | ||
71 | |||
72 | freq = | ||
73 | ((cpu_clock_freq / 1000) * | ||
74 | loongson2_clockmod_table[newstate].index) / 8; | ||
75 | if (freq < policy->min || freq > policy->max) | ||
76 | return -EINVAL; | ||
77 | |||
78 | pr_debug("cpufreq: requested frequency %u Hz\n", target_freq * 1000); | ||
79 | |||
80 | freqs.old = loongson2_cpufreq_get(cpu); | ||
81 | freqs.new = freq; | ||
82 | freqs.flags = 0; | ||
83 | |||
84 | if (freqs.new == freqs.old) | ||
85 | return 0; | ||
86 | |||
87 | /* notifiers */ | ||
88 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); | ||
89 | |||
90 | set_cpus_allowed_ptr(current, &cpus_allowed); | ||
91 | |||
92 | /* setting the cpu frequency */ | ||
93 | clk_set_rate(cpuclk, freq); | ||
94 | |||
95 | /* notifiers */ | ||
96 | cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); | ||
97 | |||
98 | pr_debug("cpufreq: set frequency %u kHz\n", freq); | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | static int loongson2_cpufreq_cpu_init(struct cpufreq_policy *policy) | ||
104 | { | ||
105 | int i; | ||
106 | unsigned long rate; | ||
107 | int ret; | ||
108 | |||
109 | cpuclk = clk_get(NULL, "cpu_clk"); | ||
110 | if (IS_ERR(cpuclk)) { | ||
111 | printk(KERN_ERR "cpufreq: couldn't get CPU clk\n"); | ||
112 | return PTR_ERR(cpuclk); | ||
113 | } | ||
114 | |||
115 | rate = cpu_clock_freq / 1000; | ||
116 | if (!rate) { | ||
117 | clk_put(cpuclk); | ||
118 | return -EINVAL; | ||
119 | } | ||
120 | ret = clk_set_rate(cpuclk, rate); | ||
121 | if (ret) { | ||
122 | clk_put(cpuclk); | ||
123 | return ret; | ||
124 | } | ||
125 | |||
126 | /* clock table init */ | ||
127 | for (i = 2; | ||
128 | (loongson2_clockmod_table[i].frequency != CPUFREQ_TABLE_END); | ||
129 | i++) | ||
130 | loongson2_clockmod_table[i].frequency = (rate * i) / 8; | ||
131 | |||
132 | policy->cur = loongson2_cpufreq_get(policy->cpu); | ||
133 | |||
134 | cpufreq_frequency_table_get_attr(&loongson2_clockmod_table[0], | ||
135 | policy->cpu); | ||
136 | |||
137 | return cpufreq_frequency_table_cpuinfo(policy, | ||
138 | &loongson2_clockmod_table[0]); | ||
139 | } | ||
140 | |||
141 | static int loongson2_cpufreq_verify(struct cpufreq_policy *policy) | ||
142 | { | ||
143 | return cpufreq_frequency_table_verify(policy, | ||
144 | &loongson2_clockmod_table[0]); | ||
145 | } | ||
146 | |||
147 | static int loongson2_cpufreq_exit(struct cpufreq_policy *policy) | ||
148 | { | ||
149 | clk_put(cpuclk); | ||
150 | return 0; | ||
151 | } | ||
152 | |||
153 | static struct freq_attr *loongson2_table_attr[] = { | ||
154 | &cpufreq_freq_attr_scaling_available_freqs, | ||
155 | NULL, | ||
156 | }; | ||
157 | |||
158 | static struct cpufreq_driver loongson2_cpufreq_driver = { | ||
159 | .owner = THIS_MODULE, | ||
160 | .name = "loongson2", | ||
161 | .init = loongson2_cpufreq_cpu_init, | ||
162 | .verify = loongson2_cpufreq_verify, | ||
163 | .target = loongson2_cpufreq_target, | ||
164 | .get = loongson2_cpufreq_get, | ||
165 | .exit = loongson2_cpufreq_exit, | ||
166 | .attr = loongson2_table_attr, | ||
167 | }; | ||
168 | |||
169 | static struct platform_device_id platform_device_ids[] = { | ||
170 | { | ||
171 | .name = "loongson2_cpufreq", | ||
172 | }, | ||
173 | {} | ||
174 | }; | ||
175 | |||
176 | MODULE_DEVICE_TABLE(platform, platform_device_ids); | ||
177 | |||
178 | static struct platform_driver platform_driver = { | ||
179 | .driver = { | ||
180 | .name = "loongson2_cpufreq", | ||
181 | .owner = THIS_MODULE, | ||
182 | }, | ||
183 | .id_table = platform_device_ids, | ||
184 | }; | ||
185 | |||
186 | /* | ||
187 | * This is the simple version of Loongson-2 wait, Maybe we need do this in | ||
188 | * interrupt disabled context. | ||
189 | */ | ||
190 | |||
191 | static DEFINE_SPINLOCK(loongson2_wait_lock); | ||
192 | |||
193 | static void loongson2_cpu_wait(void) | ||
194 | { | ||
195 | unsigned long flags; | ||
196 | u32 cpu_freq; | ||
197 | |||
198 | spin_lock_irqsave(&loongson2_wait_lock, flags); | ||
199 | cpu_freq = LOONGSON_CHIPCFG0; | ||
200 | LOONGSON_CHIPCFG0 &= ~0x7; /* Put CPU into wait mode */ | ||
201 | LOONGSON_CHIPCFG0 = cpu_freq; /* Restore CPU state */ | ||
202 | spin_unlock_irqrestore(&loongson2_wait_lock, flags); | ||
203 | } | ||
204 | |||
205 | static int __init cpufreq_init(void) | ||
206 | { | ||
207 | int ret; | ||
208 | |||
209 | /* Register platform stuff */ | ||
210 | ret = platform_driver_register(&platform_driver); | ||
211 | if (ret) | ||
212 | return ret; | ||
213 | |||
214 | pr_info("cpufreq: Loongson-2F CPU frequency driver.\n"); | ||
215 | |||
216 | cpufreq_register_notifier(&loongson2_cpufreq_notifier_block, | ||
217 | CPUFREQ_TRANSITION_NOTIFIER); | ||
218 | |||
219 | ret = cpufreq_register_driver(&loongson2_cpufreq_driver); | ||
220 | |||
221 | if (!ret && !nowait) { | ||
222 | saved_cpu_wait = cpu_wait; | ||
223 | cpu_wait = loongson2_cpu_wait; | ||
224 | } | ||
225 | |||
226 | return ret; | ||
227 | } | ||
228 | |||
229 | static void __exit cpufreq_exit(void) | ||
230 | { | ||
231 | if (!nowait && saved_cpu_wait) | ||
232 | cpu_wait = saved_cpu_wait; | ||
233 | cpufreq_unregister_driver(&loongson2_cpufreq_driver); | ||
234 | cpufreq_unregister_notifier(&loongson2_cpufreq_notifier_block, | ||
235 | CPUFREQ_TRANSITION_NOTIFIER); | ||
236 | |||
237 | platform_driver_unregister(&platform_driver); | ||
238 | } | ||
239 | |||
240 | module_init(cpufreq_init); | ||
241 | module_exit(cpufreq_exit); | ||
242 | |||
243 | module_param(nowait, uint, 0644); | ||
244 | MODULE_PARM_DESC(nowait, "Disable Loongson-2F specific wait"); | ||
245 | |||
246 | MODULE_AUTHOR("Yanhua <yanh@lemote.com>"); | ||
247 | MODULE_DESCRIPTION("cpufreq driver for Loongson2F"); | ||
248 | MODULE_LICENSE("GPL"); | ||