//SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2019 MediaTek Inc. */ #include "../../drivers/misc/mediatek/base/power/include/mtk_upower.h" #include "../../drivers/misc/mediatek/include/mt-plat/mtk_cpufreq_common_api.h" static inline unsigned long get_freq_capacity(int cpu, unsigned long freq) { int i; int tmp; int idx = -1; struct upower_tbl *tbl; tbl = upower_get_core_tbl(cpu); for (i = 0; i < tbl->row_num ; i++) { tmp = mt_cpufreq_get_cpu_freq(cpu, i); if (unlikely(!tmp)) { WARN(1, "frequency not in opp table!\n"); idx = tbl->row_num - 1; break; } if (tmp >= freq) { idx = i; break; } } if (idx < 0) idx = tbl->row_num - 1; return tbl->row[idx].cap; } static inline unsigned long get_freq_capacity_lt(int cpu, unsigned long freq) { int i; int tmp; int idx = -1; struct upower_tbl *tbl; tbl = upower_get_core_tbl(cpu); for (i = tbl->row_num - 1; i >= 0; i--) { tmp = mt_cpufreq_get_cpu_freq(cpu, i); if (unlikely(!tmp)) { WARN(1, "frequency not in opp table!\n"); idx = 0; break; } if (tmp <= freq) { idx = i; break; } } if (idx < 0) idx = 0; return tbl->row[idx].cap; } void arch_set_freq_scale(struct cpumask *cpus, unsigned long cur_freq, unsigned long max_freq) { unsigned long scale; int i; int cpu = cpumask_first(cpus); unsigned long cur_cap, max_cap; cur_cap = get_freq_capacity(cpu, cur_freq); max_cap = get_freq_capacity(cpu, max_freq); scale = (cur_cap << SCHED_CAPACITY_SHIFT) / max_cap; for_each_cpu(i, cpus) { per_cpu(freq_scale, i) = scale; per_cpu(max_cpu_freq, i) = max_freq; } } void arch_set_max_freq_scale(struct cpumask *cpus, unsigned long policy_max_freq) { unsigned long scale, max_freq; int cpu = cpumask_first(cpus); unsigned long policy_max_cap, max_cap; if (cpu > nr_cpu_ids) return; max_freq = per_cpu(max_cpu_freq, cpu); if (!max_freq) return; policy_max_cap = get_freq_capacity_lt(cpu, policy_max_freq); max_cap = get_freq_capacity_lt(cpu, max_freq); scale = (policy_max_cap << SCHED_CAPACITY_SHIFT) / max_cap; for_each_cpu(cpu, cpus) per_cpu(max_freq_scale, cpu) = scale; } void arch_set_min_freq_scale(struct cpumask *cpus, unsigned long policy_min_freq) { unsigned long scale, max_freq; int cpu = cpumask_first(cpus); unsigned long policy_min_cap, max_cap; if (cpu > nr_cpu_ids) return; max_freq = per_cpu(max_cpu_freq, cpu); if (!max_freq) return; policy_min_cap = get_freq_capacity(cpu, policy_min_freq); max_cap = get_freq_capacity(cpu, max_freq); scale = (policy_min_cap << SCHED_CAPACITY_SHIFT) / max_cap; for_each_cpu(cpu, cpus) per_cpu(min_freq_scale, cpu) = scale; }