1 /* 2 * cpufreq driver for the cell processor 3 * 4 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007 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/module.h> 25 #include <linux/of_platform.h> 26 27 #include <asm/machdep.h> 28 #include <asm/prom.h> 29 #include <asm/cell-regs.h> 30 31 #include "ppc_cbe_cpufreq.h" 32 33 static DEFINE_MUTEX(cbe_switch_mutex); 34 35 36 /* the CBE supports an 8 step frequency scaling */ 37 static struct cpufreq_frequency_table cbe_freqs[] = { 38 {1, 0}, 39 {2, 0}, 40 {3, 0}, 41 {4, 0}, 42 {5, 0}, 43 {6, 0}, 44 {8, 0}, 45 {10, 0}, 46 {0, CPUFREQ_TABLE_END}, 47 }; 48 49 /* 50 * hardware specific functions 51 */ 52 53 static int set_pmode(unsigned int cpu, unsigned int slow_mode) 54 { 55 int rc; 56 57 if (cbe_cpufreq_has_pmi) 58 rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode); 59 else 60 rc = cbe_cpufreq_set_pmode(cpu, slow_mode); 61 62 pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu)); 63 64 return rc; 65 } 66 67 /* 68 * cpufreq functions 69 */ 70 71 static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) 72 { 73 const u32 *max_freqp; 74 u32 max_freq; 75 int i, cur_pmode; 76 struct device_node *cpu; 77 78 cpu = of_get_cpu_node(policy->cpu, NULL); 79 80 if (!cpu) 81 return -ENODEV; 82 83 pr_debug("init cpufreq on CPU %d\n", policy->cpu); 84 85 /* 86 * Let's check we can actually get to the CELL regs 87 */ 88 if (!cbe_get_cpu_pmd_regs(policy->cpu) || 89 !cbe_get_cpu_mic_tm_regs(policy->cpu)) { 90 pr_info("invalid CBE regs pointers for cpufreq\n"); 91 return -EINVAL; 92 } 93 94 max_freqp = of_get_property(cpu, "clock-frequency", NULL); 95 96 of_node_put(cpu); 97 98 if (!max_freqp) 99 return -EINVAL; 100 101 /* we need the freq in kHz */ 102 max_freq = *max_freqp / 1000; 103 104 pr_debug("max clock-frequency is at %u kHz\n", max_freq); 105 pr_debug("initializing frequency table\n"); 106 107 /* initialize frequency table */ 108 for (i=0; cbe_freqs[i].frequency!=CPUFREQ_TABLE_END; i++) { 109 cbe_freqs[i].frequency = max_freq / cbe_freqs[i].driver_data; 110 pr_debug("%d: %d\n", i, cbe_freqs[i].frequency); 111 } 112 113 /* if DEBUG is enabled set_pmode() measures the latency 114 * of a transition */ 115 policy->cpuinfo.transition_latency = 25000; 116 117 cur_pmode = cbe_cpufreq_get_pmode(policy->cpu); 118 pr_debug("current pmode is at %d\n",cur_pmode); 119 120 policy->cur = cbe_freqs[cur_pmode].frequency; 121 122 #ifdef CONFIG_SMP 123 cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu)); 124 #endif 125 126 cpufreq_frequency_table_get_attr(cbe_freqs, policy->cpu); 127 128 /* this ensures that policy->cpuinfo_min 129 * and policy->cpuinfo_max are set correctly */ 130 return cpufreq_frequency_table_cpuinfo(policy, cbe_freqs); 131 } 132 133 static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy) 134 { 135 cpufreq_frequency_table_put_attr(policy->cpu); 136 return 0; 137 } 138 139 static int cbe_cpufreq_verify(struct cpufreq_policy *policy) 140 { 141 return cpufreq_frequency_table_verify(policy, cbe_freqs); 142 } 143 144 static int cbe_cpufreq_target(struct cpufreq_policy *policy, 145 unsigned int target_freq, 146 unsigned int relation) 147 { 148 int rc; 149 struct cpufreq_freqs freqs; 150 unsigned int cbe_pmode_new; 151 152 cpufreq_frequency_table_target(policy, 153 cbe_freqs, 154 target_freq, 155 relation, 156 &cbe_pmode_new); 157 158 freqs.old = policy->cur; 159 freqs.new = cbe_freqs[cbe_pmode_new].frequency; 160 161 mutex_lock(&cbe_switch_mutex); 162 cpufreq_notify_transition(policy, &freqs, CPUFREQ_PRECHANGE); 163 164 pr_debug("setting frequency for cpu %d to %d kHz, " \ 165 "1/%d of max frequency\n", 166 policy->cpu, 167 cbe_freqs[cbe_pmode_new].frequency, 168 cbe_freqs[cbe_pmode_new].driver_data); 169 170 rc = set_pmode(policy->cpu, cbe_pmode_new); 171 172 cpufreq_notify_transition(policy, &freqs, CPUFREQ_POSTCHANGE); 173 mutex_unlock(&cbe_switch_mutex); 174 175 return rc; 176 } 177 178 static struct cpufreq_driver cbe_cpufreq_driver = { 179 .verify = cbe_cpufreq_verify, 180 .target = cbe_cpufreq_target, 181 .init = cbe_cpufreq_cpu_init, 182 .exit = cbe_cpufreq_cpu_exit, 183 .name = "cbe-cpufreq", 184 .owner = THIS_MODULE, 185 .flags = CPUFREQ_CONST_LOOPS, 186 }; 187 188 /* 189 * module init and destoy 190 */ 191 192 static int __init cbe_cpufreq_init(void) 193 { 194 if (!machine_is(cell)) 195 return -ENODEV; 196 197 return cpufreq_register_driver(&cbe_cpufreq_driver); 198 } 199 200 static void __exit cbe_cpufreq_exit(void) 201 { 202 cpufreq_unregister_driver(&cbe_cpufreq_driver); 203 } 204 205 module_init(cbe_cpufreq_init); 206 module_exit(cbe_cpufreq_exit); 207 208 MODULE_LICENSE("GPL"); 209 MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>"); 210