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