qti_devfreq_cdev.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2021, The Linux Foundation. All rights reserved.
  4. * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved.
  5. */
  6. #define pr_fmt(fmt) "%s:%s " fmt, KBUILD_MODNAME, __func__
  7. #include <linux/devfreq.h>
  8. #include <linux/module.h>
  9. #include <linux/of.h>
  10. #include <linux/platform_device.h>
  11. #include <linux/pm_opp.h>
  12. #include <linux/pm_qos.h>
  13. #include <linux/slab.h>
  14. #include <linux/thermal.h>
  15. #include <linux/workqueue.h>
  16. #define MAX_RETRY_CNT 20
  17. #define RETRY_DELAY msecs_to_jiffies(1000)
  18. #define DEVFREQ_CDEV_NAME "gpu"
  19. #define DEVFREQ_CDEV "qcom-devfreq-cdev"
  20. struct devfreq_cdev_device {
  21. struct device_node *np;
  22. struct devfreq *devfreq;
  23. struct device *dev;
  24. unsigned long *freq_table;
  25. int cur_state;
  26. int max_state;
  27. int retry_cnt;
  28. struct dev_pm_qos_request qos_max_freq_req;
  29. struct delayed_work register_work;
  30. struct thermal_cooling_device *cdev;
  31. };
  32. static struct devfreq_cdev_device *devfreq_cdev;
  33. static int devfreq_cdev_set_state(struct thermal_cooling_device *cdev,
  34. unsigned long state)
  35. {
  36. struct devfreq_cdev_device *cdev_data = cdev->devdata;
  37. int ret = 0;
  38. unsigned long freq;
  39. if (state > cdev_data->max_state)
  40. return -EINVAL;
  41. if (state == cdev_data->cur_state)
  42. return 0;
  43. freq = cdev_data->freq_table[state];
  44. pr_debug("cdev:%s Limit:%lu\n", cdev->type, freq);
  45. ret = dev_pm_qos_update_request(&cdev_data->qos_max_freq_req, freq);
  46. if (ret < 0) {
  47. pr_err("Error placing qos request:%u. cdev:%s err:%d\n",
  48. freq, cdev->type, ret);
  49. return ret;
  50. }
  51. cdev_data->cur_state = state;
  52. return 0;
  53. }
  54. static int devfreq_cdev_get_state(struct thermal_cooling_device *cdev,
  55. unsigned long *state)
  56. {
  57. struct devfreq_cdev_device *cdev_data = cdev->devdata;
  58. *state = cdev_data->cur_state;
  59. return 0;
  60. }
  61. static int devfreq_cdev_get_max_state(struct thermal_cooling_device *cdev,
  62. unsigned long *state)
  63. {
  64. struct devfreq_cdev_device *cdev_data = cdev->devdata;
  65. *state = cdev_data->max_state;
  66. return 0;
  67. }
  68. static struct thermal_cooling_device_ops devfreq_cdev_ops = {
  69. .set_cur_state = devfreq_cdev_set_state,
  70. .get_cur_state = devfreq_cdev_get_state,
  71. .get_max_state = devfreq_cdev_get_max_state,
  72. };
  73. static void devfreq_cdev_work(struct work_struct *work)
  74. {
  75. struct devfreq *df = NULL;
  76. unsigned long freq = ULONG_MAX;
  77. unsigned long *freq_table;
  78. struct dev_pm_opp *opp;
  79. int ret = 0, freq_ct, i;
  80. struct devfreq_cdev_device *cdev_data = container_of(work,
  81. struct devfreq_cdev_device,
  82. register_work.work);
  83. df = devfreq_get_devfreq_by_node(cdev_data->np);
  84. if (IS_ERR(df)) {
  85. ret = PTR_ERR(df);
  86. pr_debug("Devfreq not available:%d\n", ret);
  87. if (--cdev_data->retry_cnt)
  88. queue_delayed_work(system_highpri_wq,
  89. &cdev_data->register_work,
  90. RETRY_DELAY);
  91. return;
  92. }
  93. cdev_data->dev = df->dev.parent;
  94. cdev_data->devfreq = df;
  95. freq_ct = dev_pm_opp_get_opp_count(cdev_data->dev);
  96. freq_table = kcalloc(freq_ct, sizeof(*freq_table), GFP_KERNEL);
  97. if (!freq_table) {
  98. ret = -ENOMEM;
  99. return;
  100. }
  101. for (i = 0, freq = ULONG_MAX; i < freq_ct; i++, freq--) {
  102. opp = dev_pm_opp_find_freq_floor(cdev_data->dev, &freq);
  103. if (IS_ERR(opp)) {
  104. ret = PTR_ERR(opp);
  105. goto qos_exit;
  106. }
  107. dev_pm_opp_put(opp);
  108. freq_table[i] = DIV_ROUND_UP(freq, 1000); //hz to khz
  109. pr_debug("%d. freq table:%d\n", i, freq_table[i]);
  110. }
  111. cdev_data->max_state = freq_ct-1;
  112. cdev_data->freq_table = freq_table;
  113. ret = dev_pm_qos_add_request(cdev_data->dev,
  114. &cdev_data->qos_max_freq_req,
  115. DEV_PM_QOS_MAX_FREQUENCY,
  116. PM_QOS_MAX_FREQUENCY_DEFAULT_VALUE);
  117. if (ret < 0)
  118. goto qos_exit;
  119. cdev_data->cdev = thermal_cooling_device_register(DEVFREQ_CDEV_NAME,
  120. cdev_data, &devfreq_cdev_ops);
  121. if (IS_ERR(cdev_data->cdev)) {
  122. pr_err("Cdev register failed for gpu, ret:%d\n",
  123. PTR_ERR(cdev_data->cdev));
  124. cdev_data->cdev = NULL;
  125. goto qos_exit;
  126. }
  127. return;
  128. qos_exit:
  129. kfree(cdev_data->freq_table);
  130. dev_pm_qos_remove_request(&cdev_data->qos_max_freq_req);
  131. }
  132. static int devfreq_cdev_probe(struct platform_device *pdev)
  133. {
  134. struct device *dev = &pdev->dev;
  135. devfreq_cdev = devm_kzalloc(dev, sizeof(*devfreq_cdev), GFP_KERNEL);
  136. if (!devfreq_cdev)
  137. return -ENOMEM;
  138. devfreq_cdev->np = of_parse_phandle(pdev->dev.of_node,
  139. "qcom,devfreq", 0);
  140. devfreq_cdev->retry_cnt = MAX_RETRY_CNT;
  141. INIT_DEFERRABLE_WORK(&devfreq_cdev->register_work, devfreq_cdev_work);
  142. queue_delayed_work(system_highpri_wq, &devfreq_cdev->register_work, 0);
  143. return 0;
  144. }
  145. static int devfreq_cdev_remove(struct platform_device *pdev)
  146. {
  147. if (devfreq_cdev->cdev) {
  148. thermal_cooling_device_unregister(devfreq_cdev->cdev);
  149. dev_pm_qos_remove_request(&devfreq_cdev->qos_max_freq_req);
  150. kfree(devfreq_cdev->freq_table);
  151. devfreq_cdev->cdev = NULL;
  152. }
  153. return 0;
  154. }
  155. static const struct of_device_id devfreq_cdev_match[] = {
  156. {.compatible = "qcom,devfreq-cdev"},
  157. {}
  158. };
  159. static struct platform_driver devfreq_cdev_driver = {
  160. .probe = devfreq_cdev_probe,
  161. .remove = devfreq_cdev_remove,
  162. .driver = {
  163. .name = DEVFREQ_CDEV,
  164. .of_match_table = devfreq_cdev_match,
  165. },
  166. };
  167. static int __init devfreq_cdev_init(void)
  168. {
  169. return platform_driver_register(&devfreq_cdev_driver);
  170. }
  171. module_init(devfreq_cdev_init);
  172. static void __exit devfreq_cdev_exit(void)
  173. {
  174. platform_driver_unregister(&devfreq_cdev_driver);
  175. }
  176. module_exit(devfreq_cdev_exit);
  177. MODULE_DESCRIPTION("Qualcomm Technologies, Inc. devfreq cooling device driver");
  178. MODULE_LICENSE("GPL");