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