diff options
-rw-r--r-- | arch/powerpc/platforms/cell/cbe_cpufreq.c | 81 |
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 | ||
73 | static struct of_device *pmi_dev; | ||
74 | |||
75 | static 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 | |||
71 | static int get_pmode(int cpu) | 105 | static 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 | ||
82 | static int set_pmode(int cpu, unsigned int pmode) | 116 | static 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 | ||
157 | static 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 | |||
164 | static 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 | |||
184 | static 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 | ||
235 | static int __init cbe_cpufreq_init(void) | 302 | static 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 | ||
240 | static void __exit cbe_cpufreq_exit(void) | 316 | static 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 | ||