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