tegra20-cpufreq.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /*
  2. * Copyright (C) 2010 Google, Inc.
  3. *
  4. * Author:
  5. * Colin Cross <ccross@google.com>
  6. * Based on arch/arm/plat-omap/cpu-omap.c, (C) 2005 Nokia Corporation
  7. *
  8. * This software is licensed under the terms of the GNU General Public
  9. * License version 2, as published by the Free Software Foundation, and
  10. * may be copied, distributed, and modified under those terms.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. */
  18. #include <linux/kernel.h>
  19. #include <linux/module.h>
  20. #include <linux/types.h>
  21. #include <linux/sched.h>
  22. #include <linux/cpufreq.h>
  23. #include <linux/delay.h>
  24. #include <linux/init.h>
  25. #include <linux/err.h>
  26. #include <linux/clk.h>
  27. #include <linux/io.h>
  28. static struct cpufreq_frequency_table freq_table[] = {
  29. { .frequency = 216000 },
  30. { .frequency = 312000 },
  31. { .frequency = 456000 },
  32. { .frequency = 608000 },
  33. { .frequency = 760000 },
  34. { .frequency = 816000 },
  35. { .frequency = 912000 },
  36. { .frequency = 1000000 },
  37. { .frequency = CPUFREQ_TABLE_END },
  38. };
  39. #define NUM_CPUS 2
  40. static struct clk *cpu_clk;
  41. static struct clk *pll_x_clk;
  42. static struct clk *pll_p_clk;
  43. static struct clk *emc_clk;
  44. static bool pll_x_prepared;
  45. static unsigned int tegra_get_intermediate(struct cpufreq_policy *policy,
  46. unsigned int index)
  47. {
  48. unsigned int ifreq = clk_get_rate(pll_p_clk) / 1000;
  49. /*
  50. * Don't switch to intermediate freq if:
  51. * - we are already at it, i.e. policy->cur == ifreq
  52. * - index corresponds to ifreq
  53. */
  54. if ((freq_table[index].frequency == ifreq) || (policy->cur == ifreq))
  55. return 0;
  56. return ifreq;
  57. }
  58. static int tegra_target_intermediate(struct cpufreq_policy *policy,
  59. unsigned int index)
  60. {
  61. int ret;
  62. /*
  63. * Take an extra reference to the main pll so it doesn't turn
  64. * off when we move the cpu off of it as enabling it again while we
  65. * switch to it from tegra_target() would take additional time.
  66. *
  67. * When target-freq is equal to intermediate freq we don't need to
  68. * switch to an intermediate freq and so this routine isn't called.
  69. * Also, we wouldn't be using pll_x anymore and must not take extra
  70. * reference to it, as it can be disabled now to save some power.
  71. */
  72. clk_prepare_enable(pll_x_clk);
  73. ret = clk_set_parent(cpu_clk, pll_p_clk);
  74. if (ret)
  75. clk_disable_unprepare(pll_x_clk);
  76. else
  77. pll_x_prepared = true;
  78. return ret;
  79. }
  80. static int tegra_target(struct cpufreq_policy *policy, unsigned int index)
  81. {
  82. unsigned long rate = freq_table[index].frequency;
  83. unsigned int ifreq = clk_get_rate(pll_p_clk) / 1000;
  84. int ret = 0;
  85. /*
  86. * Vote on memory bus frequency based on cpu frequency
  87. * This sets the minimum frequency, display or avp may request higher
  88. */
  89. if (rate >= 816000)
  90. clk_set_rate(emc_clk, 600000000); /* cpu 816 MHz, emc max */
  91. else if (rate >= 456000)
  92. clk_set_rate(emc_clk, 300000000); /* cpu 456 MHz, emc 150Mhz */
  93. else
  94. clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */
  95. /*
  96. * target freq == pll_p, don't need to take extra reference to pll_x_clk
  97. * as it isn't used anymore.
  98. */
  99. if (rate == ifreq)
  100. return clk_set_parent(cpu_clk, pll_p_clk);
  101. ret = clk_set_rate(pll_x_clk, rate * 1000);
  102. /* Restore to earlier frequency on error, i.e. pll_x */
  103. if (ret)
  104. pr_err("Failed to change pll_x to %lu\n", rate);
  105. ret = clk_set_parent(cpu_clk, pll_x_clk);
  106. /* This shouldn't fail while changing or restoring */
  107. WARN_ON(ret);
  108. /*
  109. * Drop count to pll_x clock only if we switched to intermediate freq
  110. * earlier while transitioning to a target frequency.
  111. */
  112. if (pll_x_prepared) {
  113. clk_disable_unprepare(pll_x_clk);
  114. pll_x_prepared = false;
  115. }
  116. return ret;
  117. }
  118. static int tegra_cpu_init(struct cpufreq_policy *policy)
  119. {
  120. int ret;
  121. if (policy->cpu >= NUM_CPUS)
  122. return -EINVAL;
  123. clk_prepare_enable(emc_clk);
  124. clk_prepare_enable(cpu_clk);
  125. /* FIXME: what's the actual transition time? */
  126. ret = cpufreq_generic_init(policy, freq_table, 300 * 1000);
  127. if (ret) {
  128. clk_disable_unprepare(cpu_clk);
  129. clk_disable_unprepare(emc_clk);
  130. return ret;
  131. }
  132. policy->clk = cpu_clk;
  133. policy->suspend_freq = freq_table[0].frequency;
  134. return 0;
  135. }
  136. static int tegra_cpu_exit(struct cpufreq_policy *policy)
  137. {
  138. clk_disable_unprepare(cpu_clk);
  139. clk_disable_unprepare(emc_clk);
  140. return 0;
  141. }
  142. static struct cpufreq_driver tegra_cpufreq_driver = {
  143. .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
  144. .verify = cpufreq_generic_frequency_table_verify,
  145. .get_intermediate = tegra_get_intermediate,
  146. .target_intermediate = tegra_target_intermediate,
  147. .target_index = tegra_target,
  148. .get = cpufreq_generic_get,
  149. .init = tegra_cpu_init,
  150. .exit = tegra_cpu_exit,
  151. .name = "tegra",
  152. .attr = cpufreq_generic_attr,
  153. .suspend = cpufreq_generic_suspend,
  154. };
  155. static int __init tegra_cpufreq_init(void)
  156. {
  157. cpu_clk = clk_get_sys(NULL, "cclk");
  158. if (IS_ERR(cpu_clk))
  159. return PTR_ERR(cpu_clk);
  160. pll_x_clk = clk_get_sys(NULL, "pll_x");
  161. if (IS_ERR(pll_x_clk))
  162. return PTR_ERR(pll_x_clk);
  163. pll_p_clk = clk_get_sys(NULL, "pll_p");
  164. if (IS_ERR(pll_p_clk))
  165. return PTR_ERR(pll_p_clk);
  166. emc_clk = clk_get_sys("cpu", "emc");
  167. if (IS_ERR(emc_clk)) {
  168. clk_put(cpu_clk);
  169. return PTR_ERR(emc_clk);
  170. }
  171. return cpufreq_register_driver(&tegra_cpufreq_driver);
  172. }
  173. static void __exit tegra_cpufreq_exit(void)
  174. {
  175. cpufreq_unregister_driver(&tegra_cpufreq_driver);
  176. clk_put(emc_clk);
  177. clk_put(cpu_clk);
  178. }
  179. MODULE_AUTHOR("Colin Cross <ccross@android.com>");
  180. MODULE_DESCRIPTION("cpufreq driver for Nvidia Tegra2");
  181. MODULE_LICENSE("GPL");
  182. module_init(tegra_cpufreq_init);
  183. module_exit(tegra_cpufreq_exit);