1 // SPDX-License-Identifier: GPL-2.0-only
3 * CPPC (Collaborative Processor Performance Control) driver for
4 * interfacing with the CPUfreq layer and governors. See
5 * cppc_acpi.c for CPPC specific methods.
7 * (C) Copyright 2014, 2015 Linaro Ltd.
8 * Author: Ashwin Chaugule <ashwin.chaugule@linaro.org>
11 #define pr_fmt(fmt) "CPPC Cpufreq:" fmt
13 #include <linux/kernel.h>
14 #include <linux/module.h>
15 #include <linux/delay.h>
16 #include <linux/cpu.h>
17 #include <linux/cpufreq.h>
18 #include <linux/dmi.h>
19 #include <linux/time.h>
20 #include <linux/vmalloc.h>
22 #include <asm/unaligned.h>
24 #include <acpi/cppc_acpi.h>
26 /* Minimum struct length needed for the DMI processor entry we want */
27 #define DMI_ENTRY_PROCESSOR_MIN_LENGTH 48
29 /* Offest in the DMI processor structure for the max frequency */
30 #define DMI_PROCESSOR_MAX_SPEED 0x14
33 * These structs contain information parsed from per CPU
34 * ACPI _CPC structures.
35 * e.g. For each CPU the highest, lowest supported
36 * performance capabilities, desired performance level
39 static struct cppc_cpudata
**all_cpu_data
;
41 struct cppc_workaround_oem_info
{
42 char oem_id
[ACPI_OEM_ID_SIZE
+ 1];
43 char oem_table_id
[ACPI_OEM_TABLE_ID_SIZE
+ 1];
47 static bool apply_hisi_workaround
;
49 static struct cppc_workaround_oem_info wa_info
[] = {
52 .oem_table_id
= "HIP07 ",
56 .oem_table_id
= "HIP08 ",
61 static unsigned int cppc_cpufreq_perf_to_khz(struct cppc_cpudata
*cpu
,
65 * HISI platform does not support delivered performance counter and
66 * reference performance counter. It can calculate the performance using the
67 * platform specific mechanism. We reuse the desired performance register to
68 * store the real performance calculated by the platform.
70 static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpunum
)
72 struct cppc_cpudata
*cpudata
= all_cpu_data
[cpunum
];
76 ret
= cppc_get_desired_perf(cpunum
, &desired_perf
);
80 return cppc_cpufreq_perf_to_khz(cpudata
, desired_perf
);
83 static void cppc_check_hisi_workaround(void)
85 struct acpi_table_header
*tbl
;
86 acpi_status status
= AE_OK
;
89 status
= acpi_get_table(ACPI_SIG_PCCT
, 0, &tbl
);
90 if (ACPI_FAILURE(status
) || !tbl
)
93 for (i
= 0; i
< ARRAY_SIZE(wa_info
); i
++) {
94 if (!memcmp(wa_info
[i
].oem_id
, tbl
->oem_id
, ACPI_OEM_ID_SIZE
) &&
95 !memcmp(wa_info
[i
].oem_table_id
, tbl
->oem_table_id
, ACPI_OEM_TABLE_ID_SIZE
) &&
96 wa_info
[i
].oem_revision
== tbl
->oem_revision
) {
97 apply_hisi_workaround
= true;
105 /* Callback function used to retrieve the max frequency from DMI */
106 static void cppc_find_dmi_mhz(const struct dmi_header
*dm
, void *private)
108 const u8
*dmi_data
= (const u8
*)dm
;
109 u16
*mhz
= (u16
*)private;
111 if (dm
->type
== DMI_ENTRY_PROCESSOR
&&
112 dm
->length
>= DMI_ENTRY_PROCESSOR_MIN_LENGTH
) {
113 u16 val
= (u16
)get_unaligned((const u16
*)
114 (dmi_data
+ DMI_PROCESSOR_MAX_SPEED
));
115 *mhz
= val
> *mhz
? val
: *mhz
;
119 /* Look up the max frequency in DMI */
120 static u64
cppc_get_dmi_max_khz(void)
124 dmi_walk(cppc_find_dmi_mhz
, &mhz
);
127 * Real stupid fallback value, just in case there is no
136 * If CPPC lowest_freq and nominal_freq registers are exposed then we can
137 * use them to convert perf to freq and vice versa
139 * If the perf/freq point lies between Nominal and Lowest, we can treat
140 * (Low perf, Low freq) and (Nom Perf, Nom freq) as 2D co-ordinates of a line
141 * and extrapolate the rest
142 * For perf/freq > Nominal, we use the ratio perf:freq at Nominal for conversion
144 static unsigned int cppc_cpufreq_perf_to_khz(struct cppc_cpudata
*cpu
,
148 struct cppc_perf_caps
*caps
= &cpu
->perf_caps
;
151 if (caps
->lowest_freq
&& caps
->nominal_freq
) {
152 if (perf
>= caps
->nominal_perf
) {
153 mul
= caps
->nominal_freq
;
154 div
= caps
->nominal_perf
;
156 mul
= caps
->nominal_freq
- caps
->lowest_freq
;
157 div
= caps
->nominal_perf
- caps
->lowest_perf
;
161 max_khz
= cppc_get_dmi_max_khz();
163 div
= cpu
->perf_caps
.highest_perf
;
165 return (u64
)perf
* mul
/ div
;
168 static unsigned int cppc_cpufreq_khz_to_perf(struct cppc_cpudata
*cpu
,
172 struct cppc_perf_caps
*caps
= &cpu
->perf_caps
;
175 if (caps
->lowest_freq
&& caps
->nominal_freq
) {
176 if (freq
>= caps
->nominal_freq
) {
177 mul
= caps
->nominal_perf
;
178 div
= caps
->nominal_freq
;
180 mul
= caps
->lowest_perf
;
181 div
= caps
->lowest_freq
;
185 max_khz
= cppc_get_dmi_max_khz();
186 mul
= cpu
->perf_caps
.highest_perf
;
190 return (u64
)freq
* mul
/ div
;
193 static int cppc_cpufreq_set_target(struct cpufreq_policy
*policy
,
194 unsigned int target_freq
,
195 unsigned int relation
)
197 struct cppc_cpudata
*cpu
;
198 struct cpufreq_freqs freqs
;
202 cpu
= all_cpu_data
[policy
->cpu
];
204 desired_perf
= cppc_cpufreq_khz_to_perf(cpu
, target_freq
);
205 /* Return if it is exactly the same perf */
206 if (desired_perf
== cpu
->perf_ctrls
.desired_perf
)
209 cpu
->perf_ctrls
.desired_perf
= desired_perf
;
210 freqs
.old
= policy
->cur
;
211 freqs
.new = target_freq
;
213 cpufreq_freq_transition_begin(policy
, &freqs
);
214 ret
= cppc_set_perf(cpu
->cpu
, &cpu
->perf_ctrls
);
215 cpufreq_freq_transition_end(policy
, &freqs
, ret
!= 0);
218 pr_debug("Failed to set target on CPU:%d. ret:%d\n",
224 static int cppc_verify_policy(struct cpufreq_policy_data
*policy
)
226 cpufreq_verify_within_cpu_limits(policy
);
230 static void cppc_cpufreq_stop_cpu(struct cpufreq_policy
*policy
)
232 int cpu_num
= policy
->cpu
;
233 struct cppc_cpudata
*cpu
= all_cpu_data
[cpu_num
];
236 cpu
->perf_ctrls
.desired_perf
= cpu
->perf_caps
.lowest_perf
;
238 ret
= cppc_set_perf(cpu_num
, &cpu
->perf_ctrls
);
240 pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
241 cpu
->perf_caps
.lowest_perf
, cpu_num
, ret
);
245 * The PCC subspace describes the rate at which platform can accept commands
246 * on the shared PCC channel (including READs which do not count towards freq
247 * trasition requests), so ideally we need to use the PCC values as a fallback
248 * if we don't have a platform specific transition_delay_us
251 #include <asm/cputype.h>
253 static unsigned int cppc_cpufreq_get_transition_delay_us(int cpu
)
255 unsigned long implementor
= read_cpuid_implementor();
256 unsigned long part_num
= read_cpuid_part_number();
257 unsigned int delay_us
= 0;
259 switch (implementor
) {
260 case ARM_CPU_IMP_QCOM
:
262 case QCOM_CPU_PART_FALKOR_V1
:
263 case QCOM_CPU_PART_FALKOR
:
267 delay_us
= cppc_get_transition_latency(cpu
) / NSEC_PER_USEC
;
272 delay_us
= cppc_get_transition_latency(cpu
) / NSEC_PER_USEC
;
281 static unsigned int cppc_cpufreq_get_transition_delay_us(int cpu
)
283 return cppc_get_transition_latency(cpu
) / NSEC_PER_USEC
;
287 static int cppc_cpufreq_cpu_init(struct cpufreq_policy
*policy
)
289 struct cppc_cpudata
*cpu
;
290 unsigned int cpu_num
= policy
->cpu
;
293 cpu
= all_cpu_data
[policy
->cpu
];
296 ret
= cppc_get_perf_caps(policy
->cpu
, &cpu
->perf_caps
);
299 pr_debug("Err reading CPU%d perf capabilities. ret:%d\n",
304 /* Convert the lowest and nominal freq from MHz to KHz */
305 cpu
->perf_caps
.lowest_freq
*= 1000;
306 cpu
->perf_caps
.nominal_freq
*= 1000;
309 * Set min to lowest nonlinear perf to avoid any efficiency penalty (see
310 * Section 8.4.7.1.1.5 of ACPI 6.1 spec)
312 policy
->min
= cppc_cpufreq_perf_to_khz(cpu
, cpu
->perf_caps
.lowest_nonlinear_perf
);
313 policy
->max
= cppc_cpufreq_perf_to_khz(cpu
, cpu
->perf_caps
.highest_perf
);
316 * Set cpuinfo.min_freq to Lowest to make the full range of performance
317 * available if userspace wants to use any perf between lowest & lowest
320 policy
->cpuinfo
.min_freq
= cppc_cpufreq_perf_to_khz(cpu
, cpu
->perf_caps
.lowest_perf
);
321 policy
->cpuinfo
.max_freq
= cppc_cpufreq_perf_to_khz(cpu
, cpu
->perf_caps
.highest_perf
);
323 policy
->transition_delay_us
= cppc_cpufreq_get_transition_delay_us(cpu_num
);
324 policy
->shared_type
= cpu
->shared_type
;
326 if (policy
->shared_type
== CPUFREQ_SHARED_TYPE_ANY
) {
329 cpumask_copy(policy
->cpus
, cpu
->shared_cpu_map
);
331 for_each_cpu(i
, policy
->cpus
) {
332 if (unlikely(i
== policy
->cpu
))
335 memcpy(&all_cpu_data
[i
]->perf_caps
, &cpu
->perf_caps
,
336 sizeof(cpu
->perf_caps
));
338 } else if (policy
->shared_type
== CPUFREQ_SHARED_TYPE_ALL
) {
339 /* Support only SW_ANY for now. */
340 pr_debug("Unsupported CPU co-ord type\n");
344 cpu
->cur_policy
= policy
;
346 /* Set policy->cur to max now. The governors will adjust later. */
347 policy
->cur
= cppc_cpufreq_perf_to_khz(cpu
,
348 cpu
->perf_caps
.highest_perf
);
349 cpu
->perf_ctrls
.desired_perf
= cpu
->perf_caps
.highest_perf
;
351 ret
= cppc_set_perf(cpu_num
, &cpu
->perf_ctrls
);
353 pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
354 cpu
->perf_caps
.highest_perf
, cpu_num
, ret
);
359 static inline u64
get_delta(u64 t1
, u64 t0
)
361 if (t1
> t0
|| t0
> ~(u32
)0)
364 return (u32
)t1
- (u32
)t0
;
367 static int cppc_get_rate_from_fbctrs(struct cppc_cpudata
*cpu
,
368 struct cppc_perf_fb_ctrs fb_ctrs_t0
,
369 struct cppc_perf_fb_ctrs fb_ctrs_t1
)
371 u64 delta_reference
, delta_delivered
;
372 u64 reference_perf
, delivered_perf
;
374 reference_perf
= fb_ctrs_t0
.reference_perf
;
376 delta_reference
= get_delta(fb_ctrs_t1
.reference
,
377 fb_ctrs_t0
.reference
);
378 delta_delivered
= get_delta(fb_ctrs_t1
.delivered
,
379 fb_ctrs_t0
.delivered
);
381 /* Check to avoid divide-by zero */
382 if (delta_reference
|| delta_delivered
)
383 delivered_perf
= (reference_perf
* delta_delivered
) /
386 delivered_perf
= cpu
->perf_ctrls
.desired_perf
;
388 return cppc_cpufreq_perf_to_khz(cpu
, delivered_perf
);
391 static unsigned int cppc_cpufreq_get_rate(unsigned int cpunum
)
393 struct cppc_perf_fb_ctrs fb_ctrs_t0
= {0}, fb_ctrs_t1
= {0};
394 struct cppc_cpudata
*cpu
= all_cpu_data
[cpunum
];
397 if (apply_hisi_workaround
)
398 return hisi_cppc_cpufreq_get_rate(cpunum
);
400 ret
= cppc_get_perf_ctrs(cpunum
, &fb_ctrs_t0
);
404 udelay(2); /* 2usec delay between sampling */
406 ret
= cppc_get_perf_ctrs(cpunum
, &fb_ctrs_t1
);
410 return cppc_get_rate_from_fbctrs(cpu
, fb_ctrs_t0
, fb_ctrs_t1
);
413 static struct cpufreq_driver cppc_cpufreq_driver
= {
414 .flags
= CPUFREQ_CONST_LOOPS
,
415 .verify
= cppc_verify_policy
,
416 .target
= cppc_cpufreq_set_target
,
417 .get
= cppc_cpufreq_get_rate
,
418 .init
= cppc_cpufreq_cpu_init
,
419 .stop_cpu
= cppc_cpufreq_stop_cpu
,
420 .name
= "cppc_cpufreq",
423 static int __init
cppc_cpufreq_init(void)
426 struct cppc_cpudata
*cpu
;
431 all_cpu_data
= kcalloc(num_possible_cpus(), sizeof(void *),
436 for_each_possible_cpu(i
) {
437 all_cpu_data
[i
] = kzalloc(sizeof(struct cppc_cpudata
), GFP_KERNEL
);
438 if (!all_cpu_data
[i
])
441 cpu
= all_cpu_data
[i
];
442 if (!zalloc_cpumask_var(&cpu
->shared_cpu_map
, GFP_KERNEL
))
446 ret
= acpi_get_psd_map(all_cpu_data
);
448 pr_debug("Error parsing PSD data. Aborting cpufreq registration.\n");
452 cppc_check_hisi_workaround();
454 ret
= cpufreq_register_driver(&cppc_cpufreq_driver
);
461 for_each_possible_cpu(i
) {
462 cpu
= all_cpu_data
[i
];
465 free_cpumask_var(cpu
->shared_cpu_map
);
473 static void __exit
cppc_cpufreq_exit(void)
475 struct cppc_cpudata
*cpu
;
478 cpufreq_unregister_driver(&cppc_cpufreq_driver
);
480 for_each_possible_cpu(i
) {
481 cpu
= all_cpu_data
[i
];
482 free_cpumask_var(cpu
->shared_cpu_map
);
489 module_exit(cppc_cpufreq_exit
);
490 MODULE_AUTHOR("Ashwin Chaugule");
491 MODULE_DESCRIPTION("CPUFreq driver based on the ACPI CPPC v5.0+ spec");
492 MODULE_LICENSE("GPL");
494 late_initcall(cppc_cpufreq_init
);
496 static const struct acpi_device_id cppc_acpi_ids
[] __used
= {
497 {ACPI_PROCESSOR_DEVICE_HID
, },
501 MODULE_DEVICE_TABLE(acpi
, cppc_acpi_ids
);