MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / arch / arm / mach-p2001 / p2001_cpufreq.c
blob4ef9b7ab0ab45f3809e95ff361f86c71cb5cd5c1
1 /*
2 * linux/arch/arm/mach-p2001/p2001_cpufreq.c
4 * Copyright (C) 2004-2005 Tobias Lorenz
6 * CPU frequency scaling support
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <linux/module.h>
22 #include <linux/types.h>
23 #include <linux/kernel.h>
24 #include <linux/cpufreq.h>
25 #include <linux/slab.h>
26 #include <linux/sched.h>
27 #include <linux/smp.h>
28 #include <linux/init.h>
30 #include <asm/hardware.h>
31 #include <asm/io.h>
33 static struct cpufreq_driver p2001_cpufreq_driver;
35 static int p2001_cpufreq_driver_init(struct cpufreq_policy *policy);
36 static int p2001_cpufreq_driver_verify(struct cpufreq_policy *policy);
37 //static int p2001_cpufreq_driver_setpolicy(struct cpufreq_policy *policy);
38 static int p2001_cpufreq_driver_target(struct cpufreq_policy *policy,
39 unsigned int target_freq,
40 unsigned int relation);
41 static unsigned int p2001_cpufreq_driver_get(unsigned int cpu);
43 static struct cpufreq_frequency_table p2001_cpufreq_frequency_table[] =
45 /* index is also the scaling factor */
46 // 6 kHz (minimum)
47 { .index = 1, .frequency = 12288 }, // 12.288 MHz (no network)
48 { .index = 2, .frequency = 24576 }, // 24.576 MHz (no network)
49 { .index = 3, .frequency = 36864 }, // 36.864 MHz
50 { .index = 4, .frequency = 49152 }, // 49.152 MHz
51 { .index = 5, .frequency = 61440 }, // 61.440 MHz
52 { .index = 6, .frequency = 73728 }, // 73.728 MHz
53 { .index = 7, .frequency = 86016 }, // 86.016 MHz (overclocked)
54 { .index = 8, .frequency = 98304 }, // 98.304 MHz (overclocked)
55 { .index = 9, .frequency = 110592 }, // 110.592 MHz (not working)
56 { .frequency = CPUFREQ_TABLE_END },
59 static int p2001_cpufreq_driver_init(struct cpufreq_policy *policy)
61 // printk("p2001_cpufreq_driver_init\n");
63 /* set default policy and cpuinfo */
64 if (policy->cpu != 0)
65 return -EINVAL;
67 policy->cur = policy->min = policy->max = p2001_cpufreq_driver_get(policy->cpu);
68 policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
69 policy->cpuinfo.max_freq = 73728; // kHz
70 policy->cpuinfo.min_freq = 36864; // kHz
71 policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */
73 return 0;
76 /**
77 * p2001_cpufreq_driver_verify - verifies a new CPUFreq policy
78 * @policy: new policy
80 * Limit must be within this model's frequency range at least one
81 * border included.
83 static int p2001_cpufreq_driver_verify(struct cpufreq_policy *policy)
85 // printk("p2001_cpufreq_driver_verify\n");
86 return cpufreq_frequency_table_verify(policy, p2001_cpufreq_frequency_table);
89 /**
90 * p2001_cpufreq_driver_verify - set a new CPUFreq policy
91 * @policy: new policy
93 * Sets a new CPUFreq policy.
96 static int p2001_cpufreq_driver_setpolicy(struct cpufreq_policy *policy)
98 // printk("p2001_cpufreq_driver_setpolicy\n");
99 // what to do here ?
100 return 0;
105 * p2001_cpufreq_driver_target - set a new CPUFreq policy
106 * @policy: new policy
107 * @target_freq: the target frequency
108 * @relation: how that frequency relates to achieved frequency (CPUFREQ_RELATION_L or CPUFREQ_RELATION_H)
110 * Sets a new CPUFreq policy.
112 static int p2001_cpufreq_driver_target(struct cpufreq_policy *policy,
113 unsigned int target_freq,
114 unsigned int relation)
116 unsigned int newstate = 0;
117 struct cpufreq_freqs freqs;
118 unsigned int M, P, S, N, PWRDN; // PLL_12288_config
119 unsigned int M_DIV, N_DIV, SEL_PLL, SEL_DIV; // DIV_12288_config
120 unsigned int config;
122 // printk("p2001_cpufreq_driver_target(target_freq=%d)\n", target_freq);
123 if (cpufreq_frequency_table_target(policy, &p2001_cpufreq_frequency_table[0], target_freq, relation, &newstate))
124 return -EINVAL;
126 freqs.old = p2001_cpufreq_driver_get(policy->cpu);
127 freqs.new = p2001_cpufreq_frequency_table[newstate].frequency;
128 freqs.cpu = 0; /* p2001_cpufreq.c is UP only driver */
130 if (freqs.new == freqs.old)
131 return 0;
132 // printk("System clock change from %d kHz to %d kHz\n", freqs.old, freqs.new);
134 M = 0;
135 S = 0;
136 P = 0;
137 N = 0;
138 PWRDN = 0;
139 M_DIV = 1;
140 N_DIV = newstate;
141 SEL_PLL = 1;
142 SEL_DIV = 0;
143 switch (p2001_cpufreq_frequency_table[newstate].index) {
144 case 1: // 12288 kHz
145 PWRDN = 1;
146 SEL_PLL = 0;
147 break;
148 case 2: // 24576 kHz
149 P = 2;
150 break;
151 case 3: // 36864 kHz
152 M = 1;
153 P = 1;
154 break;
155 case 4: // 49152 kHz
156 M = 0;
157 break;
158 case 5: // 61440 kHz
159 M = 2;
160 break;
161 case 6: // 73728 kHz
162 M = 4;
163 break;
164 case 7: // 86016 kHz
165 M = 6;
166 break;
167 case 8: // 98304 kHz
168 M = 8;
169 break;
170 case 9: // 110592 kHz
171 M = 10;
172 break;
175 /* notifier */
176 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
178 /* change DIV first to bypass PLL before PWRDN */
179 config = (M_DIV<<0) | (N_DIV<<8) | (SEL_PLL<<16) | (SEL_DIV<<17);
180 P2001_TIMER->DIV_12288_config = config;
181 config = (M<<0) | (P<<8) | (S<<14) | (N<<16) | (PWRDN<<26);
182 P2001_TIMER->PLL_12288_config = config;
184 /* notifier */
185 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
187 return 0;
191 * returns current frequency in kHz
193 static unsigned int p2001_cpufreq_driver_get(unsigned int cpu)
195 cpumask_t cpus_allowed;
196 unsigned int current_freq;
197 unsigned int M, P, S, N, PWRDN; // PLL_12288_config
198 unsigned int M_DIV, N_DIV, SEL_PLL, SEL_DIV; // DIV_12288_config
200 // printk("p2001_cpufreq_driver_get\n");
202 * Save this threads cpus_allowed mask.
204 cpus_allowed = current->cpus_allowed;
207 * Bind to the specified CPU. When this call returns,
208 * we should be running on the right CPU.
210 set_cpus_allowed(current, cpumask_of_cpu(cpu));
211 BUG_ON(cpu != smp_processor_id());
213 /* get current setting */
214 M = (P2001_TIMER->PLL_12288_config >> 0) & 0x00ff;
215 P = (P2001_TIMER->PLL_12288_config >> 8) & 0x003f;
216 S = (P2001_TIMER->PLL_12288_config >> 14) & 0x0003;
217 N = (P2001_TIMER->PLL_12288_config >> 16) & 0x03ff;
218 PWRDN = (P2001_TIMER->PLL_12288_config >> 26) & 0x0001;
219 M_DIV = (P2001_TIMER->DIV_12288_config >> 0) & 0x00ff;
220 N_DIV = (P2001_TIMER->DIV_12288_config >> 8) & 0x00ff;
221 SEL_PLL = (P2001_TIMER->DIV_12288_config >> 16) & 0x0001;
222 SEL_DIV = (P2001_TIMER->DIV_12288_config >> 17) & 0x0001;
223 // printk("M=%d P=%d S=%d N=%d PWRDN=%d\n", M, P, S, N, PWRDN);
224 // printk("M_DIV=%d N_DIV=%d SEL_PLL=%d SEL_DIV=%d\n", M_DIV, N_DIV, SEL_PLL, SEL_DIV);
226 current_freq = 12288; // External 12.288 MHz oscillator
227 // printk("cpufreq after OSC: %d\n", current_freq);
229 switch (SEL_PLL) {
230 case 0: // shortcut
231 break;
232 case 1: // PLL
233 /* WARNING: 2^S=2 for S=0 (CodeSourcery ARM Q1A 2004) */
234 // current_freq *= PWRDN ? 0 : ((M+8) / ( (2^S) * (P+2) )); // correct
235 current_freq *= PWRDN ? 0 : ((M+8) / (P+2)); // working
236 break;
237 case 2: // 0
238 current_freq = 0;
239 break;
241 // printk("cpufreq after PLL: %d\n", current_freq);
243 switch (SEL_DIV) {
244 case 0: // shortcut
245 break;
246 case 1:
247 current_freq /= (2*(N+1));
248 break;
250 // printk("cpufreq after DIV: %d\n", current_freq);
253 * Restore the CPUs allowed mask.
255 set_cpus_allowed(current, cpus_allowed);
257 return current_freq;
260 static struct cpufreq_driver p2001_cpufreq_driver = {
261 .name = "P2001 cpufreq",
262 .init = p2001_cpufreq_driver_init,
263 .verify = p2001_cpufreq_driver_verify,
264 // .setpolicy = p2001_cpufreq_driver_setpolicy,
265 .target = p2001_cpufreq_driver_target,
266 .get = p2001_cpufreq_driver_get,
269 static int __init p2001_cpufreq_module_init(void)
271 // printk("p2001_cpufreq_module_init\n");
272 return cpufreq_register_driver(&p2001_cpufreq_driver);
275 static void __exit p2001_cpufreq_module_exit(void)
277 // printk("p2001_cpufreq_module_exit\n");
278 cpufreq_unregister_driver(&p2001_cpufreq_driver);
281 module_init(p2001_cpufreq_module_init);
282 module_exit(p2001_cpufreq_module_exit);
284 MODULE_AUTHOR("Tobias Lorenz");
285 MODULE_DESCRIPTION("P2001 cpu frequency scaling driver");
286 MODULE_LICENSE("GPL");