soc: sam0: Make init code common between all samd2x SoCs

The init routines are the same for SAMD20, SAMD21 and SAMR21, so
move them into common/ to not have three copies of the same code.

Signed-off-by: Benjamin Valentin <benjamin.valentin@ml-pa.com>
This commit is contained in:
Benjamin Valentin 2019-03-25 16:08:41 +01:00 committed by Anas Nashif
commit 86bd319d1f
8 changed files with 17 additions and 413 deletions

View file

@ -3,4 +3,4 @@
# Copyright (c) 2017 Google LLC.
# SPDX-License-Identifier: Apache-2.0
add_subdirectory(${SOC_SERIES})
add_subdirectory(common)

View file

@ -0,0 +1,8 @@
# Makefile - Atmel SAM0 MCU family
#
# Copyright (c) 2019 ML!PA Consulting GmbH
# SPDX-License-Identifier: Apache-2.0
zephyr_sources_ifdef(CONFIG_SOC_SERIES_SAMD20 soc_samd2x.c)
zephyr_sources_ifdef(CONFIG_SOC_SERIES_SAMD21 soc_samd2x.c)
zephyr_sources_ifdef(CONFIG_SOC_SERIES_SAMR21 soc_samd2x.c)

View file

@ -55,8 +55,13 @@ static void xosc32k_init(void)
static void osc32k_init(void)
{
#ifdef FUSES_OSC32K_CAL_ADDR
u32_t fuse = *(u32_t *)FUSES_OSC32K_CAL_ADDR;
u32_t calib = (fuse & FUSES_OSC32K_CAL_Msk) >> FUSES_OSC32K_CAL_Pos;
#else
u32_t fuse = *(u32_t *)FUSES_OSC32KCAL_ADDR;
u32_t calib = (fuse & FUSES_OSC32KCAL_Msk) >> FUSES_OSC32KCAL_Pos;
#endif
SYSCTRL->OSC32K.reg = SYSCTRL_OSC32K_CALIB(calib) |
SYSCTRL_OSC32K_STARTUP(0x6u) |
@ -108,7 +113,9 @@ static void dfll_init(void)
}
SYSCTRL->DFLLCTRL.reg |= SYSCTRL_DFLLCTRL_MODE |
#ifdef SYSCTRL_DFLLCTRL_WAITLOCK
SYSCTRL_DFLLCTRL_WAITLOCK |
#endif
SYSCTRL_DFLLCTRL_QLDIS;
while (!SYSCTRL->PCLKSR.bit.DFLLRDY) {
}
@ -126,7 +133,7 @@ static void dfll_init(void)
static void osc8m_init(void)
{
/* Turn off the prescaler */
SYSCTRL->OSC8M.bit.PRESC = SYSCTRL_OSC8M_PRESC_0_Val;
SYSCTRL->OSC8M.bit.PRESC = SYSCTRL_OSC8M_PRESC(0);
SYSCTRL->OSC8M.bit.ONDEMAND = 0;
}

View file

@ -1,6 +0,0 @@
# Makefile - Atmel SAMD20 MCU series.
#
# Copyright (c) 2018 Sean Nyekjaer
# SPDX-License-Identifier: Apache-2.0
zephyr_sources(soc.c)

View file

@ -1,196 +0,0 @@
/*
* Copyright (c) 2018 Sean Nyekjaer
*
* 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_OSC32KCAL_ADDR;
u32_t calib = (fuse & FUSES_OSC32KCAL_Msk) >> FUSES_OSC32KCAL_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_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);
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();
z_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);

View file

@ -1,6 +0,0 @@
# Makefile - Atmel SAMD21 MCU series.
#
# Copyright (c) 2017 Google LLC.
# SPDX-License-Identifier: Apache-2.0
zephyr_sources(soc.c)

View file

@ -1,6 +0,0 @@
# Makefile - Atmel SAMR21 MCU series.
#
# Copyright (c) 2017 Google LLC.
# SPDX-License-Identifier: Apache-2.0
zephyr_sources(soc.c)

View file

@ -1,197 +0,0 @@
/*
* Copyright (c) 2017 Google LLC.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Atmel SAMR21 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_samr_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_samr_init, PRE_KERNEL_1, 0);