mali_kbase_devfreq.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*
  2. *
  3. * (C) COPYRIGHT 2014-2015 ARM Limited. All rights reserved.
  4. *
  5. * This program is free software and is provided to you under the terms of the
  6. * GNU General Public License version 2 as published by the Free Software
  7. * Foundation, and any use by you of this program is subject to the terms
  8. * of such GNU licence.
  9. *
  10. * A copy of the licence is included with the program, and can also be obtained
  11. * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  12. * Boston, MA 02110-1301, USA.
  13. *
  14. */
  15. #include <mali_kbase.h>
  16. #include <mali_kbase_config_defaults.h>
  17. #include <backend/gpu/mali_kbase_pm_internal.h>
  18. #ifdef CONFIG_DEVFREQ_THERMAL
  19. #include <backend/gpu/mali_kbase_power_model_simple.h>
  20. #endif
  21. #include <linux/clk.h>
  22. #include <linux/devfreq.h>
  23. #ifdef CONFIG_DEVFREQ_THERMAL
  24. #include <linux/devfreq_cooling.h>
  25. #endif
  26. #include <linux/version.h>
  27. #include <linux/pm_opp.h>
  28. static int
  29. kbase_devfreq_target(struct device *dev, unsigned long *target_freq, u32 flags)
  30. {
  31. struct kbase_device *kbdev = dev_get_drvdata(dev);
  32. struct dev_pm_opp *opp;
  33. unsigned long freq = 0;
  34. unsigned long voltage;
  35. int err;
  36. freq = *target_freq;
  37. rcu_read_lock();
  38. opp = devfreq_recommended_opp(dev, &freq, flags);
  39. voltage = dev_pm_opp_get_voltage(opp);
  40. rcu_read_unlock();
  41. if (IS_ERR_OR_NULL(opp)) {
  42. dev_err(dev, "Failed to get opp (%ld)\n", PTR_ERR(opp));
  43. return PTR_ERR(opp);
  44. }
  45. /*
  46. * Only update if there is a change of frequency
  47. */
  48. if (kbdev->current_freq == freq) {
  49. *target_freq = freq;
  50. return 0;
  51. }
  52. #ifdef CONFIG_REGULATOR
  53. if (kbdev->regulator && kbdev->current_voltage != voltage
  54. && kbdev->current_freq < freq) {
  55. err = regulator_set_voltage(kbdev->regulator, voltage, voltage);
  56. if (err) {
  57. dev_err(dev, "Failed to increase voltage (%d)\n", err);
  58. return err;
  59. }
  60. }
  61. #endif
  62. err = clk_set_rate(kbdev->clock, freq);
  63. if (err) {
  64. dev_err(dev, "Failed to set clock %lu (target %lu)\n",
  65. freq, *target_freq);
  66. return err;
  67. }
  68. #ifdef CONFIG_REGULATOR
  69. if (kbdev->regulator && kbdev->current_voltage != voltage
  70. && kbdev->current_freq > freq) {
  71. err = regulator_set_voltage(kbdev->regulator, voltage, voltage);
  72. if (err) {
  73. dev_err(dev, "Failed to decrease voltage (%d)\n", err);
  74. return err;
  75. }
  76. }
  77. #endif
  78. *target_freq = freq;
  79. kbdev->current_voltage = voltage;
  80. kbdev->current_freq = freq;
  81. kbase_pm_reset_dvfs_utilisation(kbdev);
  82. return err;
  83. }
  84. static int
  85. kbase_devfreq_cur_freq(struct device *dev, unsigned long *freq)
  86. {
  87. struct kbase_device *kbdev = dev_get_drvdata(dev);
  88. *freq = kbdev->current_freq;
  89. return 0;
  90. }
  91. static int
  92. kbase_devfreq_status(struct device *dev, struct devfreq_dev_status *stat)
  93. {
  94. struct kbase_device *kbdev = dev_get_drvdata(dev);
  95. stat->current_frequency = kbdev->current_freq;
  96. kbase_pm_get_dvfs_utilisation(kbdev,
  97. &stat->total_time, &stat->busy_time);
  98. stat->private_data = NULL;
  99. #ifdef CONFIG_DEVFREQ_THERMAL
  100. if (kbdev->devfreq_cooling)
  101. memcpy(&kbdev->devfreq_cooling->last_status, stat,
  102. sizeof(*stat));
  103. #endif
  104. return 0;
  105. }
  106. static int kbase_devfreq_init_freq_table(struct kbase_device *kbdev,
  107. struct devfreq_dev_profile *dp)
  108. {
  109. int count;
  110. int i = 0;
  111. unsigned long freq = 0;
  112. struct dev_pm_opp *opp;
  113. rcu_read_lock();
  114. count = dev_pm_opp_get_opp_count(kbdev->dev);
  115. if (count < 0) {
  116. rcu_read_unlock();
  117. return count;
  118. }
  119. rcu_read_unlock();
  120. dp->freq_table = kmalloc_array(count, sizeof(dp->freq_table[0]),
  121. GFP_KERNEL);
  122. if (!dp->freq_table)
  123. return -ENOMEM;
  124. rcu_read_lock();
  125. for (i = 0; i < count; i++, freq++) {
  126. opp = dev_pm_opp_find_freq_ceil(kbdev->dev, &freq);
  127. if (IS_ERR(opp))
  128. break;
  129. dp->freq_table[i] = freq;
  130. }
  131. rcu_read_unlock();
  132. if (count != i)
  133. dev_warn(kbdev->dev, "Unable to enumerate all OPPs (%d!=%d\n",
  134. count, i);
  135. dp->max_state = i;
  136. return 0;
  137. }
  138. static void kbase_devfreq_term_freq_table(struct kbase_device *kbdev)
  139. {
  140. struct devfreq_dev_profile *dp = kbdev->devfreq->profile;
  141. kfree(dp->freq_table);
  142. }
  143. static void kbase_devfreq_exit(struct device *dev)
  144. {
  145. struct kbase_device *kbdev = dev_get_drvdata(dev);
  146. kbase_devfreq_term_freq_table(kbdev);
  147. }
  148. int kbase_devfreq_init(struct kbase_device *kbdev)
  149. {
  150. struct devfreq_dev_profile *dp;
  151. int err;
  152. if (!kbdev->clock)
  153. return -ENODEV;
  154. kbdev->current_freq = clk_get_rate(kbdev->clock);
  155. dp = &kbdev->devfreq_profile;
  156. dp->initial_freq = kbdev->current_freq;
  157. dp->polling_ms = 100;
  158. dp->target = kbase_devfreq_target;
  159. dp->get_dev_status = kbase_devfreq_status;
  160. dp->get_cur_freq = kbase_devfreq_cur_freq;
  161. dp->exit = kbase_devfreq_exit;
  162. if (kbase_devfreq_init_freq_table(kbdev, dp))
  163. return -EFAULT;
  164. kbdev->devfreq = devfreq_add_device(kbdev->dev, dp,
  165. "simple_ondemand", NULL);
  166. if (IS_ERR(kbdev->devfreq)) {
  167. kbase_devfreq_term_freq_table(kbdev);
  168. return PTR_ERR(kbdev->devfreq);
  169. }
  170. err = devfreq_register_opp_notifier(kbdev->dev, kbdev->devfreq);
  171. if (err) {
  172. dev_err(kbdev->dev,
  173. "Failed to register OPP notifier (%d)\n", err);
  174. goto opp_notifier_failed;
  175. }
  176. #ifdef CONFIG_DEVFREQ_THERMAL
  177. err = kbase_power_model_simple_init(kbdev);
  178. if (err && err != -ENODEV && err != -EPROBE_DEFER) {
  179. dev_err(kbdev->dev,
  180. "Failed to initialize simple power model (%d)\n",
  181. err);
  182. goto cooling_failed;
  183. }
  184. if (err == -EPROBE_DEFER)
  185. goto cooling_failed;
  186. if (err != -ENODEV) {
  187. kbdev->devfreq_cooling = of_devfreq_cooling_register_power(
  188. kbdev->dev->of_node,
  189. kbdev->devfreq,
  190. &power_model_simple_ops);
  191. if (IS_ERR_OR_NULL(kbdev->devfreq_cooling)) {
  192. err = PTR_ERR(kbdev->devfreq_cooling);
  193. dev_err(kbdev->dev,
  194. "Failed to register cooling device (%d)\n",
  195. err);
  196. goto cooling_failed;
  197. }
  198. } else {
  199. err = 0;
  200. }
  201. #endif
  202. return 0;
  203. #ifdef CONFIG_DEVFREQ_THERMAL
  204. cooling_failed:
  205. devfreq_unregister_opp_notifier(kbdev->dev, kbdev->devfreq);
  206. #endif /* CONFIG_DEVFREQ_THERMAL */
  207. opp_notifier_failed:
  208. if (devfreq_remove_device(kbdev->devfreq))
  209. dev_err(kbdev->dev, "Failed to terminate devfreq (%d)\n", err);
  210. else
  211. kbdev->devfreq = NULL;
  212. return err;
  213. }
  214. void kbase_devfreq_term(struct kbase_device *kbdev)
  215. {
  216. int err;
  217. dev_dbg(kbdev->dev, "Term Mali devfreq\n");
  218. #ifdef CONFIG_DEVFREQ_THERMAL
  219. if (kbdev->devfreq_cooling)
  220. devfreq_cooling_unregister(kbdev->devfreq_cooling);
  221. #endif
  222. devfreq_unregister_opp_notifier(kbdev->dev, kbdev->devfreq);
  223. err = devfreq_remove_device(kbdev->devfreq);
  224. if (err)
  225. dev_err(kbdev->dev, "Failed to terminate devfreq (%d)\n", err);
  226. else
  227. kbdev->devfreq = NULL;
  228. }