mvebu-cpufreq.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * CPUFreq support for Armada 370/XP platforms.
  4. *
  5. * Copyright (C) 2012-2016 Marvell
  6. *
  7. * Yehuda Yitschak <[email protected]>
  8. * Gregory Clement <[email protected]>
  9. * Thomas Petazzoni <[email protected]>
  10. */
  11. #define pr_fmt(fmt) "mvebu-pmsu: " fmt
  12. #include <linux/clk.h>
  13. #include <linux/cpu.h>
  14. #include <linux/init.h>
  15. #include <linux/kernel.h>
  16. #include <linux/of_address.h>
  17. #include <linux/platform_device.h>
  18. #include <linux/pm_opp.h>
  19. #include <linux/resource.h>
  20. static int __init armada_xp_pmsu_cpufreq_init(void)
  21. {
  22. struct device_node *np;
  23. struct resource res;
  24. int ret, cpu;
  25. if (!of_machine_is_compatible("marvell,armadaxp"))
  26. return 0;
  27. /*
  28. * In order to have proper cpufreq handling, we need to ensure
  29. * that the Device Tree description of the CPU clock includes
  30. * the definition of the PMU DFS registers. If not, we do not
  31. * register the clock notifier and the cpufreq driver. This
  32. * piece of code is only for compatibility with old Device
  33. * Trees.
  34. */
  35. np = of_find_compatible_node(NULL, NULL, "marvell,armada-xp-cpu-clock");
  36. if (!np)
  37. return 0;
  38. ret = of_address_to_resource(np, 1, &res);
  39. if (ret) {
  40. pr_warn(FW_WARN "not enabling cpufreq, deprecated armada-xp-cpu-clock binding\n");
  41. of_node_put(np);
  42. return 0;
  43. }
  44. of_node_put(np);
  45. /*
  46. * For each CPU, this loop registers the operating points
  47. * supported (which are the nominal CPU frequency and half of
  48. * it), and registers the clock notifier that will take care
  49. * of doing the PMSU part of a frequency transition.
  50. */
  51. for_each_possible_cpu(cpu) {
  52. struct device *cpu_dev;
  53. struct clk *clk;
  54. int ret;
  55. cpu_dev = get_cpu_device(cpu);
  56. if (!cpu_dev) {
  57. pr_err("Cannot get CPU %d\n", cpu);
  58. continue;
  59. }
  60. clk = clk_get(cpu_dev, NULL);
  61. if (IS_ERR(clk)) {
  62. pr_err("Cannot get clock for CPU %d\n", cpu);
  63. return PTR_ERR(clk);
  64. }
  65. ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk), 0);
  66. if (ret) {
  67. clk_put(clk);
  68. return ret;
  69. }
  70. ret = dev_pm_opp_add(cpu_dev, clk_get_rate(clk) / 2, 0);
  71. if (ret) {
  72. dev_pm_opp_remove(cpu_dev, clk_get_rate(clk));
  73. clk_put(clk);
  74. dev_err(cpu_dev, "Failed to register OPPs\n");
  75. return ret;
  76. }
  77. ret = dev_pm_opp_set_sharing_cpus(cpu_dev,
  78. cpumask_of(cpu_dev->id));
  79. if (ret)
  80. dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n",
  81. __func__, ret);
  82. clk_put(clk);
  83. }
  84. platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
  85. return 0;
  86. }
  87. device_initcall(armada_xp_pmsu_cpufreq_init);