Skip to content

Commit

Permalink
arch: sam3x: Use ASF library
Browse files Browse the repository at this point in the history
This patch converts Atmel sam3x MCU series to use register
header files from Atmel Software Framework (ASF) library.
By using ASF different Atmel SAM MCU series can use common
device drivers.

Signed-off-by: Piotr Mienkowski <[email protected]>
  • Loading branch information
mnkp authored and Anas Nashif committed May 19, 2017
1 parent 05d0726 commit ee66ee6
Show file tree
Hide file tree
Showing 12 changed files with 421 additions and 854 deletions.
1 change: 1 addition & 0 deletions arch/arm/soc/atmel_sam/sam3x/Kconfig.series
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ config SOC_SERIES_SAM3X
select SOC_FAMILY_SAM
select SYS_POWER_LOW_POWER_STATE_SUPPORTED
select CPU_HAS_SYSTICK
select ASF
help
Enable support for Atmel SAM3X Cortex-M3 microcontrollers.
Part No.: SAM3X8E
228 changes: 140 additions & 88 deletions arch/arm/soc/atmel_sam/sam3x/soc.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

/**
* @file
* @brief System/hardware module for Atmel SAM3X series processor
* @brief Atmel SAM3X MCU series initialization code
*
* This module provides routines to initialize and support board-level hardware
* for the Atmel SAM3X series processor.
Expand All @@ -17,125 +17,187 @@
#include <device.h>
#include <init.h>
#include <soc.h>

#include <arch/cpu.h>
#include <cortex_m/exc.h>

/**
* @brief Setup various clock on SoC.
/*
* PLL clock = Main * (MULA + 1) / DIVA
*
* Setup the SoC clocks according to section 28.12 in datasheet.
* By default, MULA == 6, DIVA == 1.
* With main crystal running at 12 MHz,
* PLL = 12 * (6 + 1) / 1 = 84 MHz
*
* Assumption:
* SLCK = 32.768kHz
* With Processor Clock prescaler at 1
* Processor Clock (HCLK) = 84 MHz.
*/
#define PMC_CKGR_PLLAR_MULA \
(CKGR_PLLAR_MULA(CONFIG_SOC_ATMEL_SAM3X_PLLA_MULA))
#define PMC_CKGR_PLLAR_DIVA \
(CKGR_PLLAR_DIVA(CONFIG_SOC_ATMEL_SAM3X_PLLA_DIVA))

/**
* @brief Setup various clocks on SoC at boot time.
*
* Setup Slow, Main, PLLA, Processor and Master clocks during the device boot.
* It is assumed that the relevant registers are at their reset value.
*/
static ALWAYS_INLINE void clock_init(void)
{
u32_t tmp;

/* Note:
* Magic numbers below are obtained by reading the registers
* when the SoC was running the SAM-BA bootloader
* (with reserved bits set to 0).
*/
u32_t reg_val;

#ifdef CONFIG_SOC_ATMEL_SAM3X_EXT_SLCK
/* This part is to switch the slow clock to using
* the external 32 kHz crystal oscillator.
*/

/* Select external crystal */
__SUPC->cr = SUPC_CR_KEY | SUPC_CR_XTALSEL;
/* Switch slow clock to the external 32 kHz crystal oscillator */
SUPC->SUPC_CR = SUPC_CR_KEY_PASSWD | SUPC_CR_XTALSEL;

/* Wait for oscillator to be stablized */
while (!(__SUPC->sr & SUPC_SR_OSCSEL))
/* Wait for oscillator to be stabilized */
while (!(SUPC->SUPC_SR & SUPC_SR_OSCSEL)) {
;
}
#endif /* CONFIG_SOC_ATMEL_SAM3X_EXT_SLCK */

#ifdef CONFIG_SOC_ATMEL_SAM3X_EXT_MAINCK
/* Start the external main oscillator */
__PMC->ckgr_mor = PMC_CKGR_MOR_KEY | PMC_CKGR_MOR_MOSCRCF_4MHZ
| PMC_CKGR_MOR_MOSCRCEN | PMC_CKGR_MOR_MOSCXTEN
| PMC_CKGR_MOR_MOSCXTST;
/*
* Setup main external crystal oscillator
*/

/* Wait for main oscillator to be stablized */
while (!(__PMC->sr & PMC_INT_MOSCXTS))
/* Start the external crystal oscillator */
PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD
/* Fast RC Oscillator Frequency is at 4 MHz (default) */
| CKGR_MOR_MOSCRCF_4_MHz
/* We select maximum setup time. While start up time
* could be shortened this optimization is not deemed
* critical now.
*/
| CKGR_MOR_MOSCXTST(0xFFu)
/* RC OSC must stay on */
| CKGR_MOR_MOSCRCEN
| CKGR_MOR_MOSCXTEN;

/* Wait for oscillator to be stabilized */
while (!(PMC->PMC_SR & PMC_SR_MOSCXTS)) {
;
}

/* Select the external crystal oscillator as the main clock source */
PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD
| CKGR_MOR_MOSCRCF_4_MHz
| CKGR_MOR_MOSCSEL
| CKGR_MOR_MOSCXTST(0xFFu)
| CKGR_MOR_MOSCRCEN
| CKGR_MOR_MOSCXTEN;

/* Wait for external oscillator to be selected */
while (!(PMC->PMC_SR & PMC_SR_MOSCSELS)) {
;
}

/* Select main oscillator as source since it is more accurate
* according to datasheet.
*/
__PMC->ckgr_mor = PMC_CKGR_MOR_KEY | PMC_CKGR_MOR_MOSCRCF_4MHZ
| PMC_CKGR_MOR_MOSCRCEN | PMC_CKGR_MOR_MOSCXTEN
| PMC_CKGR_MOR_MOSCXTST | PMC_CKGR_MOR_MOSCSEL;
/* Turn off RC OSC, not used any longer, to save power */
PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD
| CKGR_MOR_MOSCSEL
| CKGR_MOR_MOSCXTST(0xFFu)
| CKGR_MOR_MOSCXTEN;

/* Wait for main oscillator to be selected */
while (!(__PMC->sr & PMC_INT_MOSCSELS))
/* Wait for RC OSC to be turned off */
while (PMC->PMC_SR & PMC_SR_MOSCRCS) {
;
}

#ifdef CONFIG_SOC_ATMEL_SAM3X_WAIT_MODE
/*
* Instruct CPU enter Wait mode instead of Sleep mode to
* Instruct CPU to enter Wait mode instead of Sleep mode to
* keep Processor Clock (HCLK) and thus be able to debug
* CPU using JTAG
*/
__PMC->fsmr |= PMC_FSMR_LPM;
PMC->PMC_FSMR |= PMC_FSMR_LPM;
#endif
#else
/*
* Setup main fast RC oscillator
*/

/*
* NOTE: MOSCRCF must be changed only if MOSCRCS is set in the PMC_SR
* register, should normally be the case here
*/
while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) {
;
}

/* Set main fast RC oscillator to 12 MHz */
__PMC->ckgr_mor = PMC_CKGR_MOR_KEY | PMC_CKGR_MOR_MOSCRCF_12MHZ
| PMC_CKGR_MOR_MOSCRCEN;
PMC->CKGR_MOR = CKGR_MOR_KEY_PASSWD
| CKGR_MOR_MOSCRCF_12_MHz
| CKGR_MOR_MOSCRCEN;

/* Wait for main fast RC oscillator to be stablized */
while (!(__PMC->sr & PMC_INT_MOSCRCS))
/* Wait for oscillator to be stabilized */
while (!(PMC->PMC_SR & PMC_SR_MOSCRCS)) {
;
}
#endif /* CONFIG_SOC_ATMEL_SAM3X_EXT_MAINCK */

/* Use PLLA as master clock.
* According to datasheet, PMC_MCKR must not be programmed in
* a single write operation. So it seems the safe way is to
* get the system to use main clock (by setting CSS). Then set
* the prescaler (PRES). Finally setting it back to using PLL.
/*
* Setup PLLA
*/

/* Switch to main clock first so we can setup PLL */
tmp = __PMC->mckr & ~PMC_MCKR_CSS_MASK;
__PMC->mckr = tmp | PMC_MCKR_CSS_MAIN;
/* Switch MCK (Master Clock) to the main clock first */
reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk;
PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_MAIN_CLK;

/* Wait for clock selection complete */
while (!(__PMC->sr & PMC_INT_MCKRDY))
/* Wait for clock selection to complete */
while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) {
;
}

/* Setup PLLA */
__PMC->ckgr_pllar = PMC_CKGR_PLLAR_DIVA | PMC_CKGR_PLLAR_ONE
| PMC_CKGR_PLLAR_MULA
| PMC_CKGR_PLLAR_PLLACOUNT;
PMC->CKGR_PLLAR = CKGR_PLLAR_ONE
| PMC_CKGR_PLLAR_MULA
| CKGR_PLLAR_PLLACOUNT(0x3Fu)
| PMC_CKGR_PLLAR_DIVA;

/*
* NOTE: Both MULA and DIVA must be set to a value greater than 0 or
* otherwise PLL will be disabled. In this case we would get stuck in
* the following loop.
*/

/* Wait for PLL lock */
while (!(__PMC->sr & PMC_INT_LOCKA))
while (!(PMC->PMC_SR & PMC_SR_LOCKA)) {
;
}

/*
* Final setup of the Master Clock
*/

/*
* NOTE: PMC_MCKR must not be programmed in a single write operation.
* If CSS or PRES are modified we must wait for MCKRDY bit to be
* set again.
*/

/* Setup prescaler */
tmp = __PMC->mckr & ~PMC_MCKR_PRES_MASK;
__PMC->mckr = tmp | PMC_MCKR_PRES_CLK;
/* Setup prescaler - PLLA Clock / Processor Clock (HCLK) */
reg_val = PMC->PMC_MCKR & ~PMC_MCKR_PRES_Msk;
PMC->PMC_MCKR = reg_val | PMC_MCKR_PRES_CLK_1;

/* Wait for main clock setup complete */
while (!(__PMC->sr & PMC_INT_MCKRDY))
/* Wait for Master Clock setup to complete */
while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) {
;
}

/* Finally select PLL as clock source */
tmp = __PMC->mckr & ~PMC_MCKR_CSS_MASK;
__PMC->mckr = tmp | PMC_MCKR_CSS_PLLA;
/* Finally select PLL as Master Clock source */
reg_val = PMC->PMC_MCKR & ~PMC_MCKR_CSS_Msk;
PMC->PMC_MCKR = reg_val | PMC_MCKR_CSS_PLLA_CLK;

/* Wait for main clock setup complete */
while (!(__PMC->sr & PMC_INT_MCKRDY))
/* Wait for Master Clock setup to complete */
while (!(PMC->PMC_SR & PMC_SR_MCKRDY)) {
;
}
}

/**
* @brief Perform basic hardware initialization at boot.
*
* This needs to be run from the very beginning.
* So the init priority has to be 0 (zero).
* This has to be run at the very beginning thus the init priority is set at
* 0 (zero).
*
* @return 0
*/
Expand All @@ -145,31 +207,21 @@ static int atmel_sam3x_init(struct device *arg)

ARG_UNUSED(arg);

/* Note:
* Magic numbers below are obtained by reading the registers
* when the SoC was running the SAM-BA bootloader
* (with reserved bits set to 0).
*/

key = irq_lock();

/* Setup the flash controller.
* The bootloader is running @ 48 MHz with
* FWS == 2.
* When running at 84 MHz, FWS == 4 seems
* to be more stable, and allows the board
* to boot.
*/
__EEFC0->fmr = 0x00000400;
__EEFC1->fmr = 0x00000400;

_ClearFaults();

/* Setup master clock */
clock_init();
/*
* Set FWS (Flash Wait State) value before increasing Master Clock
* (MCK) frequency.
* TODO: set FWS based on the actual MCK frequency and VDDCORE value
* rather than maximum supported 84 MHz at standard VDDCORE=1.8V
*/
EFC0->EEFC_FMR = EEFC_FMR_FWS(4);
EFC1->EEFC_FMR = EEFC_FMR_FWS(4);

/* Disable watchdog timer, not used by system */
__WDT->mr |= WDT_DISABLE;
/* Setup system clocks */
clock_init();

/* Install default handler that simply resets the CPU
* if configured in the kernel, NOP otherwise
Expand Down
Loading

0 comments on commit ee66ee6

Please sign in to comment.