fbc79062216a4ad8207e23423412e65a1aa91860
[bertos.git] / bertos / cpu / cortex-m3 / drv / clock_sam3.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
30  *
31  * -->
32  *
33  * \brief AT91SAM3 clocking driver.
34  *
35  * \author Stefano Fedrigo <aleph@develer.com>
36  */
37
38 #include "clock_sam3.h"
39 #include <io/sam3_pmc.h>
40 #include <cfg/compiler.h>
41 #include <cfg/macros.h>
42
43 /* Value to use when writing CKGR_MOR, to unlock write */
44 #define CKGR_KEY  0x37
45
46 /*
47  * Try to evaluate the correct divider and multiplier value depending
48  * on the desired CPU frequency.
49  *
50  * We try all combinations in a certain range of divider and multiplier
51  * values.  The range can change, with better match with "strange"
52  * frequencies, but boot time will be longer.
53  *
54  * Limits for SAM3N: divider [1,255], multiplier [1,2047].
55  */
56 INLINE uint32_t evaluate_pll(void)
57 {
58         int mul, div, best_mul, best_div;
59         int best_delta = CPU_FREQ;
60         int freq = 0;
61
62         for (mul = 1; mul <= 8; mul++)
63         {
64                 for (div = 1; div <= 24; div++)
65                 {
66                         // RC oscillator set to 12 MHz
67                         freq = 12000000 / div * (1 + mul);
68                         if (ABS((int)CPU_FREQ - freq) < best_delta) {
69                                 best_delta = ABS((int)CPU_FREQ - freq);
70                                 best_mul = mul;
71                                 best_div = div;
72                         }
73                 }
74         }
75
76         // Bit 29 must always be set to 1
77         return CKGR_PLLR_DIV(best_div) | CKGR_PLLR_MUL(best_mul) | BV(29);
78 }
79
80
81 void clock_init(void)
82 {
83         /* Enable and configure internal Fast RC oscillator */
84         CKGR_MOR_R =
85                 CKGR_MOR_KEY(CKGR_KEY)       // Unlock key
86                 | CKGR_MOR_MOSCRCEN          // Main On-Chip RC oscillator enable
87                 | CKGR_MOR_MOSCRCF_12MHZ;    // RC oscillator frequency
88
89         /* Master clock: select PLL clock and no prescaling */
90         PMC_MCKR_R = PMC_MCKR_CSS_PLL_CLK;
91
92         CKGR_PLLR_R = evaluate_pll();
93 }