You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

203 rivejä
6.0 KiB

  1. /** @defgroup ccm_file CCM
  2. *
  3. * @ingroup VF6xx
  4. *
  5. * @section vf6xx_ccm_api_ex Clock Controller Module API.
  6. *
  7. * @brief <b>VF6xx Clock Controller Module</b>
  8. *
  9. * @author @htmlonly &copy; @endhtmlonly 2014 Stefan Agner <stefan@agner.ch>
  10. *
  11. * @date 30 Jun 2014
  12. *
  13. * This library supports the Clock Controller Module in the VF6xx SoCs
  14. * by Freescale.
  15. *
  16. * LGPL License Terms @ref lgpl_license
  17. */
  18. /*
  19. * This file is part of the libopencm3 project.
  20. *
  21. * Copyright (C) 2014 Stefan Agner <stefan@agner.ch>
  22. *
  23. * This library is free software: you can redistribute it and/or modify
  24. * it under the terms of the GNU Lesser General Public License as published by
  25. * the Free Software Foundation, either version 3 of the License, or
  26. * (at your option) any later version.
  27. *
  28. * This library is distributed in the hope that it will be useful,
  29. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  31. * GNU Lesser General Public License for more details.
  32. *
  33. * You should have received a copy of the GNU Lesser General Public License
  34. * along with this library. If not, see <http://www.gnu.org/licenses/>.
  35. */
  36. #include <libopencm3/vf6xx/memorymap.h>
  37. #include <libopencm3/vf6xx/ccm.h>
  38. #include <libopencm3/vf6xx/anadig.h>
  39. /**@{*/
  40. static const uint32_t pll1_main_clk = 528000000;
  41. static const uint32_t pll2_main_clk = 528000000;
  42. static const uint32_t pll3_main_clk = 480000000;
  43. /* ARM Cortex-A5 clock, core clock */
  44. uint32_t ccm_core_clk;
  45. /* Platform bus clock and Cortex-M4 core clock */
  46. uint32_t ccm_platform_bus_clk;
  47. /* IPS bus clock */
  48. uint32_t ccm_ipg_bus_clk;
  49. uint32_t ccm_get_pll_pfd(uint32_t pfd_sel, uint32_t pll_pfd, uint32_t pll_clk);
  50. /*---------------------------------------------------------------------------*/
  51. /** @brief Enable clock of given device
  52. This enables (gates) the clock for the given device.
  53. @param[in] gr enum ccm_clock_gate. Device
  54. */
  55. void ccm_clock_gate_enable(enum ccm_clock_gate gr)
  56. {
  57. uint32_t offset = (uint32_t)gr / 16;
  58. uint32_t gr_mask = 0x3 << ((gr % 16) * 2);
  59. CCM_CCGR(offset * 4) |= gr_mask;
  60. }
  61. /*---------------------------------------------------------------------------*/
  62. /** @brief Disable clock of given device
  63. This disables (ungates) the clock for the given device.
  64. @param[in] gr enum ccm_clock_gate. Device
  65. */
  66. void ccm_clock_gate_disable(enum ccm_clock_gate gr)
  67. {
  68. uint32_t offset = (uint32_t)gr / 16;
  69. uint32_t gr_mask = 0x3 << ((gr % 16) * 2);
  70. CCM_CCGR(offset * 4) &= ~gr_mask;
  71. }
  72. /*---------------------------------------------------------------------------*/
  73. /** @brief Calculate PFD clock
  74. This function calculates the PFD clock for PLL1/2 or 3. All those PLLs
  75. have the same PFD clock muxing/calculating logic, hence we can use one
  76. function for all of them
  77. @param[in] pfd_sel uint32_t. The PFD selection (muxing) value
  78. @param[in] pll_pfd uint32_t. The ANADIG PFD register containing the fractions
  79. for all possible PFDs
  80. @param[in] pll_clk uint32_t. PLLs main clock (which the PFDs are derived from)
  81. */
  82. uint32_t ccm_get_pll_pfd(uint32_t pfd_sel, uint32_t pll_pfd, uint32_t pll_clk)
  83. {
  84. uint64_t pll_pfd_clk;
  85. uint32_t pll_pfd_frac = pll_pfd;
  86. switch (pfd_sel) {
  87. case CCM_CCSR_PLL_PFD_CLK_SEL_MAIN:
  88. return pll_clk;
  89. case CCM_CCSR_PLL_PFD_CLK_SEL_PFD1:
  90. pll_pfd_frac &= ANADIG_PLL_PFD1_FRAC_MASK;
  91. pll_pfd_frac >>= ANADIG_PLL_PFD1_FRAC_SHIFT;
  92. break;
  93. case CCM_CCSR_PLL_PFD_CLK_SEL_PFD2:
  94. pll_pfd_frac &= ANADIG_PLL_PFD2_FRAC_MASK;
  95. pll_pfd_frac >>= ANADIG_PLL_PFD2_FRAC_SHIFT;
  96. break;
  97. case CCM_CCSR_PLL_PFD_CLK_SEL_PFD3:
  98. pll_pfd_frac &= ANADIG_PLL_PFD3_FRAC_MASK;
  99. pll_pfd_frac >>= ANADIG_PLL_PFD3_FRAC_SHIFT;
  100. break;
  101. case CCM_CCSR_PLL_PFD_CLK_SEL_PFD4:
  102. pll_pfd_frac &= ANADIG_PLL_PFD4_FRAC_MASK;
  103. pll_pfd_frac >>= ANADIG_PLL_PFD4_FRAC_SHIFT;
  104. break;
  105. }
  106. /* Calculate using to PLL PFD fraction */
  107. pll_pfd_clk = pll_clk;
  108. pll_pfd_clk *= 18;
  109. pll_pfd_clk /= pll_pfd_frac;
  110. return (uint32_t)pll_pfd_clk;
  111. }
  112. /*---------------------------------------------------------------------------*/
  113. /** @brief Calculate clocks
  114. This function calculates the root clocks from the registers. On Vybrid, we
  115. assume that the clocks/device is setup by the main operating system running
  116. on the Cortex-A5 (for instance Linux). However, in order to calculate clocks
  117. for peripherals its important to know the current value of those clocks.
  118. This are mainly the @ref ccm_core_clk which the Cortex-A5 is running with
  119. and lots of other clocks derive from.
  120. The @ref ccm_platform_bus_clk is the clock which the Cortex-M4 is running
  121. with.
  122. And the @ref ccm_ipg_bus_clk is the clock most peripherals run with.
  123. */
  124. void ccm_calculate_clocks()
  125. {
  126. uint32_t ccsr = CCM_CCSR;
  127. uint32_t cacrr = CCM_CACRR;
  128. uint32_t arm_clk_div = (cacrr & CCM_CACRR_ARM_CLK_DIV_MASK) + 1;
  129. uint32_t bus_clk_div = cacrr & CCM_CACRR_BUS_CLK_DIV_MASK;
  130. uint32_t ipg_clk_div = cacrr & CCM_CACRR_IPG_CLK_DIV_MASK;
  131. uint32_t pll_pfd_sel;
  132. bus_clk_div >>= CCM_CACRR_BUS_CLK_DIV_SHIFT;
  133. bus_clk_div += 1;
  134. ipg_clk_div >>= CCM_CACRR_IPG_CLK_DIV_SHIFT;
  135. ipg_clk_div += 1;
  136. /* Get Cortex-A5 core clock from system clock selection */
  137. switch (ccsr & CCM_CCSR_SYS_CLK_SEL_MASK) {
  138. case CCM_CCSR_SYS_CLK_SEL_FAST:
  139. ccm_core_clk = 24000000;
  140. break;
  141. case CCM_CCSR_SYS_CLK_SEL_SLOW:
  142. ccm_core_clk = 32000;
  143. break;
  144. case CCM_CCSR_SYS_CLK_SEL_PLL2_PFD:
  145. pll_pfd_sel = ccsr & CCM_CCSR_PLL2_PFD_CLK_SEL_MASK;
  146. pll_pfd_sel >>= CCM_CCSR_PLL2_PFD_CLK_SEL_SHIFT;
  147. ccm_core_clk = ccm_get_pll_pfd(pll_pfd_sel, ANADIG_PLL2_PFD,
  148. pll2_main_clk);
  149. break;
  150. case CCM_CCSR_SYS_CLK_SEL_PLL2:
  151. ccm_core_clk = pll2_main_clk;
  152. break;
  153. case CCM_CCSR_SYS_CLK_SEL_PLL1_PFD:
  154. pll_pfd_sel = ccsr & CCM_CCSR_PLL1_PFD_CLK_SEL_MASK;
  155. pll_pfd_sel >>= CCM_CCSR_PLL1_PFD_CLK_SEL_SHIFT;
  156. ccm_core_clk = ccm_get_pll_pfd(pll_pfd_sel, ANADIG_PLL1_PFD,
  157. pll1_main_clk);
  158. break;
  159. case CCM_CCSR_SYS_CLK_SEL_PLL3:
  160. ccm_core_clk = pll3_main_clk;
  161. break;
  162. }
  163. ccm_core_clk /= arm_clk_div;
  164. ccm_platform_bus_clk = ccm_core_clk / bus_clk_div;
  165. ccm_ipg_bus_clk = ccm_platform_bus_clk / ipg_clk_div;
  166. return;
  167. }
  168. /**@}*/