scpi-cpufreq.c 5.9 KB

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