0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/cpufreq.h>
0011 #include <linux/module.h>
0012 #include <linux/of_platform.h>
0013
0014 #include <asm/machdep.h>
0015 #include <asm/cell-regs.h>
0016
0017 #include "ppc_cbe_cpufreq.h"
0018
0019
0020 static struct cpufreq_frequency_table cbe_freqs[] = {
0021 {0, 1, 0},
0022 {0, 2, 0},
0023 {0, 3, 0},
0024 {0, 4, 0},
0025 {0, 5, 0},
0026 {0, 6, 0},
0027 {0, 8, 0},
0028 {0, 10, 0},
0029 {0, 0, CPUFREQ_TABLE_END},
0030 };
0031
0032
0033
0034
0035
0036 static int set_pmode(unsigned int cpu, unsigned int slow_mode)
0037 {
0038 int rc;
0039
0040 if (cbe_cpufreq_has_pmi)
0041 rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode);
0042 else
0043 rc = cbe_cpufreq_set_pmode(cpu, slow_mode);
0044
0045 pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu));
0046
0047 return rc;
0048 }
0049
0050
0051
0052
0053
0054 static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
0055 {
0056 struct cpufreq_frequency_table *pos;
0057 const u32 *max_freqp;
0058 u32 max_freq;
0059 int cur_pmode;
0060 struct device_node *cpu;
0061
0062 cpu = of_get_cpu_node(policy->cpu, NULL);
0063
0064 if (!cpu)
0065 return -ENODEV;
0066
0067 pr_debug("init cpufreq on CPU %d\n", policy->cpu);
0068
0069
0070
0071
0072 if (!cbe_get_cpu_pmd_regs(policy->cpu) ||
0073 !cbe_get_cpu_mic_tm_regs(policy->cpu)) {
0074 pr_info("invalid CBE regs pointers for cpufreq\n");
0075 of_node_put(cpu);
0076 return -EINVAL;
0077 }
0078
0079 max_freqp = of_get_property(cpu, "clock-frequency", NULL);
0080
0081 of_node_put(cpu);
0082
0083 if (!max_freqp)
0084 return -EINVAL;
0085
0086
0087 max_freq = *max_freqp / 1000;
0088
0089 pr_debug("max clock-frequency is at %u kHz\n", max_freq);
0090 pr_debug("initializing frequency table\n");
0091
0092
0093 cpufreq_for_each_entry(pos, cbe_freqs) {
0094 pos->frequency = max_freq / pos->driver_data;
0095 pr_debug("%d: %d\n", (int)(pos - cbe_freqs), pos->frequency);
0096 }
0097
0098
0099
0100 policy->cpuinfo.transition_latency = 25000;
0101
0102 cur_pmode = cbe_cpufreq_get_pmode(policy->cpu);
0103 pr_debug("current pmode is at %d\n",cur_pmode);
0104
0105 policy->cur = cbe_freqs[cur_pmode].frequency;
0106
0107 #ifdef CONFIG_SMP
0108 cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu));
0109 #endif
0110
0111 policy->freq_table = cbe_freqs;
0112 cbe_cpufreq_pmi_policy_init(policy);
0113 return 0;
0114 }
0115
0116 static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
0117 {
0118 cbe_cpufreq_pmi_policy_exit(policy);
0119 return 0;
0120 }
0121
0122 static int cbe_cpufreq_target(struct cpufreq_policy *policy,
0123 unsigned int cbe_pmode_new)
0124 {
0125 pr_debug("setting frequency for cpu %d to %d kHz, " \
0126 "1/%d of max frequency\n",
0127 policy->cpu,
0128 cbe_freqs[cbe_pmode_new].frequency,
0129 cbe_freqs[cbe_pmode_new].driver_data);
0130
0131 return set_pmode(policy->cpu, cbe_pmode_new);
0132 }
0133
0134 static struct cpufreq_driver cbe_cpufreq_driver = {
0135 .verify = cpufreq_generic_frequency_table_verify,
0136 .target_index = cbe_cpufreq_target,
0137 .init = cbe_cpufreq_cpu_init,
0138 .exit = cbe_cpufreq_cpu_exit,
0139 .name = "cbe-cpufreq",
0140 .flags = CPUFREQ_CONST_LOOPS,
0141 };
0142
0143
0144
0145
0146
0147 static int __init cbe_cpufreq_init(void)
0148 {
0149 int ret;
0150
0151 if (!machine_is(cell))
0152 return -ENODEV;
0153
0154 cbe_cpufreq_pmi_init();
0155
0156 ret = cpufreq_register_driver(&cbe_cpufreq_driver);
0157 if (ret)
0158 cbe_cpufreq_pmi_exit();
0159
0160 return ret;
0161 }
0162
0163 static void __exit cbe_cpufreq_exit(void)
0164 {
0165 cpufreq_unregister_driver(&cbe_cpufreq_driver);
0166 cbe_cpufreq_pmi_exit();
0167 }
0168
0169 module_init(cbe_cpufreq_init);
0170 module_exit(cbe_cpufreq_exit);
0171
0172 MODULE_LICENSE("GPL");
0173 MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");