Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * System Control and Power Interface (SCPI) based CPUFreq Interface driver
0004  *
0005  * Copyright (C) 2015 ARM Ltd.
0006  * Sudeep Holla <sudeep.holla@arm.com>
0007  */
0008 
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010 
0011 #include <linux/clk.h>
0012 #include <linux/cpu.h>
0013 #include <linux/cpufreq.h>
0014 #include <linux/cpumask.h>
0015 #include <linux/export.h>
0016 #include <linux/module.h>
0017 #include <linux/of_platform.h>
0018 #include <linux/pm_opp.h>
0019 #include <linux/scpi_protocol.h>
0020 #include <linux/slab.h>
0021 #include <linux/types.h>
0022 
0023 struct scpi_data {
0024     struct clk *clk;
0025     struct device *cpu_dev;
0026 };
0027 
0028 static struct scpi_ops *scpi_ops;
0029 
0030 static unsigned int scpi_cpufreq_get_rate(unsigned int cpu)
0031 {
0032     struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
0033     struct scpi_data *priv = policy->driver_data;
0034     unsigned long rate = clk_get_rate(priv->clk);
0035 
0036     return rate / 1000;
0037 }
0038 
0039 static int
0040 scpi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index)
0041 {
0042     u64 rate = policy->freq_table[index].frequency * 1000;
0043     struct scpi_data *priv = policy->driver_data;
0044     int ret;
0045 
0046     ret = clk_set_rate(priv->clk, rate);
0047 
0048     if (ret)
0049         return ret;
0050 
0051     if (clk_get_rate(priv->clk) != rate)
0052         return -EIO;
0053 
0054     return 0;
0055 }
0056 
0057 static int
0058 scpi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
0059 {
0060     int cpu, domain, tdomain;
0061     struct device *tcpu_dev;
0062 
0063     domain = scpi_ops->device_domain_id(cpu_dev);
0064     if (domain < 0)
0065         return domain;
0066 
0067     for_each_possible_cpu(cpu) {
0068         if (cpu == cpu_dev->id)
0069             continue;
0070 
0071         tcpu_dev = get_cpu_device(cpu);
0072         if (!tcpu_dev)
0073             continue;
0074 
0075         tdomain = scpi_ops->device_domain_id(tcpu_dev);
0076         if (tdomain == domain)
0077             cpumask_set_cpu(cpu, cpumask);
0078     }
0079 
0080     return 0;
0081 }
0082 
0083 static int scpi_cpufreq_init(struct cpufreq_policy *policy)
0084 {
0085     int ret;
0086     unsigned int latency;
0087     struct device *cpu_dev;
0088     struct scpi_data *priv;
0089     struct cpufreq_frequency_table *freq_table;
0090 
0091     cpu_dev = get_cpu_device(policy->cpu);
0092     if (!cpu_dev) {
0093         pr_err("failed to get cpu%d device\n", policy->cpu);
0094         return -ENODEV;
0095     }
0096 
0097     ret = scpi_ops->add_opps_to_device(cpu_dev);
0098     if (ret) {
0099         dev_warn(cpu_dev, "failed to add opps to the device\n");
0100         return ret;
0101     }
0102 
0103     ret = scpi_get_sharing_cpus(cpu_dev, policy->cpus);
0104     if (ret) {
0105         dev_warn(cpu_dev, "failed to get sharing cpumask\n");
0106         return ret;
0107     }
0108 
0109     ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus);
0110     if (ret) {
0111         dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
0112             __func__, ret);
0113         return ret;
0114     }
0115 
0116     ret = dev_pm_opp_get_opp_count(cpu_dev);
0117     if (ret <= 0) {
0118         dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n");
0119         ret = -EPROBE_DEFER;
0120         goto out_free_opp;
0121     }
0122 
0123     priv = kzalloc(sizeof(*priv), GFP_KERNEL);
0124     if (!priv) {
0125         ret = -ENOMEM;
0126         goto out_free_opp;
0127     }
0128 
0129     ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
0130     if (ret) {
0131         dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
0132         goto out_free_priv;
0133     }
0134 
0135     priv->cpu_dev = cpu_dev;
0136     priv->clk = clk_get(cpu_dev, NULL);
0137     if (IS_ERR(priv->clk)) {
0138         dev_err(cpu_dev, "%s: Failed to get clk for cpu: %d\n",
0139             __func__, cpu_dev->id);
0140         ret = PTR_ERR(priv->clk);
0141         goto out_free_cpufreq_table;
0142     }
0143 
0144     policy->driver_data = priv;
0145     policy->freq_table = freq_table;
0146 
0147     /* scpi allows DVFS request for any domain from any CPU */
0148     policy->dvfs_possible_from_any_cpu = true;
0149 
0150     latency = scpi_ops->get_transition_latency(cpu_dev);
0151     if (!latency)
0152         latency = CPUFREQ_ETERNAL;
0153 
0154     policy->cpuinfo.transition_latency = latency;
0155 
0156     policy->fast_switch_possible = false;
0157 
0158     return 0;
0159 
0160 out_free_cpufreq_table:
0161     dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
0162 out_free_priv:
0163     kfree(priv);
0164 out_free_opp:
0165     dev_pm_opp_remove_all_dynamic(cpu_dev);
0166 
0167     return ret;
0168 }
0169 
0170 static int scpi_cpufreq_exit(struct cpufreq_policy *policy)
0171 {
0172     struct scpi_data *priv = policy->driver_data;
0173 
0174     clk_put(priv->clk);
0175     dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
0176     dev_pm_opp_remove_all_dynamic(priv->cpu_dev);
0177     kfree(priv);
0178 
0179     return 0;
0180 }
0181 
0182 static struct cpufreq_driver scpi_cpufreq_driver = {
0183     .name   = "scpi-cpufreq",
0184     .flags  = CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
0185           CPUFREQ_NEED_INITIAL_FREQ_CHECK |
0186           CPUFREQ_IS_COOLING_DEV,
0187     .verify = cpufreq_generic_frequency_table_verify,
0188     .attr   = cpufreq_generic_attr,
0189     .get    = scpi_cpufreq_get_rate,
0190     .init   = scpi_cpufreq_init,
0191     .exit   = scpi_cpufreq_exit,
0192     .target_index   = scpi_cpufreq_set_target,
0193     .register_em    = cpufreq_register_em_with_opp,
0194 };
0195 
0196 static int scpi_cpufreq_probe(struct platform_device *pdev)
0197 {
0198     int ret;
0199 
0200     scpi_ops = get_scpi_ops();
0201     if (!scpi_ops)
0202         return -EIO;
0203 
0204     ret = cpufreq_register_driver(&scpi_cpufreq_driver);
0205     if (ret)
0206         dev_err(&pdev->dev, "%s: registering cpufreq failed, err: %d\n",
0207             __func__, ret);
0208     return ret;
0209 }
0210 
0211 static int scpi_cpufreq_remove(struct platform_device *pdev)
0212 {
0213     cpufreq_unregister_driver(&scpi_cpufreq_driver);
0214     scpi_ops = NULL;
0215     return 0;
0216 }
0217 
0218 static struct platform_driver scpi_cpufreq_platdrv = {
0219     .driver = {
0220         .name   = "scpi-cpufreq",
0221     },
0222     .probe      = scpi_cpufreq_probe,
0223     .remove     = scpi_cpufreq_remove,
0224 };
0225 module_platform_driver(scpi_cpufreq_platdrv);
0226 
0227 MODULE_ALIAS("platform:scpi-cpufreq");
0228 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
0229 MODULE_DESCRIPTION("ARM SCPI CPUFreq interface driver");
0230 MODULE_LICENSE("GPL v2");