4 * This file is part of BeRTOS.
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.
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.
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
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.
29 * Copyright 2010 Develer S.r.l. (http://www.develer.com/)
34 * \author Francesco Sacchi <batt@develer.com>
36 * \brief AT91SAM7S256 CRT.
40 #include <cfg/macros.h>
42 #define USE_FIXED_PLL 1
44 #define XTAL_FREQ 18432000UL
47 #if CPU_FREQ != 48054857L
48 /* Avoid errors on nightly test */
49 #if !defined(ARCH_NIGHTTEST) || !(ARCH & ARCH_NIGHTTEST)
50 #warning Clock registers set for 48.055MHz operation, revise following code if you want a different clock.
55 * With a 18.432MHz cristal, master clock is:
56 * (((18.432 * (PLL_MUL_VAL + 1)) / PLL_DIV_VAL) / AT91MCK_PRES) = 48.055MHz
58 #define PLL_MUL_VAL 72 /**< Real multiplier value is PLL_MUL_VAL + 1! */
59 #define PLL_DIV_VAL 14
60 #define AT91MCK_PRES PMC_PRES_CLK_2
62 #else /* !USE_FIXED_PLL*/
64 #define PLL_IN_MIN 1000000UL
65 #define PLL_IN_MAX 32000000UL
66 #define PLL_OUT_MIN 80000000UL
67 #define PLL_OUT_MAX 160000000UL
69 #define DIV_HARD_MIN 1
70 #define DIV_HARD_MAX 255
72 #define DIV_MIN (DIV_ROUND(XTAL_FREQ, PLL_IN_MAX) \
73 < DIV_HARD_MIN ? DIV_HARD_MIN : DIV_ROUND(XTAL_FREQ, PLL_IN_MAX))
75 #define DIV_MAX (DIV_ROUND(XTAL_FREQ, PLL_IN_MIN) \
76 > DIV_HARD_MAX ? DIV_HARD_MAX : DIV_ROUND(XTAL_FREQ, PLL_IN_MIN))
81 typedef struct PllRegs
89 * Code used to automatically compute the PLL registers.
90 * Since the processor uses the internal 32kHz oscillator
91 * this function takes a lot of time to be executed (~3s!).
93 static const PllRegs pllCostants(void)
95 uint32_t best_err = CPU_FREQ;
98 for (uint32_t div = DIV_MIN; div <= DIV_MAX; div++)
100 for (uint32_t pres = 0; pres < 8; pres++)
102 uint32_t mul = DIV_ROUND((CPU_FREQ * div) << pres, XTAL_FREQ) - 1;
105 uint32_t pll = (XTAL_FREQ * (mul + 1)) / div;
106 if (pll >= PLL_OUT_MIN && pll <= PLL_OUT_MAX)
108 uint32_t err = ABS((int32_t)((pll >> pres) - CPU_FREQ));
129 #endif /* !USE_FIXED_PLL*/
132 * Override dummy hardware init functions supplied by the ASM startup
140 * Early hardware initialization routine1.
141 * This will be called by the ASM CRT routine just
142 * *before* clearing .bss and loading .data sections.
143 * Usually only basic tasks are performed here (i.e. setting the PLL).
144 * For more generic tasks, __init2() should be used.
146 * \note Please keep in mind that since .bss and .data are not yet set, care
147 * must be taken. No static data can be used inside this funcition.
148 * Also some libc functions or floating point operations could potentially
149 * use initialized static data, be aware!
154 * Compute number of master clock cycles in 1.5us.
155 * Needed by flash writing functions.
156 * The maximum FMCN value is 0xFF and 0 can be used only if
157 * master clock is less than 33kHz.
159 #define MCN DIV_ROUNDUP(CPU_FREQ, 666667UL)
160 #define FMCN (CPU_FREQ <= 33333UL ? 0 : (MCN < 0xFF ? MCN : 0xFF))
162 #if CPU_FREQ < 30000000UL
163 /* Use 1 cycles for flash access. */
164 MC_FMR = FMCN << MC_FMCN_SHIFT | MC_FWS_1R2W;
166 /* Use 2 cycles for flash access. */
167 MC_FMR = FMCN << MC_FMCN_SHIFT | MC_FWS_2R3W;
170 /* Disable all interrupts. Useful for debugging w/o target reset. */
171 AIC_EOICR = 0xFFFFFFFF;
172 AIC_IDCR = 0xFFFFFFFF;
174 /* The watchdog is enabled after processor reset. Disable it. */
175 WDT_MR = BV(WDT_WDDIS);
178 * Enable the main oscillator. Set startup time of 6 * 8 slow
179 * clock cycles and wait until oscillator is stabilized.
181 CKGR_MOR = (6 << 8) | BV(CKGR_MOSCEN);
182 while (!(PMC_SR & BV(PMC_MOSCS))) ;
184 /* Switch to Slow oscillator clock. */
185 PMC_MCKR &= ~PMC_CSS_MASK;
186 while (!(PMC_SR & BV(PMC_MCKRDY))) ;
188 /* Switch to prescaler div 1 factor. */
189 PMC_MCKR &= ~PMC_PRES_MASK;
190 while (!(PMC_SR & BV(PMC_MCKRDY))) ;
192 uint32_t div, pres, mul;
198 PllRegs pll = pllCostants();
201 pres = pll.pres << PMC_PRES_SHIFT;
206 * PLLfreq = crystal / divider * (multiplier + 1)
207 * Wait 28 clock cycles until PLL is locked.
209 CKGR_PLLR = ((mul << CKGR_MUL_SHIFT)
210 | (28 << CKGR_PLLCOUNT_SHIFT) | div);
211 while (!(PMC_SR & BV(PMC_LOCK))) ;
213 /* Set master clock prescaler. */
215 while (!(PMC_SR & BV(PMC_MCKRDY))) ;
218 * Switch to PLL clock. Trying to set this together with the
219 * prescaler fails (see datasheets).
221 PMC_MCKR |= PMC_CSS_PLL_CLK;
222 while (!(PMC_SR & BV(PMC_MCKRDY))) ;
226 * Early hardware initialization routine2.
227 * This will be called by the ASM CRT routine just
228 * *after* clearing .bss and loading .data sections and before calling main().
232 /* Enable external reset key. */
233 RSTC_MR = (RSTC_KEY | BV(RSTC_URSTEN));
235 /* Enable clock for PIO(s) */
236 PMC_PCER = BV(PIOA_ID);
238 PMC_PCER |= BV(PIOB_ID);