clock.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  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 ahb clock.
  126. */
  127. static u32 get_ahb_clk(void)
  128. {
  129. uint32_t freq, div, reg;
  130. freq = get_periph_clk();
  131. reg = __raw_readl(&mxc_ccm->cbcdr);
  132. div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
  133. MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1;
  134. return freq / div;
  135. }
  136. /*
  137. * Get the rate of ipg clock.
  138. */
  139. static u32 get_ipg_clk(void)
  140. {
  141. uint32_t freq, reg, div;
  142. freq = get_ahb_clk();
  143. reg = __raw_readl(&mxc_ccm->cbcdr);
  144. div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
  145. MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1;
  146. return freq / div;
  147. }
  148. /*
  149. * Get the rate of ipg_per clock.
  150. */
  151. static u32 get_ipg_per_clk(void)
  152. {
  153. u32 pred1, pred2, podf;
  154. if (__raw_readl(&mxc_ccm->cbcmr) & MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL)
  155. return get_ipg_clk();
  156. /* Fixme: not handle what about lpm*/
  157. podf = __raw_readl(&mxc_ccm->cbcdr);
  158. pred1 = (podf & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >>
  159. MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET;
  160. pred2 = (podf & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >>
  161. MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET;
  162. podf = (podf & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >>
  163. MXC_CCM_CBCDR_PERCLK_PODF_OFFSET;
  164. return get_periph_clk() / ((pred1 + 1) * (pred2 + 1) * (podf + 1));
  165. }
  166. /*
  167. * Get the rate of uart clk.
  168. */
  169. static u32 get_uart_clk(void)
  170. {
  171. unsigned int freq, reg, pred, podf;
  172. reg = __raw_readl(&mxc_ccm->cscmr1);
  173. switch ((reg & MXC_CCM_CSCMR1_UART_CLK_SEL_MASK) >>
  174. MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET) {
  175. case 0x0:
  176. freq = decode_pll(mxc_plls[PLL1_CLOCK],
  177. CONFIG_SYS_MX5_HCLK);
  178. break;
  179. case 0x1:
  180. freq = decode_pll(mxc_plls[PLL2_CLOCK],
  181. CONFIG_SYS_MX5_HCLK);
  182. break;
  183. case 0x2:
  184. freq = decode_pll(mxc_plls[PLL3_CLOCK],
  185. CONFIG_SYS_MX5_HCLK);
  186. break;
  187. default:
  188. return 66500000;
  189. }
  190. reg = __raw_readl(&mxc_ccm->cscdr1);
  191. pred = (reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >>
  192. MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET;
  193. podf = (reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >>
  194. MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET;
  195. freq /= (pred + 1) * (podf + 1);
  196. return freq;
  197. }
  198. /*
  199. * This function returns the low power audio clock.
  200. */
  201. u32 get_lp_apm(void)
  202. {
  203. u32 ret_val = 0;
  204. u32 ccsr = __raw_readl(&mxc_ccm->ccsr);
  205. if (((ccsr >> 9) & 1) == 0)
  206. ret_val = CONFIG_SYS_MX5_HCLK;
  207. else
  208. ret_val = ((32768 * 1024));
  209. return ret_val;
  210. }
  211. /*
  212. * get cspi clock rate.
  213. */
  214. u32 imx_get_cspiclk(void)
  215. {
  216. u32 ret_val = 0, pdf, pre_pdf, clk_sel;
  217. u32 cscmr1 = __raw_readl(&mxc_ccm->cscmr1);
  218. u32 cscdr2 = __raw_readl(&mxc_ccm->cscdr2);
  219. pre_pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PRED_MASK) \
  220. >> MXC_CCM_CSCDR2_CSPI_CLK_PRED_OFFSET;
  221. pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PODF_MASK) \
  222. >> MXC_CCM_CSCDR2_CSPI_CLK_PODF_OFFSET;
  223. clk_sel = (cscmr1 & MXC_CCM_CSCMR1_CSPI_CLK_SEL_MASK) \
  224. >> MXC_CCM_CSCMR1_CSPI_CLK_SEL_OFFSET;
  225. switch (clk_sel) {
  226. case 0:
  227. ret_val = decode_pll(mxc_plls[PLL1_CLOCK],
  228. CONFIG_SYS_MX5_HCLK) /
  229. ((pre_pdf + 1) * (pdf + 1));
  230. break;
  231. case 1:
  232. ret_val = decode_pll(mxc_plls[PLL2_CLOCK],
  233. CONFIG_SYS_MX5_HCLK) /
  234. ((pre_pdf + 1) * (pdf + 1));
  235. break;
  236. case 2:
  237. ret_val = decode_pll(mxc_plls[PLL3_CLOCK],
  238. CONFIG_SYS_MX5_HCLK) /
  239. ((pre_pdf + 1) * (pdf + 1));
  240. break;
  241. default:
  242. ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
  243. break;
  244. }
  245. return ret_val;
  246. }
  247. /*
  248. * The API of get mxc clockes.
  249. */
  250. unsigned int mxc_get_clock(enum mxc_clock clk)
  251. {
  252. switch (clk) {
  253. case MXC_ARM_CLK:
  254. return get_mcu_main_clk();
  255. case MXC_AHB_CLK:
  256. return get_ahb_clk();
  257. case MXC_IPG_CLK:
  258. return get_ipg_clk();
  259. case MXC_IPG_PERCLK:
  260. return get_ipg_per_clk();
  261. case MXC_UART_CLK:
  262. return get_uart_clk();
  263. case MXC_CSPI_CLK:
  264. return imx_get_cspiclk();
  265. case MXC_FEC_CLK:
  266. return decode_pll(mxc_plls[PLL1_CLOCK],
  267. CONFIG_SYS_MX5_HCLK);
  268. default:
  269. break;
  270. }
  271. return -1;
  272. }
  273. u32 imx_get_uartclk(void)
  274. {
  275. return get_uart_clk();
  276. }
  277. u32 imx_get_fecclk(void)
  278. {
  279. return mxc_get_clock(MXC_IPG_CLK);
  280. }
  281. /*
  282. * Dump some core clockes.
  283. */
  284. int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  285. {
  286. u32 freq;
  287. freq = decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_SYS_MX5_HCLK);
  288. printf("PLL1 %8d MHz\n", freq / 1000000);
  289. freq = decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_SYS_MX5_HCLK);
  290. printf("PLL2 %8d MHz\n", freq / 1000000);
  291. freq = decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_SYS_MX5_HCLK);
  292. printf("PLL3 %8d MHz\n", freq / 1000000);
  293. #ifdef CONFIG_MX53
  294. freq = decode_pll(mxc_plls[PLL4_CLOCK], CONFIG_SYS_MX5_HCLK);
  295. printf("PLL4 %8d MHz\n", freq / 1000000);
  296. #endif
  297. printf("\n");
  298. printf("AHB %8d kHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000);
  299. printf("IPG %8d kHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000);
  300. printf("IPG PERCLK %8d kHz\n", mxc_get_clock(MXC_IPG_PERCLK) / 1000);
  301. return 0;
  302. }
  303. /***************************************************/
  304. U_BOOT_CMD(
  305. clocks, CONFIG_SYS_MAXARGS, 1, do_mx5_showclocks,
  306. "display clocks",
  307. ""
  308. );