clock.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. /*
  2. * (C) Copyright 2007
  3. * Sascha Hauer, Pengutronix
  4. *
  5. * (C) Copyright 2009 Freescale Semiconductor, Inc.
  6. *
  7. * See file CREDITS for list of people who contributed to this
  8. * project.
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License as
  12. * published by the Free Software Foundation; either version 2 of
  13. * the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  23. * MA 02111-1307 USA
  24. */
  25. #include <common.h>
  26. #include <asm/io.h>
  27. #include <asm/errno.h>
  28. #include <asm/arch/imx-regs.h>
  29. #include <asm/arch/crm_regs.h>
  30. #include <asm/arch/clock.h>
  31. #include <div64.h>
  32. enum pll_clocks {
  33. PLL1_CLOCK = 0,
  34. PLL2_CLOCK,
  35. PLL3_CLOCK,
  36. PLL4_CLOCK,
  37. PLL_CLOCKS,
  38. };
  39. struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = {
  40. [PLL1_CLOCK] = (struct mxc_pll_reg *)PLL1_BASE_ADDR,
  41. [PLL2_CLOCK] = (struct mxc_pll_reg *)PLL2_BASE_ADDR,
  42. [PLL3_CLOCK] = (struct mxc_pll_reg *)PLL3_BASE_ADDR,
  43. #ifdef CONFIG_MX53
  44. [PLL4_CLOCK] = (struct mxc_pll_reg *)PLL4_BASE_ADDR,
  45. #endif
  46. };
  47. struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;
  48. /*
  49. * Calculate the frequency of PLLn.
  50. */
  51. static uint32_t decode_pll(struct mxc_pll_reg *pll, uint32_t infreq)
  52. {
  53. uint32_t ctrl, op, mfd, mfn, mfi, pdf, ret;
  54. uint64_t refclk, temp;
  55. int32_t mfn_abs;
  56. ctrl = readl(&pll->ctrl);
  57. if (ctrl & MXC_DPLLC_CTL_HFSM) {
  58. mfn = __raw_readl(&pll->hfs_mfn);
  59. mfd = __raw_readl(&pll->hfs_mfd);
  60. op = __raw_readl(&pll->hfs_op);
  61. } else {
  62. mfn = __raw_readl(&pll->mfn);
  63. mfd = __raw_readl(&pll->mfd);
  64. op = __raw_readl(&pll->op);
  65. }
  66. mfd &= MXC_DPLLC_MFD_MFD_MASK;
  67. mfn &= MXC_DPLLC_MFN_MFN_MASK;
  68. pdf = op & MXC_DPLLC_OP_PDF_MASK;
  69. mfi = (op & MXC_DPLLC_OP_MFI_MASK) >> MXC_DPLLC_OP_MFI_OFFSET;
  70. /* 21.2.3 */
  71. if (mfi < 5)
  72. mfi = 5;
  73. /* Sign extend */
  74. if (mfn >= 0x04000000) {
  75. mfn |= 0xfc000000;
  76. mfn_abs = -mfn;
  77. } else
  78. mfn_abs = mfn;
  79. refclk = infreq * 2;
  80. if (ctrl & MXC_DPLLC_CTL_DPDCK0_2_EN)
  81. refclk *= 2;
  82. refclk /= pdf + 1;
  83. temp = refclk * mfn_abs;
  84. do_div(temp, mfd + 1);
  85. ret = refclk * mfi;
  86. if ((int)mfn < 0)
  87. ret -= temp;
  88. else
  89. ret += temp;
  90. return ret;
  91. }
  92. /*
  93. * Get mcu main rate
  94. */
  95. u32 get_mcu_main_clk(void)
  96. {
  97. u32 reg, freq;
  98. reg = (__raw_readl(&mxc_ccm->cacrr) & MXC_CCM_CACRR_ARM_PODF_MASK) >>
  99. MXC_CCM_CACRR_ARM_PODF_OFFSET;
  100. freq = decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_SYS_MX5_HCLK);
  101. return freq / (reg + 1);
  102. }
  103. /*
  104. * Get the rate of peripheral's root clock.
  105. */
  106. static u32 get_periph_clk(void)
  107. {
  108. u32 reg;
  109. reg = __raw_readl(&mxc_ccm->cbcdr);
  110. if (!(reg & MXC_CCM_CBCDR_PERIPH_CLK_SEL))
  111. return decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_SYS_MX5_HCLK);
  112. reg = __raw_readl(&mxc_ccm->cbcmr);
  113. switch ((reg & MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK) >>
  114. MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET) {
  115. case 0:
  116. return decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_SYS_MX5_HCLK);
  117. case 1:
  118. return decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_SYS_MX5_HCLK);
  119. default:
  120. return 0;
  121. }
  122. /* NOTREACHED */
  123. }
  124. /*
  125. * Get the rate of ipg clock.
  126. */
  127. static u32 get_ipg_clk(void)
  128. {
  129. u32 ahb_podf, ipg_podf;
  130. ahb_podf = __raw_readl(&mxc_ccm->cbcdr);
  131. ipg_podf = (ahb_podf & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
  132. MXC_CCM_CBCDR_IPG_PODF_OFFSET;
  133. ahb_podf = (ahb_podf & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
  134. MXC_CCM_CBCDR_AHB_PODF_OFFSET;
  135. return get_periph_clk() / ((ahb_podf + 1) * (ipg_podf + 1));
  136. }
  137. /*
  138. * Get the rate of ipg_per clock.
  139. */
  140. static u32 get_ipg_per_clk(void)
  141. {
  142. u32 pred1, pred2, podf;
  143. if (__raw_readl(&mxc_ccm->cbcmr) & MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL)
  144. return get_ipg_clk();
  145. /* Fixme: not handle what about lpm*/
  146. podf = __raw_readl(&mxc_ccm->cbcdr);
  147. pred1 = (podf & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >>
  148. MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET;
  149. pred2 = (podf & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >>
  150. MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET;
  151. podf = (podf & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >>
  152. MXC_CCM_CBCDR_PERCLK_PODF_OFFSET;
  153. return get_periph_clk() / ((pred1 + 1) * (pred2 + 1) * (podf + 1));
  154. }
  155. /*
  156. * Get the rate of uart clk.
  157. */
  158. static u32 get_uart_clk(void)
  159. {
  160. unsigned int freq, reg, pred, podf;
  161. reg = __raw_readl(&mxc_ccm->cscmr1);
  162. switch ((reg & MXC_CCM_CSCMR1_UART_CLK_SEL_MASK) >>
  163. MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET) {
  164. case 0x0:
  165. freq = decode_pll(mxc_plls[PLL1_CLOCK],
  166. CONFIG_SYS_MX5_HCLK);
  167. break;
  168. case 0x1:
  169. freq = decode_pll(mxc_plls[PLL2_CLOCK],
  170. CONFIG_SYS_MX5_HCLK);
  171. break;
  172. case 0x2:
  173. freq = decode_pll(mxc_plls[PLL3_CLOCK],
  174. CONFIG_SYS_MX5_HCLK);
  175. break;
  176. default:
  177. return 66500000;
  178. }
  179. reg = __raw_readl(&mxc_ccm->cscdr1);
  180. pred = (reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >>
  181. MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET;
  182. podf = (reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >>
  183. MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET;
  184. freq /= (pred + 1) * (podf + 1);
  185. return freq;
  186. }
  187. /*
  188. * This function returns the low power audio clock.
  189. */
  190. u32 get_lp_apm(void)
  191. {
  192. u32 ret_val = 0;
  193. u32 ccsr = __raw_readl(&mxc_ccm->ccsr);
  194. if (((ccsr >> 9) & 1) == 0)
  195. ret_val = CONFIG_SYS_MX5_HCLK;
  196. else
  197. ret_val = ((32768 * 1024));
  198. return ret_val;
  199. }
  200. /*
  201. * get cspi clock rate.
  202. */
  203. u32 imx_get_cspiclk(void)
  204. {
  205. u32 ret_val = 0, pdf, pre_pdf, clk_sel;
  206. u32 cscmr1 = __raw_readl(&mxc_ccm->cscmr1);
  207. u32 cscdr2 = __raw_readl(&mxc_ccm->cscdr2);
  208. pre_pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PRED_MASK) \
  209. >> MXC_CCM_CSCDR2_CSPI_CLK_PRED_OFFSET;
  210. pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PODF_MASK) \
  211. >> MXC_CCM_CSCDR2_CSPI_CLK_PODF_OFFSET;
  212. clk_sel = (cscmr1 & MXC_CCM_CSCMR1_CSPI_CLK_SEL_MASK) \
  213. >> MXC_CCM_CSCMR1_CSPI_CLK_SEL_OFFSET;
  214. switch (clk_sel) {
  215. case 0:
  216. ret_val = decode_pll(mxc_plls[PLL1_CLOCK],
  217. CONFIG_SYS_MX5_HCLK) /
  218. ((pre_pdf + 1) * (pdf + 1));
  219. break;
  220. case 1:
  221. ret_val = decode_pll(mxc_plls[PLL2_CLOCK],
  222. CONFIG_SYS_MX5_HCLK) /
  223. ((pre_pdf + 1) * (pdf + 1));
  224. break;
  225. case 2:
  226. ret_val = decode_pll(mxc_plls[PLL3_CLOCK],
  227. CONFIG_SYS_MX5_HCLK) /
  228. ((pre_pdf + 1) * (pdf + 1));
  229. break;
  230. default:
  231. ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
  232. break;
  233. }
  234. return ret_val;
  235. }
  236. /*
  237. * The API of get mxc clockes.
  238. */
  239. unsigned int mxc_get_clock(enum mxc_clock clk)
  240. {
  241. switch (clk) {
  242. case MXC_ARM_CLK:
  243. return get_mcu_main_clk();
  244. case MXC_AHB_CLK:
  245. break;
  246. case MXC_IPG_CLK:
  247. return get_ipg_clk();
  248. case MXC_IPG_PERCLK:
  249. return get_ipg_per_clk();
  250. case MXC_UART_CLK:
  251. return get_uart_clk();
  252. case MXC_CSPI_CLK:
  253. return imx_get_cspiclk();
  254. case MXC_FEC_CLK:
  255. return decode_pll(mxc_plls[PLL1_CLOCK],
  256. CONFIG_SYS_MX5_HCLK);
  257. default:
  258. break;
  259. }
  260. return -1;
  261. }
  262. u32 imx_get_uartclk(void)
  263. {
  264. return get_uart_clk();
  265. }
  266. u32 imx_get_fecclk(void)
  267. {
  268. return mxc_get_clock(MXC_IPG_CLK);
  269. }
  270. /*
  271. * Dump some core clockes.
  272. */
  273. int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  274. {
  275. u32 freq;
  276. freq = decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_SYS_MX5_HCLK);
  277. printf("pll1: %dMHz\n", freq / 1000000);
  278. freq = decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_SYS_MX5_HCLK);
  279. printf("pll2: %dMHz\n", freq / 1000000);
  280. freq = decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_SYS_MX5_HCLK);
  281. printf("pll3: %dMHz\n", freq / 1000000);
  282. #ifdef CONFIG_MX53
  283. freq = decode_pll(mxc_plls[PLL4_CLOCK], CONFIG_SYS_MX5_HCLK);
  284. printf("pll4: %dMHz\n", freq / 1000000);
  285. #endif
  286. printf("ipg clock : %dHz\n", mxc_get_clock(MXC_IPG_CLK));
  287. printf("ipg per clock : %dHz\n", mxc_get_clock(MXC_IPG_PERCLK));
  288. return 0;
  289. }
  290. /***************************************************/
  291. U_BOOT_CMD(
  292. clocks, CONFIG_SYS_MAXARGS, 1, do_mx5_showclocks,
  293. "display clocks",
  294. ""
  295. );