1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * pmi backend for the cbe_cpufreq driver
5 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007
7 * Author: Christian Krafft <krafft@de.ibm.com>
10 #include <linux/kernel.h>
11 #include <linux/types.h>
12 #include <linux/timer.h>
13 #include <linux/init.h>
14 #include <linux/of_platform.h>
15 #include <linux/pm_qos.h>
17 #include <asm/processor.h>
20 #include <asm/cell-regs.h>
26 #include "ppc_cbe_cpufreq.h"
28 bool cbe_cpufreq_has_pmi
= false;
29 EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi
);
32 * hardware specific functions
35 int cbe_cpufreq_set_pmode_pmi(int cpu
, unsigned int pmode
)
38 pmi_message_t pmi_msg
;
42 pmi_msg
.type
= PMI_TYPE_FREQ_CHANGE
;
43 pmi_msg
.data1
= cbe_cpu_to_node(cpu
);
44 pmi_msg
.data2
= pmode
;
49 pmi_send_message(pmi_msg
);
52 time
= jiffies
- time
;
53 time
= jiffies_to_msecs(time
);
54 pr_debug("had to wait %lu ms for a transition using " \
58 pr_debug("PMI returned slow mode %d\n", ret
);
62 EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi
);
65 static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg
)
67 struct cpufreq_policy
*policy
;
68 struct dev_pm_qos_request
*req
;
72 BUG_ON(pmi_msg
.type
!= PMI_TYPE_FREQ_CHANGE
);
75 slow_mode
= pmi_msg
.data2
;
77 cpu
= cbe_node_to_cpu(node
);
79 pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node
, slow_mode
);
81 policy
= cpufreq_cpu_get(cpu
);
83 pr_warn("cpufreq policy not found cpu%d\n", cpu
);
87 req
= policy
->driver_data
;
89 ret
= dev_pm_qos_update_request(req
,
90 policy
->freq_table
[slow_mode
].frequency
);
92 pr_warn("Failed to update freq constraint: %d\n", ret
);
94 pr_debug("limiting node %d to slow mode %d\n", node
, slow_mode
);
96 cpufreq_cpu_put(policy
);
99 static struct pmi_handler cbe_pmi_handler
= {
100 .type
= PMI_TYPE_FREQ_CHANGE
,
101 .handle_pmi_message
= cbe_cpufreq_handle_pmi
,
104 void cbe_cpufreq_pmi_policy_init(struct cpufreq_policy
*policy
)
106 struct dev_pm_qos_request
*req
;
109 if (!cbe_cpufreq_has_pmi
)
112 req
= kzalloc(sizeof(*req
), GFP_KERNEL
);
116 ret
= dev_pm_qos_add_request(get_cpu_device(policy
->cpu
), req
,
117 DEV_PM_QOS_MAX_FREQUENCY
,
118 policy
->freq_table
[0].frequency
);
120 pr_err("Failed to add freq constraint (%d)\n", ret
);
125 policy
->driver_data
= req
;
127 EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_policy_init
);
129 void cbe_cpufreq_pmi_policy_exit(struct cpufreq_policy
*policy
)
131 struct dev_pm_qos_request
*req
= policy
->driver_data
;
133 if (cbe_cpufreq_has_pmi
) {
134 dev_pm_qos_remove_request(req
);
138 EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_policy_exit
);
140 void cbe_cpufreq_pmi_init(void)
142 if (!pmi_register_handler(&cbe_pmi_handler
))
143 cbe_cpufreq_has_pmi
= true;
145 EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_init
);
147 void cbe_cpufreq_pmi_exit(void)
149 pmi_unregister_handler(&cbe_pmi_handler
);
150 cbe_cpufreq_has_pmi
= false;
152 EXPORT_SYMBOL_GPL(cbe_cpufreq_pmi_exit
);