Move the SoC outside of the architecture tree and put them at the same level as boards and architectures allowing both SoCs and boards to be maintained outside the tree. Signed-off-by: Anas Nashif <anas.nashif@intel.com>
197 lines
4.4 KiB
C
197 lines
4.4 KiB
C
/*
|
|
* Copyright (c) 2017 Google LLC.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* @brief Atmel SAMD MCU series initialization code
|
|
*/
|
|
|
|
#include <arch/cpu.h>
|
|
#include <cortex_m/exc.h>
|
|
#include <device.h>
|
|
#include <init.h>
|
|
#include <kernel.h>
|
|
#include <soc.h>
|
|
|
|
static void flash_waitstates_init(void)
|
|
{
|
|
/* One wait state at 48 MHz. */
|
|
NVMCTRL->CTRLB.bit.RWS = NVMCTRL_CTRLB_RWS_HALF_Val;
|
|
}
|
|
|
|
/* Follows the same structure as the Arduino Zero, namely:
|
|
* XOSC32K -> GCLK1 -> DFLL48M -> GCLK0
|
|
* OSC8M -> 8 MHz -> GCLK3
|
|
*/
|
|
|
|
static void xosc_init(void)
|
|
{
|
|
#ifdef CONFIG_SOC_ATMEL_SAMD_XOSC
|
|
#error External oscillator support is not implemented.
|
|
#endif
|
|
}
|
|
|
|
static void wait_gclk_synchronization(void)
|
|
{
|
|
while (GCLK->STATUS.bit.SYNCBUSY) {
|
|
}
|
|
}
|
|
|
|
static void xosc32k_init(void)
|
|
{
|
|
#ifdef CONFIG_SOC_ATMEL_SAMD_XOSC32K
|
|
SYSCTRL->XOSC32K.reg = SYSCTRL_XOSC32K_STARTUP(6) |
|
|
SYSCTRL_XOSC32K_XTALEN | SYSCTRL_XOSC32K_EN32K;
|
|
|
|
SYSCTRL->XOSC32K.bit.ENABLE = 1;
|
|
/* Wait for the crystal to stabalise. */
|
|
while (!SYSCTRL->PCLKSR.bit.XOSC32KRDY) {
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void osc32k_init(void)
|
|
{
|
|
u32_t fuse = *(u32_t *)FUSES_OSC32K_CAL_ADDR;
|
|
u32_t calib = (fuse & FUSES_OSC32K_CAL_Msk) >> FUSES_OSC32K_CAL_Pos;
|
|
|
|
SYSCTRL->OSC32K.reg = SYSCTRL_OSC32K_CALIB(calib) |
|
|
SYSCTRL_OSC32K_STARTUP(0x6u) |
|
|
SYSCTRL_OSC32K_EN32K | SYSCTRL_OSC32K_ENABLE;
|
|
|
|
/* Wait for the oscillator to stabalise. */
|
|
while (!SYSCTRL->PCLKSR.bit.OSC32KRDY) {
|
|
}
|
|
}
|
|
|
|
static void dfll_init(void)
|
|
{
|
|
/* No prescaler */
|
|
GCLK->GENDIV.reg = GCLK_GENDIV_ID(1) | GCLK_GENDIV_DIV(0);
|
|
wait_gclk_synchronization();
|
|
|
|
|
|
#if defined(CONFIG_SOC_ATMEL_SAMD_XOSC32K_AS_MAIN)
|
|
/* Route XOSC32K to GCLK1 */
|
|
GCLK->GENCTRL.reg =
|
|
GCLK_GENCTRL_ID(1) | GCLK_GENCTRL_SRC_XOSC32K | GCLK_GENCTRL_GENEN;
|
|
#elif defined(CONFIG_SOC_ATMEL_SAMD_OSC8M_AS_MAIN)
|
|
/* Route OSC8M to GCLK1 */
|
|
GCLK->GENCTRL.reg =
|
|
GCLK_GENCTRL_ID(1) | GCLK_GENCTRL_SRC_OSC8M | GCLK_GENCTRL_GENEN;
|
|
#else
|
|
#error Unsupported main clock source.
|
|
#endif
|
|
|
|
wait_gclk_synchronization();
|
|
|
|
/* Route GCLK1 to multiplexer 1 */
|
|
GCLK->CLKCTRL.reg =
|
|
GCLK_CLKCTRL_ID(0) | GCLK_CLKCTRL_GEN_GCLK1 | GCLK_CLKCTRL_CLKEN;
|
|
wait_gclk_synchronization();
|
|
|
|
SYSCTRL->DFLLCTRL.reg = SYSCTRL_DFLLCTRL_ENABLE;
|
|
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
|
|
}
|
|
|
|
u32_t mul = (SOC_ATMEL_SAM0_MCK_FREQ_HZ +
|
|
SOC_ATMEL_SAM0_GCLK1_FREQ_HZ / 2) /
|
|
SOC_ATMEL_SAM0_GCLK1_FREQ_HZ;
|
|
|
|
SYSCTRL->DFLLMUL.reg = SYSCTRL_DFLLMUL_CSTEP(31) |
|
|
SYSCTRL_DFLLMUL_FSTEP(511) |
|
|
SYSCTRL_DFLLMUL_MUL(mul);
|
|
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
|
|
}
|
|
|
|
SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_MODE |
|
|
SYSCTRL_DFLLCTRL_WAITLOCK |
|
|
SYSCTRL_DFLLCTRL_QLDIS;
|
|
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
|
|
}
|
|
|
|
/* Enable the DFLL */
|
|
SYSCTRL->DFLLCTRL.bit.ENABLE = 1;
|
|
|
|
while (!SYSCTRL->PCLKSR.bit.DFLLLCKC || !SYSCTRL->PCLKSR.bit.DFLLLCKF) {
|
|
}
|
|
|
|
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
|
|
}
|
|
}
|
|
|
|
static void osc8m_init(void)
|
|
{
|
|
/* Turn off the prescaler */
|
|
SYSCTRL->OSC8M.bit.PRESC = SYSCTRL_OSC8M_PRESC_0_Val;
|
|
SYSCTRL->OSC8M.bit.ONDEMAND = 0;
|
|
}
|
|
|
|
static void gclks_init(void)
|
|
{
|
|
/* DFLL/1 -> GCLK0 */
|
|
GCLK->GENDIV.reg = GCLK_GENDIV_ID(0) | GCLK_GENDIV_DIV(0);
|
|
wait_gclk_synchronization();
|
|
|
|
GCLK->GENCTRL.reg = GCLK_GENCTRL_ID(0) | GCLK_GENCTRL_SRC_DFLL48M |
|
|
GCLK_GENCTRL_IDC | GCLK_GENCTRL_GENEN;
|
|
wait_gclk_synchronization();
|
|
|
|
/* OSC8M/1 -> GCLK3 */
|
|
GCLK->GENCTRL.reg =
|
|
GCLK_GENCTRL_ID(3) | GCLK_GENCTRL_SRC_OSC8M | GCLK_GENCTRL_GENEN;
|
|
wait_gclk_synchronization();
|
|
|
|
/* OSCULP32K/32 -> GCLK2 */
|
|
GCLK->GENDIV.reg = GCLK_GENDIV_ID(2) | GCLK_GENDIV_DIV(32 - 1);
|
|
wait_gclk_synchronization();
|
|
|
|
GCLK->GENCTRL.reg =
|
|
GCLK_GENCTRL_ID(2) | GCLK_GENCTRL_SRC_OSC32K | GCLK_GENCTRL_GENEN;
|
|
wait_gclk_synchronization();
|
|
}
|
|
|
|
static void dividers_init(void)
|
|
{
|
|
/* Set the CPU, APBA, B, and C dividers */
|
|
PM->CPUSEL.reg = PM_CPUSEL_CPUDIV_DIV1;
|
|
PM->APBASEL.reg = PM_APBASEL_APBADIV_DIV1_Val;
|
|
PM->APBBSEL.reg = PM_APBBSEL_APBBDIV_DIV1_Val;
|
|
PM->APBCSEL.reg = PM_APBCSEL_APBCDIV_DIV1_Val;
|
|
|
|
/* TODO(mlhx): enable clock failure detection? */
|
|
}
|
|
|
|
static int atmel_samd_init(struct device *arg)
|
|
{
|
|
u32_t key;
|
|
|
|
ARG_UNUSED(arg);
|
|
|
|
key = irq_lock();
|
|
|
|
_ClearFaults();
|
|
|
|
flash_waitstates_init();
|
|
osc8m_init();
|
|
osc32k_init();
|
|
xosc_init();
|
|
xosc32k_init();
|
|
dfll_init();
|
|
gclks_init();
|
|
dividers_init();
|
|
|
|
/* Install default handler that simply resets the CPU
|
|
* if configured in the kernel, NOP otherwise
|
|
*/
|
|
NMI_INIT();
|
|
|
|
irq_unlock(key);
|
|
|
|
return 0;
|
|
}
|
|
|
|
SYS_INIT(atmel_samd_init, PRE_KERNEL_1, 0);
|