]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_A5_SAMA5D2x_Xplained_IAR/AtmelFiles/drivers/peripherals/pmc.c
Add SAMA5D2 Xplained IAR demo.
[freertos] / FreeRTOS / Demo / CORTEX_A5_SAMA5D2x_Xplained_IAR / AtmelFiles / drivers / peripherals / pmc.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License\r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2015, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\r
8  * Redistribution and use in source and binary forms, with or without\r
9  * modification, are permitted provided that the following conditions are met:\r
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\r
14  * Atmel's name may not be used to endorse or promote products derived from\r
15  * this software without specific prior written permission.\r
16  *\r
17  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR\r
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE\r
20  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,\r
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\r
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,\r
23  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
25  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
26  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
27  * ----------------------------------------------------------------------------\r
28  */\r
29 \r
30 /** \addtogroup pmc_module Working with PMC\r
31  * \section Purpose\r
32  * The PMC driver provides the Interface for configuration the Power Management\r
33  *  Controller (PMC).\r
34  *\r
35  * \section Usage\r
36  * <ul>\r
37  * <li>  Enable & disable peripherals using pmc_enable_peripheral() and\r
38  * pmc_enable_all_peripherals() or pmc_disable_peripheral() and\r
39  * pmc_disable_all_peripherals().\r
40  * <li>  Get & set maximum frequency clock for giving peripheral using\r
41  * pmc_get_peri_max_freq() and pmc_set_peri_max_clock().\r
42  * <li>  Get Peripheral Status for the given peripheral using pmc_is_periph_enabled()\r
43  * <li>  Select clocks's source using pmc_select_external_crystal(),\r
44  * pmc_select_internal_crystal(), pmc_select_external_osc() and pmc_select_internal_osc().\r
45  * <li>  Switch MCK using pmc_switch_mck_to_pll(), pmc_switch_mck_to_main() and\r
46  * pmc_switch_mck_to_slck().\r
47  * <li>  Config PLL using pmc_set_pll_a() and pmc_disable_pll_a().\r
48  * </li>\r
49  * </ul>\r
50  * For more accurate information, please look at the PMC section of the\r
51  * Datasheet.\r
52  *\r
53  * Related files :\n\r
54  * \ref pmc.c\n\r
55  * \ref pmc.h\n\r
56 */\r
57 /*@{*/\r
58 /*@}*/\r
59 \r
60 /**\r
61  * \file\r
62  *\r
63  * Implementation of PIO (Parallel Input/Output) controller.\r
64  *\r
65  */\r
66 /*----------------------------------------------------------------------------\r
67  *        Headers\r
68  *----------------------------------------------------------------------------*/\r
69 \r
70 #include "chip.h"\r
71 #include "board.h"\r
72 #include "peripherals/pmc.h"\r
73 #include "trace.h"\r
74 #include <assert.h>\r
75 \r
76 /*----------------------------------------------------------------------------\r
77  *        Variables\r
78  *----------------------------------------------------------------------------*/\r
79 \r
80 static uint32_t _pmc_mck = 0;\r
81 \r
82 /*----------------------------------------------------------------------------\r
83  *        Private functions\r
84  *----------------------------------------------------------------------------*/\r
85 \r
86 static void _pmc_compute_mck(void)\r
87 {\r
88         uint32_t clk = 0;\r
89         uint32_t mckr = PMC->PMC_MCKR;\r
90 \r
91         uint32_t css = mckr & PMC_MCKR_CSS_Msk;\r
92         switch (css) {\r
93         case PMC_MCKR_CSS_SLOW_CLK:\r
94                 clk = pmc_get_slow_clock();\r
95                 break;\r
96         case PMC_MCKR_CSS_MAIN_CLK:\r
97                 clk = pmc_get_main_clock();\r
98                 break;\r
99         case PMC_MCKR_CSS_PLLA_CLK:\r
100                 clk = pmc_get_plla_clock();\r
101                 break;\r
102         case PMC_MCKR_CSS_UPLL_CLK:\r
103                 clk = pmc_get_upll_clock();\r
104                 break;\r
105         default:\r
106                 /* should never get here... */\r
107                 break;\r
108         }\r
109 \r
110         uint32_t pres = mckr & PMC_MCKR_PRES_Msk;\r
111         switch (pres) {\r
112         case PMC_MCKR_PRES_CLOCK:\r
113                 break;\r
114         case PMC_MCKR_PRES_CLOCK_DIV2:\r
115                 clk >>= 1;\r
116                 break;\r
117         case PMC_MCKR_PRES_CLOCK_DIV4:\r
118                 clk >>= 2;\r
119                 break;\r
120         case PMC_MCKR_PRES_CLOCK_DIV8:\r
121                 clk >>= 3;\r
122                 break;\r
123         case PMC_MCKR_PRES_CLOCK_DIV16:\r
124                 clk >>= 4;\r
125                 break;\r
126         case PMC_MCKR_PRES_CLOCK_DIV32:\r
127                 clk >>= 5;\r
128                 break;\r
129         case PMC_MCKR_PRES_CLOCK_DIV64:\r
130                 clk >>= 6;\r
131                 break;\r
132         default:\r
133                 /* should never get here... */\r
134                 break;\r
135         }\r
136 \r
137         uint32_t mdiv = mckr & PMC_MCKR_MDIV_Msk;\r
138         switch (mdiv) {\r
139         case PMC_MCKR_MDIV_EQ_PCK:\r
140                 break;\r
141         case PMC_MCKR_MDIV_PCK_DIV2:\r
142                 clk >>= 1; // divide by 2\r
143                 break;\r
144         case PMC_MCKR_MDIV_PCK_DIV4:\r
145                 clk >>= 2; // divide by 4\r
146                 break;\r
147         case PMC_MCKR_MDIV_PCK_DIV3:\r
148                 clk /= 3;  // divide by 3\r
149                 break;\r
150         default:\r
151                 /* should never get here... */\r
152                 break;\r
153         }\r
154 \r
155         _pmc_mck = clk;\r
156 }\r
157 \r
158 static uint32_t _pmc_get_pck_clock(uint32_t index)\r
159 {\r
160         uint32_t clk = 0;\r
161         uint32_t pck = PMC->PMC_PCK[index];\r
162 \r
163         switch (pck & PMC_PCK_CSS_Msk) {\r
164         case PMC_PCK_CSS_SLOW_CLK:\r
165                 clk = pmc_get_slow_clock();\r
166                 break;\r
167         case PMC_PCK_CSS_MAIN_CLK:\r
168                 clk = pmc_get_main_clock();\r
169                 break;\r
170         case PMC_PCK_CSS_PLLA_CLK:\r
171                 clk = pmc_get_plla_clock();\r
172                 break;\r
173         case PMC_PCK_CSS_UPLL_CLK:\r
174                 clk = pmc_get_upll_clock();\r
175                 break;\r
176         case PMC_PCK_CSS_MCK_CLK:\r
177                 clk = pmc_get_master_clock();\r
178                 break;\r
179 #ifdef CONFIG_HAVE_PMC_AUDIO_CLOCK\r
180         case PMC_PCK_CSS_AUDIO_CLK:\r
181                 clk = pmc_get_audio_pmc_clock();\r
182                 break;\r
183 #endif\r
184         }\r
185 \r
186         uint32_t prescaler = (pck & PMC_PCK_PRES_Msk) >> PMC_PCK_PRES_Pos;\r
187         return clk / (prescaler + 1);\r
188 }\r
189 \r
190 static bool _pmc_get_system_clock_bits(enum _pmc_system_clock clock,\r
191         uint32_t *scer, uint32_t* scdr, uint32_t *scsr)\r
192 {\r
193         uint32_t e, d, s;\r
194 \r
195         switch (clock)\r
196         {\r
197 #ifdef PMC_SCDR_PCK\r
198         case PMC_SYSTEM_CLOCK_PCK:\r
199                 e = 0;\r
200                 d = PMC_SCDR_PCK;\r
201                 s = PMC_SCSR_PCK;\r
202                 break;\r
203 #endif\r
204         case PMC_SYSTEM_CLOCK_DDR:\r
205                 e = PMC_SCER_DDRCK;\r
206                 d = PMC_SCDR_DDRCK;\r
207                 s = PMC_SCSR_DDRCK;\r
208                 break;\r
209         case PMC_SYSTEM_CLOCK_LCD:\r
210                 e = PMC_SCER_LCDCK;\r
211                 d = PMC_SCDR_LCDCK;\r
212                 s = PMC_SCSR_LCDCK;\r
213                 break;\r
214 #ifdef PMC_SCER_SMDCK\r
215         case PMC_SYSTEM_CLOCK_SMD:\r
216                 e = PMC_SCER_SMDCK;\r
217                 d = PMC_SCDR_SMDCK;\r
218                 s = PMC_SCSR_SMDCK;\r
219                 break;\r
220 #endif\r
221         case PMC_SYSTEM_CLOCK_UHP:\r
222                 e = PMC_SCER_UHP;\r
223                 d = PMC_SCDR_UHP;\r
224                 s = PMC_SCSR_UHP;\r
225                 break;\r
226         case PMC_SYSTEM_CLOCK_UDP:\r
227                 e = PMC_SCER_UDP;\r
228                 d = PMC_SCDR_UDP;\r
229                 s = PMC_SCSR_UDP;\r
230                 break;\r
231         case PMC_SYSTEM_CLOCK_PCK0:\r
232                 e = PMC_SCER_PCK0;\r
233                 d = PMC_SCDR_PCK0;\r
234                 s = PMC_SCSR_PCK0;\r
235                 break;\r
236         case PMC_SYSTEM_CLOCK_PCK1:\r
237                 e = PMC_SCER_PCK1;\r
238                 d = PMC_SCDR_PCK1;\r
239                 s = PMC_SCSR_PCK1;\r
240                 break;\r
241         case PMC_SYSTEM_CLOCK_PCK2:\r
242                 e = PMC_SCER_PCK2;\r
243                 d = PMC_SCDR_PCK2;\r
244                 s = PMC_SCSR_PCK2;\r
245                 break;\r
246 #ifdef PMC_SCER_ISCCK\r
247         case PMC_SYSTEM_CLOCK_ISC:\r
248                 e = PMC_SCER_ISCCK;\r
249                 d = PMC_SCDR_ISCCK;\r
250                 s = PMC_SCSR_ISCCK;\r
251                 break;\r
252 #endif\r
253         default:\r
254                 return false;\r
255         }\r
256 \r
257         if (scer) {\r
258                 if (e)\r
259                         *scer = e;\r
260                 else\r
261                         return false;\r
262         }\r
263 \r
264         if (scdr) {\r
265                 if (d)\r
266                         *scdr = d;\r
267                 else\r
268                         return false;\r
269         }\r
270 \r
271         if (scsr) {\r
272                 if (s)\r
273                         *scsr = s;\r
274                 else\r
275                         return false;\r
276         }\r
277 \r
278         return true;\r
279 }\r
280 \r
281 /*----------------------------------------------------------------------------\r
282  *        Exported functions (General)\r
283  *----------------------------------------------------------------------------*/\r
284 \r
285 uint32_t pmc_get_master_clock(void)\r
286 {\r
287         if (!_pmc_mck) {\r
288                 _pmc_compute_mck();\r
289         }\r
290         return _pmc_mck;\r
291 }\r
292 \r
293 uint32_t pmc_get_slow_clock(void)\r
294 {\r
295         if (SCKC->SCKC_CR & SCKC_CR_OSCSEL)\r
296                 return SLOW_CLOCK_INT_OSC; /* on-chip slow clock RC */\r
297         else\r
298                 return BOARD_SLOW_CLOCK_EXT_OSC; /* external crystal */\r
299 }\r
300 \r
301 uint32_t pmc_get_main_clock(void)\r
302 {\r
303         if (PMC->CKGR_MOR & CKGR_MOR_MOSCSEL)\r
304                 return MAIN_CLOCK_INT_OSC; /* on-chip main clock RC */\r
305         else\r
306                 return BOARD_MAIN_CLOCK_EXT_OSC; /* external crystal */\r
307 }\r
308 \r
309 uint32_t pmc_get_plla_clock(void)\r
310 {\r
311         uint32_t pllaclk, pllar, pllmula, plldiva;\r
312 \r
313         if (PMC->CKGR_MOR & CKGR_MOR_MOSCSEL)\r
314                 pllaclk = MAIN_CLOCK_INT_OSC; /* on-chip main clock RC */\r
315         else\r
316                 pllaclk = BOARD_MAIN_CLOCK_EXT_OSC; /* external crystal */\r
317 \r
318         pllar = PMC->CKGR_PLLAR;\r
319         pllmula = (pllar & CKGR_PLLAR_MULA_Msk) >> CKGR_PLLAR_MULA_Pos;\r
320         plldiva = (pllar & CKGR_PLLAR_DIVA_Msk) >> CKGR_PLLAR_DIVA_Pos;\r
321         if (plldiva == 0 || pllmula == 0) {\r
322                 pllaclk = 0;\r
323         } else {\r
324                 pllaclk = pllaclk * (pllmula + 1) / plldiva;\r
325                 if (PMC->PMC_MCKR & PMC_MCKR_PLLADIV2)\r
326                         pllaclk >>= 1;\r
327         }\r
328 \r
329         return pllaclk;\r
330 }\r
331 \r
332 uint32_t pmc_get_processor_clock(void)\r
333 {\r
334         uint32_t procclk, mdiv;\r
335 \r
336         procclk = pmc_get_master_clock();\r
337 \r
338         mdiv = PMC->PMC_MCKR & PMC_MCKR_MDIV_Msk;\r
339         switch (mdiv) {\r
340         case PMC_MCKR_MDIV_EQ_PCK:\r
341                 break;\r
342         case PMC_MCKR_MDIV_PCK_DIV2:\r
343                 procclk <<= 1; // multiply by 2\r
344                 break;\r
345         case PMC_MCKR_MDIV_PCK_DIV3:\r
346                 procclk *= 3;  // multiply by 3\r
347                 break;\r
348         case PMC_MCKR_MDIV_PCK_DIV4:\r
349                 procclk <<= 2; // multiply by 4\r
350                 break;\r
351         default:\r
352                 /* should never get here... */\r
353                 break;\r
354         }\r
355 \r
356         return procclk;\r
357 }\r
358 \r
359 void pmc_select_external_crystal(void)\r
360 {\r
361         int return_to_sclock = 0;\r
362 \r
363         if (PMC->PMC_MCKR == PMC_MCKR_CSS(PMC_MCKR_CSS_SLOW_CLK)) {\r
364                 pmc_switch_mck_to_main();\r
365                 return_to_sclock = 1;\r
366         }\r
367 \r
368         /* switch from internal RC 32kHz to external OSC 32 kHz */\r
369         SCKC->SCKC_CR = (SCKC->SCKC_CR & ~SCKC_CR_OSCSEL) | SCKC_CR_OSCSEL_XTAL;\r
370 \r
371         /* Wait 5 slow clock cycles for internal resynchronization */\r
372         volatile int count;\r
373         for (count = 0; count < 0x1000; count++);\r
374 \r
375         /* Switch to slow clock again if needed */\r
376         if (return_to_sclock)\r
377                 pmc_switch_mck_to_slck();\r
378 }\r
379 \r
380 void pmc_select_internal_crystal(void)\r
381 {\r
382         int return_to_sclock = 0;\r
383 \r
384         if (PMC->PMC_MCKR == PMC_MCKR_CSS(PMC_MCKR_CSS_SLOW_CLK)) {\r
385                 pmc_switch_mck_to_main();\r
386                 return_to_sclock = 1;\r
387         }\r
388 \r
389         /* switch from extenal OSC 32kHz to internal RC 32 kHz */\r
390         /* switch slow clock source to internal OSC 32 kHz */\r
391         SCKC->SCKC_CR = (SCKC->SCKC_CR & ~SCKC_CR_OSCSEL) | SCKC_CR_OSCSEL_RC;\r
392 \r
393         /* Wait 5 slow clock cycles for internal resynchronization */\r
394         volatile int count;\r
395         for (count = 0; count < 0x1000; count++);\r
396 \r
397         /* Switch to slow clock again if needed */\r
398         if (return_to_sclock)\r
399                 pmc_switch_mck_to_slck();\r
400 }\r
401 \r
402 void pmc_select_external_osc(void)\r
403 {\r
404         /* Enable external osc 12 MHz when needed */\r
405         if ((PMC->CKGR_MOR & CKGR_MOR_MOSCXTEN) != CKGR_MOR_MOSCXTEN) {\r
406                 PMC->CKGR_MOR |= CKGR_MOR_MOSCXTST(18) | CKGR_MOR_MOSCXTEN | CKGR_MOR_KEY_PASSWD;\r
407                 /* Wait Main Oscillator ready */\r
408                 while(!(PMC->PMC_SR & PMC_SR_MOSCXTS));\r
409         }\r
410 \r
411         /* Return if external osc had been selected */\r
412         if ((PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) == CKGR_MOR_MOSCSEL)\r
413                 return;\r
414 \r
415         /* switch MAIN clock to external OSC 12 MHz */\r
416         PMC->CKGR_MOR |= CKGR_MOR_MOSCSEL | CKGR_MOR_KEY_PASSWD;\r
417 \r
418         /* wait for the command to be taken into account */\r
419         while ((PMC->CKGR_MOR & CKGR_MOR_MOSCSEL) != CKGR_MOR_MOSCSEL);\r
420 \r
421         /* wait MAIN clock status change for external OSC 12 MHz selection */\r
422         while (!(PMC->PMC_SR & PMC_SR_MOSCSELS));\r
423 \r
424         /* disable internal RC 12 MHz to save power */\r
425         pmc_disable_internal_osc();\r
426 }\r
427 \r
428 void pmc_disable_external_osc(void)\r
429 {\r
430         /* disable external OSC 12 MHz   */\r
431         PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCXTEN) | CKGR_MOR_KEY_PASSWD;\r
432 }\r
433 \r
434 void pmc_select_internal_osc(void)\r
435 {\r
436 #ifdef CKGR_MOR_MOSCRCEN\r
437         /* Enable internal RC 12 MHz when needed */\r
438         if ((PMC->CKGR_MOR & CKGR_MOR_MOSCRCEN) != CKGR_MOR_MOSCRCEN) {\r
439                 PMC->CKGR_MOR |= CKGR_MOR_MOSCRCEN | CKGR_MOR_KEY_PASSWD;\r
440                 /* Wait internal 12 MHz RC Startup Time for clock stabilization */\r
441                 while (!(PMC->PMC_SR & PMC_SR_MOSCRCS));\r
442         }\r
443 #endif\r
444 \r
445         /* switch MAIN clock to internal RC 12 MHz */\r
446         PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCSEL) | CKGR_MOR_KEY_PASSWD;\r
447 \r
448         /* in case where MCK is running on MAIN CLK */\r
449         while (!(PMC->PMC_SR & PMC_SR_MCKRDY));\r
450 \r
451         /* disable external OSC 12 MHz to save power*/\r
452         pmc_disable_external_osc();\r
453 }\r
454 \r
455 void pmc_disable_internal_osc(void)\r
456 {\r
457 #ifdef CKGR_MOR_MOSCRCEN\r
458         /* disable internal RC 12 MHz   */\r
459         PMC->CKGR_MOR = (PMC->CKGR_MOR & ~CKGR_MOR_MOSCRCEN) | CKGR_MOR_KEY_PASSWD;\r
460 #endif\r
461 }\r
462 \r
463 void pmc_switch_mck_to_pll(void)\r
464 {\r
465         /* Select PLL as input clock for PCK and MCK */\r
466         PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_PLLA_CLK;\r
467         while (!(PMC->PMC_SR & PMC_SR_MCKRDY));\r
468 \r
469         _pmc_mck = 0;\r
470 }\r
471 \r
472 void pmc_switch_mck_to_upll(void)\r
473 {\r
474         /* Select UPLL as input clock for PCK and MCK */\r
475         PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_MCKR_CSS_UPLL_CLK;\r
476         while (!(PMC->PMC_SR & PMC_SR_MCKRDY));\r
477 \r
478         _pmc_mck = 0;\r
479 }\r
480 \r
481 void pmc_switch_mck_to_main(void)\r
482 {\r
483         /* Select Main Oscillator as input clock for PCK and MCK */\r
484         PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_PCK_CSS_MAIN_CLK;\r
485         while (!(PMC->PMC_SR & PMC_SR_MCKRDY));\r
486 \r
487         _pmc_mck = 0;\r
488 }\r
489 \r
490 void pmc_switch_mck_to_slck(void)\r
491 {\r
492         /* Select Slow Clock as input clock for PCK and MCK */\r
493         PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk) | PMC_PCK_CSS_SLOW_CLK;\r
494         while (!(PMC->PMC_SR & PMC_SR_MCKRDY));\r
495 \r
496         _pmc_mck = 0;\r
497 }\r
498 \r
499 void pmc_set_mck_prescaler(uint32_t prescaler)\r
500 {\r
501         /* Change MCK Prescaler divider in PMC_MCKR register */\r
502         PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk) | prescaler;\r
503         while (!(PMC->PMC_SR & PMC_SR_MCKRDY));\r
504 }\r
505 \r
506 void pmc_set_mck_plla_div(uint32_t divider)\r
507 {\r
508         if ((PMC->PMC_MCKR & PMC_MCKR_PLLADIV2) == PMC_MCKR_PLLADIV2) {\r
509                 if (divider == 0) {\r
510                         PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_PLLADIV2);\r
511                 }\r
512         } else {\r
513                 if (divider == PMC_MCKR_PLLADIV2) {\r
514                         PMC->PMC_MCKR = (PMC->PMC_MCKR | PMC_MCKR_PLLADIV2);\r
515                 }\r
516         }\r
517         while (!(PMC->PMC_SR & PMC_SR_MCKRDY));\r
518 }\r
519 \r
520 void pmc_set_mck_h32mxdiv(uint32_t divider)\r
521 {\r
522         if ((PMC->PMC_MCKR & PMC_MCKR_H32MXDIV) == PMC_MCKR_H32MXDIV_H32MXDIV2) {\r
523                 if (divider == PMC_MCKR_H32MXDIV_H32MXDIV1) {\r
524                         PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_H32MXDIV);\r
525                 }\r
526         } else {\r
527                 if (divider == PMC_MCKR_H32MXDIV_H32MXDIV2) {\r
528                         PMC->PMC_MCKR = (PMC->PMC_MCKR | PMC_MCKR_H32MXDIV_H32MXDIV2);\r
529                 }\r
530         }\r
531         while (!(PMC->PMC_SR & PMC_SR_MCKRDY));\r
532 }\r
533 \r
534 void pmc_set_mck_divider(uint32_t divider)\r
535 {\r
536         /* change MCK Prescaler divider in PMC_MCKR register */\r
537         PMC->PMC_MCKR = (PMC->PMC_MCKR & ~PMC_MCKR_MDIV_Msk) | divider;\r
538         while (!(PMC->PMC_SR & PMC_SR_MCKRDY));\r
539 }\r
540 \r
541 void pmc_set_plla(uint32_t pll, uint32_t cpcr)\r
542 {\r
543         PMC->CKGR_PLLAR = pll;\r
544         PMC->PMC_PLLICPR = cpcr;\r
545 \r
546         if ((pll & CKGR_PLLAR_DIVA_Msk) != CKGR_PLLAR_DIVA_0) {\r
547                 while (!(PMC->PMC_SR & PMC_SR_LOCKA));\r
548         }\r
549 }\r
550 \r
551 void pmc_disable_plla(void)\r
552 {\r
553         PMC->CKGR_PLLAR = (PMC->CKGR_PLLAR & ~CKGR_PLLAR_MULA_Msk) | CKGR_PLLAR_MULA(0);\r
554 }\r
555 \r
556 void pmc_enable_system_clock(enum _pmc_system_clock clock)\r
557 {\r
558         uint32_t scer, scsr;\r
559         if (!_pmc_get_system_clock_bits(clock, &scer, NULL, &scsr))\r
560                 return;\r
561 \r
562         PMC->PMC_SCER |= scer;\r
563         while (!(PMC->PMC_SCSR & scsr));\r
564 }\r
565 \r
566 void pmc_disable_system_clock(enum _pmc_system_clock clock)\r
567 {\r
568         uint32_t scdr, scsr;\r
569         if (!_pmc_get_system_clock_bits(clock, NULL, &scdr, &scsr))\r
570                 return;\r
571 \r
572         PMC->PMC_SCDR |= scdr;\r
573         while (PMC->PMC_SCSR & scsr);\r
574 }\r
575 \r
576 #ifdef CONFIG_HAVE_PMC_FAST_STARTUP\r
577 void pmc_set_fast_startup_mode(uint32_t startup_mode)\r
578 {\r
579         PMC->PMC_FSMR = startup_mode;\r
580 }\r
581 \r
582 void pmc_set_fast_startup_polarity(uint32_t high_level, uint32_t low_level)\r
583 {\r
584         PMC->PMC_FSPR &= ~low_level;\r
585         PMC->PMC_FSPR |= high_level;\r
586 }\r
587 #endif /* CONFIG_HAVE_PMC_FAST_STARTUP */\r
588 \r
589 void pmc_set_custom_pck_mck(struct pck_mck_cfg *cfg)\r
590 {\r
591         pmc_switch_mck_to_slck();\r
592 \r
593         if (cfg->ext12m)\r
594                 pmc_select_external_osc();\r
595         else\r
596                 pmc_select_internal_osc();\r
597 \r
598         pmc_switch_mck_to_main();\r
599 \r
600         if (cfg->ext32k)\r
601                 pmc_select_external_crystal();\r
602         else\r
603                 pmc_select_internal_crystal();\r
604 \r
605         pmc_set_mck_prescaler(cfg->pck_pres);\r
606         pmc_set_mck_divider(cfg->mck_div);\r
607 \r
608         pmc_set_mck_plla_div(cfg->plla_div2 ? PMC_MCKR_PLLADIV2 : 0);\r
609         if (cfg->plla_mul > 0) {\r
610                 pmc_disable_plla();\r
611                 uint32_t tmp = CKGR_PLLAR_ONE |\r
612                         CKGR_PLLAR_PLLACOUNT(0x3F) |\r
613                         CKGR_PLLAR_OUTA(0x0) |\r
614                         CKGR_PLLAR_MULA(cfg->plla_mul) |\r
615                         CKGR_PLLAR_DIVA(cfg->plla_div);\r
616                 pmc_set_plla(tmp, PMC_PLLICPR_IPLL_PLLA(0x3));\r
617         } else {\r
618                 pmc_disable_plla();\r
619         }\r
620 \r
621         if (cfg->h32mxdiv2)\r
622                 pmc_set_mck_h32mxdiv(PMC_MCKR_H32MXDIV_H32MXDIV2);\r
623         else\r
624                 pmc_set_mck_h32mxdiv(PMC_MCKR_H32MXDIV_H32MXDIV1);\r
625 \r
626         switch (cfg->pck_input) {\r
627         case PMC_MCKR_CSS_PLLA_CLK:\r
628                 pmc_switch_mck_to_pll();\r
629                 break;\r
630 \r
631         case PMC_MCKR_CSS_UPLL_CLK:\r
632                 pmc_switch_mck_to_upll();\r
633                 break;\r
634 \r
635         case PMC_MCKR_CSS_SLOW_CLK:\r
636                 pmc_switch_mck_to_slck();\r
637                 pmc_disable_internal_osc();\r
638                 pmc_disable_external_osc();\r
639                 break;\r
640         }\r
641 }\r
642 \r
643 /*----------------------------------------------------------------------------\r
644  *        Exported functions (Peripherals)\r
645  *----------------------------------------------------------------------------*/\r
646 \r
647 void pmc_enable_peripheral(uint32_t id)\r
648 {\r
649         assert(id > 1 && id < ID_PERIPH_COUNT);\r
650 \r
651         PMC->PMC_PCR = PMC_PCR_PID(id);\r
652         volatile uint32_t pcr = PMC->PMC_PCR;\r
653 \r
654         PMC->PMC_PCR = pcr | PMC_PCR_CMD | PMC_PCR_EN;\r
655 }\r
656 \r
657 void pmc_disable_peripheral(uint32_t id)\r
658 {\r
659         assert(id > 1 && id < ID_PERIPH_COUNT);\r
660 \r
661         PMC->PMC_PCR = PMC_PCR_PID(id);\r
662         volatile uint32_t pcr = PMC->PMC_PCR;\r
663 \r
664         PMC->PMC_PCR = PMC_PCR_CMD | (pcr & ~PMC_PCR_EN);\r
665 }\r
666 \r
667 uint32_t pmc_is_peripheral_enabled(uint32_t id)\r
668 {\r
669         assert(id > 1 && id < ID_PERIPH_COUNT);\r
670 \r
671         PMC->PMC_PCR = PMC_PCR_PID(id);\r
672         volatile uint32_t pcr = PMC->PMC_PCR;\r
673 \r
674         return !!(pcr & PMC_PCR_EN);\r
675 }\r
676 \r
677 uint32_t pmc_get_peripheral_clock(uint32_t id)\r
678 {\r
679         assert(id > 1 && id < ID_PERIPH_COUNT);\r
680 \r
681         uint32_t div = get_peripheral_clock_divider(id);\r
682         if (div)\r
683                 return pmc_get_master_clock() / div;\r
684 \r
685         return 0;\r
686 }\r
687 \r
688 void pmc_disable_all_peripherals(void)\r
689 {\r
690         int i;\r
691         for (i = 2; i < ID_PERIPH_COUNT; i++)\r
692                 pmc_disable_peripheral(i);\r
693 }\r
694 \r
695 /*----------------------------------------------------------------------------\r
696  *        Exported functions (PCK0-2)\r
697  *----------------------------------------------------------------------------*/\r
698 \r
699 void pmc_configure_pck0(uint32_t clock_source, uint32_t prescaler)\r
700 {\r
701         pmc_disable_pck0();\r
702         PMC->PMC_PCK[0] = (clock_source & PMC_PCK_CSS_Msk) | PMC_PCK_PRES(prescaler);\r
703 }\r
704 \r
705 void pmc_enable_pck0(void)\r
706 {\r
707         PMC->PMC_SCER = PMC_SCER_PCK0;\r
708         while (!(PMC->PMC_SR & PMC_SR_PCKRDY0));\r
709 }\r
710 \r
711 void pmc_disable_pck0(void)\r
712 {\r
713         PMC->PMC_SCDR = PMC_SCDR_PCK0;\r
714         while (PMC->PMC_SCSR & PMC_SCSR_PCK0);\r
715 }\r
716 \r
717 uint32_t pmc_get_pck0_clock(void)\r
718 {\r
719         return _pmc_get_pck_clock(0);\r
720 }\r
721 \r
722 void pmc_configure_pck1(uint32_t clock_source, uint32_t prescaler)\r
723 {\r
724         pmc_disable_pck1();\r
725         PMC->PMC_PCK[1] = (clock_source & PMC_PCK_CSS_Msk) | PMC_PCK_PRES(prescaler);\r
726 }\r
727 \r
728 void pmc_enable_pck1(void)\r
729 {\r
730         PMC->PMC_SCER = PMC_SCER_PCK1;\r
731         while (!(PMC->PMC_SR & PMC_SR_PCKRDY1));\r
732 }\r
733 \r
734 void pmc_disable_pck1(void)\r
735 {\r
736         PMC->PMC_SCDR = PMC_SCDR_PCK1;\r
737         while (PMC->PMC_SCSR & PMC_SCSR_PCK1);\r
738 }\r
739 \r
740 uint32_t pmc_get_pck1_clock(void)\r
741 {\r
742         return _pmc_get_pck_clock(1);\r
743 }\r
744 \r
745 void pmc_configure_pck2(uint32_t clock_source, uint32_t prescaler)\r
746 {\r
747         pmc_disable_pck2();\r
748         PMC->PMC_PCK[2] = (clock_source & PMC_PCK_CSS_Msk) | PMC_PCK_PRES(prescaler);\r
749 }\r
750 \r
751 void pmc_enable_pck2(void)\r
752 {\r
753         PMC->PMC_SCER = PMC_SCER_PCK2;\r
754         while (!(PMC->PMC_SR & PMC_SR_PCKRDY2));\r
755 }\r
756 \r
757 void pmc_disable_pck2(void)\r
758 {\r
759         PMC->PMC_SCDR = PMC_SCDR_PCK2;\r
760         while (PMC->PMC_SCSR & PMC_SCSR_PCK2);\r
761 }\r
762 \r
763 uint32_t pmc_get_pck2_clock(void)\r
764 {\r
765         return _pmc_get_pck_clock(2);\r
766 }\r
767 \r
768 /*----------------------------------------------------------------------------\r
769  *        Exported functions (UPLL)\r
770  *----------------------------------------------------------------------------*/\r
771 \r
772 void pmc_enable_upll_clock(void)\r
773 {\r
774         /* enable 480Mhz UPLL */\r
775         PMC->CKGR_UCKR = CKGR_UCKR_UPLLEN | CKGR_UCKR_UPLLCOUNT(0x3)\r
776                 | CKGR_UCKR_BIASCOUNT(0x1);\r
777 \r
778         /* wait until UPLL is locked */\r
779         while (!(PMC->PMC_SR & PMC_SR_LOCKU));\r
780 }\r
781 \r
782 void pmc_disable_upll_clock(void)\r
783 {\r
784         PMC->CKGR_UCKR &= ~CKGR_UCKR_UPLLEN;\r
785 }\r
786 \r
787 uint32_t pmc_get_upll_clock(void)\r
788 {\r
789 #ifdef SFR_UTMICKTRIM_FREQ_Msk\r
790         uint32_t clktrim = SFR->SFR_UTMICKTRIM & SFR_UTMICKTRIM_FREQ_Msk;\r
791         switch (clktrim) {\r
792                 case SFR_UTMICKTRIM_FREQ_16:\r
793                         return 30 * BOARD_MAIN_CLOCK_EXT_OSC;\r
794                 case SFR_UTMICKTRIM_FREQ_24:\r
795                         return 20 * BOARD_MAIN_CLOCK_EXT_OSC;\r
796                 default:\r
797                         return 40 * BOARD_MAIN_CLOCK_EXT_OSC;\r
798         }\r
799 #else\r
800         return 40 * BOARD_MAIN_CLOCK_EXT_OSC;\r
801 #endif\r
802 }\r
803 \r
804 void pmc_enable_upll_bias(void)\r
805 {\r
806         PMC->CKGR_UCKR |= CKGR_UCKR_BIASEN;\r
807 }\r
808 \r
809 void pmc_disable_upll_bias(void)\r
810 {\r
811         PMC->CKGR_UCKR &= ~CKGR_UCKR_BIASEN;\r
812 }\r
813 \r
814 /*----------------------------------------------------------------------------\r
815  *        Exported functions (Generated clocks)\r
816  *----------------------------------------------------------------------------*/\r
817 \r
818 #ifdef CONFIG_HAVE_PMC_GENERATED_CLOCKS\r
819 void pmc_configure_gck(uint32_t id, uint32_t clock_source, uint32_t div)\r
820 {\r
821         assert(id > 1 && id < ID_PERIPH_COUNT);\r
822         assert(!(clock_source & ~PMC_PCR_GCKCSS_Msk));\r
823         assert(!(div << PMC_PCR_GCKDIV_Pos & ~PMC_PCR_GCKDIV_Msk));\r
824 \r
825         pmc_disable_gck(id);\r
826         PMC->PMC_PCR = PMC_PCR_PID(id);\r
827         volatile uint32_t pcr = PMC->PMC_PCR;\r
828         PMC->PMC_PCR = pcr | (clock_source & PMC_PCR_GCKCSS_Msk) | PMC_PCR_CMD\r
829             | PMC_PCR_GCKDIV(div);\r
830 }\r
831 \r
832 void pmc_enable_gck(uint32_t id)\r
833 {\r
834         assert(id > 1 && id < ID_PERIPH_COUNT);\r
835 \r
836         PMC->PMC_PCR = PMC_PCR_PID(id);\r
837         volatile uint32_t pcr = PMC->PMC_PCR;\r
838         PMC->PMC_PCR = pcr | PMC_PCR_CMD | PMC_PCR_GCKEN;\r
839         while (!(PMC->PMC_SR & PMC_SR_GCKRDY));\r
840 }\r
841 \r
842 void pmc_disable_gck(uint32_t id)\r
843 {\r
844         assert(id > 1 && id < ID_PERIPH_COUNT);\r
845 \r
846         PMC->PMC_PCR = PMC_PCR_PID(id);\r
847         volatile uint32_t pcr = PMC->PMC_PCR;\r
848         PMC->PMC_PCR = PMC_PCR_CMD | (pcr & ~PMC_PCR_GCKEN);\r
849 }\r
850 \r
851 uint32_t pmc_get_gck_clock(uint32_t id)\r
852 {\r
853         uint32_t clk = 0;\r
854         assert(id > 1 && id < ID_PERIPH_COUNT);\r
855 \r
856         PMC->PMC_PCR = PMC_PCR_PID(id);\r
857         volatile uint32_t pcr = PMC->PMC_PCR;\r
858 \r
859         switch (pcr & PMC_PCR_GCKCSS_Msk) {\r
860         case PMC_PCR_GCKCSS_SLOW_CLK:\r
861                 clk = pmc_get_slow_clock();\r
862                 break;\r
863         case PMC_PCR_GCKCSS_MAIN_CLK:\r
864                 clk = pmc_get_main_clock();\r
865                 break;\r
866         case PMC_PCR_GCKCSS_PLLA_CLK:\r
867                 clk = pmc_get_plla_clock();\r
868                 break;\r
869         case PMC_PCR_GCKCSS_UPLL_CLK:\r
870                 clk = pmc_get_upll_clock();\r
871                 break;\r
872         case PMC_PCR_GCKCSS_MCK_CLK:\r
873                 clk = pmc_get_master_clock();\r
874                 break;\r
875 #ifdef CONFIG_HAVE_PMC_AUDIO_CLOCK\r
876         case PMC_PCR_GCKCSS_AUDIO_CLK:\r
877                 clk = pmc_get_audio_pmc_clock();\r
878                 break;\r
879 #endif\r
880         }\r
881 \r
882         uint32_t div = (pcr & PMC_PCR_GCKDIV_Msk) >> PMC_PCR_GCKDIV_Pos;\r
883         return ROUND_INT_DIV(clk, div + 1);\r
884 }\r
885 #endif /* CONFIG_HAVE_PMC_GENERATED_CLOCKS */\r
886 \r
887 /*----------------------------------------------------------------------------\r
888  *        Exported functions (Audio PLL)\r
889  *----------------------------------------------------------------------------*/\r
890 \r
891 #ifdef CONFIG_HAVE_PMC_AUDIO_CLOCK\r
892 void pmc_configure_audio(struct _pmc_audio_cfg *cfg)\r
893 {\r
894         /* reset audio clock */\r
895         PMC->PMC_AUDIO_PLL0 &= ~PMC_AUDIO_PLL0_RESETN;\r
896         PMC->PMC_AUDIO_PLL0 |= PMC_AUDIO_PLL0_RESETN;\r
897 \r
898         /* configure values */\r
899         uint32_t pll0 = PMC->PMC_AUDIO_PLL0;\r
900         pll0 &= ~PMC_AUDIO_PLL0_ND_Msk;\r
901         pll0 |= cfg->nd << PMC_AUDIO_PLL0_ND_Pos;\r
902         pll0 &= ~PMC_AUDIO_PLL0_QDPMC_Msk;\r
903         pll0 |= cfg->qdpmc << PMC_AUDIO_PLL0_QDPMC_Pos;\r
904         PMC->PMC_AUDIO_PLL0 = pll0;\r
905         uint32_t pll1 = PMC->PMC_AUDIO_PLL1;\r
906         pll1 &= ~PMC_AUDIO_PLL1_DIV_Msk;\r
907         pll1 |= cfg->div << PMC_AUDIO_PLL1_DIV_Pos;\r
908         pll1 &= ~PMC_AUDIO_PLL1_FRACR_Msk;\r
909         pll1 |= cfg->fracr << PMC_AUDIO_PLL1_FRACR_Pos;\r
910         pll1 &= ~PMC_AUDIO_PLL1_QDAUDIO_Msk;\r
911         pll1 |= cfg->qdaudio << PMC_AUDIO_PLL1_QDAUDIO_Pos;\r
912         PMC->PMC_AUDIO_PLL1 = pll1;\r
913 }\r
914 \r
915 void pmc_enable_audio(bool pmc_clock, bool pad_clock)\r
916 {\r
917         uint32_t bits = PMC_AUDIO_PLL0_PLLEN | PMC_AUDIO_PLL0_RESETN;\r
918         uint32_t nbits = 0;\r
919 \r
920         if (pad_clock)\r
921                 bits |= PMC_AUDIO_PLL0_PADEN;\r
922         else\r
923                 nbits |= PMC_AUDIO_PLL0_PADEN;\r
924 \r
925         if (pmc_clock)\r
926                 bits |= PMC_AUDIO_PLL0_PMCEN;\r
927         else\r
928                 nbits |= PMC_AUDIO_PLL0_PMCEN;\r
929 \r
930         PMC->PMC_AUDIO_PLL0 = (PMC->PMC_AUDIO_PLL0 & ~nbits) | bits;\r
931 }\r
932 \r
933 void pmc_disable_audio()\r
934 {\r
935         uint32_t nbits = PMC_AUDIO_PLL0_PLLEN | PMC_AUDIO_PLL0_RESETN |\r
936                 PMC_AUDIO_PLL0_PADEN | PMC_AUDIO_PLL0_PMCEN;\r
937         PMC->PMC_AUDIO_PLL0 &= ~nbits;\r
938 }\r
939 \r
940 uint32_t pmc_get_audio_pmc_clock(void)\r
941 {\r
942         uint32_t pll0 = PMC->PMC_AUDIO_PLL0;\r
943         uint32_t pll1 = PMC->PMC_AUDIO_PLL1;\r
944 \r
945         uint32_t nd = (pll0 & PMC_AUDIO_PLL0_ND_Msk) >> PMC_AUDIO_PLL0_ND_Pos;\r
946         uint32_t fracr = (pll1 & PMC_AUDIO_PLL1_FRACR_Msk) >> PMC_AUDIO_PLL1_FRACR_Pos;\r
947         uint32_t qdpmc = (pll0 & PMC_AUDIO_PLL0_QDPMC_Msk) >> PMC_AUDIO_PLL0_QDPMC_Pos;\r
948 \r
949         uint64_t clk = BOARD_MAIN_CLOCK_EXT_OSC;\r
950         clk *= ((nd + 1) << 22) + fracr;\r
951         clk /= 1 << 22;\r
952         clk /= qdpmc + 1;\r
953         return (uint32_t)clk;\r
954 }\r
955 \r
956 uint32_t pmc_get_audio_pad_clock(void)\r
957 {\r
958         uint32_t pll0 = PMC->PMC_AUDIO_PLL0;\r
959         uint32_t pll1 = PMC->PMC_AUDIO_PLL1;\r
960 \r
961         uint32_t nd = (pll0 & PMC_AUDIO_PLL0_ND_Msk) >> PMC_AUDIO_PLL0_ND_Pos;\r
962         uint32_t fracr = (pll1 & PMC_AUDIO_PLL1_FRACR_Msk) >> PMC_AUDIO_PLL1_FRACR_Pos;\r
963         uint32_t qdaudio = (pll1 & PMC_AUDIO_PLL1_QDAUDIO_Msk) >> PMC_AUDIO_PLL1_QDAUDIO_Pos;\r
964         if (qdaudio == 0)\r
965                 return 0;\r
966 \r
967         uint32_t div = (pll1 & PMC_AUDIO_PLL1_DIV_Msk) >> PMC_AUDIO_PLL1_DIV_Pos;\r
968         if (div != 2 && div != 3)\r
969                 return 0;\r
970 \r
971         uint64_t clk = BOARD_MAIN_CLOCK_EXT_OSC;\r
972         clk *= ((nd + 1) << 22) + fracr;\r
973         clk /= 1 << 22;\r
974         clk /= div * qdaudio;\r
975         return (uint32_t)clk;\r
976 }\r
977 #endif /* CONFIG_HAVE_PMC_AUDIO_CLOCK */\r
978 \r