clock.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  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. void set_usboh3_clk(void)
  49. {
  50. unsigned int reg;
  51. reg = readl(&mxc_ccm->cscmr1) &
  52. ~MXC_CCM_CSCMR1_USBOH3_CLK_SEL_MASK;
  53. reg |= 1 << MXC_CCM_CSCMR1_USBOH3_CLK_SEL_OFFSET;
  54. writel(reg, &mxc_ccm->cscmr1);
  55. reg = readl(&mxc_ccm->cscdr1);
  56. reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PODF_MASK;
  57. reg &= ~MXC_CCM_CSCDR1_USBOH3_CLK_PRED_MASK;
  58. reg |= 4 << MXC_CCM_CSCDR1_USBOH3_CLK_PRED_OFFSET;
  59. reg |= 1 << MXC_CCM_CSCDR1_USBOH3_CLK_PODF_OFFSET;
  60. writel(reg, &mxc_ccm->cscdr1);
  61. }
  62. void enable_usboh3_clk(unsigned char enable)
  63. {
  64. unsigned int reg;
  65. reg = readl(&mxc_ccm->CCGR2);
  66. if (enable)
  67. reg |= 1 << MXC_CCM_CCGR2_CG14_OFFSET;
  68. else
  69. reg &= ~(1 << MXC_CCM_CCGR2_CG14_OFFSET);
  70. writel(reg, &mxc_ccm->CCGR2);
  71. }
  72. void set_usb_phy1_clk(void)
  73. {
  74. unsigned int reg;
  75. reg = readl(&mxc_ccm->cscmr1);
  76. reg &= ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL;
  77. writel(reg, &mxc_ccm->cscmr1);
  78. }
  79. void enable_usb_phy1_clk(unsigned char enable)
  80. {
  81. unsigned int reg;
  82. reg = readl(&mxc_ccm->CCGR4);
  83. if (enable)
  84. reg |= 1 << MXC_CCM_CCGR4_CG5_OFFSET;
  85. else
  86. reg &= ~(1 << MXC_CCM_CCGR4_CG5_OFFSET);
  87. writel(reg, &mxc_ccm->CCGR4);
  88. }
  89. void set_usb_phy2_clk(void)
  90. {
  91. unsigned int reg;
  92. reg = readl(&mxc_ccm->cscmr1);
  93. reg &= ~MXC_CCM_CSCMR1_USB_PHY_CLK_SEL;
  94. writel(reg, &mxc_ccm->cscmr1);
  95. }
  96. void enable_usb_phy2_clk(unsigned char enable)
  97. {
  98. unsigned int reg;
  99. reg = readl(&mxc_ccm->CCGR4);
  100. if (enable)
  101. reg |= 1 << MXC_CCM_CCGR4_CG6_OFFSET;
  102. else
  103. reg &= ~(1 << MXC_CCM_CCGR4_CG6_OFFSET);
  104. writel(reg, &mxc_ccm->CCGR4);
  105. }
  106. /*
  107. * Calculate the frequency of PLLn.
  108. */
  109. static uint32_t decode_pll(struct mxc_pll_reg *pll, uint32_t infreq)
  110. {
  111. uint32_t ctrl, op, mfd, mfn, mfi, pdf, ret;
  112. uint64_t refclk, temp;
  113. int32_t mfn_abs;
  114. ctrl = readl(&pll->ctrl);
  115. if (ctrl & MXC_DPLLC_CTL_HFSM) {
  116. mfn = __raw_readl(&pll->hfs_mfn);
  117. mfd = __raw_readl(&pll->hfs_mfd);
  118. op = __raw_readl(&pll->hfs_op);
  119. } else {
  120. mfn = __raw_readl(&pll->mfn);
  121. mfd = __raw_readl(&pll->mfd);
  122. op = __raw_readl(&pll->op);
  123. }
  124. mfd &= MXC_DPLLC_MFD_MFD_MASK;
  125. mfn &= MXC_DPLLC_MFN_MFN_MASK;
  126. pdf = op & MXC_DPLLC_OP_PDF_MASK;
  127. mfi = (op & MXC_DPLLC_OP_MFI_MASK) >> MXC_DPLLC_OP_MFI_OFFSET;
  128. /* 21.2.3 */
  129. if (mfi < 5)
  130. mfi = 5;
  131. /* Sign extend */
  132. if (mfn >= 0x04000000) {
  133. mfn |= 0xfc000000;
  134. mfn_abs = -mfn;
  135. } else
  136. mfn_abs = mfn;
  137. refclk = infreq * 2;
  138. if (ctrl & MXC_DPLLC_CTL_DPDCK0_2_EN)
  139. refclk *= 2;
  140. do_div(refclk, pdf + 1);
  141. temp = refclk * mfn_abs;
  142. do_div(temp, mfd + 1);
  143. ret = refclk * mfi;
  144. if ((int)mfn < 0)
  145. ret -= temp;
  146. else
  147. ret += temp;
  148. return ret;
  149. }
  150. /*
  151. * Get mcu main rate
  152. */
  153. u32 get_mcu_main_clk(void)
  154. {
  155. u32 reg, freq;
  156. reg = (__raw_readl(&mxc_ccm->cacrr) & MXC_CCM_CACRR_ARM_PODF_MASK) >>
  157. MXC_CCM_CACRR_ARM_PODF_OFFSET;
  158. freq = decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_SYS_MX5_HCLK);
  159. return freq / (reg + 1);
  160. }
  161. /*
  162. * Get the rate of peripheral's root clock.
  163. */
  164. static u32 get_periph_clk(void)
  165. {
  166. u32 reg;
  167. reg = __raw_readl(&mxc_ccm->cbcdr);
  168. if (!(reg & MXC_CCM_CBCDR_PERIPH_CLK_SEL))
  169. return decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_SYS_MX5_HCLK);
  170. reg = __raw_readl(&mxc_ccm->cbcmr);
  171. switch ((reg & MXC_CCM_CBCMR_PERIPH_CLK_SEL_MASK) >>
  172. MXC_CCM_CBCMR_PERIPH_CLK_SEL_OFFSET) {
  173. case 0:
  174. return decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_SYS_MX5_HCLK);
  175. case 1:
  176. return decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_SYS_MX5_HCLK);
  177. default:
  178. return 0;
  179. }
  180. /* NOTREACHED */
  181. }
  182. /*
  183. * Get the rate of ahb clock.
  184. */
  185. static u32 get_ahb_clk(void)
  186. {
  187. uint32_t freq, div, reg;
  188. freq = get_periph_clk();
  189. reg = __raw_readl(&mxc_ccm->cbcdr);
  190. div = ((reg & MXC_CCM_CBCDR_AHB_PODF_MASK) >>
  191. MXC_CCM_CBCDR_AHB_PODF_OFFSET) + 1;
  192. return freq / div;
  193. }
  194. /*
  195. * Get the rate of ipg clock.
  196. */
  197. static u32 get_ipg_clk(void)
  198. {
  199. uint32_t freq, reg, div;
  200. freq = get_ahb_clk();
  201. reg = __raw_readl(&mxc_ccm->cbcdr);
  202. div = ((reg & MXC_CCM_CBCDR_IPG_PODF_MASK) >>
  203. MXC_CCM_CBCDR_IPG_PODF_OFFSET) + 1;
  204. return freq / div;
  205. }
  206. /*
  207. * Get the rate of ipg_per clock.
  208. */
  209. static u32 get_ipg_per_clk(void)
  210. {
  211. u32 pred1, pred2, podf;
  212. if (__raw_readl(&mxc_ccm->cbcmr) & MXC_CCM_CBCMR_PERCLK_IPG_CLK_SEL)
  213. return get_ipg_clk();
  214. /* Fixme: not handle what about lpm*/
  215. podf = __raw_readl(&mxc_ccm->cbcdr);
  216. pred1 = (podf & MXC_CCM_CBCDR_PERCLK_PRED1_MASK) >>
  217. MXC_CCM_CBCDR_PERCLK_PRED1_OFFSET;
  218. pred2 = (podf & MXC_CCM_CBCDR_PERCLK_PRED2_MASK) >>
  219. MXC_CCM_CBCDR_PERCLK_PRED2_OFFSET;
  220. podf = (podf & MXC_CCM_CBCDR_PERCLK_PODF_MASK) >>
  221. MXC_CCM_CBCDR_PERCLK_PODF_OFFSET;
  222. return get_periph_clk() / ((pred1 + 1) * (pred2 + 1) * (podf + 1));
  223. }
  224. /*
  225. * Get the rate of uart clk.
  226. */
  227. static u32 get_uart_clk(void)
  228. {
  229. unsigned int freq, reg, pred, podf;
  230. reg = __raw_readl(&mxc_ccm->cscmr1);
  231. switch ((reg & MXC_CCM_CSCMR1_UART_CLK_SEL_MASK) >>
  232. MXC_CCM_CSCMR1_UART_CLK_SEL_OFFSET) {
  233. case 0x0:
  234. freq = decode_pll(mxc_plls[PLL1_CLOCK],
  235. CONFIG_SYS_MX5_HCLK);
  236. break;
  237. case 0x1:
  238. freq = decode_pll(mxc_plls[PLL2_CLOCK],
  239. CONFIG_SYS_MX5_HCLK);
  240. break;
  241. case 0x2:
  242. freq = decode_pll(mxc_plls[PLL3_CLOCK],
  243. CONFIG_SYS_MX5_HCLK);
  244. break;
  245. default:
  246. return 66500000;
  247. }
  248. reg = __raw_readl(&mxc_ccm->cscdr1);
  249. pred = (reg & MXC_CCM_CSCDR1_UART_CLK_PRED_MASK) >>
  250. MXC_CCM_CSCDR1_UART_CLK_PRED_OFFSET;
  251. podf = (reg & MXC_CCM_CSCDR1_UART_CLK_PODF_MASK) >>
  252. MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET;
  253. freq /= (pred + 1) * (podf + 1);
  254. return freq;
  255. }
  256. /*
  257. * This function returns the low power audio clock.
  258. */
  259. u32 get_lp_apm(void)
  260. {
  261. u32 ret_val = 0;
  262. u32 ccsr = __raw_readl(&mxc_ccm->ccsr);
  263. if (((ccsr >> 9) & 1) == 0)
  264. ret_val = CONFIG_SYS_MX5_HCLK;
  265. else
  266. ret_val = ((32768 * 1024));
  267. return ret_val;
  268. }
  269. /*
  270. * get cspi clock rate.
  271. */
  272. u32 imx_get_cspiclk(void)
  273. {
  274. u32 ret_val = 0, pdf, pre_pdf, clk_sel;
  275. u32 cscmr1 = __raw_readl(&mxc_ccm->cscmr1);
  276. u32 cscdr2 = __raw_readl(&mxc_ccm->cscdr2);
  277. pre_pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PRED_MASK) \
  278. >> MXC_CCM_CSCDR2_CSPI_CLK_PRED_OFFSET;
  279. pdf = (cscdr2 & MXC_CCM_CSCDR2_CSPI_CLK_PODF_MASK) \
  280. >> MXC_CCM_CSCDR2_CSPI_CLK_PODF_OFFSET;
  281. clk_sel = (cscmr1 & MXC_CCM_CSCMR1_CSPI_CLK_SEL_MASK) \
  282. >> MXC_CCM_CSCMR1_CSPI_CLK_SEL_OFFSET;
  283. switch (clk_sel) {
  284. case 0:
  285. ret_val = decode_pll(mxc_plls[PLL1_CLOCK],
  286. CONFIG_SYS_MX5_HCLK) /
  287. ((pre_pdf + 1) * (pdf + 1));
  288. break;
  289. case 1:
  290. ret_val = decode_pll(mxc_plls[PLL2_CLOCK],
  291. CONFIG_SYS_MX5_HCLK) /
  292. ((pre_pdf + 1) * (pdf + 1));
  293. break;
  294. case 2:
  295. ret_val = decode_pll(mxc_plls[PLL3_CLOCK],
  296. CONFIG_SYS_MX5_HCLK) /
  297. ((pre_pdf + 1) * (pdf + 1));
  298. break;
  299. default:
  300. ret_val = get_lp_apm() / ((pre_pdf + 1) * (pdf + 1));
  301. break;
  302. }
  303. return ret_val;
  304. }
  305. /*
  306. * The API of get mxc clockes.
  307. */
  308. unsigned int mxc_get_clock(enum mxc_clock clk)
  309. {
  310. switch (clk) {
  311. case MXC_ARM_CLK:
  312. return get_mcu_main_clk();
  313. case MXC_AHB_CLK:
  314. return get_ahb_clk();
  315. case MXC_IPG_CLK:
  316. return get_ipg_clk();
  317. case MXC_IPG_PERCLK:
  318. return get_ipg_per_clk();
  319. case MXC_UART_CLK:
  320. return get_uart_clk();
  321. case MXC_CSPI_CLK:
  322. return imx_get_cspiclk();
  323. case MXC_FEC_CLK:
  324. return decode_pll(mxc_plls[PLL1_CLOCK],
  325. CONFIG_SYS_MX5_HCLK);
  326. default:
  327. break;
  328. }
  329. return -1;
  330. }
  331. u32 imx_get_uartclk(void)
  332. {
  333. return get_uart_clk();
  334. }
  335. u32 imx_get_fecclk(void)
  336. {
  337. return mxc_get_clock(MXC_IPG_CLK);
  338. }
  339. /*
  340. * Dump some core clockes.
  341. */
  342. int do_mx5_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
  343. {
  344. u32 freq;
  345. freq = decode_pll(mxc_plls[PLL1_CLOCK], CONFIG_SYS_MX5_HCLK);
  346. printf("PLL1 %8d MHz\n", freq / 1000000);
  347. freq = decode_pll(mxc_plls[PLL2_CLOCK], CONFIG_SYS_MX5_HCLK);
  348. printf("PLL2 %8d MHz\n", freq / 1000000);
  349. freq = decode_pll(mxc_plls[PLL3_CLOCK], CONFIG_SYS_MX5_HCLK);
  350. printf("PLL3 %8d MHz\n", freq / 1000000);
  351. #ifdef CONFIG_MX53
  352. freq = decode_pll(mxc_plls[PLL4_CLOCK], CONFIG_SYS_MX5_HCLK);
  353. printf("PLL4 %8d MHz\n", freq / 1000000);
  354. #endif
  355. printf("\n");
  356. printf("AHB %8d kHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000);
  357. printf("IPG %8d kHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000);
  358. printf("IPG PERCLK %8d kHz\n", mxc_get_clock(MXC_IPG_PERCLK) / 1000);
  359. return 0;
  360. }
  361. /***************************************************/
  362. U_BOOT_CMD(
  363. clocks, CONFIG_SYS_MAXARGS, 1, do_mx5_showclocks,
  364. "display clocks",
  365. ""
  366. );