1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * cpufreq driver for the cell processor 4 * 5 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007 6 * 7 * Author: Christian Krafft <krafft@de.ibm.com> 8 */ 9 10 #include <linux/cpufreq.h> 11 #include <linux/module.h> 12 #include <linux/of_platform.h> 13 14 #include <asm/machdep.h> 15 #include <asm/prom.h> 16 #include <asm/cell-regs.h> 17 18 #include "ppc_cbe_cpufreq.h" 19 20 /* the CBE supports an 8 step frequency scaling */ 21 static struct cpufreq_frequency_table cbe_freqs[] = { 22 {0, 1, 0}, 23 {0, 2, 0}, 24 {0, 3, 0}, 25 {0, 4, 0}, 26 {0, 5, 0}, 27 {0, 6, 0}, 28 {0, 8, 0}, 29 {0, 10, 0}, 30 {0, 0, CPUFREQ_TABLE_END}, 31 }; 32 33 /* 34 * hardware specific functions 35 */ 36 37 static int set_pmode(unsigned int cpu, unsigned int slow_mode) 38 { 39 int rc; 40 41 if (cbe_cpufreq_has_pmi) 42 rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode); 43 else 44 rc = cbe_cpufreq_set_pmode(cpu, slow_mode); 45 46 pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu)); 47 48 return rc; 49 } 50 51 /* 52 * cpufreq functions 53 */ 54 55 static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy) 56 { 57 struct cpufreq_frequency_table *pos; 58 const u32 *max_freqp; 59 u32 max_freq; 60 int cur_pmode; 61 struct device_node *cpu; 62 63 cpu = of_get_cpu_node(policy->cpu, NULL); 64 65 if (!cpu) 66 return -ENODEV; 67 68 pr_debug("init cpufreq on CPU %d\n", policy->cpu); 69 70 /* 71 * Let's check we can actually get to the CELL regs 72 */ 73 if (!cbe_get_cpu_pmd_regs(policy->cpu) || 74 !cbe_get_cpu_mic_tm_regs(policy->cpu)) { 75 pr_info("invalid CBE regs pointers for cpufreq\n"); 76 of_node_put(cpu); 77 return -EINVAL; 78 } 79 80 max_freqp = of_get_property(cpu, "clock-frequency", NULL); 81 82 of_node_put(cpu); 83 84 if (!max_freqp) 85 return -EINVAL; 86 87 /* we need the freq in kHz */ 88 max_freq = *max_freqp / 1000; 89 90 pr_debug("max clock-frequency is at %u kHz\n", max_freq); 91 pr_debug("initializing frequency table\n"); 92 93 /* initialize frequency table */ 94 cpufreq_for_each_entry(pos, cbe_freqs) { 95 pos->frequency = max_freq / pos->driver_data; 96 pr_debug("%d: %d\n", (int)(pos - cbe_freqs), pos->frequency); 97 } 98 99 /* if DEBUG is enabled set_pmode() measures the latency 100 * of a transition */ 101 policy->cpuinfo.transition_latency = 25000; 102 103 cur_pmode = cbe_cpufreq_get_pmode(policy->cpu); 104 pr_debug("current pmode is at %d\n",cur_pmode); 105 106 policy->cur = cbe_freqs[cur_pmode].frequency; 107 108 #ifdef CONFIG_SMP 109 cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu)); 110 #endif 111 112 policy->freq_table = cbe_freqs; 113 cbe_cpufreq_pmi_policy_init(policy); 114 return 0; 115 } 116 117 static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy) 118 { 119 cbe_cpufreq_pmi_policy_exit(policy); 120 return 0; 121 } 122 123 static int cbe_cpufreq_target(struct cpufreq_policy *policy, 124 unsigned int cbe_pmode_new) 125 { 126 pr_debug("setting frequency for cpu %d to %d kHz, " \ 127 "1/%d of max frequency\n", 128 policy->cpu, 129 cbe_freqs[cbe_pmode_new].frequency, 130 cbe_freqs[cbe_pmode_new].driver_data); 131 132 return set_pmode(policy->cpu, cbe_pmode_new); 133 } 134 135 static struct cpufreq_driver cbe_cpufreq_driver = { 136 .verify = cpufreq_generic_frequency_table_verify, 137 .target_index = cbe_cpufreq_target, 138 .init = cbe_cpufreq_cpu_init, 139 .exit = cbe_cpufreq_cpu_exit, 140 .name = "cbe-cpufreq", 141 .flags = CPUFREQ_CONST_LOOPS, 142 }; 143 144 /* 145 * module init and destoy 146 */ 147 148 static int __init cbe_cpufreq_init(void) 149 { 150 int ret; 151 152 if (!machine_is(cell)) 153 return -ENODEV; 154 155 cbe_cpufreq_pmi_init(); 156 157 ret = cpufreq_register_driver(&cbe_cpufreq_driver); 158 if (ret) 159 cbe_cpufreq_pmi_exit(); 160 161 return ret; 162 } 163 164 static void __exit cbe_cpufreq_exit(void) 165 { 166 cpufreq_unregister_driver(&cbe_cpufreq_driver); 167 cbe_cpufreq_pmi_exit(); 168 } 169 170 module_init(cbe_cpufreq_init); 171 module_exit(cbe_cpufreq_exit); 172 173 MODULE_LICENSE("GPL"); 174 MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>"); 175