fsl_clock.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915
  1. /*
  2. * Copyright (c) 2016, Freescale Semiconductor, Inc.
  3. * Copyright (c) 2016 - 2017 , NXP
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * o Redistributions of source code must retain the above copyright notice, this list
  10. * of conditions and the following disclaimer.
  11. *
  12. * o Redistributions in binary form must reproduce the above copyright notice, this
  13. * list of conditions and the following disclaimer in the documentation and/or
  14. * other materials provided with the distribution.
  15. *
  16. * o Neither the name of copyright holder nor the names of its
  17. * contributors may be used to endorse or promote products derived from this
  18. * software without specific prior written permission.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  21. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  22. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  23. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
  24. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  25. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  26. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  27. * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. */
  31. #include "fsl_common.h"
  32. #include "fsl_clock.h"
  33. /*******************************************************************************
  34. * Definitions
  35. ******************************************************************************/
  36. /*******************************************************************************
  37. * Variables
  38. ******************************************************************************/
  39. /* External XTAL (OSC) clock frequency. */
  40. uint32_t g_xtalFreq;
  41. /* External RTC XTAL clock frequency. */
  42. uint32_t g_rtcXtalFreq;
  43. /*******************************************************************************
  44. * Prototypes
  45. ******************************************************************************/
  46. /*******************************************************************************
  47. * Code
  48. ******************************************************************************/
  49. static uint32_t CLOCK_GetPeriphClkFreq(void)
  50. {
  51. uint32_t freq;
  52. /* Periph_clk2_clk ---> Periph_clk */
  53. if (CCM->CBCDR & CCM_CBCDR_PERIPH_CLK_SEL_MASK)
  54. {
  55. switch (CCM->CBCMR & CCM_CBCMR_PERIPH_CLK2_SEL_MASK)
  56. {
  57. /* Pll3_sw_clk ---> Periph_clk2_clk ---> Periph_clk */
  58. case CCM_CBCMR_PERIPH_CLK2_SEL(0U):
  59. freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
  60. break;
  61. /* Osc_clk ---> Periph_clk2_clk ---> Periph_clk */
  62. case CCM_CBCMR_PERIPH_CLK2_SEL(1U):
  63. freq = CLOCK_GetOscFreq();
  64. break;
  65. case CCM_CBCMR_PERIPH_CLK2_SEL(2U):
  66. case CCM_CBCMR_PERIPH_CLK2_SEL(3U):
  67. default:
  68. freq = 0U;
  69. break;
  70. }
  71. freq /= (((CCM->CBCDR & CCM_CBCDR_PERIPH_CLK2_PODF_MASK) >> CCM_CBCDR_PERIPH_CLK2_PODF_SHIFT) + 1U);
  72. }
  73. /* Pll2_main_clk ---> Periph_clk */
  74. else
  75. {
  76. switch (CCM->CBCMR & CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK)
  77. {
  78. /* PLL2 ---> Pll2_main_clk ---> Periph_clk */
  79. case CCM_CBCMR_PRE_PERIPH_CLK_SEL(0U):
  80. freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
  81. break;
  82. /* PLL2 PFD2 ---> Pll2_main_clk ---> Periph_clk */
  83. case CCM_CBCMR_PRE_PERIPH_CLK_SEL(1U):
  84. freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);
  85. break;
  86. /* PLL2 PFD0 ---> Pll2_main_clk ---> Periph_clk */
  87. case CCM_CBCMR_PRE_PERIPH_CLK_SEL(2U):
  88. freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0);
  89. break;
  90. /* PLL2 PFD2 divided(/2) ---> Pll2_main_clk ---> Periph_clk */
  91. case CCM_CBCMR_PRE_PERIPH_CLK_SEL(3U):
  92. freq = (CLOCK_GetSysPfdFreq(kCLOCK_Pfd2) >> 1U);
  93. break;
  94. default:
  95. freq = 0U;
  96. break;
  97. }
  98. }
  99. return freq;
  100. }
  101. void CLOCK_InitExternalClk(bool bypassXtalOsc)
  102. {
  103. /* This device does not support bypass XTAL OSC. */
  104. assert(!bypassXtalOsc);
  105. CCM_ANALOG->MISC0_CLR = CCM_ANALOG_MISC0_XTAL_24M_PWD_MASK; /* Power up */
  106. while ((PMU->LOWPWR_CTRL & PMU_LOWPWR_CTRL_XTALOSC_PWRUP_STAT_MASK) == 0)
  107. {
  108. }
  109. CCM_ANALOG->MISC0_SET = CCM_ANALOG_MISC0_OSC_XTALOK_EN_MASK; /* detect freq */
  110. while ((CCM_ANALOG->MISC0 & CCM_ANALOG_MISC0_OSC_XTALOK_MASK) == 0)
  111. {
  112. }
  113. CCM_ANALOG->MISC0_CLR = CCM_ANALOG_MISC0_OSC_XTALOK_EN_MASK;
  114. }
  115. void CLOCK_DeinitExternalClk(void)
  116. {
  117. CCM_ANALOG->MISC0_SET = CCM_ANALOG_MISC0_XTAL_24M_PWD_MASK; /* Power down */
  118. }
  119. void CLOCK_SwitchOsc(clock_osc_t osc)
  120. {
  121. if (osc == kCLOCK_RcOsc)
  122. PMU->LOWPWR_CTRL_SET = PMU_LOWPWR_CTRL_OSC_SEL_MASK;
  123. else
  124. PMU->LOWPWR_CTRL_CLR = PMU_LOWPWR_CTRL_OSC_SEL_MASK;
  125. }
  126. void CLOCK_InitRcOsc24M(void)
  127. {
  128. PMU->LOWPWR_CTRL |= PMU_LOWPWR_CTRL_RC_OSC_EN_MASK;
  129. }
  130. void CLOCK_DeinitRcOsc24M(void)
  131. {
  132. PMU->LOWPWR_CTRL &= ~PMU_LOWPWR_CTRL_RC_OSC_EN_MASK;
  133. }
  134. uint32_t CLOCK_GetFreq(clock_name_t name)
  135. {
  136. uint32_t freq;
  137. switch (name)
  138. {
  139. case kCLOCK_CpuClk:
  140. switch (CCM->CCSR & (CCM_CCSR_STEP_SEL_MASK | CCM_CCSR_SECONDARY_CLK_SEL_MASK | CCM_CCSR_PLL1_SW_CLK_SEL_MASK))
  141. {
  142. /* ARM PLL ---> CPU Clock */
  143. case 0U:
  144. freq = CLOCK_GetPllFreq(kCLOCK_PllArm);
  145. break;
  146. /* Osc_clk (24M) ---> Step Clock ---> CPU Clock */
  147. case (CCM_CCSR_PLL1_SW_CLK_SEL_MASK):
  148. freq = CLOCK_GetOscFreq();
  149. break;
  150. /* PLL2 PFD2 ---> Secondary_clk ---> Step Clock ---> CPU Clock */
  151. case (CCM_CCSR_PLL1_SW_CLK_SEL_MASK | CCM_CCSR_STEP_SEL_MASK):
  152. freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);
  153. break;
  154. /* PLL2 ---> Secondary_clk ---> Step Clock ---> CPU Clock */
  155. case (CCM_CCSR_STEP_SEL_MASK | CCM_CCSR_SECONDARY_CLK_SEL_MASK | CCM_CCSR_PLL1_SW_CLK_SEL_MASK):
  156. freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
  157. break;
  158. default:
  159. freq = 0U;
  160. break;
  161. }
  162. freq /= (((CCM->CACRR & CCM_CACRR_ARM_PODF_MASK) >> CCM_CACRR_ARM_PODF_SHIFT) + 1U);
  163. break;
  164. case kCLOCK_AxiClk:
  165. /* AXI alternative clock ---> AXI Clock */
  166. if (CCM->CBCDR & CCM_CBCDR_AXI_SEL_MASK)
  167. {
  168. /* PLL3 PFD1 ---> AXI alternative clock ---> AXI Clock */
  169. if (CCM->CBCDR & CCM_CBCDR_AXI_ALT_SEL_MASK)
  170. {
  171. freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd1);
  172. }
  173. /* PLL2 PFD2 ---> AXI alternative clock ---> AXI Clock */
  174. else
  175. {
  176. freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);
  177. }
  178. }
  179. /* Periph_clk ---> AXI Clock */
  180. else
  181. {
  182. freq = CLOCK_GetPeriphClkFreq();
  183. }
  184. freq /= (((CCM->CBCDR & CCM_CBCDR_AXI_PODF_MASK) >> CCM_CBCDR_AXI_PODF_SHIFT) + 1U);
  185. break;
  186. case kCLOCK_AhbClk:
  187. /* Periph_clk ---> AHB Clock */
  188. freq = CLOCK_GetPeriphClkFreq() / (((CCM->CBCDR & CCM_CBCDR_AHB_PODF_MASK) >> CCM_CBCDR_AHB_PODF_SHIFT) + 1U);
  189. break;
  190. case kCLOCK_IpgClk:
  191. /* Periph_clk ---> AHB Clock ---> IPG Clock */
  192. freq = CLOCK_GetPeriphClkFreq() / (((CCM->CBCDR & CCM_CBCDR_AHB_PODF_MASK) >> CCM_CBCDR_AHB_PODF_SHIFT) + 1U);
  193. freq /= (((CCM->CBCDR & CCM_CBCDR_IPG_PODF_MASK) >> CCM_CBCDR_IPG_PODF_SHIFT) + 1U);
  194. break;
  195. case kCLOCK_MmdcClk:
  196. /* periph2_clk2 ---> MMDC Clock */
  197. if (CCM->CBCDR & CCM_CBCDR_PERIPH2_CLK_SEL_MASK)
  198. {
  199. /* OSC ---> periph2_clk2 ---> MMDC Clock */
  200. if (CCM->CBCMR & CCM_CBCMR_PERIPH2_CLK2_SEL_MASK)
  201. {
  202. freq = CLOCK_GetOscFreq();
  203. }
  204. /* pll3_sw_clk ---> periph2_clk2 ---> MMDC Clock */
  205. else
  206. {
  207. freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
  208. }
  209. freq /= (((CCM->CBCDR & CCM_CBCDR_PERIPH2_CLK2_PODF_MASK) >> CCM_CBCDR_PERIPH2_CLK2_PODF_SHIFT) + 1U);
  210. }
  211. /* pll2_main_clk ---> MMDC Clock */
  212. else
  213. {
  214. switch (CCM->CBCMR & CCM_CBCMR_PRE_PERIPH2_CLK_SEL_MASK)
  215. {
  216. /* PLL2 ---> pll2_main_clk ---> MMDC Clock */
  217. case CCM_CBCMR_PRE_PERIPH2_CLK_SEL(0U):
  218. freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
  219. break;
  220. /* PLL2 PFD2 ---> pll2_main_clk ---> MMDC Clock */
  221. case CCM_CBCMR_PRE_PERIPH2_CLK_SEL(1U):
  222. freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);
  223. break;
  224. /* PLL2 PFD0 ---> pll2_main_clk ---> MMDC Clock */
  225. case CCM_CBCMR_PRE_PERIPH2_CLK_SEL(2U):
  226. freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0);
  227. break;
  228. /* PLL4 ---> pll2_main_clk ---> MMDC Clock */
  229. case CCM_CBCMR_PRE_PERIPH2_CLK_SEL(3U):
  230. freq = CLOCK_GetPllFreq(kCLOCK_PllAudio);
  231. break;
  232. default:
  233. freq = 0U;
  234. break;
  235. }
  236. }
  237. freq /= (((CCM->CBCDR & CCM_CBCDR_FABRIC_MMDC_PODF_MASK) >> CCM_CBCDR_FABRIC_MMDC_PODF_SHIFT) + 1U);
  238. break;
  239. case kCLOCK_OscClk:
  240. freq = CLOCK_GetOscFreq();
  241. break;
  242. case kCLOCK_RtcClk:
  243. freq = CLOCK_GetRtcFreq();
  244. break;
  245. case kCLOCK_ArmPllClk:
  246. freq = CLOCK_GetPllFreq(kCLOCK_PllArm);
  247. break;
  248. case kCLOCK_Usb1PllClk:
  249. freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
  250. break;
  251. case kCLOCK_Usb1PllPfd0Clk:
  252. freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd0);
  253. break;
  254. case kCLOCK_Usb1PllPfd1Clk:
  255. freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd1);
  256. break;
  257. case kCLOCK_Usb1PllPfd2Clk:
  258. freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd2);
  259. break;
  260. case kCLOCK_Usb1PllPfd3Clk:
  261. freq = CLOCK_GetUsb1PfdFreq(kCLOCK_Pfd3);
  262. break;
  263. case kCLOCK_Usb2PllClk:
  264. freq = CLOCK_GetPllFreq(kCLOCK_PllUsb2);
  265. break;
  266. case kCLOCK_SysPllClk:
  267. freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
  268. break;
  269. case kCLOCK_SysPllPfd0Clk:
  270. freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd0);
  271. break;
  272. case kCLOCK_SysPllPfd1Clk:
  273. freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd1);
  274. break;
  275. case kCLOCK_SysPllPfd2Clk:
  276. freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd2);
  277. break;
  278. case kCLOCK_SysPllPfd3Clk:
  279. freq = CLOCK_GetSysPfdFreq(kCLOCK_Pfd3);
  280. break;
  281. case kCLOCK_EnetPll0Clk:
  282. freq = CLOCK_GetPllFreq(kCLOCK_PllEnet0);
  283. break;
  284. case kCLOCK_EnetPll1Clk:
  285. freq = CLOCK_GetPllFreq(kCLOCK_PllEnet1);
  286. break;
  287. case kCLOCK_EnetPll2Clk:
  288. freq = CLOCK_GetPllFreq(kCLOCK_PllEnet2);
  289. break;
  290. case kCLOCK_AudioPllClk:
  291. freq = CLOCK_GetPllFreq(kCLOCK_PllAudio);
  292. break;
  293. case kCLOCK_VideoPllClk:
  294. freq = CLOCK_GetPllFreq(kCLOCK_PllVideo);
  295. break;
  296. default:
  297. freq = 0U;
  298. break;
  299. }
  300. return freq;
  301. }
  302. void CLOCK_InitArmPll(const clock_arm_pll_config_t *config)
  303. {
  304. CCM_ANALOG->PLL_ARM = CCM_ANALOG_PLL_ARM_ENABLE_MASK |
  305. CCM_ANALOG_PLL_ARM_DIV_SELECT(config->loopDivider);
  306. while ((CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_LOCK_MASK) == 0)
  307. {
  308. }
  309. }
  310. void CLOCK_DeinitArmPll(void)
  311. {
  312. CCM_ANALOG->PLL_ARM = CCM_ANALOG_PLL_ARM_POWERDOWN_MASK;
  313. }
  314. void CLOCK_InitSysPll(const clock_sys_pll_config_t *config)
  315. {
  316. CCM_ANALOG->PLL_SYS = CCM_ANALOG_PLL_SYS_ENABLE_MASK |
  317. CCM_ANALOG_PLL_SYS_DIV_SELECT(config->loopDivider);
  318. while ((CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_LOCK_MASK) == 0)
  319. {
  320. }
  321. }
  322. void CLOCK_DeinitSysPll(void)
  323. {
  324. CCM_ANALOG->PLL_SYS = CCM_ANALOG_PLL_SYS_POWERDOWN_MASK;
  325. }
  326. void CLOCK_InitUsb1Pll(const clock_usb_pll_config_t *config)
  327. {
  328. CCM_ANALOG->PLL_USB1 = CCM_ANALOG_PLL_USB1_ENABLE_MASK |
  329. CCM_ANALOG_PLL_USB1_POWER_MASK |
  330. CCM_ANALOG_PLL_USB1_EN_USB_CLKS_MASK |
  331. CCM_ANALOG_PLL_USB1_DIV_SELECT(config->loopDivider);
  332. while ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_LOCK_MASK) == 0)
  333. {
  334. }
  335. }
  336. void CLOCK_DeinitUsb1Pll(void)
  337. {
  338. CCM_ANALOG->PLL_USB1 = 0U;
  339. }
  340. void CLOCK_InitUsb2Pll(const clock_usb_pll_config_t *config)
  341. {
  342. CCM_ANALOG->PLL_USB2 = CCM_ANALOG_PLL_USB2_ENABLE_MASK |
  343. CCM_ANALOG_PLL_USB2_POWER_MASK |
  344. CCM_ANALOG_PLL_USB2_EN_USB_CLKS_MASK |
  345. CCM_ANALOG_PLL_USB2_DIV_SELECT(config->loopDivider);
  346. while ((CCM_ANALOG->PLL_USB2 & CCM_ANALOG_PLL_USB2_LOCK_MASK) == 0)
  347. {
  348. }
  349. }
  350. void CLOCK_DeinitUsb2Pll(void)
  351. {
  352. CCM_ANALOG->PLL_USB2 = 0U;
  353. }
  354. void CLOCK_InitAudioPll(const clock_audio_pll_config_t *config)
  355. {
  356. uint32_t pllAudio;
  357. uint32_t misc2 = 0;
  358. CCM_ANALOG->PLL_AUDIO_NUM = CCM_ANALOG_PLL_AUDIO_NUM_A(config->numerator);
  359. CCM_ANALOG->PLL_AUDIO_DENOM = CCM_ANALOG_PLL_AUDIO_DENOM_B(config->denominator);
  360. /*
  361. * Set post divider:
  362. *
  363. * ------------------------------------------------------------------------
  364. * | config->postDivider | PLL_AUDIO[POST_DIV_SELECT] | MISC2[AUDIO_DIV] |
  365. * ------------------------------------------------------------------------
  366. * | 1 | 2 | 0 |
  367. * ------------------------------------------------------------------------
  368. * | 2 | 1 | 0 |
  369. * ------------------------------------------------------------------------
  370. * | 4 | 2 | 3 |
  371. * ------------------------------------------------------------------------
  372. * | 8 | 1 | 3 |
  373. * ------------------------------------------------------------------------
  374. * | 16 | 0 | 3 |
  375. * ------------------------------------------------------------------------
  376. */
  377. pllAudio = CCM_ANALOG_PLL_AUDIO_ENABLE_MASK | CCM_ANALOG_PLL_AUDIO_DIV_SELECT(config->loopDivider);
  378. switch (config->postDivider)
  379. {
  380. case 16:
  381. pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(0);
  382. misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
  383. break;
  384. case 8:
  385. pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1);
  386. misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
  387. break;
  388. case 4:
  389. pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2);
  390. misc2 = CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK;
  391. break;
  392. case 2:
  393. pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1);
  394. break;
  395. default:
  396. pllAudio |= CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(2);
  397. break;
  398. }
  399. CCM_ANALOG->MISC2 = (CCM_ANALOG->MISC2 & ~(CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK))
  400. | misc2;
  401. CCM_ANALOG->PLL_AUDIO = pllAudio;
  402. while ((CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_LOCK_MASK) == 0)
  403. {
  404. }
  405. }
  406. void CLOCK_DeinitAudioPll(void)
  407. {
  408. CCM_ANALOG->PLL_AUDIO = CCM_ANALOG_PLL_AUDIO_POWERDOWN_MASK;
  409. }
  410. void CLOCK_InitVideoPll(const clock_video_pll_config_t *config)
  411. {
  412. uint32_t pllVideo;
  413. uint32_t misc2 = 0;
  414. CCM_ANALOG->PLL_VIDEO_NUM = CCM_ANALOG_PLL_VIDEO_NUM_A(config->numerator);
  415. CCM_ANALOG->PLL_VIDEO_DENOM = CCM_ANALOG_PLL_VIDEO_DENOM_B(config->denominator);
  416. /*
  417. * Set post divider:
  418. *
  419. * ------------------------------------------------------------------------
  420. * | config->postDivider | PLL_VIDEO[POST_DIV_SELECT] | MISC2[VIDEO_DIV] |
  421. * ------------------------------------------------------------------------
  422. * | 1 | 2 | 0 |
  423. * ------------------------------------------------------------------------
  424. * | 2 | 1 | 0 |
  425. * ------------------------------------------------------------------------
  426. * | 4 | 2 | 3 |
  427. * ------------------------------------------------------------------------
  428. * | 8 | 1 | 3 |
  429. * ------------------------------------------------------------------------
  430. * | 16 | 0 | 3 |
  431. * ------------------------------------------------------------------------
  432. */
  433. pllVideo = CCM_ANALOG_PLL_VIDEO_ENABLE_MASK | CCM_ANALOG_PLL_VIDEO_DIV_SELECT(config->loopDivider);
  434. switch (config->postDivider)
  435. {
  436. case 16:
  437. pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(0);
  438. misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3);
  439. break;
  440. case 8:
  441. pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1);
  442. misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3);
  443. break;
  444. case 4:
  445. pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2);
  446. misc2 = CCM_ANALOG_MISC2_VIDEO_DIV(3);
  447. break;
  448. case 2:
  449. pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1);
  450. break;
  451. default:
  452. pllVideo |= CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(2);
  453. break;
  454. }
  455. CCM_ANALOG->MISC2 = (CCM_ANALOG->MISC2 & ~CCM_ANALOG_MISC2_VIDEO_DIV_MASK) | misc2;
  456. CCM_ANALOG->PLL_VIDEO = pllVideo;
  457. while ((CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_LOCK_MASK) == 0)
  458. {
  459. }
  460. }
  461. void CLOCK_DeinitVideoPll(void)
  462. {
  463. CCM_ANALOG->PLL_VIDEO = CCM_ANALOG_PLL_VIDEO_POWERDOWN_MASK;
  464. }
  465. void CLOCK_InitEnetPll(const clock_enet_pll_config_t *config)
  466. {
  467. uint32_t enet_pll = CCM_ANALOG_PLL_ENET_ENET1_DIV_SELECT(config->loopDivider1) |
  468. CCM_ANALOG_PLL_ENET_ENET0_DIV_SELECT(config->loopDivider0);
  469. if (config->enableClkOutput0)
  470. {
  471. enet_pll |= CCM_ANALOG_PLL_ENET_ENET1_125M_EN_MASK;
  472. }
  473. if (config->enableClkOutput1)
  474. {
  475. enet_pll |= CCM_ANALOG_PLL_ENET_ENET2_125M_EN_MASK;
  476. }
  477. if (config->enableClkOutput2)
  478. {
  479. enet_pll |= CCM_ANALOG_PLL_ENET_ENET_25M_REF_EN_MASK;
  480. }
  481. CCM_ANALOG->PLL_ENET = enet_pll;
  482. /* Wait for stable */
  483. while ((CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_LOCK_MASK) == 0)
  484. {
  485. }
  486. }
  487. void CLOCK_DeinitEnetPll(void)
  488. {
  489. CCM_ANALOG->PLL_ENET = CCM_ANALOG_PLL_ENET_POWERDOWN_MASK;
  490. }
  491. uint32_t CLOCK_GetPllFreq(clock_pll_t pll)
  492. {
  493. uint32_t freq;
  494. uint32_t divSelect;
  495. uint64_t freqTmp;
  496. const uint32_t enetRefClkFreq[] = {
  497. 25000000U, /* 25M */
  498. 50000000U, /* 50M */
  499. 100000000U, /* 100M */
  500. 125000000U /* 125M */
  501. };
  502. switch (pll)
  503. {
  504. case kCLOCK_PllArm:
  505. freq = ((CLOCK_GetOscFreq() * ((CCM_ANALOG->PLL_ARM & CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK) >>
  506. CCM_ANALOG_PLL_ARM_DIV_SELECT_SHIFT)) >> 1U);
  507. break;
  508. case kCLOCK_PllSys:
  509. freq = CLOCK_GetOscFreq();
  510. /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */
  511. freqTmp = ((uint64_t)freq * ((uint64_t)(CCM_ANALOG->PLL_SYS_NUM))) / ((uint64_t)(CCM_ANALOG->PLL_SYS_DENOM));
  512. if (CCM_ANALOG->PLL_SYS & CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK)
  513. {
  514. freq *= 22U;
  515. }
  516. else
  517. {
  518. freq *= 20U;
  519. }
  520. freq += (uint32_t)freqTmp;
  521. break;
  522. case kCLOCK_PllUsb1:
  523. freq = (CLOCK_GetOscFreq() * ((CCM_ANALOG->PLL_USB1 & CCM_ANALOG_PLL_USB1_DIV_SELECT_MASK) ? 22U : 20U));
  524. break;
  525. case kCLOCK_PllAudio:
  526. freq = CLOCK_GetOscFreq();
  527. /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */
  528. divSelect = (CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_AUDIO_DIV_SELECT_SHIFT;
  529. freqTmp = ((uint64_t)freq * ((uint64_t)(CCM_ANALOG->PLL_AUDIO_NUM))) / ((uint64_t)(CCM_ANALOG->PLL_AUDIO_DENOM));
  530. freq = freq * divSelect + (uint32_t)freqTmp;
  531. /* AUDIO PLL output = PLL output frequency / POSTDIV. */
  532. /*
  533. * Post divider:
  534. *
  535. * PLL_AUDIO[POST_DIV_SELECT]:
  536. * 0x00: 4
  537. * 0x01: 2
  538. * 0x02: 1
  539. *
  540. * MISC2[AUDO_DIV]:
  541. * 0x00: 1
  542. * 0x01: 2
  543. * 0x02: 1
  544. * 0x03: 4
  545. */
  546. switch (CCM_ANALOG->PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT_MASK)
  547. {
  548. case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(0U):
  549. freq = freq >> 2U;
  550. break;
  551. case CCM_ANALOG_PLL_AUDIO_POST_DIV_SELECT(1U):
  552. freq = freq >> 1U;
  553. break;
  554. default:
  555. break;
  556. }
  557. switch (CCM_ANALOG->MISC2 & (CCM_ANALOG_MISC2_AUDIO_DIV_MSB_MASK | CCM_ANALOG_MISC2_AUDIO_DIV_LSB_MASK))
  558. {
  559. case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(1) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(1):
  560. freq >>= 2U;
  561. break;
  562. case CCM_ANALOG_MISC2_AUDIO_DIV_MSB(0) | CCM_ANALOG_MISC2_AUDIO_DIV_LSB(1):
  563. freq >>= 1U;
  564. break;
  565. default:
  566. break;
  567. }
  568. break;
  569. case kCLOCK_PllVideo:
  570. freq = CLOCK_GetOscFreq();
  571. /* PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM). */
  572. divSelect = (CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_DIV_SELECT_MASK) >> CCM_ANALOG_PLL_VIDEO_DIV_SELECT_SHIFT;
  573. freqTmp = ((uint64_t)freq * ((uint64_t)(CCM_ANALOG->PLL_VIDEO_NUM))) / ((uint64_t)(CCM_ANALOG->PLL_VIDEO_DENOM));
  574. freq = freq * divSelect + (uint32_t)freqTmp;
  575. /* VIDEO PLL output = PLL output frequency / POSTDIV. */
  576. /*
  577. * Post divider:
  578. *
  579. * PLL_VIDEO[POST_DIV_SELECT]:
  580. * 0x00: 4
  581. * 0x01: 2
  582. * 0x02: 1
  583. *
  584. * MISC2[VIDEO_DIV]:
  585. * 0x00: 1
  586. * 0x01: 2
  587. * 0x02: 1
  588. * 0x03: 4
  589. */
  590. switch (CCM_ANALOG->PLL_VIDEO & CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT_MASK)
  591. {
  592. case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(0U):
  593. freq = freq >> 2U;
  594. break;
  595. case CCM_ANALOG_PLL_VIDEO_POST_DIV_SELECT(1U):
  596. freq = freq >> 1U;
  597. break;
  598. default:
  599. break;
  600. }
  601. switch (CCM_ANALOG->MISC2 & CCM_ANALOG_MISC2_VIDEO_DIV_MASK)
  602. {
  603. case CCM_ANALOG_MISC2_VIDEO_DIV(3):
  604. freq >>= 2U;
  605. break;
  606. case CCM_ANALOG_MISC2_VIDEO_DIV(1):
  607. freq >>= 1U;
  608. break;
  609. default:
  610. break;
  611. }
  612. break;
  613. case kCLOCK_PllEnet0:
  614. divSelect = (CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_ENET0_DIV_SELECT_MASK)
  615. >> CCM_ANALOG_PLL_ENET_ENET0_DIV_SELECT_SHIFT;
  616. freq = enetRefClkFreq[divSelect];
  617. break;
  618. case kCLOCK_PllEnet1:
  619. divSelect = (CCM_ANALOG->PLL_ENET & CCM_ANALOG_PLL_ENET_ENET1_DIV_SELECT_MASK)
  620. >> CCM_ANALOG_PLL_ENET_ENET1_DIV_SELECT_SHIFT;
  621. freq = enetRefClkFreq[divSelect];
  622. break;
  623. case kCLOCK_PllEnet2:
  624. /* ref_enetpll2 if fixed at 25MHz. */
  625. freq = 25000000UL;
  626. break;
  627. case kCLOCK_PllUsb2:
  628. freq = (CLOCK_GetOscFreq() * ((CCM_ANALOG->PLL_USB2 & CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK) ? 22U : 20U));
  629. break;
  630. default:
  631. freq = 0U;
  632. break;
  633. }
  634. return freq;
  635. }
  636. void CLOCK_InitSysPfd(clock_pfd_t pfd, uint8_t pfdFrac)
  637. {
  638. uint32_t pfdIndex = (uint32_t)pfd;
  639. uint32_t pfd528;
  640. pfd528 = CCM_ANALOG->PFD_528 & ~((CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK | CCM_ANALOG_PFD_528_PFD0_FRAC_MASK) << (8 * pfdIndex));
  641. /* Disable the clock output first. */
  642. CCM_ANALOG->PFD_528 = pfd528 | (CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8 * pfdIndex));
  643. /* Set the new value and enable output. */
  644. CCM_ANALOG->PFD_528 = pfd528 | (CCM_ANALOG_PFD_528_PFD0_FRAC(pfdFrac) << (8 * pfdIndex));
  645. }
  646. void CLOCK_DeinitSysPfd(clock_pfd_t pfd)
  647. {
  648. CCM_ANALOG->PFD_528 |= CCM_ANALOG_PFD_528_PFD0_CLKGATE_MASK << (8 * pfd);
  649. }
  650. void CLOCK_InitUsb1Pfd(clock_pfd_t pfd, uint8_t pfdFrac)
  651. {
  652. uint32_t pfdIndex = (uint32_t)pfd;
  653. uint32_t pfd480;
  654. pfd480 = CCM_ANALOG->PFD_480 & ~((CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK | CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) << (8 * pfdIndex));
  655. /* Disable the clock output first. */
  656. CCM_ANALOG->PFD_480 = pfd480 | (CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8 * pfdIndex));
  657. /* Set the new value and enable output. */
  658. CCM_ANALOG->PFD_480 = pfd480 | (CCM_ANALOG_PFD_480_PFD0_FRAC(pfdFrac) << (8 * pfdIndex));
  659. }
  660. void CLOCK_DeinitUsb1Pfd(clock_pfd_t pfd)
  661. {
  662. CCM_ANALOG->PFD_480 |= CCM_ANALOG_PFD_480_PFD0_CLKGATE_MASK << (8 * pfd);
  663. }
  664. uint32_t CLOCK_GetSysPfdFreq(clock_pfd_t pfd)
  665. {
  666. uint32_t freq = CLOCK_GetPllFreq(kCLOCK_PllSys);
  667. switch (pfd)
  668. {
  669. case kCLOCK_Pfd0:
  670. freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD0_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD0_FRAC_SHIFT);
  671. break;
  672. case kCLOCK_Pfd1:
  673. freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD1_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD1_FRAC_SHIFT);
  674. break;
  675. case kCLOCK_Pfd2:
  676. freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD2_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD2_FRAC_SHIFT);
  677. break;
  678. case kCLOCK_Pfd3:
  679. freq /= ((CCM_ANALOG->PFD_528 & CCM_ANALOG_PFD_528_PFD3_FRAC_MASK) >> CCM_ANALOG_PFD_528_PFD3_FRAC_SHIFT);
  680. break;
  681. default:
  682. freq = 0U;
  683. break;
  684. }
  685. freq *= 18U;
  686. return freq;
  687. }
  688. uint32_t CLOCK_GetUsb1PfdFreq(clock_pfd_t pfd)
  689. {
  690. uint32_t freq = CLOCK_GetPllFreq(kCLOCK_PllUsb1);
  691. switch (pfd)
  692. {
  693. case kCLOCK_Pfd0:
  694. freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD0_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD0_FRAC_SHIFT);
  695. break;
  696. case kCLOCK_Pfd1:
  697. freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD1_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD1_FRAC_SHIFT);
  698. break;
  699. case kCLOCK_Pfd2:
  700. freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD2_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD2_FRAC_SHIFT);
  701. break;
  702. case kCLOCK_Pfd3:
  703. freq /= ((CCM_ANALOG->PFD_480 & CCM_ANALOG_PFD_480_PFD3_FRAC_MASK) >> CCM_ANALOG_PFD_480_PFD3_FRAC_SHIFT);
  704. break;
  705. default:
  706. freq = 0U;
  707. break;
  708. }
  709. freq *= 18U;
  710. return freq;
  711. }
  712. bool CLOCK_EnableUsbhs0Clock(clock_usb_src_t src, uint32_t freq)
  713. {
  714. CCM->CCGR6 |= CCM_CCGR6_CG0_MASK ;
  715. USB1->USBCMD |= USBHS_USBCMD_RST_MASK;
  716. PMU->REG_3P0 = (PMU->REG_3P0 & (~PMU_REG_3P0_OUTPUT_TRG_MASK)) | (PMU_REG_3P0_OUTPUT_TRG(0x17) | PMU_REG_3P0_ENABLE_LINREG_MASK);
  717. return true;
  718. }
  719. bool CLOCK_EnableUsbhs1Clock(clock_usb_src_t src, uint32_t freq)
  720. {
  721. CCM->CCGR6 |= CCM_CCGR6_CG0_MASK ;
  722. USB1->USBCMD |= USBHS_USBCMD_RST_MASK;
  723. PMU->REG_3P0 = (PMU->REG_3P0 & (~PMU_REG_3P0_OUTPUT_TRG_MASK)) | (PMU_REG_3P0_OUTPUT_TRG(0x17) | PMU_REG_3P0_ENABLE_LINREG_MASK);
  724. return true;
  725. }
  726. bool CLOCK_EnableUsbhs0PhyPllClock(clock_usb_phy_src_t src, uint32_t freq)
  727. {
  728. const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U};
  729. CLOCK_InitUsb1Pll(&g_ccmConfigUsbPll);
  730. USBPHY1->CTRL &= ~USBPHY_CTRL_SFTRST_MASK; /* release PHY from reset */
  731. USBPHY1->CTRL &= ~USBPHY_CTRL_CLKGATE_MASK;
  732. USBPHY1->PWD = 0;
  733. USBPHY1->CTRL |=
  734. USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK |
  735. USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK |
  736. USBPHY_CTRL_ENUTMILEVEL2_MASK |
  737. USBPHY_CTRL_ENUTMILEVEL3_MASK;
  738. return true;
  739. }
  740. bool CLOCK_EnableUsbhs1PhyPllClock(clock_usb_phy_src_t src, uint32_t freq)
  741. {
  742. const clock_usb_pll_config_t g_ccmConfigUsbPll = {.loopDivider = 0U};
  743. CLOCK_InitUsb2Pll(&g_ccmConfigUsbPll);
  744. USBPHY2->CTRL &= ~USBPHY_CTRL_SFTRST_MASK; /* release PHY from reset */
  745. USBPHY2->CTRL &= ~USBPHY_CTRL_CLKGATE_MASK;
  746. USBPHY2->PWD = 0;
  747. USBPHY2->CTRL |=
  748. USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK |
  749. USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK |
  750. USBPHY_CTRL_ENUTMILEVEL2_MASK |
  751. USBPHY_CTRL_ENUTMILEVEL3_MASK;
  752. return true;
  753. }
  754. void CLOCK_DisableUsbhs0PhyPllClock(void)
  755. {
  756. CLOCK_DeinitUsb1Pll();
  757. USBPHY1->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* Set to 1U to gate clocks */
  758. }
  759. void CLOCK_DisableUsbhs1PhyPllClock(void)
  760. {
  761. CLOCK_DeinitUsb2Pll();
  762. USBPHY2->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* Set to 1U to gate clocks */
  763. }