xref: /linux/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c (revision afe969074eb7d0f52761ed80da15e9a282d19677)
1de6cc651SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
26eb1c377SViresh Kumar /*
36eb1c377SViresh Kumar  * pmi backend for the cbe_cpufreq driver
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/kernel.h>
116eb1c377SViresh Kumar #include <linux/types.h>
126eb1c377SViresh Kumar #include <linux/timer.h>
13dbbe972cSPaul Gortmaker #include <linux/init.h>
146eb1c377SViresh Kumar #include <linux/of_platform.h>
15*afe96907SViresh Kumar #include <linux/pm_qos.h>
166eb1c377SViresh Kumar 
176eb1c377SViresh Kumar #include <asm/processor.h>
186eb1c377SViresh Kumar #include <asm/prom.h>
196eb1c377SViresh Kumar #include <asm/pmi.h>
206eb1c377SViresh Kumar #include <asm/cell-regs.h>
216eb1c377SViresh Kumar 
226eb1c377SViresh Kumar #ifdef DEBUG
236eb1c377SViresh Kumar #include <asm/time.h>
246eb1c377SViresh Kumar #endif
256eb1c377SViresh Kumar 
266eb1c377SViresh Kumar #include "ppc_cbe_cpufreq.h"
276eb1c377SViresh Kumar 
286eb1c377SViresh Kumar bool cbe_cpufreq_has_pmi = false;
296eb1c377SViresh Kumar EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi);
306eb1c377SViresh Kumar 
316eb1c377SViresh Kumar /*
326eb1c377SViresh Kumar  * hardware specific functions
336eb1c377SViresh Kumar  */
346eb1c377SViresh Kumar 
356eb1c377SViresh Kumar int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode)
366eb1c377SViresh Kumar {
376eb1c377SViresh Kumar 	int ret;
386eb1c377SViresh Kumar 	pmi_message_t pmi_msg;
396eb1c377SViresh Kumar #ifdef DEBUG
406eb1c377SViresh Kumar 	long time;
416eb1c377SViresh Kumar #endif
426eb1c377SViresh Kumar 	pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
436eb1c377SViresh Kumar 	pmi_msg.data1 =	cbe_cpu_to_node(cpu);
446eb1c377SViresh Kumar 	pmi_msg.data2 = pmode;
456eb1c377SViresh Kumar 
466eb1c377SViresh Kumar #ifdef DEBUG
476eb1c377SViresh Kumar 	time = jiffies;
486eb1c377SViresh Kumar #endif
496eb1c377SViresh Kumar 	pmi_send_message(pmi_msg);
506eb1c377SViresh Kumar 
516eb1c377SViresh Kumar #ifdef DEBUG
526eb1c377SViresh Kumar 	time = jiffies  - time;
536eb1c377SViresh Kumar 	time = jiffies_to_msecs(time);
546eb1c377SViresh Kumar 	pr_debug("had to wait %lu ms for a transition using " \
556eb1c377SViresh Kumar 		 "PMI\n", time);
566eb1c377SViresh Kumar #endif
576eb1c377SViresh Kumar 	ret = pmi_msg.data2;
586eb1c377SViresh Kumar 	pr_debug("PMI returned slow mode %d\n", ret);
596eb1c377SViresh Kumar 
606eb1c377SViresh Kumar 	return ret;
616eb1c377SViresh Kumar }
626eb1c377SViresh Kumar EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi);
636eb1c377SViresh Kumar 
646eb1c377SViresh Kumar 
656eb1c377SViresh Kumar static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg)
666eb1c377SViresh Kumar {
67*afe96907SViresh Kumar 	struct cpufreq_policy *policy;
68*afe96907SViresh Kumar 	struct dev_pm_qos_request *req;
696eb1c377SViresh Kumar 	u8 node, slow_mode;
70*afe96907SViresh Kumar 	int cpu, ret;
716eb1c377SViresh Kumar 
726eb1c377SViresh Kumar 	BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
736eb1c377SViresh Kumar 
746eb1c377SViresh Kumar 	node = pmi_msg.data1;
756eb1c377SViresh Kumar 	slow_mode = pmi_msg.data2;
766eb1c377SViresh Kumar 
77*afe96907SViresh Kumar 	cpu = cbe_node_to_cpu(node);
786eb1c377SViresh Kumar 
796eb1c377SViresh Kumar 	pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node, slow_mode);
80*afe96907SViresh Kumar 
81*afe96907SViresh Kumar 	policy = cpufreq_cpu_get(cpu);
82*afe96907SViresh Kumar 	if (!policy) {
83*afe96907SViresh Kumar 		pr_warn("cpufreq policy not found cpu%d\n", cpu);
84*afe96907SViresh Kumar 		return;
856eb1c377SViresh Kumar 	}
866eb1c377SViresh Kumar 
87*afe96907SViresh Kumar 	req = policy->driver_data;
886eb1c377SViresh Kumar 
89*afe96907SViresh Kumar 	ret = dev_pm_qos_update_request(req,
90*afe96907SViresh Kumar 			policy->freq_table[slow_mode].frequency);
91*afe96907SViresh Kumar 	if (ret < 0)
92*afe96907SViresh Kumar 		pr_warn("Failed to update freq constraint: %d\n", ret);
93*afe96907SViresh Kumar 	else
94*afe96907SViresh Kumar 		pr_debug("limiting node %d to slow mode %d\n", node, slow_mode);
956eb1c377SViresh Kumar 
96*afe96907SViresh Kumar 	cpufreq_cpu_put(policy);
976eb1c377SViresh Kumar }
986eb1c377SViresh Kumar 
996eb1c377SViresh Kumar static struct pmi_handler cbe_pmi_handler = {
1006eb1c377SViresh Kumar 	.type			= PMI_TYPE_FREQ_CHANGE,
1016eb1c377SViresh Kumar 	.handle_pmi_message	= cbe_cpufreq_handle_pmi,
1026eb1c377SViresh Kumar };
1036eb1c377SViresh Kumar 
104*afe96907SViresh Kumar void cbe_cpufreq_pmi_policy_init(struct cpufreq_policy *policy)
1056eb1c377SViresh Kumar {
106*afe96907SViresh Kumar 	struct dev_pm_qos_request *req;
107*afe96907SViresh Kumar 	int ret;
1086eb1c377SViresh Kumar 
1096eb1c377SViresh Kumar 	if (!cbe_cpufreq_has_pmi)
110*afe96907SViresh Kumar 		return;
1116eb1c377SViresh Kumar 
112*afe96907SViresh Kumar 	req = kzalloc(sizeof(*req), GFP_KERNEL);
113*afe96907SViresh Kumar 	if (!req)
114*afe96907SViresh Kumar 		return;
1156eb1c377SViresh Kumar 
116*afe96907SViresh Kumar 	ret = dev_pm_qos_add_request(get_cpu_device(policy->cpu), req,
117*afe96907SViresh Kumar 				     DEV_PM_QOS_MAX_FREQUENCY,
118*afe96907SViresh Kumar 				     policy->freq_table[0].frequency);
119*afe96907SViresh Kumar 	if (ret < 0) {
120*afe96907SViresh Kumar 		pr_err("Failed to add freq constraint (%d)\n", ret);
121*afe96907SViresh Kumar 		kfree(req);
122*afe96907SViresh Kumar 		return;
1236eb1c377SViresh Kumar 	}
124*afe96907SViresh Kumar 
125*afe96907SViresh Kumar 	policy->driver_data = req;
126*afe96907SViresh Kumar }
127*afe96907SViresh Kumar EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_policy_init);
128*afe96907SViresh Kumar 
129*afe96907SViresh Kumar void cbe_cpufreq_pmi_policy_exit(struct cpufreq_policy *policy)
130*afe96907SViresh Kumar {
131*afe96907SViresh Kumar 	struct dev_pm_qos_request *req = policy->driver_data;
132*afe96907SViresh Kumar 
133*afe96907SViresh Kumar 	if (cbe_cpufreq_has_pmi) {
134*afe96907SViresh Kumar 		dev_pm_qos_remove_request(req);
135*afe96907SViresh Kumar 		kfree(req);
136*afe96907SViresh Kumar 	}
137*afe96907SViresh Kumar }
138*afe96907SViresh Kumar EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_policy_exit);
139*afe96907SViresh Kumar 
140*afe96907SViresh Kumar void cbe_cpufreq_pmi_init(void)
141*afe96907SViresh Kumar {
142*afe96907SViresh Kumar 	if (!pmi_register_handler(&cbe_pmi_handler))
143*afe96907SViresh Kumar 		cbe_cpufreq_has_pmi = true;
144*afe96907SViresh Kumar }
145*afe96907SViresh Kumar EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_init);
146*afe96907SViresh Kumar 
147*afe96907SViresh Kumar void cbe_cpufreq_pmi_exit(void)
148*afe96907SViresh Kumar {
149*afe96907SViresh Kumar 	pmi_unregister_handler(&cbe_pmi_handler);
150*afe96907SViresh Kumar 	cbe_cpufreq_has_pmi = false;
151*afe96907SViresh Kumar }
152*afe96907SViresh Kumar EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_exit);
153