fsl_clock.c 30 KB

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