clk_ast2500.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /*
  2. * (C) Copyright 2016 Google, Inc
  3. *
  4. * SPDX-License-Identifier: GPL-2.0
  5. */
  6. #include <common.h>
  7. #include <clk-uclass.h>
  8. #include <dm.h>
  9. #include <asm/io.h>
  10. #include <asm/arch/scu_ast2500.h>
  11. #include <dm/lists.h>
  12. #include <dt-bindings/clock/ast2500-scu.h>
  13. DECLARE_GLOBAL_DATA_PTR;
  14. /*
  15. * For H-PLL and M-PLL the formula is
  16. * (Output Frequency) = CLKIN * ((M + 1) / (N + 1)) / (P + 1)
  17. * M - Numerator
  18. * N - Denumerator
  19. * P - Post Divider
  20. * They have the same layout in their control register.
  21. */
  22. /*
  23. * Get the rate of the M-PLL clock from input clock frequency and
  24. * the value of the M-PLL Parameter Register.
  25. */
  26. static ulong ast2500_get_mpll_rate(ulong clkin, u32 mpll_reg)
  27. {
  28. const ulong num = (mpll_reg >> SCU_MPLL_NUM_SHIFT) & SCU_MPLL_NUM_MASK;
  29. const ulong denum = (mpll_reg >> SCU_MPLL_DENUM_SHIFT)
  30. & SCU_MPLL_DENUM_MASK;
  31. const ulong post_div = (mpll_reg >> SCU_MPLL_POST_SHIFT)
  32. & SCU_MPLL_POST_MASK;
  33. return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1);
  34. }
  35. /*
  36. * Get the rate of the H-PLL clock from input clock frequency and
  37. * the value of the H-PLL Parameter Register.
  38. */
  39. static ulong ast2500_get_hpll_rate(ulong clkin, u32 hpll_reg)
  40. {
  41. const ulong num = (hpll_reg >> SCU_HPLL_NUM_SHIFT) & SCU_HPLL_NUM_MASK;
  42. const ulong denum = (hpll_reg >> SCU_HPLL_DENUM_SHIFT)
  43. & SCU_HPLL_DENUM_MASK;
  44. const ulong post_div = (hpll_reg >> SCU_HPLL_POST_SHIFT)
  45. & SCU_HPLL_POST_MASK;
  46. return (clkin * ((num + 1) / (denum + 1))) / (post_div + 1);
  47. }
  48. static ulong ast2500_get_clkin(struct ast2500_scu *scu)
  49. {
  50. return readl(&scu->hwstrap) & SCU_HWSTRAP_CLKIN_25MHZ
  51. ? 25 * 1000 * 1000 : 24 * 1000 * 1000;
  52. }
  53. /**
  54. * Get current rate or uart clock
  55. *
  56. * @scu SCU registers
  57. * @uart_index UART index, 1-5
  58. *
  59. * @return current setting for uart clock rate
  60. */
  61. static ulong ast2500_get_uart_clk_rate(struct ast2500_scu *scu, int uart_index)
  62. {
  63. /*
  64. * ast2500 datasheet is very confusing when it comes to UART clocks,
  65. * especially when CLKIN = 25 MHz. The settings are in
  66. * different registers and it is unclear how they interact.
  67. *
  68. * This has only been tested with default settings and CLKIN = 24 MHz.
  69. */
  70. ulong uart_clkin;
  71. if (readl(&scu->misc_ctrl2) &
  72. (1 << (uart_index - 1 + SCU_MISC2_UARTCLK_SHIFT)))
  73. uart_clkin = 192 * 1000 * 1000;
  74. else
  75. uart_clkin = 24 * 1000 * 1000;
  76. if (readl(&scu->misc_ctrl1) & SCU_MISC_UARTCLK_DIV13)
  77. uart_clkin /= 13;
  78. return uart_clkin;
  79. }
  80. static ulong ast2500_clk_get_rate(struct clk *clk)
  81. {
  82. struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
  83. ulong clkin = ast2500_get_clkin(priv->scu);
  84. ulong rate;
  85. switch (clk->id) {
  86. case PLL_HPLL:
  87. case ARMCLK:
  88. /*
  89. * This ignores dynamic/static slowdown of ARMCLK and may
  90. * be inaccurate.
  91. */
  92. rate = ast2500_get_hpll_rate(clkin,
  93. readl(&priv->scu->h_pll_param));
  94. break;
  95. case MCLK_DDR:
  96. rate = ast2500_get_mpll_rate(clkin,
  97. readl(&priv->scu->m_pll_param));
  98. break;
  99. case PCLK_UART1:
  100. rate = ast2500_get_uart_clk_rate(priv->scu, 1);
  101. break;
  102. case PCLK_UART2:
  103. rate = ast2500_get_uart_clk_rate(priv->scu, 2);
  104. break;
  105. case PCLK_UART3:
  106. rate = ast2500_get_uart_clk_rate(priv->scu, 3);
  107. break;
  108. case PCLK_UART4:
  109. rate = ast2500_get_uart_clk_rate(priv->scu, 4);
  110. break;
  111. case PCLK_UART5:
  112. rate = ast2500_get_uart_clk_rate(priv->scu, 5);
  113. break;
  114. default:
  115. return -ENOENT;
  116. }
  117. return rate;
  118. }
  119. static void ast2500_scu_unlock(struct ast2500_scu *scu)
  120. {
  121. writel(SCU_UNLOCK_VALUE, &scu->protection_key);
  122. while (!readl(&scu->protection_key))
  123. ;
  124. }
  125. static void ast2500_scu_lock(struct ast2500_scu *scu)
  126. {
  127. writel(~SCU_UNLOCK_VALUE, &scu->protection_key);
  128. while (readl(&scu->protection_key))
  129. ;
  130. }
  131. static ulong ast2500_configure_ddr(struct ast2500_scu *scu, ulong rate)
  132. {
  133. ulong clkin = ast2500_get_clkin(scu);
  134. u32 mpll_reg;
  135. /*
  136. * There are not that many combinations of numerator, denumerator
  137. * and post divider, so just brute force the best combination.
  138. * However, to avoid overflow when multiplying, use kHz.
  139. */
  140. const ulong clkin_khz = clkin / 1000;
  141. const ulong rate_khz = rate / 1000;
  142. ulong best_num = 0;
  143. ulong best_denum = 0;
  144. ulong best_post = 0;
  145. ulong delta = rate;
  146. ulong num, denum, post;
  147. for (denum = 0; denum <= SCU_MPLL_DENUM_MASK; ++denum) {
  148. for (post = 0; post <= SCU_MPLL_POST_MASK; ++post) {
  149. num = (rate_khz * (post + 1) / clkin_khz) * (denum + 1);
  150. ulong new_rate_khz = (clkin_khz
  151. * ((num + 1) / (denum + 1)))
  152. / (post + 1);
  153. /* Keep the rate below requested one. */
  154. if (new_rate_khz > rate_khz)
  155. continue;
  156. if (new_rate_khz - rate_khz < delta) {
  157. delta = new_rate_khz - rate_khz;
  158. best_num = num;
  159. best_denum = denum;
  160. best_post = post;
  161. if (delta == 0)
  162. goto rate_calc_done;
  163. }
  164. }
  165. }
  166. rate_calc_done:
  167. mpll_reg = readl(&scu->m_pll_param);
  168. mpll_reg &= ~((SCU_MPLL_POST_MASK << SCU_MPLL_POST_SHIFT)
  169. | (SCU_MPLL_NUM_MASK << SCU_MPLL_NUM_SHIFT)
  170. | (SCU_MPLL_DENUM_MASK << SCU_MPLL_DENUM_SHIFT));
  171. mpll_reg |= (best_post << SCU_MPLL_POST_SHIFT)
  172. | (best_num << SCU_MPLL_NUM_SHIFT)
  173. | (best_denum << SCU_MPLL_DENUM_SHIFT);
  174. ast2500_scu_unlock(scu);
  175. writel(mpll_reg, &scu->m_pll_param);
  176. ast2500_scu_lock(scu);
  177. return ast2500_get_mpll_rate(clkin, mpll_reg);
  178. }
  179. static ulong ast2500_clk_set_rate(struct clk *clk, ulong rate)
  180. {
  181. struct ast2500_clk_priv *priv = dev_get_priv(clk->dev);
  182. ulong new_rate;
  183. switch (clk->id) {
  184. case PLL_MPLL:
  185. case MCLK_DDR:
  186. new_rate = ast2500_configure_ddr(priv->scu, rate);
  187. break;
  188. default:
  189. return -ENOENT;
  190. }
  191. return new_rate;
  192. }
  193. struct clk_ops ast2500_clk_ops = {
  194. .get_rate = ast2500_clk_get_rate,
  195. .set_rate = ast2500_clk_set_rate,
  196. };
  197. static int ast2500_clk_probe(struct udevice *dev)
  198. {
  199. struct ast2500_clk_priv *priv = dev_get_priv(dev);
  200. priv->scu = dev_get_addr_ptr(dev);
  201. if (IS_ERR(priv->scu))
  202. return PTR_ERR(priv->scu);
  203. return 0;
  204. }
  205. static int ast2500_clk_bind(struct udevice *dev)
  206. {
  207. int ret;
  208. /* The reset driver does not have a device node, so bind it here */
  209. ret = device_bind_driver(gd->dm_root, "ast_sysreset", "reset", &dev);
  210. if (ret)
  211. debug("Warning: No reset driver: ret=%d\n", ret);
  212. return 0;
  213. }
  214. static const struct udevice_id ast2500_clk_ids[] = {
  215. { .compatible = "aspeed,ast2500-scu" },
  216. { }
  217. };
  218. U_BOOT_DRIVER(aspeed_ast2500_scu) = {
  219. .name = "aspeed_ast2500_scu",
  220. .id = UCLASS_CLK,
  221. .of_match = ast2500_clk_ids,
  222. .priv_auto_alloc_size = sizeof(struct ast2500_clk_priv),
  223. .ops = &ast2500_clk_ops,
  224. .bind = ast2500_clk_bind,
  225. .probe = ast2500_clk_probe,
  226. };