clk-exynos7420.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /*
  2. * Samsung Exynos7420 clock driver.
  3. * Copyright (C) 2016 Samsung Electronics
  4. * Thomas Abraham <thomas.ab@samsung.com>
  5. *
  6. * SPDX-License-Identifier: GPL-2.0+
  7. */
  8. #include <common.h>
  9. #include <dm.h>
  10. #include <errno.h>
  11. #include <clk-uclass.h>
  12. #include <asm/io.h>
  13. #include <dt-bindings/clock/exynos7420-clk.h>
  14. #include "clk-pll.h"
  15. DECLARE_GLOBAL_DATA_PTR;
  16. #define DIVIDER(reg, shift, mask) \
  17. (((readl(reg) >> shift) & mask) + 1)
  18. /* CMU TOPC block device structure */
  19. struct exynos7420_clk_cmu_topc {
  20. unsigned int rsvd1[68];
  21. unsigned int bus0_pll_con[2];
  22. unsigned int rsvd2[2];
  23. unsigned int bus1_pll_con[2];
  24. unsigned int rsvd3[54];
  25. unsigned int mux_sel[6];
  26. unsigned int rsvd4[250];
  27. unsigned int div[4];
  28. };
  29. /* CMU TOP0 block device structure */
  30. struct exynos7420_clk_cmu_top0 {
  31. unsigned int rsvd0[128];
  32. unsigned int mux_sel[7];
  33. unsigned int rsvd1[261];
  34. unsigned int div_peric[5];
  35. };
  36. /**
  37. * struct exynos7420_clk_topc_priv - private data for CMU topc clock driver.
  38. *
  39. * @topc: base address of the memory mapped CMU TOPC controller.
  40. * @fin_freq: frequency of the Oscillator clock.
  41. * @sclk_bus0_pll_a: frequency of sclk_bus0_pll_a clock.
  42. * @sclk_bus1_pll_a: frequency of sclk_bus1_pll_a clock.
  43. */
  44. struct exynos7420_clk_topc_priv {
  45. struct exynos7420_clk_cmu_topc *topc;
  46. unsigned long fin_freq;
  47. unsigned long sclk_bus0_pll_a;
  48. unsigned long sclk_bus1_pll_a;
  49. };
  50. /**
  51. * struct exynos7420_clk_top0_priv - private data for CMU top0 clock driver.
  52. *
  53. * @top0: base address of the memory mapped CMU TOP0 controller.
  54. * @mout_top0_bus0_pll_half: frequency of mout_top0_bus0_pll_half clock
  55. * @sclk_uart2: frequency of sclk_uart2 clock.
  56. */
  57. struct exynos7420_clk_top0_priv {
  58. struct exynos7420_clk_cmu_top0 *top0;
  59. unsigned long mout_top0_bus0_pll_half;
  60. unsigned long sclk_uart2;
  61. };
  62. static ulong exynos7420_topc_get_rate(struct clk *clk)
  63. {
  64. struct exynos7420_clk_topc_priv *priv = dev_get_priv(clk->dev);
  65. switch (clk->id) {
  66. case DOUT_SCLK_BUS0_PLL:
  67. case SCLK_BUS0_PLL_A:
  68. case SCLK_BUS0_PLL_B:
  69. return priv->sclk_bus0_pll_a;
  70. case DOUT_SCLK_BUS1_PLL:
  71. case SCLK_BUS1_PLL_A:
  72. case SCLK_BUS1_PLL_B:
  73. return priv->sclk_bus1_pll_a;
  74. default:
  75. return 0;
  76. }
  77. }
  78. static struct clk_ops exynos7420_clk_topc_ops = {
  79. .get_rate = exynos7420_topc_get_rate,
  80. };
  81. static int exynos7420_clk_topc_probe(struct udevice *dev)
  82. {
  83. struct exynos7420_clk_topc_priv *priv = dev_get_priv(dev);
  84. struct exynos7420_clk_cmu_topc *topc;
  85. struct clk in_clk;
  86. unsigned long rate;
  87. fdt_addr_t base;
  88. int ret;
  89. base = dev_get_addr(dev);
  90. if (base == FDT_ADDR_T_NONE)
  91. return -EINVAL;
  92. topc = (struct exynos7420_clk_cmu_topc *)base;
  93. priv->topc = topc;
  94. ret = clk_get_by_index(dev, 0, &in_clk);
  95. if (ret >= 0)
  96. priv->fin_freq = clk_get_rate(&in_clk);
  97. rate = pll145x_get_rate(&topc->bus0_pll_con[0], priv->fin_freq);
  98. if (readl(&topc->mux_sel[1]) & (1 << 16))
  99. rate >>= 1;
  100. rate /= DIVIDER(&topc->div[3], 0, 0xf);
  101. priv->sclk_bus0_pll_a = rate;
  102. rate = pll145x_get_rate(&topc->bus1_pll_con[0], priv->fin_freq) /
  103. DIVIDER(&topc->div[3], 8, 0xf);
  104. priv->sclk_bus1_pll_a = rate;
  105. return 0;
  106. }
  107. static ulong exynos7420_top0_get_rate(struct clk *clk)
  108. {
  109. struct exynos7420_clk_top0_priv *priv = dev_get_priv(clk->dev);
  110. struct exynos7420_clk_cmu_top0 *top0 = priv->top0;
  111. switch (clk->id) {
  112. case CLK_SCLK_UART2:
  113. return priv->mout_top0_bus0_pll_half /
  114. DIVIDER(&top0->div_peric[3], 8, 0xf);
  115. default:
  116. return 0;
  117. }
  118. }
  119. static struct clk_ops exynos7420_clk_top0_ops = {
  120. .get_rate = exynos7420_top0_get_rate,
  121. };
  122. static int exynos7420_clk_top0_probe(struct udevice *dev)
  123. {
  124. struct exynos7420_clk_top0_priv *priv;
  125. struct exynos7420_clk_cmu_top0 *top0;
  126. struct clk in_clk;
  127. fdt_addr_t base;
  128. int ret;
  129. priv = dev_get_priv(dev);
  130. if (!priv)
  131. return -EINVAL;
  132. base = dev_get_addr(dev);
  133. if (base == FDT_ADDR_T_NONE)
  134. return -EINVAL;
  135. top0 = (struct exynos7420_clk_cmu_top0 *)base;
  136. priv->top0 = top0;
  137. ret = clk_get_by_index(dev, 1, &in_clk);
  138. if (ret >= 0) {
  139. priv->mout_top0_bus0_pll_half =
  140. clk_get_rate(&in_clk);
  141. if (readl(&top0->mux_sel[1]) & (1 << 16))
  142. priv->mout_top0_bus0_pll_half >>= 1;
  143. }
  144. return 0;
  145. }
  146. static ulong exynos7420_peric1_get_rate(struct clk *clk)
  147. {
  148. struct clk in_clk;
  149. unsigned int ret;
  150. unsigned long freq = 0;
  151. switch (clk->id) {
  152. case SCLK_UART2:
  153. ret = clk_get_by_index(clk->dev, 3, &in_clk);
  154. if (ret < 0)
  155. return ret;
  156. freq = clk_get_rate(&in_clk);
  157. break;
  158. }
  159. return freq;
  160. }
  161. static struct clk_ops exynos7420_clk_peric1_ops = {
  162. .get_rate = exynos7420_peric1_get_rate,
  163. };
  164. static const struct udevice_id exynos7420_clk_topc_compat[] = {
  165. { .compatible = "samsung,exynos7-clock-topc" },
  166. { }
  167. };
  168. U_BOOT_DRIVER(exynos7420_clk_topc) = {
  169. .name = "exynos7420-clock-topc",
  170. .id = UCLASS_CLK,
  171. .of_match = exynos7420_clk_topc_compat,
  172. .probe = exynos7420_clk_topc_probe,
  173. .priv_auto_alloc_size = sizeof(struct exynos7420_clk_topc_priv),
  174. .ops = &exynos7420_clk_topc_ops,
  175. .flags = DM_FLAG_PRE_RELOC,
  176. };
  177. static const struct udevice_id exynos7420_clk_top0_compat[] = {
  178. { .compatible = "samsung,exynos7-clock-top0" },
  179. { }
  180. };
  181. U_BOOT_DRIVER(exynos7420_clk_top0) = {
  182. .name = "exynos7420-clock-top0",
  183. .id = UCLASS_CLK,
  184. .of_match = exynos7420_clk_top0_compat,
  185. .probe = exynos7420_clk_top0_probe,
  186. .priv_auto_alloc_size = sizeof(struct exynos7420_clk_top0_priv),
  187. .ops = &exynos7420_clk_top0_ops,
  188. .flags = DM_FLAG_PRE_RELOC,
  189. };
  190. static const struct udevice_id exynos7420_clk_peric1_compat[] = {
  191. { .compatible = "samsung,exynos7-clock-peric1" },
  192. { }
  193. };
  194. U_BOOT_DRIVER(exynos7420_clk_peric1) = {
  195. .name = "exynos7420-clock-peric1",
  196. .id = UCLASS_CLK,
  197. .of_match = exynos7420_clk_peric1_compat,
  198. .ops = &exynos7420_clk_peric1_ops,
  199. .flags = DM_FLAG_PRE_RELOC,
  200. };