1/* 2 * cpufreq driver for the cell processor 3 * 4 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005 5 * 6 * Author: Christian Krafft <krafft@de.ibm.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2, or (at your option) 11 * any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 */ 22 23#include <linux/cpufreq.h> 24#include <linux/timer.h> 25 26#include <asm/hw_irq.h> 27#include <asm/io.h> 28#include <asm/machdep.h> 29#include <asm/processor.h> 30#include <asm/prom.h> 31#include <asm/time.h> 32#include <asm/pmi.h> 33#include <asm/of_platform.h> 34 35#include "cbe_regs.h" 36 37static DEFINE_MUTEX(cbe_switch_mutex); 38 39 40/* the CBE supports an 8 step frequency scaling */ 41static struct cpufreq_frequency_table cbe_freqs[] = { 42 {1, 0}, 43 {2, 0}, 44 {3, 0}, 45 {4, 0}, 46 {5, 0}, 47 {6, 0}, 48 {8, 0}, 49 {10, 0}, 50 {0, CPUFREQ_TABLE_END}, 51}; 52 53/* to write to MIC register */ 54static u64 MIC_Slow_Fast_Timer_table[] = { 55 [0 ... 7] = 0x007fc00000000000ull, 56}; 57 58/* more values for the MIC */ 59static u64 MIC_Slow_Next_Timer_table[] = { 60 0x0000240000000000ull, 61 0x0000268000000000ull, 62 0x000029C000000000ull, 63 0x00002D0000000000ull, 64 0x0000300000000000ull, 65 0x0000334000000000ull, 66 0x000039C000000000ull, 67 0x00003FC000000000ull, 68}; 69 70static unsigned int pmi_frequency_limit = 0; 71/* 72 * hardware specific functions 73 */ 74 75static struct of_device *pmi_dev; 76 77#ifdef CONFIG_PPC_PMI 78static int set_pmode_pmi(int cpu, unsigned int pmode) 79{ 80 int ret; 81 pmi_message_t pmi_msg; 82#ifdef DEBUG 83 u64 time; 84#endif 85 86 pmi_msg.type = PMI_TYPE_FREQ_CHANGE; 87 pmi_msg.data1 = cbe_cpu_to_node(cpu); 88 pmi_msg.data2 = pmode; 89 90#ifdef DEBUG 91 time = (u64) get_cycles(); 92#endif 93 94 pmi_send_message(pmi_dev, pmi_msg); 95 ret = pmi_msg.data2; 96 97 pr_debug("PMI returned slow mode %d\n", ret); 98 99#ifdef DEBUG 100 time = (u64) get_cycles() - time; /* actual cycles (not cpu cycles!) */ 101 time = 1000000000 * time / CLOCK_TICK_RATE; /* time in ns (10^-9) */ 102 pr_debug("had to wait %lu ns for a transition\n", time); 103#endif 104 return ret; 105} 106#endif 107 108static int get_pmode(int cpu) 109{ 110 int ret; 111 struct cbe_pmd_regs __iomem *pmd_regs; 112 113 pmd_regs = cbe_get_cpu_pmd_regs(cpu); 114 ret = in_be64(&pmd_regs->pmsr) & 0x07; 115 116 return ret; 117} 118 119static int set_pmode_reg(int cpu, unsigned int pmode) 120{ 121 struct cbe_pmd_regs __iomem *pmd_regs; 122 struct cbe_mic_tm_regs __iomem *mic_tm_regs; 123 u64 flags; 124 u64 value; 125 126 local_irq_save(flags); 127 128 mic_tm_regs = cbe_get_cpu_mic_tm_regs(cpu); 129 pmd_regs = cbe_get_cpu_pmd_regs(cpu); 130 131 pr_debug("pm register is mapped at %p\n", &pmd_regs->pmcr); 132 pr_debug("mic register is mapped at %p\n", &mic_tm_regs->slow_fast_timer_0); 133 134 out_be64(&mic_tm_regs->slow_fast_timer_0, MIC_Slow_Fast_Timer_table[pmode]); 135 out_be64(&mic_tm_regs->slow_fast_timer_1, MIC_Slow_Fast_Timer_table[pmode]); 136 137 out_be64(&mic_tm_regs->slow_next_timer_0, MIC_Slow_Next_Timer_table[pmode]); 138 out_be64(&mic_tm_regs->slow_next_timer_1, MIC_Slow_Next_Timer_table[pmode]); 139 140 value = in_be64(&pmd_regs->pmcr); 141 /* set bits to zero */ 142 value &= 0xFFFFFFFFFFFFFFF8ull; 143 /* set bits to next pmode */ 144 value |= pmode; 145 146 out_be64(&pmd_regs->pmcr, value); 147 148 /* wait until new pmode appears in status register */ 149 value = in_be64(&pmd_regs->pmsr) & 0x07; 150 while(value != pmode) { 151 cpu_relax(); 152 value = in_be64(&pmd_regs->pmsr) & 0x07; 153 } 154 155 local_irq_restore(flags); 156 157 return 0; 158} 159 160static int set_pmode(int cpu, unsigned int slow_mode) { 161#ifdef CONFIG_PPC_PMI 162 if (pmi_dev) 163 return set_pmode_pmi(cpu, slow_mode); 164 else 165#endif 166 return set_pmode_reg(cpu, slow_mode); 167} 168 169static void cbe_cpufreq_handle_pmi(struct of_device *dev, pmi_message_t pmi_msg) 170{ 171 u8 cpu; 172 u8 cbe_pmode_new; 173 174 BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE); 175 176 cpu = cbe_node_to_cpu(pmi_msg.data1); 177 cbe_pmode_new = pmi_msg.data2; 178 179 pmi_frequency_limit = cbe_freqs[cbe_pmode_new].frequency; 180 181 pr_debug("cbe_handle_pmi: max freq=%d\n", pmi_frequency_limit); 182} 183 184static int pmi_notifier(struct notifier_block *nb, 185 unsigned long event, void *data) 186{ 187 struct cpufreq_policy *policy = data; 188 189 if (event != CPUFREQ_INCOMPATIBLE) 190 return 0; 191 192 cpufreq_verify_within_limits(policy, 0, pmi_frequency_limit); 193 return 0; 194} 195 196static struct notifier_block pmi_notifier_block = { 197 .notifier_call = pmi_notifier, 198}; 199 200static struct pmi_handler cbe_pmi_handler = { 201 .type = PMI_TYPE_FREQ_CHANGE, 202 .handle_pmi_message = cbe_cpufreq_handle_pmi, 203}; 204 205 206/* 207 * cpufreq functions 208 */ 209 210static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) 211{ 212 const u32 *max_freqp; 213 u32 max_freq; 214 int i, cur_pmode; 215 struct device_node *cpu; 216 217 cpu = of_get_cpu_node(policy->cpu, NULL); 218 219 if (!cpu) 220 return -ENODEV; 221 222 pr_debug("init cpufreq on CPU %d\n", policy->cpu); 223 224 max_freqp = of_get_property(cpu, "clock-frequency", NULL); 225 226 if (!max_freqp) 227 return -EINVAL; 228 229 /* we need the freq in kHz */ 230 max_freq = *max_freqp / 1000; 231 232 pr_debug("max clock-frequency is at %u kHz\n", max_freq); 233 pr_debug("initializing frequency table\n"); 234 235 /* initialize frequency table */ 236 for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) { 237 cbe_freqs[i].frequency = max_freq / cbe_freqs[i].index; 238 pr_debug("%d: %d\n", i, cbe_freqs[i].frequency); 239 } 240 241 policy->governor = CPUFREQ_DEFAULT_GOVERNOR; 242 /* if DEBUG is enabled set_pmode() measures the correct latency of a transition */ 243 policy->cpuinfo.transition_latency = 25000; 244 245 cur_pmode = get_pmode(policy->cpu); 246 pr_debug("current pmode is at %d\n",cur_pmode); 247 248 policy->cur = cbe_freqs[cur_pmode].frequency; 249 250#ifdef CONFIG_SMP 251 policy->cpus = cpu_sibling_map[policy->cpu]; 252#endif 253 254 cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu); 255 256 if (pmi_dev) { 257 /* frequency might get limited later, initialize limit with max_freq */ 258 pmi_frequency_limit = max_freq; 259 cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); 260 } 261 262 /* this ensures that policy->cpuinfo_min and policy->cpuinfo_max are set correctly */ 263 return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs); 264} 265 266static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy) 267{ 268 if (pmi_dev) 269 cpufreq_unregister_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); 270 271 cpufreq_frequency_table_put_attr(policy->cpu); 272 return 0; 273} 274 275static int cbe_cpufreq_verify(struct cpufreq_policy *policy) 276{ 277 return cpufreq_frequency_table_verify(policy, cbe_freqs); 278} 279 280 281static int cbe_cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq, 282 unsigned int relation) 283{ 284 int rc; 285 struct cpufreq_freqs freqs; 286 int cbe_pmode_new; 287 288 cpufreq_frequency_table_target(policy, 289 cbe_freqs, 290 target_freq, 291 relation, 292 &cbe_pmode_new); 293 294 freqs.old = policy->cur; 295 freqs.new = cbe_freqs[cbe_pmode_new].frequency; 296 freqs.cpu = policy->cpu; 297 298 mutex_lock(&cbe_switch_mutex); 299 cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); 300 301 pr_debug("setting frequency for cpu %d to %d kHz, 1/%d of max frequency\n", 302 policy->cpu, 303 cbe_freqs[cbe_pmode_new].frequency, 304 cbe_freqs[cbe_pmode_new].index); 305 306 rc = set_pmode(policy->cpu, cbe_pmode_new); 307 cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE); 308 mutex_unlock(&cbe_switch_mutex); 309 310 return rc; 311} 312 313static struct cpufreq_driver cbe_cpufreq_driver = { 314 .verify = cbe_cpufreq_verify, 315 .target = cbe_cpufreq_target, 316 .init = cbe_cpufreq_cpu_init, 317 .exit = cbe_cpufreq_cpu_exit, 318 .name = "cbe-cpufreq", 319 .owner = THIS_MODULE, 320 .flags = CPUFREQ_CONST_LOOPS, 321}; 322 323/* 324 * module init and destoy 325 */ 326 327static int __init cbe_cpufreq_init(void) 328{ 329#ifdef CONFIG_PPC_PMI 330 struct device_node *np; 331#endif 332 if (!machine_is(cell)) 333 return -ENODEV; 334#ifdef CONFIG_PPC_PMI 335 np = of_find_node_by_type(NULL, "ibm,pmi"); 336 337 pmi_dev = of_find_device_by_node(np); 338 339 if (pmi_dev) 340 pmi_register_handler(pmi_dev, &cbe_pmi_handler); 341#endif 342 return cpufreq_register_driver(&cbe_cpufreq_driver); 343} 344 345static void __exit cbe_cpufreq_exit(void) 346{ 347#ifdef CONFIG_PPC_PMI 348 if (pmi_dev) 349 pmi_unregister_handler(pmi_dev, &cbe_pmi_handler); 350#endif 351 cpufreq_unregister_driver(&cbe_cpufreq_driver); 352} 353 354module_init(cbe_cpufreq_init); 355module_exit(cbe_cpufreq_exit); 356 357MODULE_LICENSE("GPL"); 358MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>"); 359