#include <linux/cpufreq.h>
#include <linux/cpumask.h>
#include <linux/cpu_cooling.h>
+#include <linux/energy_model.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/pm_opp.h>
return 0;
}
+static int
+scmi_get_cpu_power(unsigned long *power, unsigned long *KHz, int cpu)
+{
+ struct device *cpu_dev = get_cpu_device(cpu);
+ unsigned long Hz;
+ int ret, domain;
+
+ if (!cpu_dev) {
+ pr_err("failed to get cpu%d device\n", cpu);
+ return -ENODEV;
+ }
+
+ domain = handle->perf_ops->device_domain_id(cpu_dev);
+ if (domain < 0)
+ return domain;
+
+ /* Get the power cost of the performance domain. */
+ Hz = *KHz * 1000;
+ ret = handle->perf_ops->power_get(handle, domain, &Hz, power);
+ if (ret)
+ return ret;
+
+ /* The EM framework specifies the frequency in KHz. */
+ *KHz = Hz / 1000;
+
+ return 0;
+}
+
static int scmi_cpufreq_init(struct cpufreq_policy *policy)
{
- int ret;
+ int ret, nr_opp;
unsigned int latency;
struct device *cpu_dev;
struct scmi_data *priv;
struct cpufreq_frequency_table *freq_table;
+ struct em_data_callback em_cb = EM_DATA_CB(scmi_get_cpu_power);
cpu_dev = get_cpu_device(policy->cpu);
if (!cpu_dev) {
ret = -EPROBE_DEFER;
goto out_free_opp;
}
+ nr_opp = ret;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
policy->cpuinfo.transition_latency = latency;
policy->fast_switch_possible = true;
+
+ em_register_freq_domain(policy->cpus, nr_opp, &em_cb);
+
return 0;
out_free_priv: