clock.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  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. enum pll_clocks {
  32. PLL1_CLOCK = 0,
  33. PLL2_CLOCK,
  34. PLL3_CLOCK,
  35. PLL_CLOCKS,
  36. };
  37. struct mxc_pll_reg *mxc_plls[PLL_CLOCKS] = {
  38. [PLL1_CLOCK] = (struct mxc_pll_reg *)PLL1_BASE_ADDR,
  39. [PLL2_CLOCK] = (struct mxc_pll_reg *)PLL2_BASE_ADDR,
  40. [PLL3_CLOCK] = (struct mxc_pll_reg *)PLL3_BASE_ADDR,
  41. };
  42. struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)MXC_CCM_BASE;
  43. /*
  44. * Calculate the frequency of this pll.
  45. */
  46. static u32 decode_pll(struct mxc_pll_reg *pll, u32 infreq)
  47. {
  48. u32 mfi, mfn, mfd, pd;
  49. mfn = __raw_readl(&pll->mfn);
  50. mfd = __raw_readl(&pll->mfd) + 1;
  51. mfi = __raw_readl(&pll->op);
  52. pd = (mfi & 0xF) + 1;
  53. mfi = (mfi >> 4) & 0xF;
  54. mfi = (mfi >= 5) ? mfi : 5;
  55. return ((4 * (infreq / 1000) * (mfi * mfd + mfn)) / (mfd * pd)) * 1000;
  56. }
  57. /*
  58. * Get mcu main rate
  59. */
  60. u32 get_mcu_main_clk(void)
  61. {
  62. u32 reg, freq;
  63. reg = (__raw_readl(&mxc_ccm->cacrr) & MXC_CCM_CACRR_ARM_PODF_MASK) >>
  64. MXC_CCM_CACRR_ARM_PODF_OFFSET;
  65. freq = decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_MX51_HCLK_FREQ);
  66. return freq / (reg + 1);
  67. }
  68. /*
  69. * Get the rate of peripheral's root clock.
  70. */
  71. static u32 get_periph_clk(void)
  72. {
  73. u32 reg;
  74. reg = __raw_readl(&mxc_ccm->cbcdr);
  75. if (!(reg & MXC_CCM_CBCDR_PERIPH_CLK_SEL))
  76. return decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_MX51_HCLK_FREQ);
  77. reg = __raw_readl(&mxc_ccm->cbcmr);
  78. switch ((reg & MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK) >>
  79. MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET) {
  80. case 0:
  81. return decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_MX51_HCLK_FREQ);
  82. case 1:
  83. return decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_MX51_HCLK_FREQ);
  84. default:
  85. return 0;
  86. }
  87. /* NOTREACHED */
  88. }
  89. /*
  90. * Get the rate of ipg clock.
  91. */
  92. static u32 get_ipg_clk(void)
  93. {
  94. u32 ahb_podf, ipg_podf;
  95. ahb_podf = __raw_readl(&mxc_ccm->cbcdr);
  96. ipg_podf = (ahb_podf & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
  97. MXC_CCM_CBCDR_IPG_PODF_OFFSET;
  98. ahb_podf = (ahb_podf & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
  99. MXC_CCM_CBCDR_AHB_PODF_OFFSET;
  100. return get_periph_clk() / ((ahb_podf + 1) * (ipg_podf + 1));
  101. }
  102. /*
  103. * Get the rate of ipg_per clock.
  104. */
  105. static u32 get_ipg_per_clk(void)
  106. {
  107. u32 pred1, pred2, podf;
  108. if (__raw_readl(&mxc_ccm->cbcmr) & MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL)
  109. return get_ipg_clk();
  110. /* Fixme: not handle what about lpm*/
  111. podf = __raw_readl(&mxc_ccm->cbcdr);
  112. pred1 = (podf & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >>
  113. MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET;
  114. pred2 = (podf & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >>
  115. MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET;
  116. podf = (podf & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >>
  117. MXC_CCM_CBCDR_PERCLK_PODF_OFFSET;
  118. return get_periph_clk() / ((pred1 + 1) * (pred2 + 1) * (podf + 1));
  119. }
  120. /*
  121. * Get the rate of uart clk.
  122. */
  123. static u32 get_uart_clk(void)
  124. {
  125. unsigned int freq, reg, pred, podf;
  126. reg = __raw_readl(&mxc_ccm->cscmr1);
  127. switch ((reg & MXC_CCM_CSCMR1_UART_CLK_SEL_MASK) >>
  128. MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET) {
  129. case 0x0:
  130. freq = decode_pll(mxc_plls[PLL1_CLOCK],
  131. CONFIG_MX51_HCLK_FREQ);
  132. break;
  133. case 0x1:
  134. freq = decode_pll(mxc_plls[PLL2_CLOCK],
  135. CONFIG_MX51_HCLK_FREQ);
  136. break;
  137. case 0x2:
  138. freq = decode_pll(mxc_plls[PLL3_CLOCK],
  139. CONFIG_MX51_HCLK_FREQ);
  140. break;
  141. default:
  142. return 66500000;
  143. }
  144. reg = __raw_readl(&mxc_ccm->cscdr1);
  145. pred = (reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >>
  146. MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET;
  147. podf = (reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >>
  148. MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET;
  149. freq /= (pred + 1) * (podf + 1);
  150. return freq;
  151. }
  152. /*
  153. * This function returns the low power audio clock.
  154. */
  155. u32 get_lp_apm(void)
  156. {
  157. u32 ret_val = 0;
  158. u32 ccsr = __raw_readl(&mxc_ccm->ccsr);
  159. if (((ccsr >> 9) & 1) == 0)
  160. ret_val = CONFIG_MX51_HCLK_FREQ;
  161. else
  162. ret_val = ((32768 * 1024));
  163. return ret_val;
  164. }
  165. /*
  166. * get cspi clock rate.
  167. */
  168. u32 imx_get_cspiclk(void)
  169. {
  170. u32 ret_val = 0, pdf, pre_pdf, clk_sel;
  171. u32 cscmr1 = __raw_readl(&mxc_ccm->cscmr1);
  172. u32 cscdr2 = __raw_readl(&mxc_ccm->cscdr2);
  173. pre_pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PRED_MASK) \
  174. >> MXC_CCM_CSCDR2_CSPI_CLK_PRED_OFFSET;
  175. pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PODF_MASK) \
  176. >> MXC_CCM_CSCDR2_CSPI_CLK_PODF_OFFSET;
  177. clk_sel = (cscmr1 & MXC_CCM_CSCMR1_CSPI_CLK_SEL_MASK) \
  178. >> MXC_CCM_CSCMR1_CSPI_CLK_SEL_OFFSET;
  179. switch (clk_sel) {
  180. case 0:
  181. ret_val = decode_pll(mxc_plls[PLL1_CLOCK],
  182. CONFIG_MX51_HCLK_FREQ) /
  183. ((pre_pdf + 1) * (pdf + 1));
  184. break;
  185. case 1:
  186. ret_val = decode_pll(mxc_plls[PLL2_CLOCK],
  187. CONFIG_MX51_HCLK_FREQ) /
  188. ((pre_pdf + 1) * (pdf + 1));
  189. break;
  190. case 2:
  191. ret_val = decode_pll(mxc_plls[PLL3_CLOCK],
  192. CONFIG_MX51_HCLK_FREQ) /
  193. ((pre_pdf + 1) * (pdf + 1));
  194. break;
  195. default:
  196. ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
  197. break;
  198. }
  199. return ret_val;
  200. }
  201. /*
  202. * The API of get mxc clockes.
  203. */
  204. unsigned int mxc_get_clock(enum mxc_clock clk)
  205. {
  206. switch (clk) {
  207. case MXC_ARM_CLK:
  208. return get_mcu_main_clk();
  209. case MXC_AHB_CLK:
  210. break;
  211. case MXC_IPG_CLK:
  212. return get_ipg_clk();
  213. case MXC_IPG_PERCLK:
  214. return get_ipg_per_clk();
  215. case MXC_UART_CLK:
  216. return get_uart_clk();
  217. case MXC_CSPI_CLK:
  218. return imx_get_cspiclk();
  219. case MXC_FEC_CLK:
  220. return decode_pll(mxc_plls[PLL1_CLOCK],
  221. CONFIG_MX51_HCLK_FREQ);
  222. default:
  223. break;
  224. }
  225. return -1;
  226. }
  227. u32 imx_get_uartclk(void)
  228. {
  229. return get_uart_clk();
  230. }
  231. u32 imx_get_fecclk(void)
  232. {
  233. return mxc_get_clock(MXC_IPG_CLK);
  234. }
  235. /*
  236. * Dump some core clockes.
  237. */
  238. int do_mx51_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  239. {
  240. u32 freq;
  241. freq = decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_MX51_HCLK_FREQ);
  242. printf("mx51 pll1: %dMHz\n", freq / 1000000);
  243. freq = decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_MX51_HCLK_FREQ);
  244. printf("mx51 pll2: %dMHz\n", freq / 1000000);
  245. freq = decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_MX51_HCLK_FREQ);
  246. printf("mx51 pll3: %dMHz\n", freq / 1000000);
  247. printf("ipg clock : %dHz\n", mxc_get_clock(MXC_IPG_CLK));
  248. printf("ipg per clock : %dHz\n", mxc_get_clock(MXC_IPG_PERCLK));
  249. return 0;
  250. }
  251. /***************************************************/
  252. U_BOOT_CMD(
  253. clockinfo, CONFIG_SYS_MAXARGS, 1, do_mx51_showclocks,
  254. "display mx51 clocks\n",
  255. ""
  256. );