| .. | .. |
|---|
| 1 | 1 | /* |
|---|
| 2 | 2 | * System Control and Power Interface (SCPI) based CPUFreq Interface driver |
|---|
| 3 | 3 | * |
|---|
| 4 | | - * It provides necessary ops to arm_big_little cpufreq driver. |
|---|
| 5 | | - * |
|---|
| 6 | 4 | * Copyright (C) 2015 ARM Ltd. |
|---|
| 7 | 5 | * Sudeep Holla <sudeep.holla@arm.com> |
|---|
| 8 | 6 | * |
|---|
| .. | .. |
|---|
| 22 | 20 | #include <linux/cpu.h> |
|---|
| 23 | 21 | #include <linux/cpufreq.h> |
|---|
| 24 | 22 | #include <linux/cpumask.h> |
|---|
| 25 | | -#include <linux/cpu_cooling.h> |
|---|
| 26 | | -#include <linux/energy_model.h> |
|---|
| 27 | 23 | #include <linux/export.h> |
|---|
| 28 | 24 | #include <linux/module.h> |
|---|
| 29 | 25 | #include <linux/of_platform.h> |
|---|
| .. | .. |
|---|
| 35 | 31 | struct scpi_data { |
|---|
| 36 | 32 | struct clk *clk; |
|---|
| 37 | 33 | struct device *cpu_dev; |
|---|
| 38 | | - struct thermal_cooling_device *cdev; |
|---|
| 39 | 34 | }; |
|---|
| 40 | 35 | |
|---|
| 41 | 36 | static struct scpi_ops *scpi_ops; |
|---|
| .. | .. |
|---|
| 52 | 47 | static int |
|---|
| 53 | 48 | scpi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index) |
|---|
| 54 | 49 | { |
|---|
| 55 | | - unsigned long freq = policy->freq_table[index].frequency; |
|---|
| 50 | + u64 rate = policy->freq_table[index].frequency * 1000; |
|---|
| 56 | 51 | struct scpi_data *priv = policy->driver_data; |
|---|
| 57 | | - u64 rate = freq * 1000; |
|---|
| 58 | 52 | int ret; |
|---|
| 59 | 53 | |
|---|
| 60 | 54 | ret = clk_set_rate(priv->clk, rate); |
|---|
| .. | .. |
|---|
| 64 | 58 | |
|---|
| 65 | 59 | if (clk_get_rate(priv->clk) != rate) |
|---|
| 66 | 60 | return -EIO; |
|---|
| 67 | | - |
|---|
| 68 | | - arch_set_freq_scale(policy->related_cpus, freq, |
|---|
| 69 | | - policy->cpuinfo.max_freq); |
|---|
| 70 | 61 | |
|---|
| 71 | 62 | return 0; |
|---|
| 72 | 63 | } |
|---|
| .. | .. |
|---|
| 99 | 90 | |
|---|
| 100 | 91 | static int scpi_cpufreq_init(struct cpufreq_policy *policy) |
|---|
| 101 | 92 | { |
|---|
| 102 | | - int ret, nr_opp; |
|---|
| 93 | + int ret; |
|---|
| 103 | 94 | unsigned int latency; |
|---|
| 104 | 95 | struct device *cpu_dev; |
|---|
| 105 | 96 | struct scpi_data *priv; |
|---|
| 106 | 97 | struct cpufreq_frequency_table *freq_table; |
|---|
| 107 | | - struct em_data_callback em_cb = EM_DATA_CB(of_dev_pm_opp_get_cpu_power); |
|---|
| 108 | 98 | |
|---|
| 109 | 99 | cpu_dev = get_cpu_device(policy->cpu); |
|---|
| 110 | 100 | if (!cpu_dev) { |
|---|
| .. | .. |
|---|
| 137 | 127 | ret = -EPROBE_DEFER; |
|---|
| 138 | 128 | goto out_free_opp; |
|---|
| 139 | 129 | } |
|---|
| 140 | | - nr_opp = ret; |
|---|
| 141 | 130 | |
|---|
| 142 | 131 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
|---|
| 143 | 132 | if (!priv) { |
|---|
| .. | .. |
|---|
| 174 | 163 | |
|---|
| 175 | 164 | policy->fast_switch_possible = false; |
|---|
| 176 | 165 | |
|---|
| 177 | | - em_register_perf_domain(policy->cpus, nr_opp, &em_cb); |
|---|
| 166 | + dev_pm_opp_of_register_em(cpu_dev, policy->cpus); |
|---|
| 178 | 167 | |
|---|
| 179 | 168 | return 0; |
|---|
| 180 | 169 | |
|---|
| .. | .. |
|---|
| 183 | 172 | out_free_priv: |
|---|
| 184 | 173 | kfree(priv); |
|---|
| 185 | 174 | out_free_opp: |
|---|
| 186 | | - dev_pm_opp_cpumask_remove_table(policy->cpus); |
|---|
| 175 | + dev_pm_opp_remove_all_dynamic(cpu_dev); |
|---|
| 187 | 176 | |
|---|
| 188 | 177 | return ret; |
|---|
| 189 | 178 | } |
|---|
| .. | .. |
|---|
| 192 | 181 | { |
|---|
| 193 | 182 | struct scpi_data *priv = policy->driver_data; |
|---|
| 194 | 183 | |
|---|
| 195 | | - cpufreq_cooling_unregister(priv->cdev); |
|---|
| 196 | 184 | clk_put(priv->clk); |
|---|
| 197 | 185 | dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table); |
|---|
| 186 | + dev_pm_opp_remove_all_dynamic(priv->cpu_dev); |
|---|
| 198 | 187 | kfree(priv); |
|---|
| 199 | | - dev_pm_opp_cpumask_remove_table(policy->related_cpus); |
|---|
| 200 | 188 | |
|---|
| 201 | 189 | return 0; |
|---|
| 202 | | -} |
|---|
| 203 | | - |
|---|
| 204 | | -static void scpi_cpufreq_ready(struct cpufreq_policy *policy) |
|---|
| 205 | | -{ |
|---|
| 206 | | - struct scpi_data *priv = policy->driver_data; |
|---|
| 207 | | - |
|---|
| 208 | | - priv->cdev = of_cpufreq_cooling_register(policy); |
|---|
| 209 | 190 | } |
|---|
| 210 | 191 | |
|---|
| 211 | 192 | static struct cpufreq_driver scpi_cpufreq_driver = { |
|---|
| 212 | 193 | .name = "scpi-cpufreq", |
|---|
| 213 | 194 | .flags = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY | |
|---|
| 214 | | - CPUFREQ_NEED_INITIAL_FREQ_CHECK, |
|---|
| 195 | + CPUFREQ_NEED_INITIAL_FREQ_CHECK | |
|---|
| 196 | + CPUFREQ_IS_COOLING_DEV, |
|---|
| 215 | 197 | .verify = cpufreq_generic_frequency_table_verify, |
|---|
| 216 | 198 | .attr = cpufreq_generic_attr, |
|---|
| 217 | 199 | .get = scpi_cpufreq_get_rate, |
|---|
| 218 | 200 | .init = scpi_cpufreq_init, |
|---|
| 219 | 201 | .exit = scpi_cpufreq_exit, |
|---|
| 220 | | - .ready = scpi_cpufreq_ready, |
|---|
| 221 | 202 | .target_index = scpi_cpufreq_set_target, |
|---|
| 222 | 203 | }; |
|---|
| 223 | 204 | |
|---|