2 * CPPC (Collaborative Processor Performance Control) driver for
3 * interfacing with the CPUfreq layer and governors. See
4 * cppc_acpi.c for CPPC specific methods.
6 * (C) Copyright 2014, 2015 Linaro Ltd.
7 * Author: Ashwin Chaugule <ashwin.chaugule@linaro.org>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; version 2
15 #define pr_fmt(fmt) "CPPC Cpufreq:" fmt
17 #include <linux/kernel.h>
18 #include <linux/module.h>
19 #include <linux/delay.h>
20 #include <linux/cpu.h>
21 #include <linux/cpufreq.h>
22 #include <linux/vmalloc.h>
24 #include <acpi/cppc_acpi.h>
27 * These structs contain information parsed from per CPU
28 * ACPI _CPC structures.
29 * e.g. For each CPU the highest, lowest supported
30 * performance capabilities, desired performance level
33 static struct cpudata
**all_cpu_data
;
35 static int cppc_cpufreq_set_target(struct cpufreq_policy
*policy
,
36 unsigned int target_freq
,
37 unsigned int relation
)
40 struct cpufreq_freqs freqs
;
43 cpu
= all_cpu_data
[policy
->cpu
];
45 cpu
->perf_ctrls
.desired_perf
= target_freq
;
46 freqs
.old
= policy
->cur
;
47 freqs
.new = target_freq
;
49 cpufreq_freq_transition_begin(policy
, &freqs
);
50 ret
= cppc_set_perf(cpu
->cpu
, &cpu
->perf_ctrls
);
51 cpufreq_freq_transition_end(policy
, &freqs
, ret
!= 0);
54 pr_debug("Failed to set target on CPU:%d. ret:%d\n",
60 static int cppc_verify_policy(struct cpufreq_policy
*policy
)
62 cpufreq_verify_within_cpu_limits(policy
);
66 static void cppc_cpufreq_stop_cpu(struct cpufreq_policy
*policy
)
68 int cpu_num
= policy
->cpu
;
69 struct cpudata
*cpu
= all_cpu_data
[cpu_num
];
72 cpu
->perf_ctrls
.desired_perf
= cpu
->perf_caps
.lowest_perf
;
74 ret
= cppc_set_perf(cpu_num
, &cpu
->perf_ctrls
);
76 pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
77 cpu
->perf_caps
.lowest_perf
, cpu_num
, ret
);
80 static int cppc_cpufreq_cpu_init(struct cpufreq_policy
*policy
)
83 unsigned int cpu_num
= policy
->cpu
;
86 cpu
= all_cpu_data
[policy
->cpu
];
89 ret
= cppc_get_perf_caps(policy
->cpu
, &cpu
->perf_caps
);
92 pr_debug("Err reading CPU%d perf capabilities. ret:%d\n",
97 policy
->min
= cpu
->perf_caps
.lowest_perf
;
98 policy
->max
= cpu
->perf_caps
.highest_perf
;
99 policy
->cpuinfo
.min_freq
= policy
->min
;
100 policy
->cpuinfo
.max_freq
= policy
->max
;
101 policy
->shared_type
= cpu
->shared_type
;
103 if (policy
->shared_type
== CPUFREQ_SHARED_TYPE_ANY
)
104 cpumask_copy(policy
->cpus
, cpu
->shared_cpu_map
);
105 else if (policy
->shared_type
== CPUFREQ_SHARED_TYPE_ALL
) {
106 /* Support only SW_ANY for now. */
107 pr_debug("Unsupported CPU co-ord type\n");
111 cpumask_set_cpu(policy
->cpu
, policy
->cpus
);
112 cpu
->cur_policy
= policy
;
114 /* Set policy->cur to max now. The governors will adjust later. */
115 policy
->cur
= cpu
->perf_ctrls
.desired_perf
= cpu
->perf_caps
.highest_perf
;
117 ret
= cppc_set_perf(cpu_num
, &cpu
->perf_ctrls
);
119 pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
120 cpu
->perf_caps
.highest_perf
, cpu_num
, ret
);
125 static struct cpufreq_driver cppc_cpufreq_driver
= {
126 .flags
= CPUFREQ_CONST_LOOPS
,
127 .verify
= cppc_verify_policy
,
128 .target
= cppc_cpufreq_set_target
,
129 .init
= cppc_cpufreq_cpu_init
,
130 .stop_cpu
= cppc_cpufreq_stop_cpu
,
131 .name
= "cppc_cpufreq",
134 static int __init
cppc_cpufreq_init(void)
142 all_cpu_data
= kzalloc(sizeof(void *) * num_possible_cpus(), GFP_KERNEL
);
146 for_each_possible_cpu(i
) {
147 all_cpu_data
[i
] = kzalloc(sizeof(struct cpudata
), GFP_KERNEL
);
148 if (!all_cpu_data
[i
])
151 cpu
= all_cpu_data
[i
];
152 if (!zalloc_cpumask_var(&cpu
->shared_cpu_map
, GFP_KERNEL
))
156 ret
= acpi_get_psd_map(all_cpu_data
);
158 pr_debug("Error parsing PSD data. Aborting cpufreq registration.\n");
162 ret
= cpufreq_register_driver(&cppc_cpufreq_driver
);
169 for_each_possible_cpu(i
)
170 kfree(all_cpu_data
[i
]);
176 static void __exit
cppc_cpufreq_exit(void)
181 cpufreq_unregister_driver(&cppc_cpufreq_driver
);
183 for_each_possible_cpu(i
) {
184 cpu
= all_cpu_data
[i
];
185 free_cpumask_var(cpu
->shared_cpu_map
);
192 module_exit(cppc_cpufreq_exit
);
193 MODULE_AUTHOR("Ashwin Chaugule");
194 MODULE_DESCRIPTION("CPUFreq driver based on the ACPI CPPC v5.0+ spec");
195 MODULE_LICENSE("GPL");
197 late_initcall(cppc_cpufreq_init
);