0001
0002
0003
0004
0005
0006
0007
0008
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010
0011 #include <linux/clk-provider.h>
0012 #include <linux/cpu.h>
0013 #include <linux/cpufreq.h>
0014 #include <linux/cpumask.h>
0015 #include <linux/energy_model.h>
0016 #include <linux/export.h>
0017 #include <linux/module.h>
0018 #include <linux/pm_opp.h>
0019 #include <linux/slab.h>
0020 #include <linux/scmi_protocol.h>
0021 #include <linux/types.h>
0022 #include <linux/units.h>
0023
0024 struct scmi_data {
0025 int domain_id;
0026 int nr_opp;
0027 struct device *cpu_dev;
0028 cpumask_var_t opp_shared_cpus;
0029 };
0030
0031 static struct scmi_protocol_handle *ph;
0032 static const struct scmi_perf_proto_ops *perf_ops;
0033
0034 static unsigned int scmi_cpufreq_get_rate(unsigned int cpu)
0035 {
0036 struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
0037 struct scmi_data *priv = policy->driver_data;
0038 unsigned long rate;
0039 int ret;
0040
0041 ret = perf_ops->freq_get(ph, priv->domain_id, &rate, false);
0042 if (ret)
0043 return 0;
0044 return rate / 1000;
0045 }
0046
0047
0048
0049
0050
0051
0052 static int
0053 scmi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index)
0054 {
0055 struct scmi_data *priv = policy->driver_data;
0056 u64 freq = policy->freq_table[index].frequency;
0057
0058 return perf_ops->freq_set(ph, priv->domain_id, freq * 1000, false);
0059 }
0060
0061 static unsigned int scmi_cpufreq_fast_switch(struct cpufreq_policy *policy,
0062 unsigned int target_freq)
0063 {
0064 struct scmi_data *priv = policy->driver_data;
0065
0066 if (!perf_ops->freq_set(ph, priv->domain_id,
0067 target_freq * 1000, true))
0068 return target_freq;
0069
0070 return 0;
0071 }
0072
0073 static int
0074 scmi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
0075 {
0076 int cpu, domain, tdomain;
0077 struct device *tcpu_dev;
0078
0079 domain = perf_ops->device_domain_id(cpu_dev);
0080 if (domain < 0)
0081 return domain;
0082
0083 for_each_possible_cpu(cpu) {
0084 if (cpu == cpu_dev->id)
0085 continue;
0086
0087 tcpu_dev = get_cpu_device(cpu);
0088 if (!tcpu_dev)
0089 continue;
0090
0091 tdomain = perf_ops->device_domain_id(tcpu_dev);
0092 if (tdomain == domain)
0093 cpumask_set_cpu(cpu, cpumask);
0094 }
0095
0096 return 0;
0097 }
0098
0099 static int __maybe_unused
0100 scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power,
0101 unsigned long *KHz)
0102 {
0103 enum scmi_power_scale power_scale = perf_ops->power_scale_get(ph);
0104 unsigned long Hz;
0105 int ret, domain;
0106
0107 domain = perf_ops->device_domain_id(cpu_dev);
0108 if (domain < 0)
0109 return domain;
0110
0111
0112 Hz = *KHz * 1000;
0113 ret = perf_ops->est_power_get(ph, domain, &Hz, power);
0114 if (ret)
0115 return ret;
0116
0117
0118 if (power_scale == SCMI_POWER_MILLIWATTS)
0119 *power *= MICROWATT_PER_MILLIWATT;
0120
0121
0122 *KHz = Hz / 1000;
0123
0124 return 0;
0125 }
0126
0127 static int scmi_cpufreq_init(struct cpufreq_policy *policy)
0128 {
0129 int ret, nr_opp;
0130 unsigned int latency;
0131 struct device *cpu_dev;
0132 struct scmi_data *priv;
0133 struct cpufreq_frequency_table *freq_table;
0134
0135 cpu_dev = get_cpu_device(policy->cpu);
0136 if (!cpu_dev) {
0137 pr_err("failed to get cpu%d device\n", policy->cpu);
0138 return -ENODEV;
0139 }
0140
0141 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
0142 if (!priv)
0143 return -ENOMEM;
0144
0145 if (!zalloc_cpumask_var(&priv->opp_shared_cpus, GFP_KERNEL)) {
0146 ret = -ENOMEM;
0147 goto out_free_priv;
0148 }
0149
0150
0151 ret = scmi_get_sharing_cpus(cpu_dev, policy->cpus);
0152 if (ret) {
0153 dev_warn(cpu_dev, "failed to get sharing cpumask\n");
0154 goto out_free_cpumask;
0155 }
0156
0157
0158
0159
0160
0161
0162 ret = dev_pm_opp_of_get_sharing_cpus(cpu_dev, priv->opp_shared_cpus);
0163 if (ret || cpumask_empty(priv->opp_shared_cpus)) {
0164
0165
0166
0167
0168
0169 cpumask_copy(priv->opp_shared_cpus, policy->cpus);
0170 }
0171
0172
0173
0174
0175
0176
0177 nr_opp = dev_pm_opp_get_opp_count(cpu_dev);
0178 if (nr_opp <= 0) {
0179 ret = perf_ops->device_opps_add(ph, cpu_dev);
0180 if (ret) {
0181 dev_warn(cpu_dev, "failed to add opps to the device\n");
0182 goto out_free_cpumask;
0183 }
0184
0185 nr_opp = dev_pm_opp_get_opp_count(cpu_dev);
0186 if (nr_opp <= 0) {
0187 dev_err(cpu_dev, "%s: No OPPs for this device: %d\n",
0188 __func__, nr_opp);
0189
0190 ret = -ENODEV;
0191 goto out_free_opp;
0192 }
0193
0194 ret = dev_pm_opp_set_sharing_cpus(cpu_dev, priv->opp_shared_cpus);
0195 if (ret) {
0196 dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
0197 __func__, ret);
0198
0199 goto out_free_opp;
0200 }
0201
0202 priv->nr_opp = nr_opp;
0203 }
0204
0205 ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
0206 if (ret) {
0207 dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
0208 goto out_free_opp;
0209 }
0210
0211 priv->cpu_dev = cpu_dev;
0212 priv->domain_id = perf_ops->device_domain_id(cpu_dev);
0213
0214 policy->driver_data = priv;
0215 policy->freq_table = freq_table;
0216
0217
0218 policy->dvfs_possible_from_any_cpu = true;
0219
0220 latency = perf_ops->transition_latency_get(ph, cpu_dev);
0221 if (!latency)
0222 latency = CPUFREQ_ETERNAL;
0223
0224 policy->cpuinfo.transition_latency = latency;
0225
0226 policy->fast_switch_possible =
0227 perf_ops->fast_switch_possible(ph, cpu_dev);
0228
0229 return 0;
0230
0231 out_free_opp:
0232 dev_pm_opp_remove_all_dynamic(cpu_dev);
0233
0234 out_free_cpumask:
0235 free_cpumask_var(priv->opp_shared_cpus);
0236
0237 out_free_priv:
0238 kfree(priv);
0239
0240 return ret;
0241 }
0242
0243 static int scmi_cpufreq_exit(struct cpufreq_policy *policy)
0244 {
0245 struct scmi_data *priv = policy->driver_data;
0246
0247 dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
0248 dev_pm_opp_remove_all_dynamic(priv->cpu_dev);
0249 free_cpumask_var(priv->opp_shared_cpus);
0250 kfree(priv);
0251
0252 return 0;
0253 }
0254
0255 static void scmi_cpufreq_register_em(struct cpufreq_policy *policy)
0256 {
0257 struct em_data_callback em_cb = EM_DATA_CB(scmi_get_cpu_power);
0258 enum scmi_power_scale power_scale = perf_ops->power_scale_get(ph);
0259 struct scmi_data *priv = policy->driver_data;
0260 bool em_power_scale = false;
0261
0262
0263
0264
0265
0266
0267
0268
0269 if (!priv->nr_opp)
0270 return;
0271
0272 if (power_scale == SCMI_POWER_MILLIWATTS
0273 || power_scale == SCMI_POWER_MICROWATTS)
0274 em_power_scale = true;
0275
0276 em_dev_register_perf_domain(get_cpu_device(policy->cpu), priv->nr_opp,
0277 &em_cb, priv->opp_shared_cpus,
0278 em_power_scale);
0279 }
0280
0281 static struct cpufreq_driver scmi_cpufreq_driver = {
0282 .name = "scmi",
0283 .flags = CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
0284 CPUFREQ_NEED_INITIAL_FREQ_CHECK |
0285 CPUFREQ_IS_COOLING_DEV,
0286 .verify = cpufreq_generic_frequency_table_verify,
0287 .attr = cpufreq_generic_attr,
0288 .target_index = scmi_cpufreq_set_target,
0289 .fast_switch = scmi_cpufreq_fast_switch,
0290 .get = scmi_cpufreq_get_rate,
0291 .init = scmi_cpufreq_init,
0292 .exit = scmi_cpufreq_exit,
0293 .register_em = scmi_cpufreq_register_em,
0294 };
0295
0296 static int scmi_cpufreq_probe(struct scmi_device *sdev)
0297 {
0298 int ret;
0299 struct device *dev = &sdev->dev;
0300 const struct scmi_handle *handle;
0301
0302 handle = sdev->handle;
0303
0304 if (!handle)
0305 return -ENODEV;
0306
0307 perf_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_PERF, &ph);
0308 if (IS_ERR(perf_ops))
0309 return PTR_ERR(perf_ops);
0310
0311 #ifdef CONFIG_COMMON_CLK
0312
0313 if (of_find_property(dev->of_node, "#clock-cells", NULL))
0314 devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, NULL);
0315 #endif
0316
0317 ret = cpufreq_register_driver(&scmi_cpufreq_driver);
0318 if (ret) {
0319 dev_err(dev, "%s: registering cpufreq failed, err: %d\n",
0320 __func__, ret);
0321 }
0322
0323 return ret;
0324 }
0325
0326 static void scmi_cpufreq_remove(struct scmi_device *sdev)
0327 {
0328 cpufreq_unregister_driver(&scmi_cpufreq_driver);
0329 }
0330
0331 static const struct scmi_device_id scmi_id_table[] = {
0332 { SCMI_PROTOCOL_PERF, "cpufreq" },
0333 { },
0334 };
0335 MODULE_DEVICE_TABLE(scmi, scmi_id_table);
0336
0337 static struct scmi_driver scmi_cpufreq_drv = {
0338 .name = "scmi-cpufreq",
0339 .probe = scmi_cpufreq_probe,
0340 .remove = scmi_cpufreq_remove,
0341 .id_table = scmi_id_table,
0342 };
0343 module_scmi_driver(scmi_cpufreq_drv);
0344
0345 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
0346 MODULE_DESCRIPTION("ARM SCMI CPUFreq interface driver");
0347 MODULE_LICENSE("GPL v2");