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