xref: /linux/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c (revision a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0)
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>
14afe96907SViresh Kumar #include <linux/pm_qos.h>
15*95996a67SChristophe Leroy #include <linux/slab.h>
166eb1c377SViresh Kumar 
176eb1c377SViresh Kumar #include <asm/processor.h>
186eb1c377SViresh Kumar #include <asm/pmi.h>
196eb1c377SViresh Kumar #include <asm/cell-regs.h>
206eb1c377SViresh Kumar 
216eb1c377SViresh Kumar #ifdef DEBUG
226eb1c377SViresh Kumar #include <asm/time.h>
236eb1c377SViresh Kumar #endif
246eb1c377SViresh Kumar 
256eb1c377SViresh Kumar #include "ppc_cbe_cpufreq.h"
266eb1c377SViresh Kumar 
276eb1c377SViresh Kumar bool cbe_cpufreq_has_pmi = false;
286eb1c377SViresh Kumar EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi);
296eb1c377SViresh Kumar 
306eb1c377SViresh Kumar /*
316eb1c377SViresh Kumar  * hardware specific functions
326eb1c377SViresh Kumar  */
336eb1c377SViresh Kumar 
cbe_cpufreq_set_pmode_pmi(int cpu,unsigned int pmode)346eb1c377SViresh Kumar int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode)
356eb1c377SViresh Kumar {
366eb1c377SViresh Kumar 	int ret;
376eb1c377SViresh Kumar 	pmi_message_t pmi_msg;
386eb1c377SViresh Kumar #ifdef DEBUG
396eb1c377SViresh Kumar 	long time;
406eb1c377SViresh Kumar #endif
416eb1c377SViresh Kumar 	pmi_msg.type = PMI_TYPE_FREQ_CHANGE;
426eb1c377SViresh Kumar 	pmi_msg.data1 =	cbe_cpu_to_node(cpu);
436eb1c377SViresh Kumar 	pmi_msg.data2 = pmode;
446eb1c377SViresh Kumar 
456eb1c377SViresh Kumar #ifdef DEBUG
466eb1c377SViresh Kumar 	time = jiffies;
476eb1c377SViresh Kumar #endif
486eb1c377SViresh Kumar 	pmi_send_message(pmi_msg);
496eb1c377SViresh Kumar 
506eb1c377SViresh Kumar #ifdef DEBUG
516eb1c377SViresh Kumar 	time = jiffies  - time;
526eb1c377SViresh Kumar 	time = jiffies_to_msecs(time);
536eb1c377SViresh Kumar 	pr_debug("had to wait %lu ms for a transition using " \
546eb1c377SViresh Kumar 		 "PMI\n", time);
556eb1c377SViresh Kumar #endif
566eb1c377SViresh Kumar 	ret = pmi_msg.data2;
576eb1c377SViresh Kumar 	pr_debug("PMI returned slow mode %d\n", ret);
586eb1c377SViresh Kumar 
596eb1c377SViresh Kumar 	return ret;
606eb1c377SViresh Kumar }
616eb1c377SViresh Kumar EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi);
626eb1c377SViresh Kumar 
636eb1c377SViresh Kumar 
cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg)646eb1c377SViresh Kumar static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg)
656eb1c377SViresh Kumar {
66afe96907SViresh Kumar 	struct cpufreq_policy *policy;
673000ce3cSRafael J. Wysocki 	struct freq_qos_request *req;
686eb1c377SViresh Kumar 	u8 node, slow_mode;
69afe96907SViresh Kumar 	int cpu, ret;
706eb1c377SViresh Kumar 
716eb1c377SViresh Kumar 	BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE);
726eb1c377SViresh Kumar 
736eb1c377SViresh Kumar 	node = pmi_msg.data1;
746eb1c377SViresh Kumar 	slow_mode = pmi_msg.data2;
756eb1c377SViresh Kumar 
76afe96907SViresh Kumar 	cpu = cbe_node_to_cpu(node);
776eb1c377SViresh Kumar 
786eb1c377SViresh Kumar 	pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node, slow_mode);
79afe96907SViresh Kumar 
80afe96907SViresh Kumar 	policy = cpufreq_cpu_get(cpu);
81afe96907SViresh Kumar 	if (!policy) {
82afe96907SViresh Kumar 		pr_warn("cpufreq policy not found cpu%d\n", cpu);
83afe96907SViresh Kumar 		return;
846eb1c377SViresh Kumar 	}
856eb1c377SViresh Kumar 
86afe96907SViresh Kumar 	req = policy->driver_data;
876eb1c377SViresh Kumar 
883000ce3cSRafael J. Wysocki 	ret = freq_qos_update_request(req,
89afe96907SViresh Kumar 			policy->freq_table[slow_mode].frequency);
90afe96907SViresh Kumar 	if (ret < 0)
91afe96907SViresh Kumar 		pr_warn("Failed to update freq constraint: %d\n", ret);
92afe96907SViresh Kumar 	else
93afe96907SViresh Kumar 		pr_debug("limiting node %d to slow mode %d\n", node, slow_mode);
946eb1c377SViresh Kumar 
95afe96907SViresh Kumar 	cpufreq_cpu_put(policy);
966eb1c377SViresh Kumar }
976eb1c377SViresh Kumar 
986eb1c377SViresh Kumar static struct pmi_handler cbe_pmi_handler = {
996eb1c377SViresh Kumar 	.type			= PMI_TYPE_FREQ_CHANGE,
1006eb1c377SViresh Kumar 	.handle_pmi_message	= cbe_cpufreq_handle_pmi,
1016eb1c377SViresh Kumar };
1026eb1c377SViresh Kumar 
cbe_cpufreq_pmi_policy_init(struct cpufreq_policy * policy)103afe96907SViresh Kumar void cbe_cpufreq_pmi_policy_init(struct cpufreq_policy *policy)
1046eb1c377SViresh Kumar {
1053000ce3cSRafael J. Wysocki 	struct freq_qos_request *req;
106afe96907SViresh Kumar 	int ret;
1076eb1c377SViresh Kumar 
1086eb1c377SViresh Kumar 	if (!cbe_cpufreq_has_pmi)
109afe96907SViresh Kumar 		return;
1106eb1c377SViresh Kumar 
111afe96907SViresh Kumar 	req = kzalloc(sizeof(*req), GFP_KERNEL);
112afe96907SViresh Kumar 	if (!req)
113afe96907SViresh Kumar 		return;
1146eb1c377SViresh Kumar 
1153000ce3cSRafael J. Wysocki 	ret = freq_qos_add_request(&policy->constraints, req, FREQ_QOS_MAX,
116afe96907SViresh Kumar 				   policy->freq_table[0].frequency);
117afe96907SViresh Kumar 	if (ret < 0) {
118afe96907SViresh Kumar 		pr_err("Failed to add freq constraint (%d)\n", ret);
119afe96907SViresh Kumar 		kfree(req);
120afe96907SViresh Kumar 		return;
1216eb1c377SViresh Kumar 	}
122afe96907SViresh Kumar 
123afe96907SViresh Kumar 	policy->driver_data = req;
124afe96907SViresh Kumar }
125afe96907SViresh Kumar EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_policy_init);
126afe96907SViresh Kumar 
cbe_cpufreq_pmi_policy_exit(struct cpufreq_policy * policy)127afe96907SViresh Kumar void cbe_cpufreq_pmi_policy_exit(struct cpufreq_policy *policy)
128afe96907SViresh Kumar {
1293000ce3cSRafael J. Wysocki 	struct freq_qos_request *req = policy->driver_data;
130afe96907SViresh Kumar 
131afe96907SViresh Kumar 	if (cbe_cpufreq_has_pmi) {
1323000ce3cSRafael J. Wysocki 		freq_qos_remove_request(req);
133afe96907SViresh Kumar 		kfree(req);
134afe96907SViresh Kumar 	}
135afe96907SViresh Kumar }
136afe96907SViresh Kumar EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_policy_exit);
137afe96907SViresh Kumar 
cbe_cpufreq_pmi_init(void)138afe96907SViresh Kumar void cbe_cpufreq_pmi_init(void)
139afe96907SViresh Kumar {
140afe96907SViresh Kumar 	if (!pmi_register_handler(&cbe_pmi_handler))
141afe96907SViresh Kumar 		cbe_cpufreq_has_pmi = true;
142afe96907SViresh Kumar }
143afe96907SViresh Kumar EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_init);
144afe96907SViresh Kumar 
cbe_cpufreq_pmi_exit(void)145afe96907SViresh Kumar void cbe_cpufreq_pmi_exit(void)
146afe96907SViresh Kumar {
147afe96907SViresh Kumar 	pmi_unregister_handler(&cbe_pmi_handler);
148afe96907SViresh Kumar 	cbe_cpufreq_has_pmi = false;
149afe96907SViresh Kumar }
150afe96907SViresh Kumar EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_exit);
151