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