blob: 7e639c32ae89b2b6e363aa5b6f781f1e63c55cf9 [file] [log] [blame]
//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;
}