scpi-cpufreq.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * System Control and Power Interface (SCPI) based CPUFreq Interface driver
  3. *
  4. * Copyright (C) 2015 ARM Ltd.
  5. * Sudeep Holla <sudeep.holla@arm.com>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  12. * kind, whether express or implied; without even the implied warranty
  13. * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. */
  16. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  17. #include <linux/clk.h>
  18. #include <linux/cpu.h>
  19. #include <linux/cpufreq.h>
  20. #include <linux/cpumask.h>
  21. #include <linux/export.h>
  22. #include <linux/module.h>
  23. #include <linux/of_platform.h>
  24. #include <linux/pm_opp.h>
  25. #include <linux/scpi_protocol.h>
  26. #include <linux/slab.h>
  27. #include <linux/types.h>
  28. struct scpi_data {
  29. struct clk *clk;
  30. struct device *cpu_dev;
  31. };
  32. static struct scpi_ops *scpi_ops;
  33. static unsigned int scpi_cpufreq_get_rate(unsigned int cpu)
  34. {
  35. struct cpufreq_policy *policy = cpufreq_cpu_get_raw(cpu);
  36. struct scpi_data *priv = policy->driver_data;
  37. unsigned long rate = clk_get_rate(priv->clk);
  38. return rate / 1000;
  39. }
  40. static int
  41. scpi_cpufreq_set_target(struct cpufreq_policy *policy, unsigned int index)
  42. {
  43. u64 rate = policy->freq_table[index].frequency * 1000;
  44. struct scpi_data *priv = policy->driver_data;
  45. int ret;
  46. ret = clk_set_rate(priv->clk, rate);
  47. if (ret)
  48. return ret;
  49. if (clk_get_rate(priv->clk) != rate)
  50. return -EIO;
  51. return 0;
  52. }
  53. static int
  54. scpi_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask)
  55. {
  56. int cpu, domain, tdomain;
  57. struct device *tcpu_dev;
  58. domain = scpi_ops->device_domain_id(cpu_dev);
  59. if (domain < 0)
  60. return domain;
  61. for_each_possible_cpu(cpu) {
  62. if (cpu == cpu_dev->id)
  63. continue;
  64. tcpu_dev = get_cpu_device(cpu);
  65. if (!tcpu_dev)
  66. continue;
  67. tdomain = scpi_ops->device_domain_id(tcpu_dev);
  68. if (tdomain == domain)
  69. cpumask_set_cpu(cpu, cpumask);
  70. }
  71. return 0;
  72. }
  73. static int scpi_cpufreq_init(struct cpufreq_policy *policy)
  74. {
  75. int ret;
  76. unsigned int latency;
  77. struct device *cpu_dev;
  78. struct scpi_data *priv;
  79. struct cpufreq_frequency_table *freq_table;
  80. cpu_dev = get_cpu_device(policy->cpu);
  81. if (!cpu_dev) {
  82. pr_err("failed to get cpu%d device\n", policy->cpu);
  83. return -ENODEV;
  84. }
  85. ret = scpi_ops->add_opps_to_device(cpu_dev);
  86. if (ret) {
  87. dev_warn(cpu_dev, "failed to add opps to the device\n");
  88. return ret;
  89. }
  90. ret = scpi_get_sharing_cpus(cpu_dev, policy->cpus);
  91. if (ret) {
  92. dev_warn(cpu_dev, "failed to get sharing cpumask\n");
  93. return ret;
  94. }
  95. ret = dev_pm_opp_set_sharing_cpus(cpu_dev, policy->cpus);
  96. if (ret) {
  97. dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
  98. __func__, ret);
  99. return ret;
  100. }
  101. ret = dev_pm_opp_get_opp_count(cpu_dev);
  102. if (ret <= 0) {
  103. dev_dbg(cpu_dev, "OPP table is not ready, deferring probe\n");
  104. ret = -EPROBE_DEFER;
  105. goto out_free_opp;
  106. }
  107. priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  108. if (!priv) {
  109. ret = -ENOMEM;
  110. goto out_free_opp;
  111. }
  112. ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
  113. if (ret) {
  114. dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
  115. goto out_free_priv;
  116. }
  117. priv->cpu_dev = cpu_dev;
  118. priv->clk = clk_get(cpu_dev, NULL);
  119. if (IS_ERR(priv->clk)) {
  120. dev_err(cpu_dev, "%s: Failed to get clk for cpu: %d\n",
  121. __func__, cpu_dev->id);
  122. ret = PTR_ERR(priv->clk);
  123. goto out_free_cpufreq_table;
  124. }
  125. policy->driver_data = priv;
  126. policy->freq_table = freq_table;
  127. /* scpi allows DVFS request for any domain from any CPU */
  128. policy->dvfs_possible_from_any_cpu = true;
  129. latency = scpi_ops->get_transition_latency(cpu_dev);
  130. if (!latency)
  131. latency = CPUFREQ_ETERNAL;
  132. policy->cpuinfo.transition_latency = latency;
  133. policy->fast_switch_possible = false;
  134. dev_pm_opp_of_register_em(cpu_dev, policy->cpus);
  135. return 0;
  136. out_free_cpufreq_table:
  137. dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
  138. out_free_priv:
  139. kfree(priv);
  140. out_free_opp:
  141. dev_pm_opp_remove_all_dynamic(cpu_dev);
  142. return ret;
  143. }
  144. static int scpi_cpufreq_exit(struct cpufreq_policy *policy)
  145. {
  146. struct scpi_data *priv = policy->driver_data;
  147. clk_put(priv->clk);
  148. dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
  149. dev_pm_opp_remove_all_dynamic(priv->cpu_dev);
  150. kfree(priv);
  151. return 0;
  152. }
  153. static struct cpufreq_driver scpi_cpufreq_driver = {
  154. .name = "scpi-cpufreq",
  155. .flags = CPUFREQ_STICKY | CPUFREQ_HAVE_GOVERNOR_PER_POLICY |
  156. CPUFREQ_NEED_INITIAL_FREQ_CHECK |
  157. CPUFREQ_IS_COOLING_DEV,
  158. .verify = cpufreq_generic_frequency_table_verify,
  159. .attr = cpufreq_generic_attr,
  160. .get = scpi_cpufreq_get_rate,
  161. .init = scpi_cpufreq_init,
  162. .exit = scpi_cpufreq_exit,
  163. .target_index = scpi_cpufreq_set_target,
  164. };
  165. static int scpi_cpufreq_probe(struct platform_device *pdev)
  166. {
  167. int ret;
  168. scpi_ops = get_scpi_ops();
  169. if (!scpi_ops)
  170. return -EIO;
  171. ret = cpufreq_register_driver(&scpi_cpufreq_driver);
  172. if (ret)
  173. dev_err(&pdev->dev, "%s: registering cpufreq failed, err: %d\n",
  174. __func__, ret);
  175. return ret;
  176. }
  177. static int scpi_cpufreq_remove(struct platform_device *pdev)
  178. {
  179. cpufreq_unregister_driver(&scpi_cpufreq_driver);
  180. scpi_ops = NULL;
  181. return 0;
  182. }
  183. static struct platform_driver scpi_cpufreq_platdrv = {
  184. .driver = {
  185. .name = "scpi-cpufreq",
  186. },
  187. .probe = scpi_cpufreq_probe,
  188. .remove = scpi_cpufreq_remove,
  189. };
  190. module_platform_driver(scpi_cpufreq_platdrv);
  191. MODULE_ALIAS("platform:scpi-cpufreq");
  192. MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
  193. MODULE_DESCRIPTION("ARM SCPI CPUFreq interface driver");
  194. MODULE_LICENSE("GPL v2");