clk-tegra-super-gen4.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved.
  4. */
  5. #include <linux/io.h>
  6. #include <linux/clk-provider.h>
  7. #include <linux/of.h>
  8. #include <linux/of_address.h>
  9. #include <linux/delay.h>
  10. #include <linux/export.h>
  11. #include <linux/clk/tegra.h>
  12. #include "clk.h"
  13. #include "clk-id.h"
  14. #define PLLX_BASE 0xe0
  15. #define PLLX_MISC 0xe4
  16. #define PLLX_MISC2 0x514
  17. #define PLLX_MISC3 0x518
  18. #define CCLKG_BURST_POLICY 0x368
  19. #define CCLKLP_BURST_POLICY 0x370
  20. #define SCLK_BURST_POLICY 0x028
  21. #define SYSTEM_CLK_RATE 0x030
  22. #define SCLK_DIVIDER 0x2c
  23. static DEFINE_SPINLOCK(sysrate_lock);
  24. enum tegra_super_gen {
  25. gen4 = 4,
  26. gen5,
  27. };
  28. struct tegra_super_gen_info {
  29. enum tegra_super_gen gen;
  30. const char **sclk_parents;
  31. const char **cclk_g_parents;
  32. const char **cclk_lp_parents;
  33. int num_sclk_parents;
  34. int num_cclk_g_parents;
  35. int num_cclk_lp_parents;
  36. };
  37. static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4",
  38. "pll_p", "pll_p_out2", "unused",
  39. "clk_32k", "pll_m_out1" };
  40. static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
  41. "pll_p", "pll_p_out4", "unused",
  42. "unused", "pll_x", "unused", "unused",
  43. "unused", "unused", "unused", "unused",
  44. "dfllCPU_out" };
  45. static const char *cclk_lp_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
  46. "pll_p", "pll_p_out4", "unused",
  47. "unused", "pll_x", "pll_x_out0" };
  48. static const struct tegra_super_gen_info tegra_super_gen_info_gen4 = {
  49. .gen = gen4,
  50. .sclk_parents = sclk_parents,
  51. .cclk_g_parents = cclk_g_parents,
  52. .cclk_lp_parents = cclk_lp_parents,
  53. .num_sclk_parents = ARRAY_SIZE(sclk_parents),
  54. .num_cclk_g_parents = ARRAY_SIZE(cclk_g_parents),
  55. .num_cclk_lp_parents = ARRAY_SIZE(cclk_lp_parents),
  56. };
  57. static const char *sclk_parents_gen5[] = { "clk_m", "pll_c_out1", "pll_c4_out3",
  58. "pll_p", "pll_p_out2", "pll_c4_out1",
  59. "clk_32k", "pll_c4_out2" };
  60. static const char *cclk_g_parents_gen5[] = { "clk_m", "unused", "clk_32k", "unused",
  61. "pll_p", "pll_p_out4", "unused",
  62. "unused", "pll_x", "unused", "unused",
  63. "unused", "unused", "unused", "unused",
  64. "dfllCPU_out" };
  65. static const char *cclk_lp_parents_gen5[] = { "clk_m", "unused", "clk_32k", "unused",
  66. "pll_p", "pll_p_out4", "unused",
  67. "unused", "pll_x", "unused", "unused",
  68. "unused", "unused", "unused", "unused",
  69. "dfllCPU_out" };
  70. static const struct tegra_super_gen_info tegra_super_gen_info_gen5 = {
  71. .gen = gen5,
  72. .sclk_parents = sclk_parents_gen5,
  73. .cclk_g_parents = cclk_g_parents_gen5,
  74. .cclk_lp_parents = cclk_lp_parents_gen5,
  75. .num_sclk_parents = ARRAY_SIZE(sclk_parents_gen5),
  76. .num_cclk_g_parents = ARRAY_SIZE(cclk_g_parents_gen5),
  77. .num_cclk_lp_parents = ARRAY_SIZE(cclk_lp_parents_gen5),
  78. };
  79. static void __init tegra_sclk_init(void __iomem *clk_base,
  80. struct tegra_clk *tegra_clks,
  81. const struct tegra_super_gen_info *gen_info)
  82. {
  83. struct clk *clk;
  84. struct clk **dt_clk;
  85. /* SCLK_MUX */
  86. dt_clk = tegra_lookup_dt_id(tegra_clk_sclk_mux, tegra_clks);
  87. if (dt_clk) {
  88. clk = tegra_clk_register_super_mux("sclk_mux",
  89. gen_info->sclk_parents,
  90. gen_info->num_sclk_parents,
  91. CLK_SET_RATE_PARENT,
  92. clk_base + SCLK_BURST_POLICY,
  93. 0, 4, 0, 0, NULL);
  94. *dt_clk = clk;
  95. /* SCLK */
  96. dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks);
  97. if (dt_clk) {
  98. clk = clk_register_divider(NULL, "sclk", "sclk_mux",
  99. CLK_IS_CRITICAL,
  100. clk_base + SCLK_DIVIDER, 0, 8,
  101. 0, &sysrate_lock);
  102. *dt_clk = clk;
  103. }
  104. } else {
  105. /* SCLK */
  106. dt_clk = tegra_lookup_dt_id(tegra_clk_sclk, tegra_clks);
  107. if (dt_clk) {
  108. clk = tegra_clk_register_super_mux("sclk",
  109. gen_info->sclk_parents,
  110. gen_info->num_sclk_parents,
  111. CLK_SET_RATE_PARENT |
  112. CLK_IS_CRITICAL,
  113. clk_base + SCLK_BURST_POLICY,
  114. 0, 4, 0, 0, NULL);
  115. *dt_clk = clk;
  116. }
  117. }
  118. /* HCLK */
  119. dt_clk = tegra_lookup_dt_id(tegra_clk_hclk, tegra_clks);
  120. if (dt_clk) {
  121. clk = clk_register_divider(NULL, "hclk_div", "sclk", 0,
  122. clk_base + SYSTEM_CLK_RATE, 4, 2, 0,
  123. &sysrate_lock);
  124. clk = clk_register_gate(NULL, "hclk", "hclk_div",
  125. CLK_SET_RATE_PARENT | CLK_IS_CRITICAL,
  126. clk_base + SYSTEM_CLK_RATE,
  127. 7, CLK_GATE_SET_TO_DISABLE, &sysrate_lock);
  128. *dt_clk = clk;
  129. }
  130. /* PCLK */
  131. dt_clk = tegra_lookup_dt_id(tegra_clk_pclk, tegra_clks);
  132. if (!dt_clk)
  133. return;
  134. clk = clk_register_divider(NULL, "pclk_div", "hclk", 0,
  135. clk_base + SYSTEM_CLK_RATE, 0, 2, 0,
  136. &sysrate_lock);
  137. clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT |
  138. CLK_IS_CRITICAL, clk_base + SYSTEM_CLK_RATE,
  139. 3, CLK_GATE_SET_TO_DISABLE, &sysrate_lock);
  140. *dt_clk = clk;
  141. }
  142. static void __init tegra_super_clk_init(void __iomem *clk_base,
  143. void __iomem *pmc_base,
  144. struct tegra_clk *tegra_clks,
  145. struct tegra_clk_pll_params *params,
  146. const struct tegra_super_gen_info *gen_info)
  147. {
  148. struct clk *clk;
  149. struct clk **dt_clk;
  150. /* CCLKG */
  151. dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_g, tegra_clks);
  152. if (dt_clk) {
  153. if (gen_info->gen == gen5) {
  154. clk = tegra_clk_register_super_mux("cclk_g",
  155. gen_info->cclk_g_parents,
  156. gen_info->num_cclk_g_parents,
  157. CLK_SET_RATE_PARENT,
  158. clk_base + CCLKG_BURST_POLICY,
  159. TEGRA210_CPU_CLK, 4, 8, 0, NULL);
  160. } else {
  161. clk = tegra_clk_register_super_mux("cclk_g",
  162. gen_info->cclk_g_parents,
  163. gen_info->num_cclk_g_parents,
  164. CLK_SET_RATE_PARENT,
  165. clk_base + CCLKG_BURST_POLICY,
  166. 0, 4, 0, 0, NULL);
  167. }
  168. *dt_clk = clk;
  169. }
  170. /* CCLKLP */
  171. dt_clk = tegra_lookup_dt_id(tegra_clk_cclk_lp, tegra_clks);
  172. if (dt_clk) {
  173. if (gen_info->gen == gen5) {
  174. /*
  175. * TEGRA210_CPU_CLK flag is not needed for cclk_lp as
  176. * cluster switching is not currently supported on
  177. * Tegra210 and also cpu_lp is not used.
  178. */
  179. clk = tegra_clk_register_super_mux("cclk_lp",
  180. gen_info->cclk_lp_parents,
  181. gen_info->num_cclk_lp_parents,
  182. CLK_SET_RATE_PARENT,
  183. clk_base + CCLKLP_BURST_POLICY,
  184. 0, 4, 8, 0, NULL);
  185. } else {
  186. clk = tegra_clk_register_super_mux("cclk_lp",
  187. gen_info->cclk_lp_parents,
  188. gen_info->num_cclk_lp_parents,
  189. CLK_SET_RATE_PARENT,
  190. clk_base + CCLKLP_BURST_POLICY,
  191. TEGRA_DIVIDER_2, 4, 8, 9, NULL);
  192. }
  193. *dt_clk = clk;
  194. }
  195. tegra_sclk_init(clk_base, tegra_clks, gen_info);
  196. #if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
  197. defined(CONFIG_ARCH_TEGRA_124_SOC) || \
  198. defined(CONFIG_ARCH_TEGRA_210_SOC)
  199. /* PLLX */
  200. dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x, tegra_clks);
  201. if (!dt_clk)
  202. return;
  203. #if defined(CONFIG_ARCH_TEGRA_210_SOC)
  204. if (gen_info->gen == gen5)
  205. clk = tegra_clk_register_pllc_tegra210("pll_x", "pll_ref",
  206. clk_base, pmc_base, CLK_IGNORE_UNUSED, params, NULL);
  207. else
  208. #endif
  209. clk = tegra_clk_register_pllxc("pll_x", "pll_ref", clk_base,
  210. pmc_base, CLK_IGNORE_UNUSED, params, NULL);
  211. *dt_clk = clk;
  212. /* PLLX_OUT0 */
  213. dt_clk = tegra_lookup_dt_id(tegra_clk_pll_x_out0, tegra_clks);
  214. if (!dt_clk)
  215. return;
  216. clk = clk_register_fixed_factor(NULL, "pll_x_out0", "pll_x",
  217. CLK_SET_RATE_PARENT, 1, 2);
  218. *dt_clk = clk;
  219. #endif
  220. }
  221. void __init tegra_super_clk_gen4_init(void __iomem *clk_base,
  222. void __iomem *pmc_base,
  223. struct tegra_clk *tegra_clks,
  224. struct tegra_clk_pll_params *params)
  225. {
  226. tegra_super_clk_init(clk_base, pmc_base, tegra_clks, params,
  227. &tegra_super_gen_info_gen4);
  228. }
  229. void __init tegra_super_clk_gen5_init(void __iomem *clk_base,
  230. void __iomem *pmc_base,
  231. struct tegra_clk *tegra_clks,
  232. struct tegra_clk_pll_params *params)
  233. {
  234. tegra_super_clk_init(clk_base, pmc_base, tegra_clks, params,
  235. &tegra_super_gen_info_gen5);
  236. }