ppc_cbe_cpufreq.c (3693B)
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/cell-regs.h> 16 17#include "ppc_cbe_cpufreq.h" 18 19/* the CBE supports an 8 step frequency scaling */ 20static 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 36static 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 54static 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 116static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy) 117{ 118 cbe_cpufreq_pmi_policy_exit(policy); 119 return 0; 120} 121 122static int cbe_cpufreq_target(struct cpufreq_policy *policy, 123 unsigned int cbe_pmode_new) 124{ 125 pr_debug("setting frequency for cpu %d to %d kHz, " \ 126 "1/%d of max frequency\n", 127 policy->cpu, 128 cbe_freqs[cbe_pmode_new].frequency, 129 cbe_freqs[cbe_pmode_new].driver_data); 130 131 return set_pmode(policy->cpu, cbe_pmode_new); 132} 133 134static struct cpufreq_driver cbe_cpufreq_driver = { 135 .verify = cpufreq_generic_frequency_table_verify, 136 .target_index = cbe_cpufreq_target, 137 .init = cbe_cpufreq_cpu_init, 138 .exit = cbe_cpufreq_cpu_exit, 139 .name = "cbe-cpufreq", 140 .flags = CPUFREQ_CONST_LOOPS, 141}; 142 143/* 144 * module init and destoy 145 */ 146 147static int __init cbe_cpufreq_init(void) 148{ 149 int ret; 150 151 if (!machine_is(cell)) 152 return -ENODEV; 153 154 cbe_cpufreq_pmi_init(); 155 156 ret = cpufreq_register_driver(&cbe_cpufreq_driver); 157 if (ret) 158 cbe_cpufreq_pmi_exit(); 159 160 return ret; 161} 162 163static void __exit cbe_cpufreq_exit(void) 164{ 165 cpufreq_unregister_driver(&cbe_cpufreq_driver); 166 cbe_cpufreq_pmi_exit(); 167} 168 169module_init(cbe_cpufreq_init); 170module_exit(cbe_cpufreq_exit); 171 172MODULE_LICENSE("GPL"); 173MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");