aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/platforms/cell/cbe_cpufreq.c81
1 files changed, 80 insertions, 1 deletions
diff --git a/arch/powerpc/platforms/cell/cbe_cpufreq.c b/arch/powerpc/platforms/cell/cbe_cpufreq.c
index 9c5d63b7e76c..4495973bff59 100644
--- a/arch/powerpc/platforms/cell/cbe_cpufreq.c
+++ b/arch/powerpc/platforms/cell/cbe_cpufreq.c
@@ -28,6 +28,8 @@
28#include <asm/processor.h> 28#include <asm/processor.h>
29#include <asm/prom.h> 29#include <asm/prom.h>
30#include <asm/time.h> 30#include <asm/time.h>
31#include <asm/pmi.h>
32#include <asm/of_platform.h>
31 33
32#include "cbe_regs.h" 34#include "cbe_regs.h"
33 35
@@ -68,6 +70,38 @@ static u64 MIC_Slow_Next_Timer_table[] = {
68 * hardware specific functions 70 * hardware specific functions
69 */ 71 */
70 72
73static struct of_device *pmi_dev;
74
75static int set_pmode_pmi(int cpu, unsigned int pmode)
76{
77 int ret;
78 pmi_message_t pmi_msg;
79#ifdef DEBUG
80 u64 time;
81#endif
82
83 pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
84 pmi_msg.data1 = cbe_cpu_to_node(cpu);
85 pmi_msg.data2 = pmode;
86
87#ifdef DEBUG
88 time = (u64) get_cycles();
89#endif
90
91 pmi_send_message(pmi_dev, pmi_msg);
92 ret = pmi_msg.data2;
93
94 pr_debug("PMI returned slow mode %d\n", ret);
95
96#ifdef DEBUG
97 time = (u64) get_cycles() - time; /* actual cycles (not cpu cycles!) */
98 time = 1000000000 * time / CLOCK_TICK_RATE; /* time in ns (10^-9) */
99 pr_debug("had to wait %lu ns for a transition\n", time);
100#endif
101 return ret;
102}
103
104
71static int get_pmode(int cpu) 105static int get_pmode(int cpu)
72{ 106{
73 int ret; 107 int ret;
@@ -79,7 +113,7 @@ static int get_pmode(int cpu)
79 return ret; 113 return ret;
80} 114}
81 115
82static int set_pmode(int cpu, unsigned int pmode) 116static int set_pmode_reg(int cpu, unsigned int pmode)
83{ 117{
84 struct cbe_pmd_regs __iomem *pmd_regs; 118 struct cbe_pmd_regs __iomem *pmd_regs;
85 struct cbe_mic_tm_regs __iomem *mic_tm_regs; 119 struct cbe_mic_tm_regs __iomem *mic_tm_regs;
@@ -120,6 +154,39 @@ static int set_pmode(int cpu, unsigned int pmode)
120 return 0; 154 return 0;
121} 155}
122 156
157static int set_pmode(int cpu, unsigned int slow_mode) {
158 if(pmi_dev)
159 return set_pmode_pmi(cpu, slow_mode);
160 else
161 return set_pmode_reg(cpu, slow_mode);
162}
163
164static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg)
165{
166 struct cpufreq_policy policy;
167 u8 cpu;
168 u8 cbe_pmode_new;
169
170 BUG_ON (pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
171
172 cpu = cbe_node_to_cpu(pmi_msg.data1);
173 cbe_pmode_new = pmi_msg.data2;
174
175 cpufreq_get_policy(&policy, cpu);
176
177 policy.max = min(policy.max, cbe_freqs[cbe_pmode_new].frequency);
178 policy.min = min(policy.min, policy.max);
179
180 pr_debug("cbe_handle_pmi: new policy.min=%d policy.max=%d\n", policy.min, policy.max);
181 cpufreq_set_policy(&policy);
182}
183
184static struct pmi_handler cbe_pmi_handler = {
185 .type = PMI_TYPE_FREQ_CHANGE,
186 .handle_pmi_message = cbe_cpufreq_handle_pmi,
187};
188
189
123/* 190/*
124 * cpufreq functions 191 * cpufreq functions
125 */ 192 */
@@ -234,11 +301,23 @@ static struct cpufreq_driver cbe_cpufreq_driver = {
234 301
235static int __init cbe_cpufreq_init(void) 302static int __init cbe_cpufreq_init(void)
236{ 303{
304 struct device_node *np;
305
306 np = of_find_node_by_type(NULL, "ibm,pmi");
307
308 pmi_dev = of_find_device_by_node(np);
309
310 if (pmi_dev)
311 pmi_register_handler(pmi_dev, &cbe_pmi_handler);
312
237 return cpufreq_register_driver(&cbe_cpufreq_driver); 313 return cpufreq_register_driver(&cbe_cpufreq_driver);
238} 314}
239 315
240static void __exit cbe_cpufreq_exit(void) 316static void __exit cbe_cpufreq_exit(void)
241{ 317{
318 if(pmi_dev)
319 pmi_unregister_handler(pmi_dev, &cbe_pmi_handler);
320
242 cpufreq_unregister_driver(&cbe_cpufreq_driver); 321 cpufreq_unregister_driver(&cbe_cpufreq_driver);
243} 322}
244 323