pm_conf_clocks.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /* This source file is part of the ATMEL AVR-UC3-SoftwareFramework-1.7.0 Release */
  2. /*This file has been prepared for Doxygen automatic documentation generation.*/
  3. /*! \file *********************************************************************
  4. *
  5. * \brief Power Manager clocks configuration helper.
  6. *
  7. *
  8. * - Compiler: IAR EWAVR32 and GNU GCC for AVR32
  9. * - Supported devices: All AVR32 devices.
  10. * - AppNote:
  11. *
  12. * \author Atmel Corporation: http://www.atmel.com \n
  13. * Support and FAQ: http://support.atmel.no/
  14. *
  15. *****************************************************************************/
  16. /* Copyright (c) 2009 Atmel Corporation. All rights reserved.
  17. *
  18. * Redistribution and use in source and binary forms, with or without
  19. * modification, are permitted provided that the following conditions are met:
  20. *
  21. * 1. Redistributions of source code must retain the above copyright notice, this
  22. * list of conditions and the following disclaimer.
  23. *
  24. * 2. Redistributions in binary form must reproduce the above copyright notice,
  25. * this list of conditions and the following disclaimer in the documentation
  26. * and/or other materials provided with the distribution.
  27. *
  28. * 3. The name of Atmel may not be used to endorse or promote products derived
  29. * from this software without specific prior written permission.
  30. *
  31. * 4. This software may only be redistributed and used in connection with an Atmel
  32. * AVR product.
  33. *
  34. * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
  35. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  36. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
  37. * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
  38. * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  39. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  40. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  41. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  42. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  43. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
  44. *
  45. */
  46. #include <string.h>
  47. #include "compiler.h"
  48. #include "pm.h"
  49. extern void flashc_set_wait_state(unsigned int wait_state);
  50. #if (defined AVR32_FLASHC_210_H_INCLUDED)
  51. extern void flashc_issue_command(unsigned int command, int page_number);
  52. #endif
  53. #define PM_MAX_MUL ((1 << AVR32_PM_PLL0_PLLMUL_SIZE) - 1)
  54. int pm_configure_clocks(pm_freq_param_t *param)
  55. {
  56. // Supported frequencies:
  57. // Fosc0 mul div PLL div2_en cpu_f pba_f Comment
  58. // 12 15 1 192 1 12 12
  59. // 12 9 3 40 1 20 20 PLL out of spec
  60. // 12 15 1 192 1 24 12
  61. // 12 9 1 120 1 30 15
  62. // 12 9 3 40 0 40 20 PLL out of spec
  63. // 12 15 1 192 1 48 12
  64. // 12 15 1 192 1 48 24
  65. // 12 8 1 108 1 54 27
  66. // 12 9 1 120 1 60 15
  67. // 12 9 1 120 1 60 30
  68. // 12 10 1 132 1 66 16.5
  69. //
  70. unsigned long in_cpu_f = param->cpu_f;
  71. unsigned long in_osc0_f = param->osc0_f;
  72. unsigned long mul, div, div2_en = 0, div2_cpu = 0, div2_pba = 0;
  73. unsigned long pll_freq, rest;
  74. Bool b_div2_pba, b_div2_cpu;
  75. // Switch to external Oscillator 0
  76. pm_switch_to_osc0(&AVR32_PM, in_osc0_f, param->osc0_startup);
  77. // Start with CPU freq config
  78. if (in_cpu_f == in_osc0_f)
  79. {
  80. param->cpu_f = in_osc0_f;
  81. param->pba_f = in_osc0_f;
  82. return PM_FREQ_STATUS_OK;
  83. }
  84. else if (in_cpu_f < in_osc0_f)
  85. {
  86. // TBD
  87. }
  88. rest = in_cpu_f % in_osc0_f;
  89. for (div = 1; div < 32; div++)
  90. {
  91. if ((div * rest) % in_osc0_f == 0)
  92. break;
  93. }
  94. if (div == 32)
  95. return PM_FREQ_STATUS_FAIL;
  96. mul = (in_cpu_f * div) / in_osc0_f;
  97. if (mul > PM_MAX_MUL)
  98. return PM_FREQ_STATUS_FAIL;
  99. // export 2power from PLL div to div2_cpu
  100. while (!(div % 2))
  101. {
  102. div /= 2;
  103. div2_cpu++;
  104. }
  105. // Here we know the mul and div parameter of the PLL config.
  106. // . Check out if the PLL has a valid in_cpu_f.
  107. // . Try to have for the PLL frequency (VCO output) the highest possible value
  108. // to reduce jitter.
  109. while (in_osc0_f * 2 * mul / div < AVR32_PM_PLL_VCO_RANGE0_MAX_FREQ)
  110. {
  111. if (2 * mul > PM_MAX_MUL)
  112. break;
  113. mul *= 2;
  114. div2_cpu++;
  115. }
  116. if (div2_cpu != 0)
  117. {
  118. div2_cpu--;
  119. div2_en = 1;
  120. }
  121. pll_freq = in_osc0_f * mul / (div * (1 << div2_en));
  122. // Update real CPU Frequency
  123. param->cpu_f = pll_freq / (1 << div2_cpu);
  124. mul--;
  125. pm_pll_setup(&AVR32_PM
  126. , 0 // pll
  127. , mul // mul
  128. , div // div
  129. , 0 // osc
  130. , 16 // lockcount
  131. );
  132. pm_pll_set_option(&AVR32_PM
  133. , 0 // pll
  134. // PLL clock is lower than 160MHz: need to set pllopt.
  135. , (pll_freq < AVR32_PM_PLL_VCO_RANGE0_MIN_FREQ) ? 1 : 0 // pll_freq
  136. , div2_en // pll_div2
  137. , 0 // pll_wbwdisable
  138. );
  139. rest = pll_freq;
  140. while (rest > AVR32_PM_PBA_MAX_FREQ ||
  141. rest != param->pba_f)
  142. {
  143. div2_pba++;
  144. rest = pll_freq / (1 << div2_pba);
  145. if (rest < param->pba_f)
  146. break;
  147. }
  148. // Update real PBA Frequency
  149. param->pba_f = pll_freq / (1 << div2_pba);
  150. // Enable PLL0
  151. pm_pll_enable(&AVR32_PM, 0);
  152. // Wait for PLL0 locked
  153. pm_wait_for_pll0_locked(&AVR32_PM);
  154. if (div2_cpu)
  155. {
  156. b_div2_cpu = TRUE;
  157. div2_cpu--;
  158. }
  159. else
  160. b_div2_cpu = FALSE;
  161. if (div2_pba)
  162. {
  163. b_div2_pba = TRUE;
  164. div2_pba--;
  165. }
  166. else
  167. b_div2_pba = FALSE;
  168. pm_cksel(&AVR32_PM
  169. , b_div2_pba, div2_pba // PBA
  170. , b_div2_cpu, div2_cpu // PBB
  171. , b_div2_cpu, div2_cpu // HSB
  172. );
  173. if (param->cpu_f > AVR32_FLASHC_FWS_0_MAX_FREQ)
  174. {
  175. flashc_set_wait_state(1);
  176. #if (defined AVR32_FLASHC_210_H_INCLUDED)
  177. if (param->cpu_f > AVR32_FLASHC_HSEN_FWS_1_MAX_FREQ)
  178. flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSEN, -1);
  179. else
  180. flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSDIS, -1);
  181. #endif
  182. }
  183. else
  184. {
  185. flashc_set_wait_state(0);
  186. #if (defined AVR32_FLASHC_210_H_INCLUDED)
  187. if (param->cpu_f > AVR32_FLASHC_HSEN_FWS_0_MAX_FREQ)
  188. flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSEN, -1);
  189. else
  190. flashc_issue_command(AVR32_FLASHC_FCMD_CMD_HSDIS, -1);
  191. #endif
  192. }
  193. pm_switch_to_clock(&AVR32_PM, AVR32_PM_MCCTRL_MCSEL_PLL0);
  194. return PM_FREQ_STATUS_OK;
  195. }
  196. void pm_configure_usb_clock(void)
  197. {
  198. #if UC3A3
  199. // Setup USB GCLK.
  200. pm_gc_setup(&AVR32_PM, AVR32_PM_GCLK_USBB, // gc
  201. 0, // osc_or_pll: use Osc (if 0) or PLL (if 1)
  202. 0, // pll_osc: select Osc0/PLL0 or Osc1/PLL1
  203. 0, // diven
  204. 0); // div
  205. // Enable USB GCLK.
  206. pm_gc_enable(&AVR32_PM, AVR32_PM_GCLK_USBB);
  207. #else
  208. // Use 12MHz from OSC0 and generate 96 MHz
  209. pm_pll_setup(&AVR32_PM, 1, // pll.
  210. 7, // mul.
  211. 1, // div.
  212. 0, // osc.
  213. 16); // lockcount.
  214. pm_pll_set_option(&AVR32_PM, 1, // pll.
  215. 1, // pll_freq: choose the range 80-180MHz.
  216. 1, // pll_div2.
  217. 0); // pll_wbwdisable.
  218. // start PLL1 and wait forl lock
  219. pm_pll_enable(&AVR32_PM, 1);
  220. // Wait for PLL1 locked.
  221. pm_wait_for_pll1_locked(&AVR32_PM);
  222. pm_gc_setup(&AVR32_PM, AVR32_PM_GCLK_USBB, // gc.
  223. 1, // osc_or_pll: use Osc (if 0) or PLL (if 1).
  224. 1, // pll_osc: select Osc0/PLL0 or Osc1/PLL1.
  225. 0, // diven.
  226. 0); // div.
  227. pm_gc_enable(&AVR32_PM, AVR32_PM_GCLK_USBB);
  228. #endif
  229. }