114-01-devfreq-qcom-Add-L2-Krait-Cache-devfreq-scaling-driv.patch 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. From b044ae89862132a86fb511648e9c52ea3cdf8c30 Mon Sep 17 00:00:00 2001
  2. From: Christian Marangi <[email protected]>
  3. Date: Wed, 5 Aug 2020 14:19:23 +0200
  4. Subject: [PATCH 1/4] devfreq: qcom: Add L2 Krait Cache devfreq scaling driver
  5. Qcom L2 Krait CPUs use the generic cpufreq-dt driver and doesn't actually
  6. scale the Cache frequency when the CPU frequency is changed. This
  7. devfreq driver register with the cpu notifier and scale the Cache
  8. based on the max Freq across all core as the CPU cache is shared across
  9. all of them. If provided this also scale the voltage of the regulator
  10. attached to the CPU cache. The scaling logic is based on the CPU freq
  11. and the 3 scaling interval are set by the device dts.
  12. Signed-off-by: Christian Marangi <[email protected]>
  13. ---
  14. drivers/devfreq/Kconfig | 11 ++
  15. drivers/devfreq/Makefile | 1 +
  16. drivers/devfreq/krait-cache-devfreq.c | 188 ++++++++++++++++++++++++++
  17. 3 files changed, 200 insertions(+)
  18. create mode 100644 drivers/devfreq/krait-cache-devfreq.c
  19. --- a/drivers/devfreq/Kconfig
  20. +++ b/drivers/devfreq/Kconfig
  21. @@ -150,6 +150,17 @@ config ARM_SUN8I_A33_MBUS_DEVFREQ
  22. This adds the DEVFREQ driver for the MBUS controller in some
  23. Allwinner sun8i (A33 through H3) and sun50i (A64 and H5) SoCs.
  24. +config ARM_KRAIT_CACHE_DEVFREQ
  25. + tristate "Scaling support for Krait CPU Cache Devfreq"
  26. + depends on ARCH_QCOM || COMPILE_TEST
  27. + select DEVFREQ_GOV_PASSIVE
  28. + help
  29. + This adds the DEVFREQ driver for the Krait CPU L2 Cache shared by all cores.
  30. +
  31. + The driver register with the cpufreq notifier and find the right frequency
  32. + based on the max frequency across all core and the range set in the device
  33. + dts. If provided this scale also the regulator attached to the l2 cache.
  34. +
  35. source "drivers/devfreq/event/Kconfig"
  36. endif # PM_DEVFREQ
  37. --- a/drivers/devfreq/Makefile
  38. +++ b/drivers/devfreq/Makefile
  39. @@ -15,6 +15,7 @@ obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ) +
  40. obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o
  41. obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ) += sun8i-a33-mbus.o
  42. obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o
  43. +obj-$(CONFIG_ARM_KRAIT_CACHE_DEVFREQ) += krait-cache-devfreq.o
  44. # DEVFREQ Event Drivers
  45. obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/
  46. --- /dev/null
  47. +++ b/drivers/devfreq/krait-cache-devfreq.c
  48. @@ -0,0 +1,181 @@
  49. +// SPDX-License-Identifier: GPL-2.0
  50. +
  51. +#include <linux/kernel.h>
  52. +#include <linux/init.h>
  53. +#include <linux/module.h>
  54. +#include <linux/cpufreq.h>
  55. +#include <linux/devfreq.h>
  56. +#include <linux/of.h>
  57. +#include <linux/platform_device.h>
  58. +#include <linux/clk.h>
  59. +#include <linux/slab.h>
  60. +#include <linux/regulator/consumer.h>
  61. +#include <linux/pm_opp.h>
  62. +
  63. +#include "governor.h"
  64. +
  65. +struct krait_cache_data {
  66. + struct clk *clk;
  67. + unsigned long idle_freq;
  68. + int token;
  69. +};
  70. +
  71. +static int krait_cache_config_clk(struct device *dev, struct opp_table *opp_table,
  72. + struct dev_pm_opp *old_opp, struct dev_pm_opp *opp,
  73. + void *data, bool scaling_down)
  74. +{
  75. + struct krait_cache_data *kdata;
  76. + unsigned long old_freq, freq;
  77. + unsigned long idle_freq;
  78. + struct clk *clk;
  79. + int ret;
  80. +
  81. + kdata = dev_get_drvdata(dev);
  82. + idle_freq = kdata->idle_freq;
  83. + clk = kdata->clk;
  84. +
  85. + old_freq = dev_pm_opp_get_freq(old_opp);
  86. + freq = dev_pm_opp_get_freq(opp);
  87. +
  88. + /*
  89. + * Set to idle bin if switching from normal to high bin
  90. + * or vice versa. It has been notice that a bug is triggered
  91. + * in cache scaling when more than one bin is scaled, to fix
  92. + * this we first need to transition to the base rate and then
  93. + * to target rate
  94. + */
  95. + if (likely(freq != idle_freq && old_freq != idle_freq)) {
  96. + ret = clk_set_rate(clk, idle_freq);
  97. + if (ret)
  98. + return ret;
  99. + }
  100. +
  101. + return clk_set_rate(clk, freq);
  102. +};
  103. +
  104. +static int krait_cache_get_cur_freq(struct device *dev, unsigned long *freq)
  105. +{
  106. + struct krait_cache_data *data = dev_get_drvdata(dev);
  107. +
  108. + *freq = clk_get_rate(data->clk);
  109. +
  110. + return 0;
  111. +};
  112. +
  113. +static int krait_cache_target(struct device *dev, unsigned long *freq,
  114. + u32 flags)
  115. +{
  116. + struct dev_pm_opp *opp;
  117. +
  118. + opp = dev_pm_opp_find_freq_ceil(dev, freq);
  119. + if (unlikely(IS_ERR(opp)))
  120. + return PTR_ERR(opp);
  121. +
  122. + dev_pm_opp_put(opp);
  123. +
  124. + return dev_pm_opp_set_rate(dev, *freq);
  125. +};
  126. +
  127. +static int krait_cache_get_dev_status(struct device *dev,
  128. + struct devfreq_dev_status *stat)
  129. +{
  130. + struct krait_cache_data *data = dev_get_drvdata(dev);
  131. +
  132. + stat->busy_time = 0;
  133. + stat->total_time = 0;
  134. + stat->current_frequency = clk_get_rate(data->clk);
  135. +
  136. + return 0;
  137. +};
  138. +
  139. +static struct devfreq_dev_profile krait_cache_devfreq_profile = {
  140. + .target = krait_cache_target,
  141. + .get_dev_status = krait_cache_get_dev_status,
  142. + .get_cur_freq = krait_cache_get_cur_freq
  143. +};
  144. +
  145. +static struct devfreq_passive_data devfreq_gov_data = {
  146. + .parent_type = CPUFREQ_PARENT_DEV,
  147. +};
  148. +
  149. +static int krait_cache_probe(struct platform_device *pdev)
  150. +{
  151. + struct dev_pm_opp_config config = { };
  152. + struct device *dev = &pdev->dev;
  153. + struct krait_cache_data *data;
  154. + struct devfreq *devfreq;
  155. + struct dev_pm_opp *opp;
  156. + struct clk *clk;
  157. + int ret, token;
  158. +
  159. + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
  160. + if (!data)
  161. + return -ENOMEM;
  162. +
  163. + clk = devm_clk_get(dev, "l2");
  164. + if (IS_ERR(clk))
  165. + return PTR_ERR(clk);
  166. +
  167. + config.regulator_names = (const char *[]){ "l2", NULL };
  168. + config.clk_names = (const char *[]){ "l2", NULL };
  169. + config.config_clks = krait_cache_config_clk;
  170. +
  171. + token = dev_pm_opp_set_config(dev, &config);
  172. + if (token < 0)
  173. + return token;
  174. +
  175. + ret = devm_pm_opp_of_add_table(dev);
  176. + if (ret)
  177. + goto free_opp;
  178. +
  179. + opp = dev_pm_opp_find_freq_ceil(dev, &data->idle_freq);
  180. + if (IS_ERR(opp)) {
  181. + ret = PTR_ERR(opp);
  182. + goto free_opp;
  183. + }
  184. + dev_pm_opp_put(opp);
  185. +
  186. + data->token = token;
  187. + data->clk = clk;
  188. + dev_set_drvdata(dev, data);
  189. + devfreq = devm_devfreq_add_device(dev, &krait_cache_devfreq_profile,
  190. + DEVFREQ_GOV_PASSIVE, &devfreq_gov_data);
  191. + if (IS_ERR(devfreq)) {
  192. + ret = PTR_ERR(devfreq);
  193. + goto free_opp;
  194. + }
  195. +
  196. + return 0;
  197. +
  198. +free_opp:
  199. + dev_pm_opp_clear_config(token);
  200. + return ret;
  201. +};
  202. +
  203. +static int krait_cache_remove(struct platform_device *pdev)
  204. +{
  205. + struct krait_cache_data *data = dev_get_drvdata(&pdev->dev);
  206. +
  207. + dev_pm_opp_clear_config(data->token);
  208. +
  209. + return 0;
  210. +};
  211. +
  212. +static const struct of_device_id krait_cache_match_table[] = {
  213. + { .compatible = "qcom,krait-cache" },
  214. + {}
  215. +};
  216. +
  217. +static struct platform_driver krait_cache_driver = {
  218. + .probe = krait_cache_probe,
  219. + .remove = krait_cache_remove,
  220. + .driver = {
  221. + .name = "krait-cache-scaling",
  222. + .of_match_table = krait_cache_match_table,
  223. + },
  224. +};
  225. +module_platform_driver(krait_cache_driver);
  226. +
  227. +MODULE_DESCRIPTION("Krait CPU Cache Scaling driver");
  228. +MODULE_AUTHOR("Christian Marangi <[email protected]>");
  229. +MODULE_LICENSE("GPL v2");