init_at91.c
Go to the documentation of this file.
00001
00039 #include <io/arm.h>
00040 #include <cfg/macros.h>
00041
00042 #include "cfg/cfg_wdt.h"
00043
00044 #define USE_FIXED_PLL 1
00045 
00046 #define XTAL_FREQ 18432000UL
00047 
00048 #if USE_FIXED_PLL
00049     #if CPU_FREQ != 48054857L
00050         /* Avoid errors on nightly test */
00051         #if !defined(ARCH_NIGHTTEST) || !(ARCH & ARCH_NIGHTTEST)
00052             #warning Clock registers set for 48.055MHz operation, revise following code if you want a different clock.
00053         #endif
00054     #endif
00055 
00056     /*
00057      * With a 18.432MHz cristal, master clock is:
00058      * (((18.432 * (PLL_MUL_VAL + 1)) / PLL_DIV_VAL) / AT91MCK_PRES) = 48.055MHz
00059      */
00060     #define PLL_MUL_VAL  72  
00061     #define PLL_DIV_VAL  14
00062     #define AT91MCK_PRES PMC_PRES_CLK_2
00063 
00064 #else /* !USE_FIXED_PLL*/
00065
00066     #define PLL_IN_MIN  1000000UL
00067     #define PLL_IN_MAX  32000000UL
00068     #define PLL_OUT_MIN 80000000UL
00069     #define PLL_OUT_MAX 160000000UL
00070 
00071     #define DIV_HARD_MIN 1
00072     #define DIV_HARD_MAX 255
00073 
00074     #define DIV_MIN  (DIV_ROUND(XTAL_FREQ, PLL_IN_MAX) \
00075         < DIV_HARD_MIN ? DIV_HARD_MIN : DIV_ROUND(XTAL_FREQ, PLL_IN_MAX))
00076 
00077     #define DIV_MAX  (DIV_ROUND(XTAL_FREQ, PLL_IN_MIN) \
00078         > DIV_HARD_MAX ? DIV_HARD_MAX : DIV_ROUND(XTAL_FREQ, PLL_IN_MIN))
00079 
00080     #define MUL_MIN  0
00081     #define MUL_MAX  2047
00082 
00083     typedef struct PllRegs
00084     {
00085         uint32_t mul;
00086         uint32_t div;
00087         uint32_t pres;
00088     } PllRegs;
00089
00095     static const PllRegs pllCostants(void)
00096     {
00097         uint32_t best_err = CPU_FREQ;
00098         PllRegs res;
00099
00100         for (uint32_t div = DIV_MIN; div <= DIV_MAX; div++)
00101         {
00102             for (uint32_t pres = 0; pres < 8; pres++)
00103             {
00104                 uint32_t mul = DIV_ROUND((CPU_FREQ * div) << pres, XTAL_FREQ) - 1;
00105                 if (mul <= MUL_MAX)
00106                 {
00107                     uint32_t pll = (XTAL_FREQ * (mul + 1)) / div;
00108                     if (pll >= PLL_OUT_MIN && pll <= PLL_OUT_MAX)
00109                     {
00110                         uint32_t err = ABS((int32_t)((pll >> pres) - CPU_FREQ));
00111                         if (err == 0)
00112                         {
00113                             res.div = div;
00114                             res.mul = mul;
00115                             res.pres = pres;
00116                             return res;
00117                         }
00118                         if (err < best_err)
00119                         {
00120                             best_err = err;
00121                             res.div = div;
00122                             res.mul = mul;
00123                             res.pres = pres;
00124                         }
00125                     }
00126                 }
00127             }
00128         }
00129         return res;
00130     }
00131 #endif  /* !USE_FIXED_PLL*/
00132
00133 /*
00134  * Override dummy hardware init functions supplied by the ASM startup
00135  * routine.
00136  */
00137
00138 void __init1(void);
00139 void __init2(void);
00140
00153 void __init1(void)
00154 {
00155     /*
00156      * Compute number of master clock cycles in 1.5us.
00157      * Needed by flash writing functions.
00158      * The maximum FMCN value is 0xFF and 0 can be used only if
00159      * master clock is less than 33kHz.
00160      */
00161     #define MCN  DIV_ROUNDUP(CPU_FREQ, 666667UL)
00162     #define FMCN (CPU_FREQ <= 33333UL ? 0 : (MCN < 0xFF ? MCN : 0xFF))
00163 
00164     #if CPU_FREQ < 30000000UL
00165         /* Use 1 cycles for flash access. */
00166         MC_FMR = FMCN << MC_FMCN_SHIFT | MC_FWS_1R2W;
00167     #else
00168         /* Use 2 cycles for flash access. */
00169         MC_FMR = FMCN << MC_FMCN_SHIFT | MC_FWS_2R3W;
00170     #endif
00171 
00172         /* Disable all interrupts. Useful for debugging w/o target reset. */
00173     AIC_EOICR = 0xFFFFFFFF;
00174     AIC_IDCR =  0xFFFFFFFF;
00175
00176     #if CONFIG_WATCHDOG == 0
00177         /* The watchdog is enabled after processor reset. Disable it. */
00178         WDT_MR = BV(WDT_WDDIS);
00179     #endif
00180 
00181         /*
00182          * Enable the main oscillator. Set startup time of 6 * 8 slow
00183          * clock cycles and wait until oscillator is stabilized.
00184          */
00185     CKGR_MOR = (6 << 8) | BV(CKGR_MOSCEN);
00186     while (!(PMC_SR & BV(PMC_MOSCS))) ;
00187
00188         /* Switch to Slow oscillator clock. */
00189     PMC_MCKR &= ~PMC_CSS_MASK;
00190     while (!(PMC_SR & BV(PMC_MCKRDY))) ;
00191
00192         /* Switch to prescaler div 1 factor. */
00193     PMC_MCKR &= ~PMC_PRES_MASK;
00194     while (!(PMC_SR & BV(PMC_MCKRDY))) ;
00195
00196     uint32_t div, pres, mul;
00197     #if USE_FIXED_PLL
00198         div = PLL_DIV_VAL;
00199         mul = PLL_MUL_VAL;
00200         pres = AT91MCK_PRES;
00201     #else
00202         PllRegs pll = pllCostants();
00203         div = pll.div;
00204         mul = pll.mul;
00205         pres = pll.pres << PMC_PRES_SHIFT;
00206     #endif
00207 
00208         /*
00209          * Set PLL:
00210          * PLLfreq = crystal / divider * (multiplier + 1)
00211          * Wait 28 clock cycles until PLL is locked.
00212          */
00213     CKGR_PLLR = ((mul << CKGR_MUL_SHIFT)
00214         | (28 << CKGR_PLLCOUNT_SHIFT) | div);
00215     while (!(PMC_SR & BV(PMC_LOCK))) ;
00216
00217     /* Set master clock prescaler.  */
00218     PMC_MCKR = pres;
00219     while (!(PMC_SR & BV(PMC_MCKRDY))) ;
00220
00221         /*
00222          * Switch to PLL clock. Trying to set this together with the
00223          * prescaler fails (see datasheets).
00224          */
00225     PMC_MCKR |= PMC_CSS_PLL_CLK;
00226     while (!(PMC_SR & BV(PMC_MCKRDY))) ;
00227 }
00228
00234 void __init2(void)
00235 {
00236     /* Enable external reset key. */
00237     RSTC_MR = (RSTC_KEY | BV(RSTC_URSTEN));
00238
00239     /* Enable clock for PIO(s) */
00240     PMC_PCER = BV(PIOA_ID);
00241     #if CPU_ARM_SAM7X
00242         PMC_PCER |= BV(PIOB_ID);
00243     #endif
00244 }