mirror of https://github.com/wolfSSL/wolfBoot.git
Added support for ATMEL SAM-R21
parent
9410a6fe7b
commit
f4f65ae31d
|
@ -0,0 +1,209 @@
|
||||||
|
/* samr21.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 wolfSSL Inc.
|
||||||
|
*
|
||||||
|
* This file is part of wolfBoot.
|
||||||
|
*
|
||||||
|
* wolfBoot is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* wolfBoot is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Clock settings for cpu samd21g18a @ 48MHz */
|
||||||
|
#define CPU_FREQ (48000000)
|
||||||
|
#define GCLK_CTRL_RESET (1)
|
||||||
|
#define GCLK_GENDIV_DIVSHIFT (8)
|
||||||
|
#define GCLK_CLKCTRL_GENSHIFT (8)
|
||||||
|
#define GCLK_STATUS_SYNCBUSY (1 << 7)
|
||||||
|
#define GCLK_GENCTRL_SRC_OSC8M (6 << 8)
|
||||||
|
#define GCLK_GENCTRL_EN (1 << 16)
|
||||||
|
#define GCLK_GENCTRL_SRC_FDPLL (1 << 11)
|
||||||
|
#define GCLK_CLKCTRL_GEN_CLK7 (7 << 8)
|
||||||
|
#define GCLK_CLKCTRL_CLKEN (1 << 14)
|
||||||
|
#define WAITSTATES (1)
|
||||||
|
|
||||||
|
/* Flash settings for samd21g18a */
|
||||||
|
#define FLASH_SIZE (256 * 1024)
|
||||||
|
#define FLASH_PAGESIZE 64
|
||||||
|
#define FLASH_N_PAGES 4096
|
||||||
|
|
||||||
|
#define WDT_CTRL *((volatile uint8_t *)(0x40001000))
|
||||||
|
#define WDT_EN (1 << 1)
|
||||||
|
|
||||||
|
|
||||||
|
#define APBAMASK_REG *((volatile uint32_t *)(0x40000418))
|
||||||
|
#define APBAMASK_PM_EN (1 << 1)
|
||||||
|
#define APBAMASK_SYSCTRL_EN (1 << 2)
|
||||||
|
#define APBAMASK_GCLK_EN (1 << 3)
|
||||||
|
|
||||||
|
#define APBBMASK_REG *((volatile uint32_t *)(0x4000041C))
|
||||||
|
#define APBBMASK_NVM_EN (1 << 2)
|
||||||
|
|
||||||
|
#define NVMCTRL_BASE (0x41004000)
|
||||||
|
#define NVMCTRLA_REG *((volatile uint16_t *)(NVMCTRL_BASE))
|
||||||
|
#define NVMCTRLB_REG *((volatile uint32_t *)(NVMCTRL_BASE + 4))
|
||||||
|
#define NVMCTRL_INTFLAG *((volatile uint8_t *)(NVMCTRL_BASE + 0x14))
|
||||||
|
#define NVMCTRL_ADDR *((volatile uint32_t *)(NVMCTRL_BASE + 0x1c))
|
||||||
|
#define NVMCMD_KEY (0xA500)
|
||||||
|
#define NVMCMD_ERASE (0x02)
|
||||||
|
#define NVMCMD_WP (0x04)
|
||||||
|
#define NVMCMD_PBC (0x44)
|
||||||
|
#define NVMCTRL_INTFLAG_NVMREADY (1)
|
||||||
|
|
||||||
|
|
||||||
|
#define GCLK_BASE (0x40000C00)
|
||||||
|
#define GCLK_CTRL *((volatile uint8_t *)(GCLK_BASE))
|
||||||
|
#define GCLK_STATUS *((volatile uint8_t *)(GCLK_BASE + 1))
|
||||||
|
#define GCLK_CLKCTRL *((volatile uint16_t *)(GCLK_BASE + 2))
|
||||||
|
#define GCLK_GENCTRL *((volatile uint32_t *)(GCLK_BASE + 4))
|
||||||
|
#define GCLK_GENDIV *((volatile uint32_t *)(GCLK_BASE + 8))
|
||||||
|
|
||||||
|
#define SYSCTRL_OSC8M *((volatile uint32_t *)(0x40000820))
|
||||||
|
#define SYSCTRL_OSC8M_ENABLE (1 << 1)
|
||||||
|
#define SYSCTRL_OSC8M_ONDEMAND (1 << 7)
|
||||||
|
#define SYSCTRL_OSC8M_PRESC_MASK (3 << 8)
|
||||||
|
#define SYSCTRL_OSC8M_RUNSTDBY (1 << 6)
|
||||||
|
|
||||||
|
#define SYSCTRL_PLLK_SR *((volatile uint32_t *)(0x4000080c))
|
||||||
|
#define PLLK_SR_OSC8M_RDY (1 << 3)
|
||||||
|
#define OSC8M_WAITBUSY() { while (!(SYSCTRL_PLLK_SR & (PLLK_SR_OSC8M_RDY))) {} }
|
||||||
|
|
||||||
|
#define SYSCTRL_DPLL (0x40000844)
|
||||||
|
#define SYSCTRL_DPLLCTRLA *((volatile uint8_t *)(0x40000844))
|
||||||
|
#define SYSCTRL_DPLLRATIO *((volatile uint32_t *)(0x40000848))
|
||||||
|
#define SYSCTRL_DPLLCTRLB *((volatile uint32_t *)(0x4000084C))
|
||||||
|
#define SYSCTRL_DPLLSTATUS *((volatile uint8_t *)(0x40000850))
|
||||||
|
|
||||||
|
#define DPLLCTRLA_ENABLE (1 << 1)
|
||||||
|
#define DPLLCTRLB_REFCLK_GCLK (1 << 5)
|
||||||
|
#define DPLLSTATUS_CLKRDY (1 << 1)
|
||||||
|
#define DPLLSTATUS_LOCK (1 << 0)
|
||||||
|
#define SYSCTRL_DPLLSTATUS_WAITLOCK() { while (!(SYSCTRL_DPLLSTATUS & (DPLLSTATUS_CLKRDY | DPLLSTATUS_LOCK))) {} }
|
||||||
|
|
||||||
|
|
||||||
|
#define PAC1_BASE (0x41000000)
|
||||||
|
#define PAC1_WPCLR *((volatile uint32_t *)(PAC1_BASE)) /* Register to clear write protection (unlock flash) */
|
||||||
|
#define PAC1_WPSET *((volatile uint32_t *)(PAC1_BASE + 4)) /* Register to set write protection (lock flash) */
|
||||||
|
#define PAC_WP_NVMCTL (1 << 1) /* Bit position for NVM in WPCLR/WPSET registers */
|
||||||
|
|
||||||
|
|
||||||
|
#define GCLK_WAITBUSY() { while (GCLK_STATUS & GCLK_STATUS_SYNCBUSY) {} }
|
||||||
|
|
||||||
|
void hal_init(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
WDT_CTRL &= (~WDT_EN);
|
||||||
|
__asm__ volatile ("cpsid i");
|
||||||
|
uint32_t i, reg;
|
||||||
|
/* enable clocks for the power, sysctrl and gclk modules */
|
||||||
|
APBAMASK_REG = APBAMASK_PM_EN | APBAMASK_SYSCTRL_EN | APBAMASK_GCLK_EN;
|
||||||
|
|
||||||
|
/* set NVM wait states */
|
||||||
|
APBBMASK_REG |= APBBMASK_NVM_EN;
|
||||||
|
NVMCTRLB_REG |= ((WAITSTATES & 0x0f) << 1);
|
||||||
|
APBBMASK_REG &= ~APBBMASK_NVM_EN;
|
||||||
|
|
||||||
|
|
||||||
|
/* Set 8MHz oscillator */
|
||||||
|
reg = SYSCTRL_OSC8M & (~(SYSCTRL_OSC8M_PRESC_MASK | SYSCTRL_OSC8M_RUNSTDBY));
|
||||||
|
SYSCTRL_OSC8M = reg | SYSCTRL_OSC8M_ENABLE | SYSCTRL_OSC8M_ONDEMAND;
|
||||||
|
OSC8M_WAITBUSY();
|
||||||
|
|
||||||
|
/* Set PLL config */
|
||||||
|
GCLK_CTRL = GCLK_CTRL_RESET;
|
||||||
|
GCLK_WAITBUSY();
|
||||||
|
GCLK_GENDIV = (8 << GCLK_GENDIV_DIVSHIFT) | 1;
|
||||||
|
GCLK_GENCTRL = GCLK_GENCTRL_EN | GCLK_GENCTRL_SRC_OSC8M | 1;
|
||||||
|
GCLK_CLKCTRL = (1 << GCLK_CLKCTRL_GENSHIFT) | GCLK_CLKCTRL_CLKEN | 1;
|
||||||
|
GCLK_WAITBUSY();
|
||||||
|
SYSCTRL_DPLLRATIO = (47);
|
||||||
|
SYSCTRL_DPLLCTRLB = DPLLCTRLB_REFCLK_GCLK;
|
||||||
|
SYSCTRL_DPLLCTRLA = DPLLCTRLA_ENABLE;
|
||||||
|
SYSCTRL_DPLLSTATUS_WAITLOCK();
|
||||||
|
GCLK_GENDIV = (1 << GCLK_GENDIV_DIVSHIFT) | 0;
|
||||||
|
GCLK_GENCTRL = GCLK_GENCTRL_EN | GCLK_GENCTRL_SRC_FDPLL;
|
||||||
|
GCLK_WAITBUSY();
|
||||||
|
for (i = 3; i <= 34; i++) {
|
||||||
|
GCLK_CLKCTRL = GCLK_CLKCTRL_GEN_CLK7 | i;
|
||||||
|
GCLK_WAITBUSY();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_prepare_boot(void)
|
||||||
|
{
|
||||||
|
/* Reset NVM wait states */
|
||||||
|
APBBMASK_REG |= APBBMASK_NVM_EN;
|
||||||
|
NVMCTRLB_REG &= ~((WAITSTATES & 0x0f) << 1);
|
||||||
|
APBBMASK_REG &= ~APBBMASK_NVM_EN;
|
||||||
|
|
||||||
|
/* Reset clock controller */
|
||||||
|
GCLK_CTRL = GCLK_CTRL_RESET;
|
||||||
|
GCLK_WAITBUSY();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int hal_flash_write(uint32_t address, const uint8_t *data, int len)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
uint32_t *src, *dst;
|
||||||
|
|
||||||
|
if (len <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Clear page buffer */
|
||||||
|
NVMCTRLA_REG = (NVMCMD_PBC | NVMCMD_KEY);
|
||||||
|
while (i < len) {
|
||||||
|
if ((len - i > 3) && ((((address + i) & 0x03) == 0) && ((((uint32_t)data) + i) & 0x03) == 0)) {
|
||||||
|
src = (uint32_t *)data;
|
||||||
|
dst = (uint32_t *)address;
|
||||||
|
dst[i >> 2] = src[i >> 2];
|
||||||
|
i+=4;
|
||||||
|
} else {
|
||||||
|
uint32_t val;
|
||||||
|
uint8_t *vbytes = (uint8_t *)(&val);
|
||||||
|
int off = (address + i) - (((address + i) >> 2) << 2);
|
||||||
|
dst = (uint32_t *)(address - off);
|
||||||
|
val = dst[i >> 2];
|
||||||
|
vbytes[off] = data[i];
|
||||||
|
dst[i >> 2] = val;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Enable write protection */
|
||||||
|
NVMCTRLA_REG = (NVMCMD_WP | NVMCMD_KEY);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_flash_unlock(void)
|
||||||
|
{
|
||||||
|
PAC1_WPCLR |= (PAC_WP_NVMCTL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_flash_lock(void)
|
||||||
|
{
|
||||||
|
PAC1_WPSET |= (PAC_WP_NVMCTL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int hal_flash_erase(uint32_t address, int len)
|
||||||
|
{
|
||||||
|
while (len > 0) {
|
||||||
|
NVMCTRL_ADDR = (address >> 1); /* This register holds the address of a 16-bit row */
|
||||||
|
NVMCTRLA_REG = NVMCMD_ERASE | NVMCMD_KEY;
|
||||||
|
while(!(NVMCTRL_INTFLAG & NVMCTRL_INTFLAG_NVMREADY))
|
||||||
|
len -= FLASH_PAGESIZE;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
FLASH (rx) : ORIGIN = 0x00000000, LENGTH = 0x0010000
|
||||||
|
RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x4000
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
_start_text = .;
|
||||||
|
KEEP(*(.isr_vector))
|
||||||
|
*(.text*)
|
||||||
|
*(.rodata*)
|
||||||
|
*(.init*)
|
||||||
|
*(.fini*)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_end_text = .;
|
||||||
|
} > FLASH
|
||||||
|
|
||||||
|
.edidx :
|
||||||
|
{
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.ARM.exidx*)
|
||||||
|
} > FLASH
|
||||||
|
|
||||||
|
_stored_data = .;
|
||||||
|
|
||||||
|
.data : AT (_stored_data)
|
||||||
|
{
|
||||||
|
_start_data = .;
|
||||||
|
KEEP(*(.data*))
|
||||||
|
. = ALIGN(4);
|
||||||
|
_end_data = .;
|
||||||
|
} > RAM
|
||||||
|
|
||||||
|
.bss (NOLOAD) :
|
||||||
|
{
|
||||||
|
_start_bss = .;
|
||||||
|
__bss_start__ = .;
|
||||||
|
*(.bss*)
|
||||||
|
*(COMMON)
|
||||||
|
. = ALIGN(4);
|
||||||
|
_end_bss = .;
|
||||||
|
__bss_end__ = .;
|
||||||
|
_end = .;
|
||||||
|
} > RAM
|
||||||
|
. = ALIGN(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
END_STACK = ORIGIN(RAM) + LENGTH(RAM);
|
Loading…
Reference in New Issue