diff options
Diffstat (limited to 'arch/arm/mach-pxa/cpufreq-pxa2xx.c')
-rw-r--r-- | arch/arm/mach-pxa/cpufreq-pxa2xx.c | 104 |
1 files changed, 85 insertions, 19 deletions
diff --git a/arch/arm/mach-pxa/cpufreq-pxa2xx.c b/arch/arm/mach-pxa/cpufreq-pxa2xx.c index 083a1d851d49..3a8ee2272add 100644 --- a/arch/arm/mach-pxa/cpufreq-pxa2xx.c +++ b/arch/arm/mach-pxa/cpufreq-pxa2xx.c | |||
@@ -36,6 +36,8 @@ | |||
36 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
37 | #include <linux/init.h> | 37 | #include <linux/init.h> |
38 | #include <linux/cpufreq.h> | 38 | #include <linux/cpufreq.h> |
39 | #include <linux/err.h> | ||
40 | #include <linux/regulator/consumer.h> | ||
39 | 41 | ||
40 | #include <mach/pxa2xx-regs.h> | 42 | #include <mach/pxa2xx-regs.h> |
41 | 43 | ||
@@ -47,6 +49,8 @@ MODULE_PARM_DESC(freq_debug, "Set the debug messages to on=1/off=0"); | |||
47 | #define freq_debug 0 | 49 | #define freq_debug 0 |
48 | #endif | 50 | #endif |
49 | 51 | ||
52 | static struct regulator *vcc_core; | ||
53 | |||
50 | static unsigned int pxa27x_maxfreq; | 54 | static unsigned int pxa27x_maxfreq; |
51 | module_param(pxa27x_maxfreq, uint, 0); | 55 | module_param(pxa27x_maxfreq, uint, 0); |
52 | MODULE_PARM_DESC(pxa27x_maxfreq, "Set the pxa27x maxfreq in MHz" | 56 | MODULE_PARM_DESC(pxa27x_maxfreq, "Set the pxa27x maxfreq in MHz" |
@@ -58,6 +62,8 @@ typedef struct { | |||
58 | unsigned int cccr; | 62 | unsigned int cccr; |
59 | unsigned int div2; | 63 | unsigned int div2; |
60 | unsigned int cclkcfg; | 64 | unsigned int cclkcfg; |
65 | int vmin; | ||
66 | int vmax; | ||
61 | } pxa_freqs_t; | 67 | } pxa_freqs_t; |
62 | 68 | ||
63 | /* Define the refresh period in mSec for the SDRAM and the number of rows */ | 69 | /* Define the refresh period in mSec for the SDRAM and the number of rows */ |
@@ -82,24 +88,24 @@ static unsigned int sdram_rows; | |||
82 | 88 | ||
83 | static pxa_freqs_t pxa255_run_freqs[] = | 89 | static pxa_freqs_t pxa255_run_freqs[] = |
84 | { | 90 | { |
85 | /* CPU MEMBUS CCCR DIV2 CCLKCFG run turbo PXbus SDRAM */ | 91 | /* CPU MEMBUS CCCR DIV2 CCLKCFG run turbo PXbus SDRAM */ |
86 | { 99500, 99500, 0x121, 1, CCLKCFG}, /* 99, 99, 50, 50 */ | 92 | { 99500, 99500, 0x121, 1, CCLKCFG, -1, -1}, /* 99, 99, 50, 50 */ |
87 | {132700, 132700, 0x123, 1, CCLKCFG}, /* 133, 133, 66, 66 */ | 93 | {132700, 132700, 0x123, 1, CCLKCFG, -1, -1}, /* 133, 133, 66, 66 */ |
88 | {199100, 99500, 0x141, 0, CCLKCFG}, /* 199, 199, 99, 99 */ | 94 | {199100, 99500, 0x141, 0, CCLKCFG, -1, -1}, /* 199, 199, 99, 99 */ |
89 | {265400, 132700, 0x143, 1, CCLKCFG}, /* 265, 265, 133, 66 */ | 95 | {265400, 132700, 0x143, 1, CCLKCFG, -1, -1}, /* 265, 265, 133, 66 */ |
90 | {331800, 165900, 0x145, 1, CCLKCFG}, /* 331, 331, 166, 83 */ | 96 | {331800, 165900, 0x145, 1, CCLKCFG, -1, -1}, /* 331, 331, 166, 83 */ |
91 | {398100, 99500, 0x161, 0, CCLKCFG}, /* 398, 398, 196, 99 */ | 97 | {398100, 99500, 0x161, 0, CCLKCFG, -1, -1}, /* 398, 398, 196, 99 */ |
92 | }; | 98 | }; |
93 | 99 | ||
94 | /* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */ | 100 | /* Use the turbo mode frequencies for the CPUFREQ_POLICY_POWERSAVE policy */ |
95 | static pxa_freqs_t pxa255_turbo_freqs[] = | 101 | static pxa_freqs_t pxa255_turbo_freqs[] = |
96 | { | 102 | { |
97 | /* CPU MEMBUS CCCR DIV2 CCLKCFG run turbo PXbus SDRAM */ | 103 | /* CPU MEMBUS CCCR DIV2 CCLKCFG run turbo PXbus SDRAM */ |
98 | { 99500, 99500, 0x121, 1, CCLKCFG}, /* 99, 99, 50, 50 */ | 104 | { 99500, 99500, 0x121, 1, CCLKCFG, -1, -1}, /* 99, 99, 50, 50 */ |
99 | {199100, 99500, 0x221, 0, CCLKCFG}, /* 99, 199, 50, 99 */ | 105 | {199100, 99500, 0x221, 0, CCLKCFG, -1, -1}, /* 99, 199, 50, 99 */ |
100 | {298500, 99500, 0x321, 0, CCLKCFG}, /* 99, 287, 50, 99 */ | 106 | {298500, 99500, 0x321, 0, CCLKCFG, -1, -1}, /* 99, 287, 50, 99 */ |
101 | {298600, 99500, 0x1c1, 0, CCLKCFG}, /* 199, 287, 99, 99 */ | 107 | {298600, 99500, 0x1c1, 0, CCLKCFG, -1, -1}, /* 199, 287, 99, 99 */ |
102 | {398100, 99500, 0x241, 0, CCLKCFG}, /* 199, 398, 99, 99 */ | 108 | {398100, 99500, 0x241, 0, CCLKCFG, -1, -1}, /* 199, 398, 99, 99 */ |
103 | }; | 109 | }; |
104 | 110 | ||
105 | #define NUM_PXA25x_RUN_FREQS ARRAY_SIZE(pxa255_run_freqs) | 111 | #define NUM_PXA25x_RUN_FREQS ARRAY_SIZE(pxa255_run_freqs) |
@@ -148,13 +154,13 @@ MODULE_PARM_DESC(pxa255_turbo_table, "Selects the frequency table (0 = run table | |||
148 | ((T) ? CCLKCFG_TURBO : 0)) | 154 | ((T) ? CCLKCFG_TURBO : 0)) |
149 | 155 | ||
150 | static pxa_freqs_t pxa27x_freqs[] = { | 156 | static pxa_freqs_t pxa27x_freqs[] = { |
151 | {104000, 104000, PXA27x_CCCR(1, 8, 2), 0, CCLKCFG2(1, 0, 1)}, | 157 | {104000, 104000, PXA27x_CCCR(1, 8, 2), 0, CCLKCFG2(1, 0, 1), 900000, 1705000 }, |
152 | {156000, 104000, PXA27x_CCCR(1, 8, 6), 0, CCLKCFG2(1, 1, 1)}, | 158 | {156000, 104000, PXA27x_CCCR(1, 8, 6), 0, CCLKCFG2(1, 1, 1), 1000000, 1705000 }, |
153 | {208000, 208000, PXA27x_CCCR(0, 16, 2), 1, CCLKCFG2(0, 0, 1)}, | 159 | {208000, 208000, PXA27x_CCCR(0, 16, 2), 1, CCLKCFG2(0, 0, 1), 1180000, 1705000 }, |
154 | {312000, 208000, PXA27x_CCCR(1, 16, 3), 1, CCLKCFG2(1, 0, 1)}, | 160 | {312000, 208000, PXA27x_CCCR(1, 16, 3), 1, CCLKCFG2(1, 0, 1), 1250000, 1705000 }, |
155 | {416000, 208000, PXA27x_CCCR(1, 16, 4), 1, CCLKCFG2(1, 0, 1)}, | 161 | {416000, 208000, PXA27x_CCCR(1, 16, 4), 1, CCLKCFG2(1, 0, 1), 1350000, 1705000 }, |
156 | {520000, 208000, PXA27x_CCCR(1, 16, 5), 1, CCLKCFG2(1, 0, 1)}, | 162 | {520000, 208000, PXA27x_CCCR(1, 16, 5), 1, CCLKCFG2(1, 0, 1), 1450000, 1705000 }, |
157 | {624000, 208000, PXA27x_CCCR(1, 16, 6), 1, CCLKCFG2(1, 0, 1)} | 163 | {624000, 208000, PXA27x_CCCR(1, 16, 6), 1, CCLKCFG2(1, 0, 1), 1550000, 1705000 } |
158 | }; | 164 | }; |
159 | 165 | ||
160 | #define NUM_PXA27x_FREQS ARRAY_SIZE(pxa27x_freqs) | 166 | #define NUM_PXA27x_FREQS ARRAY_SIZE(pxa27x_freqs) |
@@ -163,6 +169,47 @@ static struct cpufreq_frequency_table | |||
163 | 169 | ||
164 | extern unsigned get_clk_frequency_khz(int info); | 170 | extern unsigned get_clk_frequency_khz(int info); |
165 | 171 | ||
172 | #ifdef CONFIG_REGULATOR | ||
173 | |||
174 | static int pxa_cpufreq_change_voltage(pxa_freqs_t *pxa_freq) | ||
175 | { | ||
176 | int ret = 0; | ||
177 | int vmin, vmax; | ||
178 | |||
179 | if (!cpu_is_pxa27x()) | ||
180 | return 0; | ||
181 | |||
182 | vmin = pxa_freq->vmin; | ||
183 | vmax = pxa_freq->vmax; | ||
184 | if ((vmin == -1) || (vmax == -1)) | ||
185 | return 0; | ||
186 | |||
187 | ret = regulator_set_voltage(vcc_core, vmin, vmax); | ||
188 | if (ret) | ||
189 | pr_err("cpufreq: Failed to set vcc_core in [%dmV..%dmV]\n", | ||
190 | vmin, vmax); | ||
191 | return ret; | ||
192 | } | ||
193 | |||
194 | static __init void pxa_cpufreq_init_voltages(void) | ||
195 | { | ||
196 | vcc_core = regulator_get(NULL, "vcc_core"); | ||
197 | if (IS_ERR(vcc_core)) { | ||
198 | pr_info("cpufreq: Didn't find vcc_core regulator\n"); | ||
199 | vcc_core = NULL; | ||
200 | } else { | ||
201 | pr_info("cpufreq: Found vcc_core regulator\n"); | ||
202 | } | ||
203 | } | ||
204 | #else | ||
205 | static int pxa_cpufreq_change_voltage(pxa_freqs_t *pxa_freq) | ||
206 | { | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | static __init void pxa_cpufreq_init_voltages(void) { } | ||
211 | #endif | ||
212 | |||
166 | static void find_freq_tables(struct cpufreq_frequency_table **freq_table, | 213 | static void find_freq_tables(struct cpufreq_frequency_table **freq_table, |
167 | pxa_freqs_t **pxa_freqs) | 214 | pxa_freqs_t **pxa_freqs) |
168 | { | 215 | { |
@@ -251,6 +298,7 @@ static int pxa_set_target(struct cpufreq_policy *policy, | |||
251 | unsigned long flags; | 298 | unsigned long flags; |
252 | unsigned int new_freq_cpu, new_freq_mem; | 299 | unsigned int new_freq_cpu, new_freq_mem; |
253 | unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg; | 300 | unsigned int unused, preset_mdrefr, postset_mdrefr, cclkcfg; |
301 | int ret = 0; | ||
254 | 302 | ||
255 | /* Get the current policy */ | 303 | /* Get the current policy */ |
256 | find_freq_tables(&pxa_freqs_table, &pxa_freq_settings); | 304 | find_freq_tables(&pxa_freqs_table, &pxa_freq_settings); |
@@ -273,6 +321,10 @@ static int pxa_set_target(struct cpufreq_policy *policy, | |||
273 | freqs.new / 1000, (pxa_freq_settings[idx].div2) ? | 321 | freqs.new / 1000, (pxa_freq_settings[idx].div2) ? |
274 | (new_freq_mem / 2000) : (new_freq_mem / 1000)); | 322 | (new_freq_mem / 2000) : (new_freq_mem / 1000)); |
275 | 323 | ||
324 | if (vcc_core && freqs.new > freqs.old) | ||
325 | ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]); | ||
326 | if (ret) | ||
327 | return ret; | ||
276 | /* | 328 | /* |
277 | * Tell everyone what we're about to do... | 329 | * Tell everyone what we're about to do... |
278 | * you should add a notify client with any platform specific | 330 | * you should add a notify client with any platform specific |
@@ -335,6 +387,18 @@ static int pxa_set_target(struct cpufreq_policy *policy, | |||
335 | */ | 387 | */ |
336 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); | 388 | cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); |
337 | 389 | ||
390 | /* | ||
391 | * Even if voltage setting fails, we don't report it, as the frequency | ||
392 | * change succeeded. The voltage reduction is not a critical failure, | ||
393 | * only power savings will suffer from this. | ||
394 | * | ||
395 | * Note: if the voltage change fails, and a return value is returned, a | ||
396 | * bug is triggered (seems a deadlock). Should anybody find out where, | ||
397 | * the "return 0" should become a "return ret". | ||
398 | */ | ||
399 | if (vcc_core && freqs.new < freqs.old) | ||
400 | ret = pxa_cpufreq_change_voltage(&pxa_freq_settings[idx]); | ||
401 | |||
338 | return 0; | 402 | return 0; |
339 | } | 403 | } |
340 | 404 | ||
@@ -349,6 +413,8 @@ static __init int pxa_cpufreq_init(struct cpufreq_policy *policy) | |||
349 | if (cpu_is_pxa27x()) | 413 | if (cpu_is_pxa27x()) |
350 | pxa27x_guess_max_freq(); | 414 | pxa27x_guess_max_freq(); |
351 | 415 | ||
416 | pxa_cpufreq_init_voltages(); | ||
417 | |||
352 | init_sdram_rows(); | 418 | init_sdram_rows(); |
353 | 419 | ||
354 | /* set default policy and cpuinfo */ | 420 | /* set default policy and cpuinfo */ |