arch: add support for the SAMD21G18A used in the Arduino Zero.

Signed-off-by: Michael Hope <mlhx@google.com>
This commit is contained in:
Michael Hope 2017-11-22 09:02:20 +01:00 committed by Anas Nashif
commit b69c452e6f
13 changed files with 620 additions and 0 deletions

View file

@ -0,0 +1,6 @@
# Makefile - Atmel SAM0 MCU family
#
# Copyright (c) 2017 Google LLC.
# SPDX-License-Identifier: Apache-2.0
add_subdirectory(${SOC_SERIES})

View file

@ -0,0 +1,18 @@
# Kconfig - Atmel SAM0 MCU family configuration options
#
# Copyright (c) 2017 Google LLC.
# SPDX-License-Identifier: Apache-2.0
config SOC_FAMILY_SAM0
bool
default n
if SOC_FAMILY_SAM0
config SOC_FAMILY
string
default atmel_sam0
endif
source "arch/arm/soc/atmel_sam0/*/Kconfig.soc"

View file

@ -0,0 +1,6 @@
# Kconfig - Atmel SAM0 MCU family default configuration options
#
# Copyright (c) 2017 Google LLC.
# SPDX-License-Identifier: Apache-2.0
source "arch/arm/soc/atmel_sam0/*/Kconfig.defconfig.series"

View file

@ -0,0 +1,6 @@
# Kconfig - Atmel SAM0 MCU series selection
#
# Copyright (c) 2017 Google LLC.
# SPDX-License-Identifier: Apache-2.0
source "arch/arm/soc/atmel_sam0/*/Kconfig.series"

View file

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

View file

@ -0,0 +1,37 @@
# Kconfig - Atmel SAMD MCU series configuration options
#
# Copyright (c) 2017 Google LLC.
# SPDX-License-Identifier: Apache-2.0
if SOC_SERIES_SAMD
config SOC_SERIES
string
default samd
config SOC_PART_NUMBER
string
default samd21e15a if SOC_PART_NUMBER_SAMD21E15A
default samd21e16a if SOC_PART_NUMBER_SAMD21E16A
default samd21e17a if SOC_PART_NUMBER_SAMD21E17A
default samd21e18a if SOC_PART_NUMBER_SAMD21E18A
default samd21g15a if SOC_PART_NUMBER_SAMD21G15A
default samd21g16a if SOC_PART_NUMBER_SAMD21G16A
default samd21g17a if SOC_PART_NUMBER_SAMD21G17A
default samd21g17au if SOC_PART_NUMBER_SAMD21G17AU
default samd21g18a if SOC_PART_NUMBER_SAMD21G18A
default samd21g18au if SOC_PART_NUMBER_SAMD21G18AU
default samd21j15a if SOC_PART_NUMBER_SAMD21J15A
default samd21j16a if SOC_PART_NUMBER_SAMD21J16A
default samd21j17a if SOC_PART_NUMBER_SAMD21J17A
default samd21j18a if SOC_PART_NUMBER_SAMD21J18A
config NUM_IRQS
int
default 29
config SYS_CLOCK_HW_CYCLES_PER_SEC
int
default 48000000
endif # SOC_SERIES_SAMD

View file

@ -0,0 +1,15 @@
# Kconfig - Atmel SAMD MCU series
#
# Copyright (c) 2017 Google LLC.
# SPDX-License-Identifier: Apache-2.0
config SOC_SERIES_SAMD
bool "Atmel SAMD MCU"
select CPU_CORTEX_M
select CPU_CORTEX_M0PLUS
select SOC_FAMILY_SAM0
select SYS_POWER_LOW_POWER_STATE_SUPPORTED
select CPU_HAS_SYSTICK
select ASF
help
Enable support for Atmel SAMD Cortex-M0+ microcontrollers.

View file

@ -0,0 +1,89 @@
# Kconfig - Atmel SAMD MCU series
#
# Copyright (c) 2017 Google LLC.
# SPDX-License-Identifier: Apache-2.0
choice
prompt "Atmel SAMD MCU Selection"
depends on SOC_SERIES_SAMD
config SOC_PART_NUMBER_SAMD21E15A
bool "SAMD21E15A"
config SOC_PART_NUMBER_SAMD21E16A
bool "SAMD21E16A"
config SOC_PART_NUMBER_SAMD21E17A
bool "SAMD21E17A"
config SOC_PART_NUMBER_SAMD21E18A
bool "SAMD21E18A"
config SOC_PART_NUMBER_SAMD21G15A
bool "SAMD21G15A"
config SOC_PART_NUMBER_SAMD21G16A
bool "SAMD21G16A"
config SOC_PART_NUMBER_SAMD21G17A
bool "SAMD21G17A"
config SOC_PART_NUMBER_SAMD21G17AU
bool "SAMD21G17AU"
config SOC_PART_NUMBER_SAMD21G18A
bool "SAMD21G18A"
config SOC_PART_NUMBER_SAMD21G18AU
bool "SAMD21G18AU"
config SOC_PART_NUMBER_SAMD21J15A
bool "SAMD21J15A"
config SOC_PART_NUMBER_SAMD21J16A
bool "SAMD21J16A"
config SOC_PART_NUMBER_SAMD21J17A
bool "SAMD21J17A"
config SOC_PART_NUMBER_SAMD21J18A
bool "SAMD21J18A"
endchoice
if SOC_SERIES_SAMD
config SOC_ATMEL_SAMD_XOSC32K
bool "Enable the external 32 kHz crystal oscillator"
default n
help
Say y to enable the external 32 kHZ crystal oscillator at
startup. This can then be selected as the main clock source
for the SOC.
config SOC_ATMEL_SAMD_XOSC
bool "Enable the external crystal oscillator"
default n
help
Say y to enable the external crystal oscillator at startup.
choice
prompt "Main clock source"
help
Selects the clock that the main clocks, such as the CPU
clock and AHB clock, will be derived from.
config SOC_ATMEL_SAMD_XOSC32K_AS_MAIN
depends on SOC_ATMEL_SAMD_XOSC32K
bool "XOSC32K"
config SOC_ATMEL_SAMD_XOSC_AS_MAIN
depends on SOC_ATMEL_SAMD_XOSC
bool "XOSC"
config SOC_ATMEL_SAMD_OSC8M_AS_MAIN
bool "OSC8M"
endchoice
endif # SOC_SERIES_SAMD

View file

@ -0,0 +1,8 @@
/* linker.ld - Linker command/script file */
/*
* Copyright (c) 2017 Google LLC.
* SPDX-License-Identifier: Apache-2.0
*/
#include <arch/arm/cortex_m/scripts/linker.ld>

View file

@ -0,0 +1,209 @@
/*
* 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>
void soc_gpio_configure(const struct soc_gpio_pin *pin)
{
PortGroup *group = &PORT->Group[pin->group];
if ((pin->pin & 1) == 0) {
group->PMUX[pin->pin / 2].bit.PMUXE = pin->mux;
} else {
group->PMUX[pin->pin / 2].bit.PMUXO = pin->mux;
}
group->PINCFG[pin->pin].bit.PMUXEN = 1;
}
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);

View file

@ -0,0 +1,81 @@
/*
* Copyright (c) 2017 Google LLC.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _ATMEL_SAMD_SOC_H_
#define _ATMEL_SAMD_SOC_H_
#ifndef _ASMLANGUAGE
#define DONT_USE_CMSIS_INIT
#include <zephyr/types.h>
#if defined(CONFIG_SOC_PART_NUMBER_SAMD21E15A)
#include <samd21e15a.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMD21E16A)
#include <samd21e16a.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMD21E17A)
#include <samd21e17a.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMD21E18A)
#include <samd21e18a.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMD21G15A)
#include <samd21g15a.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMD21G16A)
#include <samd21g16a.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMD21G17A)
#include <samd21g17a.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMD21G17AU)
#include <samd21g17au.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMD21G18A)
#include <samd21g18a.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMD21G18AU)
#include <samd21g18au.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMD21J15A)
#include <samd21j15a.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMD21J16A)
#include <samd21j16a.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMD21J17A)
#include <samd21j17a.h>
#elif defined(CONFIG_SOC_PART_NUMBER_SAMD21J18A)
#include <samd21j18a.h>
#else
#error Library does not support the specified device.
#endif
#include "soc_pinmap.h"
struct soc_gpio_pin {
u8_t group;
u8_t pin;
u8_t mux;
};
void soc_gpio_configure(const struct soc_gpio_pin *pin);
#endif /* _ASMLANGUAGE */
/** Processor Clock (HCLK) Frequency */
#define SOC_ATMEL_SAM0_HCLK_FREQ_HZ CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC
/** Master Clock (MCK) Frequency */
#define SOC_ATMEL_SAM0_MCK_FREQ_HZ SOC_ATMEL_SAM0_HCLK_FREQ_HZ
#define SOC_ATMEL_SAM0_XOSC32K_FREQ_HZ 32768
#define SOC_ATMEL_SAM0_OSC8M_FREQ_HZ 8000000
#define SOC_ATMEL_SAM0_GCLK0_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
#if defined(CONFIG_SOC_ATMEL_SAMD_XOSC32K_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_FREQ_HZ SOC_ATMEL_SAM0_XOSC32K_FREQ_HZ
#elif defined(CONFIG_SOC_ATMEL_SAMD_OSC8M_AS_MAIN)
#define SOC_ATMEL_SAM0_GCLK1_FREQ_HZ SOC_ATMEL_SAM0_OSC8M_FREQ_HZ
#else
#error Unsupported GCLK1 clock source.
#endif
#define SOC_ATMEL_SAM0_GCLK3_FREQ_HZ SOC_ATMEL_SAM0_OSC8M_FREQ_HZ
#define SOC_ATMEL_SAM0_APBA_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
#define SOC_ATMEL_SAM0_APBB_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
#define SOC_ATMEL_SAM0_APBC_FREQ_HZ SOC_ATMEL_SAM0_MCK_FREQ_HZ
#endif /* _ATMEL_SAMD_SOC_H_ */

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2017 Google LLC.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _ATMEL_SAMD_SOC_PINMAP_H_
#define _ATMEL_SAMD_SOC_PINMAP_H_
/* SERCOM in UART mode */
/* SERCOM0 on RX=PA11, TX=PA10 */
#define PIN_UART_SAM0_SERCOM0_RX {0, 11, PORT_PMUX_PMUXE_C_Val}
#define PIN_UART_SAM0_SERCOM0_TX {0, 10, PORT_PMUX_PMUXE_C_Val}
/* SERCOM1 on RX=PA19, TX=PA18 */
#define PIN_UART_SAM0_SERCOM1_RX {0, 19, PORT_PMUX_PMUXE_C_Val}
#define PIN_UART_SAM0_SERCOM1_TX {0, 18, PORT_PMUX_PMUXE_C_Val}
/* SERCOM2 on RX=PA15, TX=PA14 */
#define PIN_UART_SAM0_SERCOM2_RX {0, 15, PORT_PMUX_PMUXE_C_Val}
#define PIN_UART_SAM0_SERCOM2_TX {0, 14, PORT_PMUX_PMUXE_C_Val}
/* SERCOM3 on RX=PA21, TX=PA20 */
#define PIN_UART_SAM0_SERCOM3_RX {0, 21, PORT_PMUX_PMUXE_D_Val}
#define PIN_UART_SAM0_SERCOM3_TX {0, 20, PORT_PMUX_PMUXE_D_Val}
/* SERCOM4 on RX=PB11, TX=PB10 */
#define PIN_UART_SAM0_SERCOM4_RX {0, 21, PORT_PMUX_PMUXE_C_Val}
#define PIN_UART_SAM0_SERCOM4_TX {0, 20, PORT_PMUX_PMUXE_C_Val}
/* SERCOM5 on RX=PB23, TX=PB22 */
#define PIN_UART_SAM0_SERCOM5_RX {1, 23, PORT_PMUX_PMUXE_D_Val}
#define PIN_UART_SAM0_SERCOM5_TX {1, 22, PORT_PMUX_PMUXE_D_Val}
#endif /* _ATMEL_SAMD_SOC_PINMAP_H_ */

103
dts/arm/atmel/samd21.dtsi Normal file
View file

@ -0,0 +1,103 @@
/*
* Copyright (c) 2017 Google LLC.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <arm/armv6-m.dtsi>
/ {
cpus {
#address-cells = <1>;
#size-cells = <0>;
cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-m0";
reg = <0>;
};
};
flash0: flash@0 {
reg = <0 0x40000>;
};
sram0: memory@20000000 {
device_type = "memory";
compatible = "mmio-sram";
reg = <0x20000000 0x8000>;
};
soc {
wdog: watchdog@40001000 {
compatible = "atmel,sam0-watchdog";
reg = <0x40001000 9>;
interrupts = <2 0>;
label = "WATCHDOG_0";
};
sercom0: uart@42000800 {
compatible = "atmel,sam0-uart";
reg = <0x42000800 0x40>;
interrupts = <9 0>;
status = "disabled";
label = "SERCOM0";
};
sercom1: uart@42000c00 {
compatible = "atmel,sam0-uart";
reg = <0x42000c00 0x40>;
interrupts = <10 0>;
status = "disabled";
label = "SERCOM1";
};
sercom2: uart@42001000 {
compatible = "atmel,sam0-uart";
reg = <0x42001000 0x40>;
interrupts = <11 0>;
status = "disabled";
label = "SERCOM2";
};
sercom3: uart@42001400 {
compatible = "atmel,sam0-uart";
reg = <0x42001400 0x40>;
interrupts = <12 0>;
status = "disabled";
label = "SERCOM3";
};
sercom4: uart@42001800 {
compatible = "atmel,sam0-uart";
reg = <0x42001800 0x40>;
interrupts = <13 0>;
status = "disabled";
label = "SERCOM4";
};
sercom5: uart@42001C00 {
compatible = "atmel,sam0-uart";
reg = <0x42001C00 0x40>;
interrupts = <14 0>;
status = "disabled";
label = "SERCOM5";
};
porta: gpio@41004400 {
compatible = "atmel,sam0-gpio";
reg = <0x41004400 0x80>;
label = "PORTA";
};
portb: gpio@41004480 {
compatible = "atmel,sam0-gpio";
reg = <0x41004480 0x80>;
label = "PORTB";
};
};
};
&nvic {
arm,num-irq-priority-bits = <2>;
};