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