1de6cc651SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
26eb1c377SViresh Kumar /*
36eb1c377SViresh Kumar * cpufreq driver for the cell processor
46eb1c377SViresh Kumar *
56eb1c377SViresh Kumar * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
66eb1c377SViresh Kumar *
76eb1c377SViresh Kumar * Author: Christian Krafft <krafft@de.ibm.com>
86eb1c377SViresh Kumar */
96eb1c377SViresh Kumar
106eb1c377SViresh Kumar #include <linux/cpufreq.h>
116eb1c377SViresh Kumar #include <linux/module.h>
12*a70eb93aSRob Herring #include <linux/of.h>
136eb1c377SViresh Kumar
146eb1c377SViresh Kumar #include <asm/machdep.h>
156eb1c377SViresh Kumar #include <asm/cell-regs.h>
166eb1c377SViresh Kumar
176eb1c377SViresh Kumar #include "ppc_cbe_cpufreq.h"
186eb1c377SViresh Kumar
196eb1c377SViresh Kumar /* the CBE supports an 8 step frequency scaling */
206eb1c377SViresh Kumar static struct cpufreq_frequency_table cbe_freqs[] = {
217f4b0461SViresh Kumar {0, 1, 0},
227f4b0461SViresh Kumar {0, 2, 0},
237f4b0461SViresh Kumar {0, 3, 0},
247f4b0461SViresh Kumar {0, 4, 0},
257f4b0461SViresh Kumar {0, 5, 0},
267f4b0461SViresh Kumar {0, 6, 0},
277f4b0461SViresh Kumar {0, 8, 0},
287f4b0461SViresh Kumar {0, 10, 0},
297f4b0461SViresh Kumar {0, 0, CPUFREQ_TABLE_END},
306eb1c377SViresh Kumar };
316eb1c377SViresh Kumar
326eb1c377SViresh Kumar /*
336eb1c377SViresh Kumar * hardware specific functions
346eb1c377SViresh Kumar */
356eb1c377SViresh Kumar
set_pmode(unsigned int cpu,unsigned int slow_mode)366eb1c377SViresh Kumar static int set_pmode(unsigned int cpu, unsigned int slow_mode)
376eb1c377SViresh Kumar {
386eb1c377SViresh Kumar int rc;
396eb1c377SViresh Kumar
406eb1c377SViresh Kumar if (cbe_cpufreq_has_pmi)
416eb1c377SViresh Kumar rc = cbe_cpufreq_set_pmode_pmi(cpu, slow_mode);
426eb1c377SViresh Kumar else
436eb1c377SViresh Kumar rc = cbe_cpufreq_set_pmode(cpu, slow_mode);
446eb1c377SViresh Kumar
456eb1c377SViresh Kumar pr_debug("register contains slow mode %d\n", cbe_cpufreq_get_pmode(cpu));
466eb1c377SViresh Kumar
476eb1c377SViresh Kumar return rc;
486eb1c377SViresh Kumar }
496eb1c377SViresh Kumar
506eb1c377SViresh Kumar /*
516eb1c377SViresh Kumar * cpufreq functions
526eb1c377SViresh Kumar */
536eb1c377SViresh Kumar
cbe_cpufreq_cpu_init(struct cpufreq_policy * policy)546eb1c377SViresh Kumar static int cbe_cpufreq_cpu_init(struct cpufreq_policy *policy)
556eb1c377SViresh Kumar {
56041526f9SStratos Karafotis struct cpufreq_frequency_table *pos;
576eb1c377SViresh Kumar const u32 *max_freqp;
586eb1c377SViresh Kumar u32 max_freq;
59041526f9SStratos Karafotis int cur_pmode;
606eb1c377SViresh Kumar struct device_node *cpu;
616eb1c377SViresh Kumar
626eb1c377SViresh Kumar cpu = of_get_cpu_node(policy->cpu, NULL);
636eb1c377SViresh Kumar
646eb1c377SViresh Kumar if (!cpu)
656eb1c377SViresh Kumar return -ENODEV;
666eb1c377SViresh Kumar
676eb1c377SViresh Kumar pr_debug("init cpufreq on CPU %d\n", policy->cpu);
686eb1c377SViresh Kumar
696eb1c377SViresh Kumar /*
706eb1c377SViresh Kumar * Let's check we can actually get to the CELL regs
716eb1c377SViresh Kumar */
726eb1c377SViresh Kumar if (!cbe_get_cpu_pmd_regs(policy->cpu) ||
736eb1c377SViresh Kumar !cbe_get_cpu_mic_tm_regs(policy->cpu)) {
746eb1c377SViresh Kumar pr_info("invalid CBE regs pointers for cpufreq\n");
7523329803SWen Yang of_node_put(cpu);
766eb1c377SViresh Kumar return -EINVAL;
776eb1c377SViresh Kumar }
786eb1c377SViresh Kumar
796eb1c377SViresh Kumar max_freqp = of_get_property(cpu, "clock-frequency", NULL);
806eb1c377SViresh Kumar
816eb1c377SViresh Kumar of_node_put(cpu);
826eb1c377SViresh Kumar
836eb1c377SViresh Kumar if (!max_freqp)
846eb1c377SViresh Kumar return -EINVAL;
856eb1c377SViresh Kumar
866eb1c377SViresh Kumar /* we need the freq in kHz */
876eb1c377SViresh Kumar max_freq = *max_freqp / 1000;
886eb1c377SViresh Kumar
896eb1c377SViresh Kumar pr_debug("max clock-frequency is at %u kHz\n", max_freq);
906eb1c377SViresh Kumar pr_debug("initializing frequency table\n");
916eb1c377SViresh Kumar
926eb1c377SViresh Kumar /* initialize frequency table */
93041526f9SStratos Karafotis cpufreq_for_each_entry(pos, cbe_freqs) {
94041526f9SStratos Karafotis pos->frequency = max_freq / pos->driver_data;
95041526f9SStratos Karafotis pr_debug("%d: %d\n", (int)(pos - cbe_freqs), pos->frequency);
966eb1c377SViresh Kumar }
976eb1c377SViresh Kumar
986eb1c377SViresh Kumar /* if DEBUG is enabled set_pmode() measures the latency
996eb1c377SViresh Kumar * of a transition */
1006eb1c377SViresh Kumar policy->cpuinfo.transition_latency = 25000;
1016eb1c377SViresh Kumar
1026eb1c377SViresh Kumar cur_pmode = cbe_cpufreq_get_pmode(policy->cpu);
1036eb1c377SViresh Kumar pr_debug("current pmode is at %d\n",cur_pmode);
1046eb1c377SViresh Kumar
1056eb1c377SViresh Kumar policy->cur = cbe_freqs[cur_pmode].frequency;
1066eb1c377SViresh Kumar
1076eb1c377SViresh Kumar #ifdef CONFIG_SMP
1086eb1c377SViresh Kumar cpumask_copy(policy->cpus, cpu_sibling_mask(policy->cpu));
1096eb1c377SViresh Kumar #endif
1106eb1c377SViresh Kumar
11120dfdb9cSViresh Kumar policy->freq_table = cbe_freqs;
112afe96907SViresh Kumar cbe_cpufreq_pmi_policy_init(policy);
113afe96907SViresh Kumar return 0;
114afe96907SViresh Kumar }
115afe96907SViresh Kumar
cbe_cpufreq_cpu_exit(struct cpufreq_policy * policy)116afe96907SViresh Kumar static int cbe_cpufreq_cpu_exit(struct cpufreq_policy *policy)
117afe96907SViresh Kumar {
118afe96907SViresh Kumar cbe_cpufreq_pmi_policy_exit(policy);
11920dfdb9cSViresh Kumar return 0;
1206eb1c377SViresh Kumar }
1216eb1c377SViresh Kumar
cbe_cpufreq_target(struct cpufreq_policy * policy,unsigned int cbe_pmode_new)1226eb1c377SViresh Kumar static int cbe_cpufreq_target(struct cpufreq_policy *policy,
1239c0ebcf7SViresh Kumar unsigned int cbe_pmode_new)
1246eb1c377SViresh Kumar {
1256eb1c377SViresh Kumar pr_debug("setting frequency for cpu %d to %d kHz, " \
1266eb1c377SViresh Kumar "1/%d of max frequency\n",
1276eb1c377SViresh Kumar policy->cpu,
1286eb1c377SViresh Kumar cbe_freqs[cbe_pmode_new].frequency,
12950701588SViresh Kumar cbe_freqs[cbe_pmode_new].driver_data);
1306eb1c377SViresh Kumar
131d4019f0aSViresh Kumar return set_pmode(policy->cpu, cbe_pmode_new);
1326eb1c377SViresh Kumar }
1336eb1c377SViresh Kumar
1346eb1c377SViresh Kumar static struct cpufreq_driver cbe_cpufreq_driver = {
135c3bc3d67SViresh Kumar .verify = cpufreq_generic_frequency_table_verify,
1369c0ebcf7SViresh Kumar .target_index = cbe_cpufreq_target,
1376eb1c377SViresh Kumar .init = cbe_cpufreq_cpu_init,
138afe96907SViresh Kumar .exit = cbe_cpufreq_cpu_exit,
1396eb1c377SViresh Kumar .name = "cbe-cpufreq",
1406eb1c377SViresh Kumar .flags = CPUFREQ_CONST_LOOPS,
1416eb1c377SViresh Kumar };
1426eb1c377SViresh Kumar
1436eb1c377SViresh Kumar /*
1446eb1c377SViresh Kumar * module init and destoy
1456eb1c377SViresh Kumar */
1466eb1c377SViresh Kumar
cbe_cpufreq_init(void)1476eb1c377SViresh Kumar static int __init cbe_cpufreq_init(void)
1486eb1c377SViresh Kumar {
149afe96907SViresh Kumar int ret;
150afe96907SViresh Kumar
1516eb1c377SViresh Kumar if (!machine_is(cell))
1526eb1c377SViresh Kumar return -ENODEV;
1536eb1c377SViresh Kumar
154afe96907SViresh Kumar cbe_cpufreq_pmi_init();
155afe96907SViresh Kumar
156afe96907SViresh Kumar ret = cpufreq_register_driver(&cbe_cpufreq_driver);
157afe96907SViresh Kumar if (ret)
158afe96907SViresh Kumar cbe_cpufreq_pmi_exit();
159afe96907SViresh Kumar
160afe96907SViresh Kumar return ret;
1616eb1c377SViresh Kumar }
1626eb1c377SViresh Kumar
cbe_cpufreq_exit(void)1636eb1c377SViresh Kumar static void __exit cbe_cpufreq_exit(void)
1646eb1c377SViresh Kumar {
1656eb1c377SViresh Kumar cpufreq_unregister_driver(&cbe_cpufreq_driver);
166afe96907SViresh Kumar cbe_cpufreq_pmi_exit();
1676eb1c377SViresh Kumar }
1686eb1c377SViresh Kumar
1696eb1c377SViresh Kumar module_init(cbe_cpufreq_init);
1706eb1c377SViresh Kumar module_exit(cbe_cpufreq_exit);
1716eb1c377SViresh Kumar
1726eb1c377SViresh Kumar MODULE_LICENSE("GPL");
1736eb1c377SViresh Kumar MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
174