1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * pmi backend for the cbe_cpufreq driver 4 * 5 * (C) Copyright IBM Deutschland Entwicklung GmbH 2005-2007 6 * 7 * Author: Christian Krafft <krafft@de.ibm.com> 8 */ 9 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 16 #include <asm/processor.h> 17 #include <asm/prom.h> 18 #include <asm/pmi.h> 19 #include <asm/cell-regs.h> 20 21 #ifdef DEBUG 22 #include <asm/time.h> 23 #endif 24 25 #include "ppc_cbe_cpufreq.h" 26 27 static u8 pmi_slow_mode_limit[MAX_CBE]; 28 29 bool cbe_cpufreq_has_pmi = false; 30 EXPORT_SYMBOL_GPL(cbe_cpufreq_has_pmi); 31 32 /* 33 * hardware specific functions 34 */ 35 36 int cbe_cpufreq_set_pmode_pmi(int cpu, unsigned int pmode) 37 { 38 int ret; 39 pmi_message_t pmi_msg; 40 #ifdef DEBUG 41 long time; 42 #endif 43 pmi_msg.type = PMI_TYPE_FREQ_CHANGE; 44 pmi_msg.data1 = cbe_cpu_to_node(cpu); 45 pmi_msg.data2 = pmode; 46 47 #ifdef DEBUG 48 time = jiffies; 49 #endif 50 pmi_send_message(pmi_msg); 51 52 #ifdef DEBUG 53 time = jiffies - time; 54 time = jiffies_to_msecs(time); 55 pr_debug("had to wait %lu ms for a transition using " \ 56 "PMI\n", time); 57 #endif 58 ret = pmi_msg.data2; 59 pr_debug("PMI returned slow mode %d\n", ret); 60 61 return ret; 62 } 63 EXPORT_SYMBOL_GPL(cbe_cpufreq_set_pmode_pmi); 64 65 66 static void cbe_cpufreq_handle_pmi(pmi_message_t pmi_msg) 67 { 68 u8 node, slow_mode; 69 70 BUG_ON(pmi_msg.type != PMI_TYPE_FREQ_CHANGE); 71 72 node = pmi_msg.data1; 73 slow_mode = pmi_msg.data2; 74 75 pmi_slow_mode_limit[node] = slow_mode; 76 77 pr_debug("cbe_handle_pmi: node: %d max_freq: %d\n", node, slow_mode); 78 } 79 80 static int pmi_notifier(struct notifier_block *nb, 81 unsigned long event, void *data) 82 { 83 struct cpufreq_policy *policy = data; 84 struct cpufreq_frequency_table *cbe_freqs = policy->freq_table; 85 u8 node; 86 87 /* Should this really be called for CPUFREQ_ADJUST and CPUFREQ_NOTIFY 88 * policy events?) 89 */ 90 node = cbe_cpu_to_node(policy->cpu); 91 92 pr_debug("got notified, event=%lu, node=%u\n", event, node); 93 94 if (pmi_slow_mode_limit[node] != 0) { 95 pr_debug("limiting node %d to slow mode %d\n", 96 node, pmi_slow_mode_limit[node]); 97 98 cpufreq_verify_within_limits(policy, 0, 99 100 cbe_freqs[pmi_slow_mode_limit[node]].frequency); 101 } 102 103 return 0; 104 } 105 106 static struct notifier_block pmi_notifier_block = { 107 .notifier_call = pmi_notifier, 108 }; 109 110 static struct pmi_handler cbe_pmi_handler = { 111 .type = PMI_TYPE_FREQ_CHANGE, 112 .handle_pmi_message = cbe_cpufreq_handle_pmi, 113 }; 114 115 116 117 static int __init cbe_cpufreq_pmi_init(void) 118 { 119 cbe_cpufreq_has_pmi = pmi_register_handler(&cbe_pmi_handler) == 0; 120 121 if (!cbe_cpufreq_has_pmi) 122 return -ENODEV; 123 124 cpufreq_register_notifier(&pmi_notifier_block, CPUFREQ_POLICY_NOTIFIER); 125 126 return 0; 127 } 128 device_initcall(cbe_cpufreq_pmi_init); 129