pm_conf_clocks.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*****************************************************************************
  2. *
  3. * \file
  4. *
  5. * \brief Power Manager clocks configuration helper.
  6. *
  7. * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
  8. *
  9. * \asf_license_start
  10. *
  11. * \page License
  12. *
  13. * Subject to your compliance with these terms, you may use Microchip
  14. * software and any derivatives exclusively with Microchip products.
  15. * It is your responsibility to comply with third party license terms applicable
  16. * to your use of third party software (including open source software) that
  17. * may accompany Microchip software.
  18. *
  19. * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
  20. * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
  21. * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
  22. * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
  23. * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
  24. * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
  25. * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
  26. * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT
  27. * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
  28. * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
  29. * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
  30. *
  31. * \asf_license_stop
  32. *
  33. *****************************************************************************/
  34. /*
  35. * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
  36. */
  37. #include <string.h>
  38. #include "compiler.h"
  39. #include "pm.h"
  40. extern void flashc_set_wait_state(unsigned int wait_state);
  41. #if (defined AVR32_FLASHC_210_H_INCLUDED)
  42. extern void flashc_issue_command(unsigned int command, int page_number);
  43. #endif
  44. #define PM_MAX_MUL ((1 << AVR32_PM_PLL0_PLLMUL_SIZE) - 1)
  45. int pm_configure_clocks(pm_freq_param_t *param)
  46. {
  47. // Supported frequencies:
  48. // Fosc0 mul div PLL div2_en cpu_f pba_f Comment
  49. // 12 15 1 192 1 12 12
  50. // 12 9 3 40 1 20 20 PLL out of spec
  51. // 12 15 1 192 1 24 12
  52. // 12 9 1 120 1 30 15
  53. // 12 9 3 40 0 40 20 PLL out of spec
  54. // 12 15 1 192 1 48 12
  55. // 12 15 1 192 1 48 24
  56. // 12 8 1 108 1 54 27
  57. // 12 9 1 120 1 60 15
  58. // 12 9 1 120 1 60 30
  59. // 12 10 1 132 1 66 16.5
  60. //
  61. unsigned long in_cpu_f = param->cpu_f;
  62. unsigned long in_osc0_f = param->osc0_f;
  63. unsigned long mul, div, div2_en = 0, div2_cpu = 0, div2_pba = 0;
  64. unsigned long pll_freq, rest;
  65. bool b_div2_pba, b_div2_cpu;
  66. // Switch to external Oscillator 0
  67. pm_switch_to_osc0(&AVR32_PM, in_osc0_f, param->osc0_startup);
  68. // Start with CPU freq config
  69. if (in_cpu_f == in_osc0_f)
  70. {
  71. param->cpu_f = in_osc0_f;
  72. param->pba_f = in_osc0_f;
  73. return PM_FREQ_STATUS_OK;
  74. }
  75. else if (in_cpu_f < in_osc0_f)
  76. {
  77. // TBD
  78. }
  79. rest = in_cpu_f % in_osc0_f;
  80. for (div = 1; div < 32; div++)
  81. {
  82. if ((div * rest) % in_osc0_f == 0)
  83. break;
  84. }
  85. if (div == 32)
  86. return PM_FREQ_STATUS_FAIL;
  87. mul = (in_cpu_f * div) / in_osc0_f;
  88. if (mul > PM_MAX_MUL)
  89. return PM_FREQ_STATUS_FAIL;
  90. // export 2power from PLL div to div2_cpu
  91. while (!(div % 2))
  92. {
  93. div /= 2;
  94. div2_cpu++;
  95. }
  96. // Here we know the mul and div parameter of the PLL config.
  97. // . Check out if the PLL has a valid in_cpu_f.
  98. // . Try to have for the PLL frequency (VCO output) the highest possible value
  99. // to reduce jitter.
  100. while (in_osc0_f * 2 * mul / div < AVR32_PM_PLL_VCO_RANGE0_MAX_FREQ)
  101. {
  102. if (2 * mul > PM_MAX_MUL)
  103. break;
  104. mul *= 2;
  105. div2_cpu++;
  106. }
  107. if (div2_cpu != 0)
  108. {
  109. div2_cpu--;
  110. div2_en = 1;
  111. }
  112. pll_freq = in_osc0_f * mul / (div * (1 << div2_en));
  113. // Update real CPU Frequency
  114. param->cpu_f = pll_freq / (1 << div2_cpu);
  115. mul--;
  116. pm_pll_setup(&AVR32_PM
  117. , 0 // pll
  118. , mul // mul
  119. , div // div
  120. , 0 // osc
  121. , 16 // lockcount
  122. );
  123. pm_pll_set_option(&AVR32_PM
  124. , 0 // pll
  125. // PLL clock is lower than 160MHz: need to set pllopt.
  126. , (pll_freq < AVR32_PM_PLL_VCO_RANGE0_MIN_FREQ) ? 1 : 0 // pll_freq
  127. , div2_en // pll_div2
  128. , 0 // pll_wbwdisable
  129. );
  130. rest = pll_freq;
  131. while (rest > AVR32_PM_PBA_MAX_FREQ ||
  132. rest != param->pba_f)
  133. {
  134. div2_pba++;
  135. rest = pll_freq / (1 << div2_pba);
  136. if (rest < param->pba_f)
  137. break;
  138. }
  139. // Update real PBA Frequency
  140. param->pba_f = pll_freq / (1 << div2_pba);
  141. // Enable PLL0
  142. pm_pll_enable(&AVR32_PM, 0);
  143. // Wait for PLL0 locked
  144. pm_wait_for_pll0_locked(&AVR32_PM);
  145. if (div2_cpu)
  146. {
  147. b_div2_cpu = true;
  148. div2_cpu--;
  149. }
  150. else
  151. b_div2_cpu = false;
  152. if (div2_pba)
  153. {
  154. b_div2_pba = true;
  155. div2_pba--;
  156. }
  157. else
  158. b_div2_pba = false;
  159. pm_cksel(&AVR32_PM
  160. , b_div2_pba, div2_pba // PBA
  161. , b_div2_cpu, div2_cpu // PBB
  162. , b_div2_cpu, div2_cpu // HSB
  163. );
  164. if (param->cpu_f > AVR32_FLASHC_FWS_0_MAX_FREQ)
  165. {
  166. flashc_set_wait_state(1);
  167. #if (defined AVR32_FLASHC_210_H_INCLUDED)
  168. if (param->cpu_f > AVR32_FLASHC_HSEN_FWS_1_MAX_FREQ)
  169. flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSEN, -1);
  170. else
  171. flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSDIS, -1);
  172. #endif
  173. }
  174. else
  175. {
  176. flashc_set_wait_state(0);
  177. #if (defined AVR32_FLASHC_210_H_INCLUDED)
  178. if (param->cpu_f > AVR32_FLASHC_HSEN_FWS_0_MAX_FREQ)
  179. flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSEN, -1);
  180. else
  181. flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSDIS, -1);
  182. #endif
  183. }
  184. pm_switch_to_clock(&AVR32_PM, AVR32_PM_MCCTRL_MCSEL_PLL0);
  185. return PM_FREQ_STATUS_OK;
  186. }
  187. void pm_configure_usb_clock(void)
  188. {
  189. #if UC3A3
  190. // Setup USB GCLK.
  191. pm_gc_setup(&AVR32_PM, AVR32_PM_GCLK_USBB, // gc
  192. 0, // osc_or_pll: use Osc (if 0) or PLL (if 1)
  193. 0, // pll_osc: select Osc0/PLL0 or Osc1/PLL1
  194. 0, // diven
  195. 0); // div
  196. // Enable USB GCLK.
  197. pm_gc_enable(&AVR32_PM, AVR32_PM_GCLK_USBB);
  198. #else
  199. // Use 12MHz from OSC0 and generate 96 MHz
  200. pm_pll_setup(&AVR32_PM, 1, // pll.
  201. 7, // mul.
  202. 1, // div.
  203. 0, // osc.
  204. 16); // lockcount.
  205. pm_pll_set_option(&AVR32_PM, 1, // pll.
  206. 1, // pll_freq: choose the range 80-180MHz.
  207. 1, // pll_div2.
  208. 0); // pll_wbwdisable.
  209. // start PLL1 and wait forl lock
  210. pm_pll_enable(&AVR32_PM, 1);
  211. // Wait for PLL1 locked.
  212. pm_wait_for_pll1_locked(&AVR32_PM);
  213. pm_gc_setup(&AVR32_PM, AVR32_PM_GCLK_USBB, // gc.
  214. 1, // osc_or_pll: use Osc (if 0) or PLL (if 1).
  215. 1, // pll_osc: select Osc0/PLL0 or Osc1/PLL1.
  216. 0, // diven.
  217. 0); // div.
  218. pm_gc_enable(&AVR32_PM, AVR32_PM_GCLK_USBB);
  219. #endif
  220. }