145-cpufreq-Add-a-cpufreq-krait-based-on-cpufre.patch 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. From dd77db4143290689d3a5e1ec61627233d0711b66 Mon Sep 17 00:00:00 2001
  2. From: Stephen Boyd <sboyd@codeaurora.org>
  3. Date: Fri, 30 May 2014 16:36:11 -0700
  4. Subject: [PATCH] FROMLIST: cpufreq: Add a cpufreq-krait based on cpufreq-cpu0
  5. Krait processors have individual clocks for each CPU that can
  6. scale independently from one another. cpufreq-cpu0 is fairly
  7. close to this, but assumes that there is only one clock for all
  8. CPUs. Add a driver to support the Krait configuration.
  9. TODO: Merge into cpufreq-cpu0? Or make generic?
  10. Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
  11. ---
  12. drivers/cpufreq/Kconfig | 13 +++
  13. drivers/cpufreq/Makefile | 1 +
  14. drivers/cpufreq/cpufreq-krait.c | 190 ++++++++++++++++++++++++++++++++++++++++
  15. 3 files changed, 204 insertions(+)
  16. create mode 100644 drivers/cpufreq/cpufreq-krait.c
  17. --- a/drivers/cpufreq/Kconfig
  18. +++ b/drivers/cpufreq/Kconfig
  19. @@ -196,6 +196,19 @@ config CPUFREQ_DT
  20. If in doubt, say N.
  21. +config GENERIC_CPUFREQ_KRAIT
  22. + tristate "Krait cpufreq driver"
  23. + depends on HAVE_CLK && OF
  24. + # if CPU_THERMAL is on and THERMAL=m, CPU0 cannot be =y:
  25. + depends on !CPU_THERMAL || THERMAL
  26. + select PM_OPP
  27. + help
  28. + This adds a generic cpufreq driver for CPU0 frequency management.
  29. + It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
  30. + systems which share clock and voltage across all CPUs.
  31. +
  32. + If in doubt, say N.
  33. +
  34. menu "x86 CPU frequency scaling drivers"
  35. depends on X86
  36. source "drivers/cpufreq/Kconfig.x86"
  37. --- a/drivers/cpufreq/Makefile
  38. +++ b/drivers/cpufreq/Makefile
  39. @@ -14,6 +14,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE)
  40. obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o
  41. obj-$(CONFIG_CPUFREQ_DT) += cpufreq-dt.o
  42. +obj-$(CONFIG_GENERIC_CPUFREQ_KRAIT) += cpufreq-krait.o
  43. ##################################################################################
  44. # x86 drivers.
  45. --- /dev/null
  46. +++ b/drivers/cpufreq/cpufreq-krait.c
  47. @@ -0,0 +1,390 @@
  48. +/*
  49. + * Copyright (C) 2012 Freescale Semiconductor, Inc.
  50. + * Copyright (c) 2014, The Linux Foundation. All rights reserved.
  51. + *
  52. + * The OPP code in function krait_set_target() is reused from
  53. + * drivers/cpufreq/omap-cpufreq.c
  54. + *
  55. + * This program is free software; you can redistribute it and/or modify
  56. + * it under the terms of the GNU General Public License version 2 as
  57. + * published by the Free Software Foundation.
  58. + */
  59. +
  60. +#include <linux/clk.h>
  61. +#include <linux/cpu.h>
  62. +#include <linux/cpu_cooling.h>
  63. +#include <linux/cpufreq.h>
  64. +#include <linux/cpumask.h>
  65. +#include <linux/err.h>
  66. +#include <linux/module.h>
  67. +#include <linux/of.h>
  68. +#include <linux/pm_opp.h>
  69. +#include <linux/platform_device.h>
  70. +#include <linux/regulator/consumer.h>
  71. +#include <linux/slab.h>
  72. +#include <linux/thermal.h>
  73. +
  74. +static unsigned int transition_latency;
  75. +static unsigned int voltage_tolerance; /* in percentage */
  76. +
  77. +static struct device *cpu_dev;
  78. +static DEFINE_PER_CPU(struct clk *, krait_cpu_clks);
  79. +static DEFINE_PER_CPU(struct regulator *, krait_supply_core);
  80. +static struct cpufreq_frequency_table *freq_table;
  81. +static struct thermal_cooling_device *cdev;
  82. +
  83. +struct cache_points {
  84. + unsigned long cache_freq;
  85. + unsigned int cache_volt;
  86. + unsigned long cpu_freq;
  87. +};
  88. +
  89. +static struct regulator *krait_l2_reg;
  90. +static struct clk *krait_l2_clk;
  91. +static struct cache_points *krait_l2_points;
  92. +static int nr_krait_l2_points;
  93. +
  94. +static int krait_parse_cache_points(struct device *dev,
  95. + struct device_node *of_node)
  96. +{
  97. + const struct property *prop;
  98. + const __be32 *val;
  99. + int nr, i;
  100. +
  101. + prop = of_find_property(of_node, "cache-points-kHz", NULL);
  102. + if (!prop)
  103. + return -ENODEV;
  104. + if (!prop->value)
  105. + return -ENODATA;
  106. +
  107. + /*
  108. + * Each OPP is a set of tuples consisting of frequency and
  109. + * cpu-frequency like <freq-kHz volt-uV freq-kHz>.
  110. + */
  111. + nr = prop->length / sizeof(u32);
  112. + if (nr % 3) {
  113. + dev_err(dev, "%s: Invalid cache points\n", __func__);
  114. + return -EINVAL;
  115. + }
  116. + nr /= 3;
  117. +
  118. + krait_l2_points = devm_kcalloc(dev, nr, sizeof(*krait_l2_points),
  119. + GFP_KERNEL);
  120. + if (!krait_l2_points)
  121. + return -ENOMEM;
  122. + nr_krait_l2_points = nr;
  123. +
  124. + for (i = 0, val = prop->value; i < nr; i++) {
  125. + unsigned long cache_freq = be32_to_cpup(val++) * 1000;
  126. + unsigned int cache_volt = be32_to_cpup(val++);
  127. + unsigned long cpu_freq = be32_to_cpup(val++) * 1000;
  128. +
  129. + krait_l2_points[i].cache_freq = cache_freq;
  130. + krait_l2_points[i].cache_volt = cache_volt;
  131. + krait_l2_points[i].cpu_freq = cpu_freq;
  132. + }
  133. +
  134. + return 0;
  135. +}
  136. +
  137. +static int krait_set_target(struct cpufreq_policy *policy, unsigned int index)
  138. +{
  139. + struct dev_pm_opp *opp;
  140. + unsigned long volt = 0, volt_old = 0, tol = 0;
  141. + unsigned long freq, max_cpu_freq = 0;
  142. + unsigned int old_freq, new_freq;
  143. + long freq_Hz, freq_exact;
  144. + int ret, i;
  145. + struct clk *cpu_clk;
  146. + struct regulator *core;
  147. + unsigned int cpu;
  148. +
  149. + cpu_clk = per_cpu(krait_cpu_clks, policy->cpu);
  150. +
  151. + freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
  152. + if (freq_Hz <= 0)
  153. + freq_Hz = freq_table[index].frequency * 1000;
  154. +
  155. + freq_exact = freq_Hz;
  156. + new_freq = freq_Hz / 1000;
  157. + old_freq = clk_get_rate(cpu_clk) / 1000;
  158. +
  159. + core = per_cpu(krait_supply_core, policy->cpu);
  160. +
  161. + rcu_read_lock();
  162. + opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz);
  163. + if (IS_ERR(opp)) {
  164. + rcu_read_unlock();
  165. + pr_err("failed to find OPP for %ld\n", freq_Hz);
  166. + return PTR_ERR(opp);
  167. + }
  168. + volt = dev_pm_opp_get_voltage(opp);
  169. + rcu_read_unlock();
  170. + tol = volt * voltage_tolerance / 100;
  171. + volt_old = regulator_get_voltage(core);
  172. +
  173. + pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
  174. + old_freq / 1000, volt_old ? volt_old / 1000 : -1,
  175. + new_freq / 1000, volt ? volt / 1000 : -1);
  176. +
  177. + /* scaling up? scale voltage before frequency */
  178. + if (new_freq > old_freq) {
  179. + ret = regulator_set_voltage_tol(core, volt, tol);
  180. + if (ret) {
  181. + pr_err("failed to scale voltage up: %d\n", ret);
  182. + return ret;
  183. + }
  184. + }
  185. +
  186. + ret = clk_set_rate(cpu_clk, freq_exact);
  187. + if (ret) {
  188. + pr_err("failed to set clock rate: %d\n", ret);
  189. + return ret;
  190. + }
  191. +
  192. + /* scaling down? scale voltage after frequency */
  193. + if (new_freq < old_freq) {
  194. + ret = regulator_set_voltage_tol(core, volt, tol);
  195. + if (ret) {
  196. + pr_err("failed to scale voltage down: %d\n", ret);
  197. + clk_set_rate(cpu_clk, old_freq * 1000);
  198. + }
  199. + }
  200. +
  201. + for_each_possible_cpu(cpu) {
  202. + freq = clk_get_rate(per_cpu(krait_cpu_clks, cpu));
  203. + max_cpu_freq = max(max_cpu_freq, freq);
  204. + }
  205. +
  206. + for (i = 0; i < nr_krait_l2_points; i++) {
  207. + if (max_cpu_freq >= krait_l2_points[i].cpu_freq) {
  208. + if (krait_l2_reg) {
  209. + ret = regulator_set_voltage_tol(krait_l2_reg,
  210. + krait_l2_points[i].cache_volt,
  211. + tol);
  212. + if (ret) {
  213. + pr_err("failed to scale l2 voltage: %d\n",
  214. + ret);
  215. + }
  216. + }
  217. + ret = clk_set_rate(krait_l2_clk,
  218. + krait_l2_points[i].cache_freq);
  219. + if (ret)
  220. + pr_err("failed to scale l2 clk: %d\n", ret);
  221. + break;
  222. + }
  223. +
  224. + }
  225. +
  226. + return ret;
  227. +}
  228. +
  229. +static int krait_cpufreq_init(struct cpufreq_policy *policy)
  230. +{
  231. + int ret;
  232. +
  233. + policy->clk = per_cpu(krait_cpu_clks, policy->cpu);
  234. +
  235. + ret = cpufreq_table_validate_and_show(policy, freq_table);
  236. + if (ret) {
  237. + pr_err("%s: invalid frequency table: %d\n", __func__, ret);
  238. + return ret;
  239. + }
  240. +
  241. + policy->cpuinfo.transition_latency = transition_latency;
  242. +
  243. + return 0;
  244. +}
  245. +
  246. +static struct cpufreq_driver krait_cpufreq_driver = {
  247. + .flags = CPUFREQ_STICKY,
  248. + .verify = cpufreq_generic_frequency_table_verify,
  249. + .target_index = krait_set_target,
  250. + .get = cpufreq_generic_get,
  251. + .init = krait_cpufreq_init,
  252. + .name = "generic_krait",
  253. + .attr = cpufreq_generic_attr,
  254. +};
  255. +
  256. +static int krait_cpufreq_probe(struct platform_device *pdev)
  257. +{
  258. + struct device_node *np, *cache;
  259. + int ret, i;
  260. + unsigned int cpu;
  261. + struct device *dev;
  262. + struct clk *clk;
  263. + struct regulator *core;
  264. + unsigned long freq_Hz, freq, max_cpu_freq = 0;
  265. + struct dev_pm_opp *opp;
  266. + unsigned long volt, tol;
  267. +
  268. + cpu_dev = get_cpu_device(0);
  269. + if (!cpu_dev) {
  270. + pr_err("failed to get krait device\n");
  271. + return -ENODEV;
  272. + }
  273. +
  274. + np = of_node_get(cpu_dev->of_node);
  275. + if (!np) {
  276. + pr_err("failed to find krait node\n");
  277. + return -ENOENT;
  278. + }
  279. +
  280. + ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
  281. + if (ret) {
  282. + pr_err("failed to init cpufreq table: %d\n", ret);
  283. + goto out_put_node;
  284. + }
  285. +
  286. + of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
  287. +
  288. + if (of_property_read_u32(np, "clock-latency", &transition_latency))
  289. + transition_latency = CPUFREQ_ETERNAL;
  290. +
  291. + cache = of_find_next_cache_node(np);
  292. + if (cache) {
  293. + struct device_node *vdd;
  294. +
  295. + vdd = of_parse_phandle(cache, "vdd_dig-supply", 0);
  296. + if (vdd) {
  297. + krait_l2_reg = regulator_get(NULL, vdd->name);
  298. + if (IS_ERR(krait_l2_reg)) {
  299. + pr_warn("failed to get l2 vdd_dig supply\n");
  300. + krait_l2_reg = NULL;
  301. + }
  302. + of_node_put(vdd);
  303. + }
  304. +
  305. + krait_l2_clk = of_clk_get(cache, 0);
  306. + if (!IS_ERR(krait_l2_clk)) {
  307. + ret = krait_parse_cache_points(&pdev->dev, cache);
  308. + if (ret)
  309. + clk_put(krait_l2_clk);
  310. + }
  311. + if (IS_ERR(krait_l2_clk) || ret)
  312. + krait_l2_clk = NULL;
  313. + }
  314. +
  315. + for_each_possible_cpu(cpu) {
  316. + dev = get_cpu_device(cpu);
  317. + if (!dev) {
  318. + pr_err("failed to get krait device\n");
  319. + ret = -ENOENT;
  320. + goto out_free_table;
  321. + }
  322. + per_cpu(krait_cpu_clks, cpu) = clk = devm_clk_get(dev, NULL);
  323. + if (IS_ERR(clk)) {
  324. + ret = PTR_ERR(clk);
  325. + goto out_free_table;
  326. + }
  327. + core = devm_regulator_get(dev, "core");
  328. + if (IS_ERR(core)) {
  329. + pr_debug("failed to get core regulator\n");
  330. + ret = PTR_ERR(core);
  331. + goto out_free_table;
  332. + }
  333. + per_cpu(krait_supply_core, cpu) = core;
  334. +
  335. + freq = freq_Hz = clk_get_rate(clk);
  336. +
  337. + rcu_read_lock();
  338. + opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz);
  339. + if (IS_ERR(opp)) {
  340. + rcu_read_unlock();
  341. + pr_err("failed to find OPP for %ld\n", freq_Hz);
  342. + ret = PTR_ERR(opp);
  343. + goto out_free_table;
  344. + }
  345. + volt = dev_pm_opp_get_voltage(opp);
  346. + rcu_read_unlock();
  347. +
  348. + tol = volt * voltage_tolerance / 100;
  349. + ret = regulator_set_voltage_tol(core, volt, tol);
  350. + if (ret) {
  351. + pr_err("failed to scale voltage up: %d\n", ret);
  352. + goto out_free_table;
  353. + }
  354. + ret = regulator_enable(core);
  355. + if (ret) {
  356. + pr_err("failed to enable regulator: %d\n", ret);
  357. + goto out_free_table;
  358. + }
  359. + max_cpu_freq = max(max_cpu_freq, freq);
  360. + }
  361. +
  362. + for (i = 0; i < nr_krait_l2_points; i++) {
  363. + if (max_cpu_freq >= krait_l2_points[i].cpu_freq) {
  364. + if (krait_l2_reg) {
  365. + ret = regulator_set_voltage_tol(krait_l2_reg,
  366. + krait_l2_points[i].cache_volt,
  367. + tol);
  368. + if (ret)
  369. + pr_err("failed to scale l2 voltage: %d\n",
  370. + ret);
  371. + ret = regulator_enable(krait_l2_reg);
  372. + if (ret)
  373. + pr_err("failed to enable l2 voltage: %d\n",
  374. + ret);
  375. + }
  376. + break;
  377. + }
  378. +
  379. + }
  380. +
  381. + ret = cpufreq_register_driver(&krait_cpufreq_driver);
  382. + if (ret) {
  383. + pr_err("failed register driver: %d\n", ret);
  384. + goto out_free_table;
  385. + }
  386. + of_node_put(np);
  387. +
  388. + /*
  389. + * For now, just loading the cooling device;
  390. + * thermal DT code takes care of matching them.
  391. + */
  392. + for_each_possible_cpu(cpu) {
  393. + dev = get_cpu_device(cpu);
  394. + np = of_node_get(dev->of_node);
  395. + if (of_find_property(np, "#cooling-cells", NULL)) {
  396. + cdev = of_cpufreq_cooling_register(np, cpumask_of(cpu));
  397. + if (IS_ERR(cdev))
  398. + pr_err("running cpufreq without cooling device: %ld\n",
  399. + PTR_ERR(cdev));
  400. + }
  401. + of_node_put(np);
  402. + }
  403. +
  404. + return 0;
  405. +
  406. +out_free_table:
  407. + regulator_put(krait_l2_reg);
  408. + clk_put(krait_l2_clk);
  409. + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
  410. +out_put_node:
  411. + of_node_put(np);
  412. + return ret;
  413. +}
  414. +
  415. +static int krait_cpufreq_remove(struct platform_device *pdev)
  416. +{
  417. + cpufreq_cooling_unregister(cdev);
  418. + cpufreq_unregister_driver(&krait_cpufreq_driver);
  419. + dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
  420. + clk_put(krait_l2_clk);
  421. + regulator_put(krait_l2_reg);
  422. +
  423. + return 0;
  424. +}
  425. +
  426. +static struct platform_driver krait_cpufreq_platdrv = {
  427. + .driver = {
  428. + .name = "cpufreq-krait",
  429. + .owner = THIS_MODULE,
  430. + },
  431. + .probe = krait_cpufreq_probe,
  432. + .remove = krait_cpufreq_remove,
  433. +};
  434. +module_platform_driver(krait_cpufreq_platdrv);
  435. +
  436. +MODULE_DESCRIPTION("Krait CPUfreq driver");
  437. +MODULE_LICENSE("GPL v2");
  438. --- a/drivers/cpufreq/qcom-cpufreq.c
  439. +++ b/drivers/cpufreq/qcom-cpufreq.c
  440. @@ -168,11 +168,8 @@ static int __init qcom_cpufreq_populate_
  441. static int __init qcom_cpufreq_driver_init(void)
  442. {
  443. - struct cpufreq_dt_platform_data pdata = { .independent_clocks = true };
  444. struct platform_device_info devinfo = {
  445. - .name = "cpufreq-dt",
  446. - .data = &pdata,
  447. - .size_data = sizeof(pdata),
  448. + .name = "cpufreq-krait",
  449. };
  450. struct device *cpu_dev;
  451. struct device_node *np;