Merge pull request #494 from danielinux/atsama5d3

Support for Microchip SAMA5D3
pull/498/head
David Garske 2024-10-02 08:13:54 -07:00 committed by GitHub
commit b6b77f01e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 1865 additions and 64 deletions

View File

@ -1,5 +1,5 @@
tar rem:3333
file wolfboot.elf
tar rem:3333
add-symbol-file test-app/image.elf
foc c

View File

@ -22,6 +22,13 @@ jobs:
# arch: riscv
# config-file: ./config/examples/hifive.config
#
#
sama5d3_test:
uses: ./.github/workflows/test-build.yml
with:
arch: arm
config-file: ./config/examples/sama5d3.config
same51_test:
uses: ./.github/workflows/test-build.yml
with:

View File

@ -130,6 +130,11 @@ ifeq ($(TARGET),nxp_t1024)
MAIN_TARGET:=factory_wstage1.bin
endif
ifeq ($(TARGET),sama5d3)
MAIN_TARGET:=wolfboot.bin test-app/image_v1_signed.bin
endif
ifeq ($(FLASH_OTP_KEYSTORE),1)
MAIN_TARGET+=tools/keytools/otp/otp-keystore-primer.bin
endif

146
arch.mk
View File

@ -70,7 +70,6 @@ ifeq ($(ARCH),ARM)
CROSS_COMPILE?=arm-none-eabi-
CFLAGS+=-mthumb -mlittle-endian -mthumb-interwork -DARCH_ARM
LDFLAGS+=-mthumb -mlittle-endian -mthumb-interwork
OBJS+=src/boot_arm.o
## Target specific configuration
ifeq ($(TARGET),samr21)
@ -176,88 +175,111 @@ ifeq ($(ARCH),ARM)
SPI_TARGET=stm32
endif
## Cortex-M CPU
ifeq ($(CORTEX_M33),1)
CFLAGS+=-mcpu=cortex-m33 -DCORTEX_M33
LDFLAGS+=-mcpu=cortex-m33
ifeq ($(TZEN),1)
OBJS+=hal/stm32_tz.o
CFLAGS+=-mcmse
ifeq ($(WOLFCRYPT_TZ),1)
SECURE_OBJS+=./src/wc_callable.o
SECURE_OBJS+=./lib/wolfssl/wolfcrypt/src/random.o
CFLAGS+=-DWOLFCRYPT_SECURE_MODE
SECURE_LDFLAGS+=-Wl,--cmse-implib -Wl,--out-implib=./src/wc_secure_calls.o
endif
endif # TZEN=1
ifeq ($(TARGET),sama5d3)
CORTEX_A5=1
UPDATE_OBJS:=src/update_ram.o
CFLAGS+=-DWOLFBOOT_DUALBOOT -DEXT_FLASH -DNAND_FLASH -fno-builtin -ffreestanding
#CFLAGS+=-DWOLFBOOT_USE_STDLIBC
endif
## Cortex CPU
ifeq ($(CORTEX_A5),1)
FPU=-mfpu=vfp4-d16
CFLAGS+=-mcpu=cortex-a5 -mtune=cortex-a5 -static -z noexecstack
LDLAGS+=-mcpu=cortex-a5 -mtune=cortex-a5 -mtune=cortex-a5 -static -z noexecstack -Ttext 0x300000
# Cortex-A uses boot_arm32.o
OBJS+=src/boot_arm32.o src/boot_arm32_start.o
ifeq ($(NO_ASM),1)
ifeq ($(SPMATH),1)
ifeq ($(NO_ASM),1)
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_c32.o
else
CFLAGS+=-DWOLFSSL_SP_ASM -DWOLFSSL_SP_ARM_CORTEX_M_ASM
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_cortexm.o
endif
endif
MATH_OBJS+=./lib/wolfssl/wolfcrypt/src/sp_c32.o
else
ifeq ($(SPMATH),1)
CFLAGS+=-DWOLFSSL_SP_ASM -DWOLFSSL_SP_ARM_CORTEX_M_ASM
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_cortexm.o
endif
MATH_OBJS+=./lib/wolfssl/wolfcrypt/src/sp_arm32.o
CFLAGS+=-DWOLFSSL_SP_ARM32_ASM
endif
else
ifeq ($(CORTEX_M7),1)
CFLAGS+=-mcpu=cortex-m7
LDFLAGS+=-mcpu=cortex-m7
ifeq ($(SPMATH),1)
ifeq ($(NO_ASM),1)
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_c32.o
else
CFLAGS+=-DWOLFSSL_SP_ASM -DWOLFSSL_SP_ARM_CORTEX_M_ASM
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_cortexm.o
# All others use boot_arm.o
OBJS+=src/boot_arm.o
ifeq ($(CORTEX_M33),1)
CFLAGS+=-mcpu=cortex-m33 -DCORTEX_M33
LDFLAGS+=-mcpu=cortex-m33
ifeq ($(TZEN),1)
OBJS+=hal/stm32_tz.o
CFLAGS+=-mcmse
ifeq ($(WOLFCRYPT_TZ),1)
SECURE_OBJS+=./src/wc_callable.o
SECURE_OBJS+=./lib/wolfssl/wolfcrypt/src/random.o
CFLAGS+=-DWOLFCRYPT_SECURE_MODE
SECURE_LDFLAGS+=-Wl,--cmse-implib -Wl,--out-implib=./src/wc_secure_calls.o
endif
endif
else
ifeq ($(CORTEX_M0),1)
CFLAGS+=-mcpu=cortex-m0
LDFLAGS+=-mcpu=cortex-m0
endif # TZEN=1
ifeq ($(NO_ASM),1)
ifeq ($(SPMATH),1)
ifeq ($(NO_ASM),1)
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_c32.o
else
CFLAGS+=-DWOLFSSL_SP_ASM -DWOLFSSL_SP_ARM_THUMB_ASM
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_armthumb.o
CFLAGS+=-DWOLFSSL_SP_ASM -DWOLFSSL_SP_ARM_CORTEX_M_ASM
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_cortexm.o
endif
endif
else
ifeq ($(CORTEX_M3),1)
CFLAGS+=-mcpu=cortex-m3
LDFLAGS+=-mcpu=cortex-m3
ifeq ($(SPMATH),1)
CFLAGS+=-DWOLFSSL_SP_ASM -DWOLFSSL_SP_ARM_CORTEX_M_ASM
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_cortexm.o
endif
endif
else
ifeq ($(CORTEX_M7),1)
CFLAGS+=-mcpu=cortex-m7
LDFLAGS+=-mcpu=cortex-m7
ifeq ($(SPMATH),1)
ifeq ($(NO_ASM),1)
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_c32.o
else
CFLAGS+=-DWOLFSSL_SP_ASM -DWOLFSSL_SP_ARM_CORTEX_M_ASM
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_cortexm.o
endif
endif
else
ifeq ($(CORTEX_M0),1)
CFLAGS+=-mcpu=cortex-m0
LDFLAGS+=-mcpu=cortex-m0
ifeq ($(SPMATH),1)
ifeq ($(NO_ASM),1)
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_c32.o
else
CFLAGS+=-DWOLFSSL_SP_ASM -DWOLFSSL_SP_ARM_THUMB_ASM
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_armthumb.o
endif
endif
else
ifeq ($(CORTEX_M3),1)
CFLAGS+=-mcpu=cortex-m3
LDFLAGS+=-mcpu=cortex-m3
ifeq ($(NO_ASM),1)
ifeq ($(SPMATH),1)
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_c32.o
endif
else
ifeq ($(SPMATH),1)
CFLAGS+=-DWOLFSSL_SP_ASM -DWOLFSSL_SP_ARM_CORTEX_M_ASM -DWOLFSSL_SP_NO_UMAAL
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_cortexm.o
endif
endif
else
# default Cortex M4
CFLAGS+=-mcpu=cortex-m4
LDFLAGS+=-mcpu=cortex-m4
ifeq ($(NO_ASM),1)
ifeq ($(SPMATH),1)
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_c32.o
endif
else
CFLAGS+=-fomit-frame-pointer # required with debug builds only
ifeq ($(SPMATH),1)
CFLAGS+=-DWOLFSSL_SP_ASM -DWOLFSSL_SP_ARM_CORTEX_M_ASM -DWOLFSSL_SP_NO_UMAAL
CFLAGS+=-DWOLFSSL_SP_ASM -DWOLFSSL_SP_ARM_CORTEX_M_ASM
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_cortexm.o
endif
endif
else
# default Cortex M4
CFLAGS+=-mcpu=cortex-m4
LDFLAGS+=-mcpu=cortex-m4
ifeq ($(NO_ASM),1)
ifeq ($(SPMATH),1)
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_c32.o
endif
else
CFLAGS+=-fomit-frame-pointer # required with debug builds only
ifeq ($(SPMATH),1)
CFLAGS+=-DWOLFSSL_SP_ASM -DWOLFSSL_SP_ARM_CORTEX_M_ASM
MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_cortexm.o
endif
endif
endif
endif

View File

@ -0,0 +1,23 @@
ARCH?=ARM
TARGET?=sama5d3
SIGN?=ECC256
HASH?=SHA256
DEBUG?=0
VTOR?=1
CORTEX_M0?=0
NO_ASM?=0
EXT_FLASH?=1
NAND_FLASH?=1
SPI_FLASH?=0
V?=0
SPMATH?=1
WOLFBOOT_PARTITION_SIZE?=0x1000000
WOLFBOOT_NO_PARTITIONS=0
WOLFBOOT_SECTOR_SIZE?=0x1000
WOLFBOOT_LOAD_ADDRESS=0x20100800
WOLFBOOT_LOAD_DTS_ADDRESS=0x21100800
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x400000
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x800000
WOLFBOOT_PARTITION_SWAP_ADDRESS=0x0
NO_XIP=1
IMAGE_HEADER_SIZE=2048

View File

@ -8,6 +8,7 @@ This README describes configuration of supported targets.
* [Cypress PSoC-6](#cypress-psoc-6)
* [Infineon AURIX TC3xx](#infineon-aurix-tc3xx)
* [Intel x86-64 Intel FSP](#intel-x86_64-with-intel-fsp-support)
* [Microchip SAMA5D3](#microchip-sama5d3)
* [Microchip SAME51](#microchip-same51)
* [NXP Kinetis](#nxp-kinetis)
* [NXP LPC54xxx](#nxp-lpc54xxx)
@ -1405,6 +1406,60 @@ the monitor command sequence below:
(gdb) mon psoc6 reset_halt
```
## Microchip SAMA5D3
SAMA5D3 is a Cortex-A5 Microprocessor. The ATSAMA5D3-XPLAINED is the evaluation
board used for wolfBoot port, which also equips a 2MB NAND flash. WolfBoot
replaces the default first stage bootloader (at91bootstrap).
### Building wolfBoot
An example configuration file is provided.
`cp config/examples/sama5d3.config .config`
Run make to build wolfBoot.bin and the test application
`make`
### Programming wolfboot.bin into NAND flash
To flash any firmware image into the device NVMs, you need the tool `sam-ba`,
distributed by Microchip.
This procedure has been tested using sam-ba v.3.8 using ATSAMA5D3-XPLAINED board,
with JP6 (aka the `SPI_CS` jumper) removed, so the system boots from NAND by
default.
Step 1: install the tool, connect a J-Link device to the J24 JTAG connector then run the
following command to activate "lowlevel" mode:
`sam-ba -p j-link -b sama5d3-xplained -t 5 -a lowlevel`
Step 2: erase the entire NAND flash:
`sam-ba -p j-link -b sama5d3-xplained -t 5 -a nandflash -c erase`
Step 3: program `wolfboot.bin` to the beginning of the flash:
`sam-ba -p j-link -b sama5d3-xplained -t 5 -a nandflash -c writeboot:wolfboot.bin`
### Programming the test application into NAND flash
The application can be written to a second partition in nand,
e.g. at address "0x40000"
`sam-ba -p j-link -b sama5d3-xplained -t 5 -a nandflash -c write:test-app/image_v1_signed.bin:0x400000`
With the example configuration, wolfBoot will evaluate two alternative images
at addresses 0x400000 and 0x800000, authenticate, load to DRAM and stage from
`LOAD_ADDRESS`.
Ensure that the application is compiled to run from `LOAD_ADDRESS`.
Check `test-app/ARM-sama5d3.ld` for details.
## Microchip SAME51
SAME51 is a Cortex-M4 microcontroller with a dual-bank, 1MB flash memory divided

758
hal/sama5d3.c 100644
View File

@ -0,0 +1,758 @@
/* atsama5d3.c
*
* Copyright (C) 2024 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 3 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 <string.h>
#include <target.h>
#include "image.h"
#include "sama5d3.h"
#ifndef ARCH_ARM
# error "wolfBoot atsama5d3 HAL: wrong architecture selected. Please compile with ARCH=ARM."
#endif
void sleep_us(uint32_t usec);
/* Manual division operation */
static int division(uint32_t dividend,
uint32_t divisor,
uint32_t *quotient,
uint32_t *remainder)
{
uint32_t shift;
uint32_t divisor_shift;
uint32_t factor = 0;
unsigned char end_flag = 0;
if (!divisor)
return 0xffffffff;
if (dividend < divisor) {
*quotient = 0;
*remainder = dividend;
return 0;
}
while (dividend >= divisor) {
for (shift = 0, divisor_shift = divisor;
dividend >= divisor_shift;
divisor_shift <<= 1, shift++) {
if (dividend - divisor_shift < divisor_shift) {
factor += 1 << shift;
dividend -= divisor_shift;
end_flag = 1;
break;
}
}
if (end_flag)
continue;
factor += 1 << (shift - 1);
dividend -= divisor_shift >> 1;
}
if (quotient)
*quotient = factor;
if (remainder)
*remainder = dividend;
return 0;
}
static uint32_t div(uint32_t dividend, uint32_t divisor)
{
uint32_t quotient = 0;
uint32_t remainder = 0;
int ret;
ret = division(dividend, divisor, &quotient, &remainder);
if (ret)
return 0xffffffff;
return quotient;
}
static uint32_t mod(uint32_t dividend, uint32_t divisor)
{
uint32_t quotient = 0;
uint32_t remainder = 0;
int ret;
ret = division(dividend, divisor, &quotient, &remainder);
if (ret)
return 0xffffffff;
return remainder;
}
/* RAM configuration: 2 x MT47H64M16 on SAMA5D3-Xplained
* 8 Mwords x 8 Banks x 16 bits x 2, total 2 Gbit
*/
static const struct dram ddram ={
.timing = { /* Hardcoded for MT47H64M16, */
.tras = 6,
.trcd = 2,
.twr = 2,
.trc = 8,
.trp = 2,
.trrd = 2,
.twtr = 2,
.tmrd = 2,
.trfc = 17,
.txsnr = 19,
.txsrd = 200,
.txp = 2,
.txard = 8,
.txards = 8,
.trpa = 2,
.trtp = 2,
.tfaw = 6,
}
};
void master_clock_set(uint32_t prescaler)
{
uint32_t mck = PMC_MCKR & (PMC_MDIV_MASK | PMC_CSS_MASK);
uint32_t diff = mck ^ prescaler;
if (diff & PMC_ALTPRES_MASK) {
/* Clear ALT_PRES field and extra PRES bit */
mck &= ~((1 << 13 | PMC_ALTPRES_MASK));
mck |= (prescaler & (PMC_ALTPRES_MASK));
PMC_MCKR = mck;
while ((PMC_SR & PMC_SR_MCKRDY) == 0)
;
}
if (diff & PMC_MDIV_MASK) {
mck &= ~PMC_MDIV_MASK;
mck |= (prescaler & PMC_MDIV_MASK);
PMC_MCKR = mck;
while ((PMC_SR & PMC_SR_MCKRDY) == 0)
;
}
if (diff & PMC_PLLADIV_MASK) {
mck &= ~PMC_PLLADIV_MASK;
mck |= (prescaler & PMC_PLLADIV_MASK);
PMC_MCKR = mck;
while ((PMC_SR & PMC_SR_MCKRDY) == 0)
;
}
if (diff & PMC_H32MXDIV_MASK) {
mck &= ~PMC_H32MXDIV_MASK;
mck |= (prescaler & PMC_H32MXDIV_MASK);
PMC_MCKR = mck;
while ((PMC_SR & PMC_SR_MCKRDY) == 0)
;
}
if (diff & PMC_CSS_MASK) {
mck &= ~PMC_CSS_MASK;
mck |= (prescaler & PMC_CSS_MASK);
PMC_MCKR = mck;
while ((PMC_SR & PMC_SR_MCKRDY) == 0)
;
}
}
static void pll_init(void)
{
/* Disable PLLA */
PMC_PLLA &= PLLA_CKGR_SRCA;
asm volatile("dmb");
/* Configure PLLA */
PMC_PLLA = PLLA_CONFIG;
/* Wait for the PLLA to lock */
while (!(PMC_SR & PMC_SR_LOCKA))
;
/* Set the current charge pump */
PMC_PLLICPR = PLLICPR_CONFIG;
/* Set main clock */
master_clock_set(PRESCALER_MAIN_CLOCK);
/* Set PLLA clock */
master_clock_set(PRESCALER_PLLA_CLOCK);
}
static void ddr_init(void)
{
uint32_t val;
uint32_t rtr, md, cr, tpr0, tpr1, tpr2;
uint32_t col, row, cas, bank;
uint32_t cal;
uint32_t ba_offset = 0;
uint32_t pmc_pcr;
volatile uint32_t *dram_base = (volatile uint32_t *)DRAM_BASE;
/* Step 1: Calculate register values
*
*/
md = MPDDRC_MD_DDR2_SDRAM | MPDDRC_MD_DBW_32BIT;
col = MPDDRC_NC_10; /* 10/9 column address */
row = MPDDRC_NR_13; /* 13-bit row address */
cas = 3 << MPDDRC_CAS_SHIFT; /* CAS latency 3 */
bank = 1 << MPDDRC_NB_SHIFT; /* NB_BANKS = 8 */
cr = col | row | bank | cas | MPDDRC_CR_DECOD_INTERLEAVED | MPDDRC_UNAL
| MPDDRC_NDQS_DISABLED;
ba_offset = 12; /* Based on col = MPDDRC_NC_10, DBW 32 bit, interleaved */
/* Set timing parameters using hardcoded values */
rtr = 0x40F;
tpr0 = (ddram.timing.tras << MPDDRC_TRAS_SHIFT) |
(ddram.timing.trcd << MPDDRC_TRCD_SHIFT) |
(ddram.timing.twr << MPDDRC_TWR_SHIFT) |
(ddram.timing.trc << MPDDRC_TRC_SHIFT) |
(ddram.timing.trp << MPDDRC_TRP_SHIFT) |
(ddram.timing.trrd << MPDDRC_TRRD_SHIFT) |
(ddram.timing.twtr << MPDDRC_TWTR_SHIFT) |
(ddram.timing.tmrd << MPDDRC_TMRD_SHIFT);
tpr1 = (ddram.timing.trfc << MPDDRC_TRFC_SHIFT) |
(ddram.timing.txsnr << MPDDRC_TXSNR_SHIFT) |
(ddram.timing.txsrd << MPDDRC_TXSRD_SHIFT) |
(ddram.timing.txp << MPDDRC_TXP_SHIFT);
tpr2 = (ddram.timing.txard << MPDDRC_TXARD_SHIFT) |
(ddram.timing.txards << MPDDRC_TXARDS_SHIFT) |
(ddram.timing.trpa << MPDDRC_TRPA_SHIFT) |
(ddram.timing.trtp << MPDDRC_TRTP_SHIFT) |
(ddram.timing.tfaw << MPDDRC_TFAW_SHIFT);
/* Step 2: Enable the DDR2 SDRAM controller
*
*/
/* Turn on the DDRAM controller peripheral clock */
PMC_PCR = MPDDRC_PMCID;
pmc_pcr = PMC_PCR & (~PMC_PCR_DIV_MASK);
pmc_pcr |= PMC_PCR_CMD | PMC_PCR_EN;
PMC_PCR = pmc_pcr;
/* Enable DDR in system clock */
PMC_SCER = MPDDRC_SCERID;
sleep_us(10); /* 10 us */
/* Step 3: Calibration
*
*/
cal = MPDDRC_IO_CALIBR;
cal &= ~(MPDDRC_IOCALIBR_RDIV_MASK);
cal |= MPDDRC_IOCALIBR_RDIV_DDR2_RZQ_50; /* 50 ohm */
cal &= ~(MPDDRC_IOCALIBR_TZQIO_MASK);
cal |= (100 << MPDDRC_IOCALIBR_TZQIO_SHIFT); /* 100 cycles at 133MHz is 0.75 us, 100 cycles at 166MHz is 0.6 us */
MPDDRC_IO_CALIBR = cal;
/* Data path configuration */
MPDDRC_RD_DATA_PATH = 0x01; /* One cycle read delay */
/* Write calibration again */
MPDDRC_IO_CALIBR = cal;
/* Step 4: Program the DDR2 SDRAM controller
*
*/
/* Program the memory device type */
MPDDRC_MD = md;
/* Program the features into configuration registers */
MPDDRC_CR = cr;
MPDDRC_TPR0 = tpr0;
MPDDRC_TPR1 = tpr1;
MPDDRC_TPR2 = tpr2;
/* Send a NOP command via mode register */
MPDDRC_MR = MPDDRC_MR_MODE_NOP;
*dram_base = 0;
sleep_us(200); /* 200 us */
/* Send a second NOP command to set CKE high */
MPDDRC_MR = MPDDRC_MR_MODE_NOP;
*dram_base = 0;
sleep_us(1); /* min 200 ns */
/* Issue precharge all command */
MPDDRC_MR = MPDDRC_MR_MODE_PRECHARGE;
*dram_base = 0;
sleep_us(1); /* min 15 ns */
/* Issue external load command to set temperature mode (EMR2) */
MPDDRC_MR = MPDDRC_MR_MODE_EXT_LOAD;
*(volatile uint32_t *)(DRAM_BASE + (0x2 << ba_offset)) = 0x00000000;
sleep_us(1); /* min 15 ns */
/* Issue external load command to set DLL to 0 (EMR3)*/
MPDDRC_MR = MPDDRC_MR_MODE_EXT_LOAD;
*(volatile uint32_t *)(DRAM_BASE + (0x3 << ba_offset)) = 0x00000000;
sleep_us(1); /* min 200 cycles */
/* Issue external load command to program D.I.C. (EMR1) */
MPDDRC_MR = MPDDRC_MR_MODE_EXT_LOAD;
*(volatile uint32_t *)(DRAM_BASE + (0x1 << ba_offset)) = 0x00000000;
sleep_us(1); /* min 200 cycles */
/* Reset DLL via Configuration Register */
MPDDRC_CR |= MPDDRC_CR_ENABLE_DLL_RESET;
/* Issue load command to set DLL to 1 */
MPDDRC_MR = MPDDRC_MR_MODE_LOAD;
*dram_base = 0;
sleep_us(1); /* min 15 ns */
/* Issue a precharge command */
MPDDRC_MR = MPDDRC_MR_MODE_PRECHARGE;
*dram_base = 0;
sleep_us(1); /* min 400 ns */
/* Issue two auto-refresh cycles */
MPDDRC_MR = MPDDRC_MR_MODE_AUTO_REFRESH;
*dram_base = 0;
sleep_us(1); /* min 400 ns */
MPDDRC_MR = MPDDRC_MR_MODE_AUTO_REFRESH;
*dram_base = 0;
sleep_us(1); /* min 400 ns */
/* Disable DLL reset */
MPDDRC_CR &= ~MPDDRC_CR_ENABLE_DLL_RESET;
/* Issue a mode register LOAD command */
MPDDRC_MR = MPDDRC_MR_MODE_LOAD;
*dram_base = 0;
sleep_us(1); /* min 15 ns */
/* Trigger OCD default calibration */
MPDDRC_CR |= MPDDRC_CR_OCD_DEFAULT;
sleep_us(1); /* min 15 ns */
/* Issue a mode register LOAD command (EMR1) */
MPDDRC_MR = MPDDRC_MR_MODE_EXT_LOAD;
*(volatile uint32_t *)(DRAM_BASE + (0x1 << ba_offset)) = 0x00000000;
sleep_us(1); /* min 15 ns */
/* Exit OCD default calibration */
MPDDRC_CR &= ~MPDDRC_CR_OCD_DEFAULT;
sleep_us(1); /* min 15 ns */
/* Issue a mode register LOAD command (EMR1) */
MPDDRC_MR = MPDDRC_MR_MODE_EXT_LOAD;
*(volatile uint32_t *)(DRAM_BASE + (0x1 << ba_offset)) = 0x00000000;
sleep_us(1); /* min 15 ns */
/* Switch mode to NORMAL */
MPDDRC_MR = MPDDRC_MR_MODE_NORMAL;
*dram_base = 0;
sleep_us(1); /* min 15 ns */
/* Perform a write access to the DDR2-SDRAM */
*(dram_base) = 0xA5A5A5D1;
/* finally, set the refresh rate */
MPDDRC_RTR = rtr;
/* DDR is now ready to use. Wait for the end of calibration */
sleep_us(10);
}
/* Static variables to hold nand info */
static uint8_t nand_manif_id;
static uint8_t nand_dev_id;
static char nand_onfi_id[4];
struct nand_flash {
uint16_t revision;
uint16_t features;
uint16_t ext_page_len;
uint16_t parameter_page;
uint32_t page_size;
uint32_t block_size;
uint32_t block_count;
uint32_t pages_per_block;
uint32_t pages_per_device;
uint32_t total_size;
uint16_t bad_block_pos;
uint16_t ecc_bytes;
uint16_t eccpos[MAX_ECC_BYTES];
uint16_t eccwordsize;
uint32_t bus_width;
uint32_t oob_size;
} nand_flash = { 0 };
static void nand_wait_ready(void)
{
NAND_CMD = NAND_CMD_STATUS;
while (!(NAND_DATA & 0x40));
}
static void nand_read_id(uint8_t *manif_id, uint8_t *dev_id)
{
NAND_CMD = NAND_CMD_READID;
NAND_ADDR = 0x00;
*manif_id = NAND_DATA;
*dev_id = NAND_DATA;
}
static void nand_reset(void)
{
NAND_CMD = NAND_CMD_RESET;
nand_wait_ready();
}
static void write_column_address(uint32_t col_address)
{
NAND_ADDR = col_address & 0xFF;
NAND_ADDR = (col_address >> 8) & 0xFF;
NAND_ADDR = (col_address >> 16) & 0xFF;
}
static void write_row_address(uint32_t row_address)
{
NAND_ADDR = row_address & 0xFF;
NAND_ADDR = (row_address >> 8) & 0xFF;
NAND_ADDR = (row_address >> 16) & 0xFF;
NAND_ADDR = (row_address >> 24) & 0xFF;
}
static void nand_read_info(void)
{
uint8_t onfi_data[ONFI_PARAMS_SIZE];
uint32_t i;
nand_reset();
nand_read_id(&nand_manif_id, &nand_dev_id);
NAND_CMD = NAND_CMD_READID;
NAND_ADDR = 0x20;
nand_onfi_id[0] = NAND_DATA;
nand_onfi_id[1] = NAND_DATA;
nand_onfi_id[2] = NAND_DATA;
nand_onfi_id[3] = NAND_DATA;
if (memcmp(nand_onfi_id, "ONFI", 4) != 0) {
/* Fail: no ONFI support */
asm("bkpt 0");
return;
}
memset(&nand_flash, 0, sizeof(nand_flash));
memset(nand_flash.eccpos, 0xFF, sizeof(nand_flash.eccpos));
NAND_CMD = NAND_CMD_READ_ONFI;
NAND_ADDR = 0x00;
nand_wait_ready();
NAND_CMD = NAND_CMD_READ1;
for (i = 0; i < ONFI_PARAMS_SIZE; i++) {
onfi_data[i] = NAND_DATA;
}
/* Store ONFI parameters in nand_flash struct */
nand_flash.page_size = *(uint16_t *)(onfi_data + PARAMS_POS_PAGESIZE);
nand_flash.pages_per_block = *(uint16_t *)(onfi_data + PARAMS_POS_BLOCKSIZE);
nand_flash.block_size = nand_flash.page_size * nand_flash.pages_per_block;
nand_flash.block_count = *(uint16_t *)(onfi_data + PARAMS_POS_NBBLOCKS);
nand_flash.total_size = nand_flash.block_count * nand_flash.block_size;
nand_flash.ecc_bytes = *(uint16_t *)(onfi_data + PARAMS_POS_ECC_BITS);
nand_flash.bad_block_pos = (*(uint16_t *)(onfi_data + PARAMS_POS_FEATURES)) & 1;
nand_flash.ext_page_len = *(uint16_t *)(onfi_data + PARAMS_POS_EXT_PARAM_PAGE_LEN);
nand_flash.parameter_page = *(uint16_t *)(onfi_data + PARAMS_POS_PARAMETER_PAGE);
nand_flash.pages_per_block = div(nand_flash.block_size, nand_flash.page_size);
nand_flash.pages_per_device = nand_flash.pages_per_block * nand_flash.block_count;
nand_flash.oob_size = *(uint16_t *)(onfi_data + PARAMS_POS_OOBSIZE);
nand_flash.revision = *(uint16_t *)(onfi_data + PARAMS_POS_REVISION);
nand_flash.features = *(uint16_t *)(onfi_data + PARAMS_POS_FEATURES);
nand_flash.bus_width = (onfi_data[PARAMS_POS_FEATURES] & PARAMS_FEATURE_BUSWIDTH) ? 16 : 8;
if (nand_flash.ecc_bytes <= MAX_ECC_BYTES) {
for (int i = 0; i < nand_flash.ecc_bytes; i++) {
nand_flash.eccpos[i] = *(uint16_t *)(onfi_data + PARAMS_POS_ECC_BITS + i * 2);
}
}
if (nand_flash.page_size != NAND_FLASH_PAGE_SIZE) {
/* Fail: unsupported page size */
asm("bkpt 0");
}
if (nand_flash.oob_size != NAND_FLASH_OOB_SIZE) {
/* Fail: unsupported oob size */
asm("bkpt 0");
}
}
static void set_col_addr(uint32_t col_address)
{
uint32_t page_size = nand_flash.page_size;
while (page_size > 0) {
NAND_ADDR = col_address & 0xFF;
col_address >>= 8;
page_size >>= 8;
}
}
static void set_row_addr(uint32_t row_address)
{
uint32_t pages_per_device = nand_flash.pages_per_device;
while (pages_per_device > 0) {
NAND_ADDR = row_address & 0xFF;
row_address >>= 8;
pages_per_device >>= 8;
}
}
static int nand_device_read(uint32_t row_address, uint8_t *data, int mode)
{
uint32_t col_address = 0x00;
uint32_t tot_len = 0;
uint32_t page_size = nand_flash.page_size;
uint32_t pages_per_device = nand_flash.pages_per_device;
uint32_t i;
if (mode == NAND_MODE_DATAPAGE) {
tot_len = nand_flash.page_size;
} else if (mode == NAND_MODE_INFO) {
tot_len = nand_flash.oob_size;
col_address = nand_flash.page_size;
} else if (mode == NAND_MODE_DATABLOCK) {
tot_len = nand_flash.block_size;
} else {
/* Fail: unknown mode */
return -1;
}
NAND_CMD = NAND_CMD_READ1;
set_col_addr(col_address);
set_row_addr(row_address);
NAND_CMD = NAND_CMD_READ2;
nand_wait_ready();
NAND_CMD = NAND_CMD_READ1;
for (i = 0; i < tot_len; i++) {
data[i] = NAND_DATA;
}
return 0;
}
static int nand_read_page(uint32_t block, uint32_t page, uint8_t *data)
{
uint32_t row_address = block * nand_flash.pages_per_block + page;
return nand_device_read(row_address, data, NAND_MODE_DATAPAGE);
}
static int nand_check_bad_block(uint32_t block)
{
uint32_t row_address = block * nand_flash.pages_per_block;
uint8_t oob[NAND_FLASH_OOB_SIZE];
uint32_t page;
for (page = 0; page < 2; page++) {
nand_device_read(row_address + page, oob, NAND_MODE_INFO);
if (oob[0] != 0xFF) {
return -1;
}
}
return 0;
}
int ext_flash_read(uintptr_t address, uint8_t *data, int len)
{
uint8_t buffer_page[NAND_FLASH_PAGE_SIZE];
uint32_t block = div(address, nand_flash.block_size); /* The block where the address falls in */
uint32_t page = div(address, nand_flash.page_size); /* The page where the address falls in */
uint32_t start_page_in_block = mod(page, nand_flash.pages_per_block); /* The start page within this block */
uint32_t in_block_offset = mod(address, nand_flash.block_size); /* The offset of the address within the block */
uint32_t remaining = nand_flash.block_size - in_block_offset; /* How many bytes remaining to read in the first block */
int len_to_read = len;
uint8_t *buffer = data;
uint32_t i;
int copy = 0;
int ret;
if (len < (int)nand_flash.page_size) {
buffer = buffer_page;
copy = 1;
len_to_read = nand_flash.page_size;
}
while (len_to_read > 0) {
uint32_t sz = len_to_read;
uint32_t pages_to_read;
if (sz > remaining)
sz = remaining;
do {
ret = nand_check_bad_block(block);
if (ret < 0) {
/* Block is bad, skip it */
block++;
}
} while (ret < 0);
/* Amount of pages to be read from this block */
pages_to_read = div((sz + nand_flash.page_size - 1), nand_flash.page_size);
if (pages_to_read * nand_flash.page_size > remaining)
pages_to_read--;
/* Read (remaining) pages off a block */
for (i = 0; i < pages_to_read; i++) {
nand_read_page(block, start_page_in_block + i, buffer);
if (sz > nand_flash.page_size)
sz = nand_flash.page_size;
len_to_read -= sz;
buffer += sz;
}
/* The block is over, move to the next one */
block++;
start_page_in_block = 0;
remaining = nand_flash.block_size;
}
if (copy) {
uint32_t *dst = (uint32_t *)data;
uint32_t *src = (uint32_t *)buffer_page;
uint32_t tot_len = (uint32_t)len;
for (i = 0; i < (tot_len >> 2); i++) {
dst[i] = src[i];
}
}
return len;
}
void pit_init(void)
{
uint32_t pmc_pcr;
/* Turn on clock for PIT */
PMC_PCR = PIT_PMCID;
pmc_pcr = PMC_PCR & (~PMC_PCR_DIV_MASK);
pmc_pcr |= PMC_PCR_CMD | PMC_PCR_EN;
PMC_PCR = pmc_pcr;
/* Set clock source to MCK/2 */
PIT_MR = MAX_PIV | PIT_MR_EN;
}
void sleep_us(uint32_t usec)
{
uint32_t base = PIT_PIIR;
uint32_t delay;
uint32_t current;
/* Since our division function which costs much run time
* causes the delay time error.
* So here using shifting to implement the division.
* to change "1000" to "1024", this cause some inaccuacy,
* but it is acceptable.
* ((MASTER_CLOCK / 1024) * usec) / (16 * 1024)
*/
delay = ((MASTER_FREQ >> 10) * usec) >> 14;
do {
current = PIT_PIIR;
current -= base;
} while (current < delay);
}
int ext_flash_write(uintptr_t address, const uint8_t *data, int len)
{
/* TODO */
(void)address;
(void)data;
(void)len;
return 0;
}
int ext_flash_erase(uintptr_t address, int len)
{
/* TODO */
(void)address;
(void)len;
return 0;
}
/* SAMA5D3 NAND flash does not have an enable pin */
void ext_flash_unlock(void)
{
}
void ext_flash_lock(void)
{
}
void* hal_get_dts_address(void)
{
return (void*)&dts_addr;
}
void* hal_get_dts_update_address(void)
{
return NULL; /* Not yet supported */
}
/* public HAL functions */
void hal_init(void)
{
pll_init();
pit_init();
watchdog_disable();
ddr_init();
nand_read_info();
}
void hal_prepare_boot(void)
{
}
int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
{
(void)address;
(void)data;
(void)len;
return 0;
}
void RAMFUNCTION hal_flash_unlock(void)
{
}
void RAMFUNCTION hal_flash_lock(void)
{
}
int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
{
(void)address;
(void)len;
return 0;
}

448
hal/sama5d3.h 100644
View File

@ -0,0 +1,448 @@
/* sama5d3.h
*
* Header file for SAMA5D3 HAL
*
* Copyright (C) 2024 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 3 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
*/
#ifndef SAMA5D3_HAL_H
#define SAMA5D3_HAL_H
#include <stdint.h>
/* CPU/Board clock settings */
#define CPU_FREQ 264000000UL
#define MASTER_FREQ 132000000UL
#define CRYSTAL_FREQ 12000000UL
#define MULA 43
/* PLLA register
*/
#define PLLA_DIVA_SHIFT 0
#define PLLA_DIVA_MASK (0xFF << PLLA_DIVA_SHIFT)
#define PLLA_COUNT_SHIFT 8
#define PLLA_COUNT_MASK (0x3F << PLLA_COUNT_SHIFT)
#define PLLA_CKGR_OUTA_SHIFT 14
#define PLLA_CKGR_OUTA_MASK (0x3 << PLLA_CKGR_OUTA_SHIFT)
#define PLLA_MULA_SHIFT 18
#define PLLA_MULA_MASK (0x7F << PLLA_MULA_SHIFT)
#define PLLA_CKGR_SRCA (0x1 << 29)
/* PMC version 1 */
#define PMC_BASE 0xFFFFFC00
#define PMC_SCER *(volatile uint32_t *)(PMC_BASE + 0x0000)
#define PMC_UCKR *(volatile uint32_t *)(PMC_BASE + 0x001C)
#define PMC_PLLA *(volatile uint32_t *)(PMC_BASE + 0x0028)
#define PMC_MCKR *(volatile uint32_t *)(PMC_BASE + 0x0030)
#define PMC_SR *(volatile uint32_t *)(PMC_BASE + 0x0068)
#define PMC_PLLICPR *(volatile uint32_t *)(PMC_BASE + 0x0080)
#define PMC_PCR *(volatile uint32_t *)(PMC_BASE + 0x010C)
#define PMC_PLLADIV_SHIFT 12
#define PMC_PLLADIV_MASK (0x1 << PMC_PLLADIV_SHIFT)
#define PMC_PLLADIV_1 (0x0 << PMC_PLLADIV_SHIFT)
#define PMC_PLLADIV_2 (0x1 << PMC_PLLADIV_SHIFT)
#define PMC_CSS_SHIFT 0
#define PMC_CSS_MASK (0x3 << PMC_CSS_SHIFT)
#define PMC_CSS_SLOW_CLK (0x0 << PMC_CSS_SHIFT)
#define PMC_CSS_MAIN_CLK (0x1 << PMC_CSS_SHIFT)
#define PMC_CSS_PLLA_CLK (0x2 << PMC_CSS_SHIFT)
#define PMC_CSS_UPLL_CLK (0x3 << PMC_CSS_SHIFT)
#define PMC_PRES_SHIFT 2
#define PMC_PRES_MASK (0xF << PMC_PRES_SHIFT)
#define PMC_ALTPRES_SHIFT 4
#define PMC_ALTPRES_MASK (0xF << PMC_ALTPRES_SHIFT)
#define PMC_MDIV_SHIFT 8
#define PMC_MDIV_MASK (0x3 << PMC_MDIV_SHIFT)
#define PMC_MDIV_1 (0x0 << PMC_MDIV_SHIFT)
#define PMC_MDIV_2 (0x1 << PMC_MDIV_SHIFT)
#define PMC_MDIV_3 (0x2 << PMC_MDIV_SHIFT)
#define PMC_MDIV_4 (0x3 << PMC_MDIV_SHIFT)
#define PMC_H32MXDIV_SHIFT 24
#define PMC_H32MXDIV_MASK (0x1 << PMC_H32MXDIV_SHIFT)
#define PMC_SR_LOCKA (0x1 << 1)
#define PMC_SR_MCKRDY (0x1 << 3)
#define PMC_PLLICPR_ICPPLLA_SHIFT 0
#define PMC_PLLICPR_ICPPLLA_MASK (0x7 << PMC_PLLICPR_ICPPLLA_SHIFT)
#define PMC_PLLICPR_IPLLA_SHIFT 8
#define PMC_PLLICPR_IPLLA_MASK (0xF << PMC_PLLICPR_IPLLA_SHIFT)
#define PMC_PCR_CMD (0x1 << 12)
#define PMC_PCR_EN (0x1 << 28)
#define PMC_PCR_DIV_SHIFT 13
#define PMC_PCR_DIV_MASK (0x3 << PMC_PCR_DIV_SHIFT)
/* Specific configuration for 264/132/12 MHz */
#define PLL_PCK (((CRYSTAL_FREQ * (PLLA_MULA + 1)) / 2))
#define PLL_MCK (BOARD_PCK / 2)
#define PLL_CKGR_PLLA (PLLA_CKGR_SRCA | (0 << PLLA_CKGR_OUTA_SHIFT))
#define PLL_PLLACOUNT (PLLA_COUNT_MASK)
#define PLL_MULA ((MULA << PLLA_MULA_SHIFT) & PLLA_MULA_MASK)
#define PLL_DIVA (0x01 & PLLA_DIVA_MASK)
#define PLLA_CONFIG (PLL_CKGR_PLLA | PLL_PLLACOUNT | PLL_MULA | PLL_DIVA)
#define PRESCALER_MAIN_CLOCK (PMC_PLLADIV_2 | PMC_MDIV_2 | PMC_CSS_MAIN_CLK)
#define PRESCALER_PLLA_CLOCK (PMC_PLLADIV_2 | PMC_MDIV_2 | PMC_CSS_PLLA_CLK)
#define PLLICPR_CONFIG (0x0 << PMC_PLLICPR_ICPPLLA_SHIFT | 0x3 << PMC_PLLICPR_IPLLA_SHIFT)
/* PIT
*
*/
#define PIT_BASE 0xFFFFFE30
#define PIT_MR *(volatile uint32_t *)(PIT_BASE + 0x00)
#define PIT_SR *(volatile uint32_t *)(PIT_BASE + 0x04)
#define PIT_PIVR *(volatile uint32_t *)(PIT_BASE + 0x08)
#define PIT_PIIR *(volatile uint32_t *)(PIT_BASE + 0x0C)
/* DRAM setup
*/
#define MPDDRC_BASE 0xFFFFEA00
#define MPDDRC_MR *(volatile uint32_t *)(MPDDRC_BASE + 0x00) /* Mode Register */
#define MPDDRC_RTR *(volatile uint32_t *)(MPDDRC_BASE + 0x04) /* Refresh Timer Register */
#define MPDDRC_CR *(volatile uint32_t *)(MPDDRC_BASE + 0x08) /* Configuration Register */
#define MPDDRC_TPR0 *(volatile uint32_t *)(MPDDRC_BASE + 0x0C) /* Timing Parameter 0 Register */
#define MPDDRC_TPR1 *(volatile uint32_t *)(MPDDRC_BASE + 0x10) /* Timing Parameter 1 Register */
#define MPDDRC_TPR2 *(volatile uint32_t *)(MPDDRC_BASE + 0x14) /* Timing Parameter 2 Register */
/* Reserved 0x18 */
#define MPDDRC_LPR *(volatile uint32_t *)(MPDDRC_BASE + 0x1C) /* Low-power Register */
#define MPDDRC_MD *(volatile uint32_t *)(MPDDRC_BASE + 0x20) /* Memory Device Register */
#define MPDDRC_HS *(volatile uint32_t *)(MPDDRC_BASE + 0x24) /* High Speed Register */
#define MPDDRC_LPDDR2_LPR *(volatile uint32_t *)(MPDDRC_BASE + 0x28) /* LPDDR2 Low-power Register */
#define MPDDRC_LPDDR2_CAL_MR4 *(volatile uint32_t *)(MPDDRC_BASE + 0x2C) /* LPDDR2 Calibration and MR4 Register */
#define MPDDRC_LPDDR2_TIM_CAL *(volatile uint32_t *)(MPDDRC_BASE + 0x30) /* LPDDR2 Timing Calibration Register */
#define MPDDRC_IO_CALIBR *(volatile uint32_t *)(MPDDRC_BASE + 0x34) /* I/O Calibration Register */
#define MPDDRC_OCMS *(volatile uint32_t *)(MPDDRC_BASE + 0x38) /* OCMS Register */
#define MPDDRC_OCMS_KEY1 *(volatile uint32_t *)(MPDDRC_BASE + 0x3C) /* OCMS Key 1 Register */
#define MPDDRC_OCMS_KEY2 *(volatile uint32_t *)(MPDDRC_BASE + 0x40) /* OCMS Key 2 Register */
/* Reserved 0x44 to 0x58 */
#define MPDDRC_RD_DATA_PATH *(volatile uint32_t *)(MPDDRC_BASE + 0x5C) /* Read Data Path Register */
/* Reserved 0x60 to 0x70 */
#define MPDDRC_DLL_MO *(volatile uint32_t *)(MPDDRC_BASE + 0x74) /* DLL Master Offset Register */
#define MPDDRC_DLL_SOF *(volatile uint32_t *)(MPDDRC_BASE + 0x78) /* DLL Slave Offset Register */
#define MPDDRC_DLL_MS *(volatile uint32_t *)(MPDDRC_BASE + 0x7C) /* DLL Master Status Register */
#define MPDDRC_DLL_SS0 *(volatile uint32_t *)(MPDDRC_BASE + 0x80) /* DLL Slave 0 Status Register */
#define MPDDRC_DLL_SS1 *(volatile uint32_t *)(MPDDRC_BASE + 0x84) /* DLL Slave 1 Status Register */
#define MPDDRC_DLL_SS2 *(volatile uint32_t *)(MPDDRC_BASE + 0x88) /* DLL Slave 2 Status Register */
#define MPDDRC_DLL_SS3 *(volatile uint32_t *)(MPDDRC_BASE + 0x8C) /* DLL Slave 3 Status Register */
/* Reserved 0x90 to 0xE0 */
#define MPDDRC_WPMR *(volatile uint32_t *)(MPDDRC_BASE + 0xE4) /* Write Protection Mode Register */
#define MPDDRC_WPSR *(volatile uint32_t *)(MPDDRC_BASE + 0xE8) /* Write Protection Status Register */
/* MPDDRC_CR: shift, mask, values */
#define MPDDRC_NC_SHIFT 0 /* Number of Column Bits */
#define MPDDRC_NC_MASK (0x3 << MPDDRC_NC_SHIFT)
#define MPDDRC_NC_9 (0x0 << MPDDRC_NC_SHIFT)
#define MPDDRC_NC_10 (0x1 << MPDDRC_NC_SHIFT)
#define MPDDRC_NC_11 (0x2 << MPDDRC_NC_SHIFT)
#define MPDDRC_NC_12 (0x3 << MPDDRC_NC_SHIFT)
#define MPDDRC_NR_SHIFT 2 /* Number of Row Bits */
#define MPDDRC_NR_MASK (0x3 << MPDDRC_NR_SHIFT)
#define MPDDRC_NR_11 (0x0 << MPDDRC_NR_SHIFT)
#define MPDDRC_NR_12 (0x1 << MPDDRC_NR_SHIFT)
#define MPDDRC_NR_13 (0x2 << MPDDRC_NR_SHIFT)
#define MPDDRC_NR_14 (0x3 << MPDDRC_NR_SHIFT)
#define MPDDRC_CAS_SHIFT 4 /* CAS Latency */
#define MPDDRC_CAS_MASK (0x7 << MPDDRC_CAS_SHIFT)
#define MPDDRC_NB_SHIFT 20 /* Number of Banks */
#define MPDDRC_NB_MASK (0x1 << MPDDRC_NB_SHIFT)
#define MPDDRC_MD_DBW_SHIFT 4 /* Data Bus Width */
#define MPDDRC_MD_DBW_MASK (0x1 << MPDDRC_MD_DBW_SHIFT)
#define MPDDRC_NQDS_DISABLED_SHIFT 21 /* NAND Data Queue in DDR2 SDRAM */
#define MPDDRC_NDQS_DISABLED (0x1 << MPDDRC_NQDS_DISABLED_SHIFT)
#define MPDDRC_UNAL_SHIFT 23 /* Support Unaligned Access */
#define MPDDRC_UNAL (0x1 << MPDDRC_UNAL_SHIFT)
#define REF_WIN 32
#define REF_CYCLE 2048
/* Configuration register */
#define MPDDRC_CR_NC_SHIFT 0
#define MPDDRC_CR_NC_MASK (0x3 << MPDDRC_CR_NC_SHIFT)
#define MPDDRC_CR_NR_SHIFT 2
#define MPDDRC_CR_NR_MASK (0x3 << MPDDRC_CR_NR_SHIFT)
#define MPDDRC_CR_CAS_SHIFT 4
#define MPDDRC_CR_CAS_MASK (0x7 << MPDDRC_CR_CAS_SHIFT)
#define MPDDRC_CR_ENABLE_DLL_RESET (1 << 7)
#define MPDDRC_CR_NB_SHIFT 8
#define MPDDRC_CR_NB_MASK (0x1 << MPDDRC_CR_NB_SHIFT)
#define MPDDRC_CR_DECOD_INTERLEAVED (1 << 22)
/* Memory device register */
#define MPDDRC_MD_SDRAM (0x0 << 0)
#define MPDDRC_MD_LP_SDRAM (0x1 << 0)
#define MPDDRC_MD_DDR_SDRAM (0x2 << 0)
#define MPDDRC_MD_LP_DDR_SDRAM (0x3 << 0)
#define MPDDRC_MD_DDR3_SDRAM (0x4 << 0)
#define MPDDRC_MD_LPDDR3_SDRAM (0x5 << 0)
#define MPDDRC_MD_DDR2_SDRAM (0x6 << 0)
#define MPDDRC_MD_LPDDR2_SDRAM (0x7 << 0)
#define MPDDRC_MD_DBW_32BIT (0x0 << 4)
#define MPDDRC_MD_DBW_16BIT (0x1 << 4)
/* Mode register */
#define MPDDRC_MR_MODE_NORMAL 0
#define MPDDRC_MR_MODE_NOP 1
#define MPDDRC_MR_MODE_PRECHARGE 2
#define MPDDRC_MR_MODE_LOAD 3
#define MPDDRC_MR_MODE_AUTO_REFRESH 4
#define MPDDRC_MR_MODE_EXT_LOAD 5
#define MPDDRC_MR_MODE_DEEP_POWER 6
#define MPDDRC_MR_MODE_LPDDR2_PDE 7
#define MPDDRC_CR_OCD_DEFAULT (0x7 << 12)
#define MPDDRC_TRAS_SHIFT 0
#define MPDDRC_TRCD_SHIFT 4
#define MPDDRC_TWR_SHIFT 8
#define MPDDRC_TRC_SHIFT 12
#define MPDDRC_TRP_SHIFT 16
#define MPDDRC_TRRD_SHIFT 20
#define MPDDRC_TWTR_SHIFT 24
#define MPDDRC_TMRD_SHIFT 28
#define MPDDRC_TRFC_SHIFT 0
#define MPDDRC_TXSNR_SHIFT 8
#define MPDDRC_TXSRD_SHIFT 16
#define MPDDRC_TXP_SHIFT 24
#define MPDDRC_TXARD_SHIFT 0
#define MPDDRC_TXARDS_SHIFT 4
#define MPDDRC_TRPA_SHIFT 8
#define MPDDRC_TRTP_SHIFT 12
#define MPDDRC_TFAW_SHIFT 16
/* Calibration register */
#define MPDDRC_IOCALIBR_RDIV_SHIFT 0
#define MPDDRC_IOCALIBR_RDIV_MASK (0x7 << MPDDRC_IOCALIBR_RDIV_SHIFT)
#define MPDDRC_IOCALIBR_RDIV_DDR2_RZQ_50 (4 << MPDDRC_IOCALIBR_RDIV_SHIFT)
#define MPDDRC_IOCALIBR_TZQIO_SHIFT 8
#define MPDDRC_IOCALIBR_TZQIO_MASK (0x7F << MPDDRC_IOCALIBR_TZQIO_SHIFT)
/* Read data path register */
#define MPDDRC_RD_DATA_PATH_CYCLES_SHIFT 0
#define MPDDRC_RD_DATA_PATH_CYCLES_MASK (0x3 << MPDDRC_RD_DATA_PATH_CYCLES_SHIFT)
/* MPDDRC Device clock */
#define MPDDRC_PMCID 0x31 /* dec: 49 for SAMA5D3 */
#define MPDDRC_SCERID (1 << 2)
/* PIT device clock */
#define PIT_PMCID 0x03 /* dec: 3 for SAMA5D3 */
#define MAX_PIV 0xfffff
#define PIT_MR_EN (1 << 24)
struct dram {
struct dram_timing {
uint32_t tras;
uint32_t trcd;
uint32_t twr;
uint32_t trc;
uint32_t trp;
uint32_t trrd;
uint32_t twtr;
uint32_t tmrd;
uint32_t trfc;
uint32_t txsnr;
uint32_t txsrd;
uint32_t txp;
uint32_t txard;
uint32_t txards;
uint32_t trpa;
uint32_t trtp;
uint32_t tfaw;
} timing;
};
/* Watchdog
*/
#define WDT_BASE 0xFFFFFD40
#define WDT_CR *(volatile uint32_t *)(WDT_BASE + 0x00)
#define WDT_MR *(volatile uint32_t *)(WDT_BASE + 0x04)
#define WDT_SR *(volatile uint32_t *)(WDT_BASE + 0x08)
#define WDT_MD_WDDIS (0x1 << 15)
#define WDT_MD_WDRSTEN (0x1 << 14)
static inline void watchdog_disable(void)
{
WDT_MR |= WDT_MD_WDDIS;
}
/*
*
* NAND flash
*/
/* Fixed addresses */
extern void *kernel_addr, *update_addr, *dts_addr;
#if defined(EXT_FLASH) && defined(NAND_FLASH)
/* Constant for local buffers */
#define NAND_FLASH_PAGE_SIZE 0x800 /* 2KB */
#define NAND_FLASH_OOB_SIZE 0x40 /* 64B */
/* Address space mapping for atsama5d3 */
#define DRAM_BASE 0x20000000UL
#define CS1_BASE 0x40000000UL
#define CS2_BASE 0x50000000UL
#define CS3_BASE 0x60000000UL
#define NFC_CMD_BASE 0x70000000UL
/* NAND flash is mapped to CS3 */
#define NAND_BASE CS3_BASE
#define NAND_MASK_ALE (1 << 21)
#define NAND_MASK_CLE (1 << 22)
#define NAND_CMD (*((volatile uint8_t *)(NAND_BASE | NAND_MASK_CLE)))
#define NAND_ADDR (*((volatile uint8_t *)(NAND_BASE | NAND_MASK_ALE)))
#define NAND_DATA (*((volatile uint8_t *)(NAND_BASE)))
/* Command set */
#define NAND_CMD_STATUS 0x70
#define NAND_CMD_READ1 0x00
#define NAND_CMD_READ2 0x30
#define NAND_CMD_READID 0x90
#define NAND_CMD_RESET 0xFF
#define NAND_CMD_ERASE1 0x60
#define NAND_CMD_ERASE2 0xD0
#define NAND_CMD_WRITE1 0x80
#define NAND_CMD_WRITE2 0x10
/* Small block */
#define NAND_CMD_READ_A0 0x00
#define NAND_CMD_READ_A1 0x01
#define NAND_CMD_READ_C 0x50
#define NAND_CMD_WRITE_A 0x00
#define NAND_CMD_WRITE_C 0x50
/* ONFI */
#define NAND_CMD_READ_ONFI 0xEC
/* Features set/get */
#define NAND_CMD_GET_FEATURES 0xEE
#define NAND_CMD_SET_FEATURES 0xEF
/* ONFI parameters and definitions */
#define ONFI_PARAMS_SIZE 256
#define PARAMS_POS_REVISION 4
#define PARAMS_REVISION_1_0 (0x1 << 1)
#define PARAMS_REVISION_2_0 (0x1 << 2)
#define PARAMS_REVISION_2_1 (0x1 << 3)
#define PARAMS_POS_FEATURES 6
#define PARAMS_FEATURE_BUSWIDTH (0x1 << 0)
#define PARAMS_FEATURE_EXTENDED_PARAM (0x1 << 7)
#define PARAMS_POS_OPT_CMD 8
#define PARAMS_OPT_CMD_SET_GET_FEATURES (0x1 << 2)
#define PARAMS_POS_EXT_PARAM_PAGE_LEN 12
#define PARAMS_POS_PARAMETER_PAGE 14
#define PARAMS_POS_PAGESIZE 80
#define PARAMS_POS_OOBSIZE 84
#define PARAMS_POS_BLOCKSIZE 92
#define PARAMS_POS_NBBLOCKS 96
#define PARAMS_POS_ECC_BITS 112
#define PARAMS_POS_TIMING_MODE 129
#define PARAMS_TIMING_MODE_0 (1 << 0)
#define PARAMS_TIMING_MODE_1 (1 << 1)
#define PARAMS_TIMING_MODE_2 (1 << 2)
#define PARAMS_TIMING_MODE_3 (1 << 3)
#define PARAMS_TIMING_MODE_4 (1 << 4)
#define PARAMS_TIMING_MODE_5 (1 << 5)
#define PARAMS_POS_CRC 254
#define ONFI_CRC_BASE 0x4F4E
#define ONFI_MAX_SECTIONS 8
#define ONFI_SECTION_TYPE_0 0
#define ONFI_SECTION_TYPE_1 1
#define ONFI_SECTION_TYPE_2 2
/* Read access modes */
#define NAND_MODE_DATAPAGE 1
#define NAND_MODE_INFO 2
#define NAND_MODE_DATABLOCK 3
#define nand_flash_read ext_flash_read
#define nand_flash_write ext_flash_write
#define nand_flash_erase ext_flash_erase
#define nand_flash_unlock ext_flash_unlock
#define nand_flash_lock ext_flash_lock
#define MAX_ECC_BYTES 8
#endif
#define GPIOE_BASE 0xFFFFFA00
#define GPIOE_PER *(volatile uint32_t *)(GPIOE_BASE + 0x00)
#define GPIOE_PDR *(volatile uint32_t *)(GPIOE_BASE + 0x04)
#define GPIOE_PSR *(volatile uint32_t *)(GPIOE_BASE + 0x08)
#define GPIOE_OER *(volatile uint32_t *)(GPIOE_BASE + 0x10)
#define GPIOE_ODR *(volatile uint32_t *)(GPIOE_BASE + 0x14)
#define GPIOE_OSR *(volatile uint32_t *)(GPIOE_BASE + 0x18)
#define GPIOE_SODR *(volatile uint32_t *)(GPIOE_BASE + 0x30)
#define GPIOE_CODR *(volatile uint32_t *)(GPIOE_BASE + 0x34)
#define GPIOE_IER *(volatile uint32_t *)(GPIOE_BASE + 0x40)
#define GPIOE_IDR *(volatile uint32_t *)(GPIOE_BASE + 0x44)
#define GPIOE_MDER *(volatile uint32_t *)(GPIOE_BASE + 0x50)
#define GPIOE_MDDR *(volatile uint32_t *)(GPIOE_BASE + 0x54)
#define GPIOE_PPUDR *(volatile uint32_t *)(GPIOE_BASE + 0x60)
#define GPIOE_PPUER *(volatile uint32_t *)(GPIOE_BASE + 0x64)
#endif

58
hal/sama5d3.ld 100644
View File

@ -0,0 +1,58 @@
OUTPUT_FORMAT("elf32-littlearm")
OUTPUT_ARCH(arm)
MEMORY
{
DDR_MEM(rwx): ORIGIN = 0x00000000, LENGTH = 0x0000F000
}
ENTRY(reset_vector_entry)
SECTIONS
{
.text : {
_start_text = .;
*(.text)
*(.rodata)
*(.rodata*)
. = ALIGN(4);
*(.glue_7)
. = ALIGN(4);
*(.eh_frame)
. = ALIGN(4);
_end_text = . ;
}
/* collect all initialized .data sections */
/* .data : AT ( ADDR (.text) + SIZEOF (.text) SIZEOF (.ARM.*) { */
. = ALIGN(4);
.dummy : {
_edummy = .;
}
.data : AT (LOADADDR(.dummy)) {
_start_data = .;
*(.vectors)
*(.data)
_end_data = .;
}
/* collect all uninitialized .bss sections */
.bss (NOLOAD) : {
. = ALIGN(4);
_start_bss = .;
*(.bss)
_end_bss = .;
}
}
kernel_addr = 0x0400000;
update_addr = 0x0800000;
_romsize = _end_data - _start_text;
_sramsize = _end_bss - _start_text;
END_STACK = _start_text;
_stack_top = ORIGIN(DDR_MEM) + LENGTH(DDR_MEM);
end = .; /* define a global symbol marking the end of application */

View File

@ -1,4 +1,5 @@
WOLFCRYPT_OBJS+=./lib/wolfssl/wolfcrypt/src/asn.o
USE_GCC?=1
# Support for Built-in ROT into OTP flash memory
ifeq ($(FLASH_OTP_KEYSTORE),1)
@ -196,7 +197,7 @@ ifeq ($(SIGN),ED448)
ifeq ($(WOLFBOOT_SMALL_STACK),1)
STACK_USAGE?=1024
else
STACK_USAGE?=4376
STACK_USAGE?=4578
endif
endif

100
src/boot_arm32.c 100644
View File

@ -0,0 +1,100 @@
/* boot_arm32.c
*
* Bring up, vectors and do_boot for 32bit Cortex-A microprocessors.
*
* Copyright (C) 2024 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 3 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>
#include "image.h"
#include "loader.h"
#include "wolfboot/wolfboot.h"
extern unsigned int __bss_start__;
extern unsigned int __bss_end__;
static volatile unsigned int cpu_id;
extern unsigned int *END_STACK;
extern void main(void);
void boot_entry_C(void)
{
register unsigned int *dst;
/* Initialize the BSS section to 0 */
dst = &__bss_start__;
while (dst < (unsigned int *)&__bss_end__) {
*dst = 0U;
dst++;
}
/* Run wolfboot! */
main();
}
/* This is the main loop for the bootloader.
*
* It performs the following actions:
* - Call the application entry point
*
*/
#ifdef MMU
void RAMFUNCTION do_boot(const uint32_t *app_offset, const uint32_t* dts_offset)
#else
void RAMFUNCTION do_boot(const uint32_t *app_offset)
#endif
{
/* Set application address via r4 */
asm volatile("mov r4, %0" : : "r"(app_offset));
#ifdef MMU
/* Move the dts pointer to r5 (as first argument) */
asm volatile("mov r5, %0" : : "r"(dts_offset));
#else
asm volatile("mov r5, 0");
#endif
/* Zero registers r1, r2, r3 */
asm volatile("mov r3, 0");
asm volatile("mov r2, 0");
asm volatile("mov r1, 0");
/* Move the dts pointer to r0 (as first argument) */
asm volatile("mov r0, r5");
/* Unconditionally jump to app_entry at r4 */
asm volatile("bx r4");
}
#ifdef RAM_CODE
#define AIRCR *(volatile uint32_t *)(0xE000ED0C)
#define AIRCR_VKEY (0r05FA << 16)
#define AIRCR_SYSRESETREQ (1 << 2)
void RAMFUNCTION arch_reboot(void)
{
AIRCR = AIRCR_SYSRESETREQ | AIRCR_VKEY;
while(1)
;
wolfBoot_panic();
}
#endif

View File

@ -0,0 +1,98 @@
/**
* Arm32 (32bit Cortex-A) boot up
* Copyright (C) 2024 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 3 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
*/
.section start
.text
/* startup entry point */
.globl reset_vector_entry
.align 4
reset_vector_entry:
/* Exception vectors (should be a branch to be detected as a valid code by the rom */
_exception_vectors:
b isr_reset /* reset */
b isr_empty /* Undefined Instruction */
b isr_swi /* Software Interrupt */
b isr_pabt /* Prefetch Abort */
b dabt_vector /* Data Abort */
.word _romsize /* Size of the binary for ROMCode loading */
b isr_irq /* IRQ : read the AIC */
b isr_fiq /* FIQ */
isr_empty:
b isr_empty
isr_swi:
b isr_swi
isr_pabt:
b isr_pabt
dabt_vector:
subs pc, r14, #4 /* return */
nop
isr_rsvd:
b isr_rsvd
isr_irq:
b isr_irq
isr_fiq:
b isr_fiq
/* Reset handler procedure. Prepare the memory and call main() */
isr_reset:
/* Initialize the stack pointer */
ldr sp,=_stack_top
/* Save BootROM supplied boot source information to stack */
push {r4}
/* Copy the data section */
ldr r2, =_lp_data
ldmia r2, {r1, r3, r4}
1:
cmp r3, r4
ldrcc r2, [r1], #4
strcc r2, [r3], #4
bcc 1b
/* Zero bss area */
adr r2, _lp_bss
ldmia r2, {r3, r4}
mov r2, #0
1:
cmp r3, r4
strcc r2, [r3], #4
bcc 1b
/* Jump to main() */
ldr r4, = main
mov lr, pc
bx r4
/* main() should never return */
_panic:
b _panic
.align
_lp_data:
.word _start_data
.word _end_data
_lp_bss:
.word _start_bss
.word _end_bss

View File

@ -0,0 +1,55 @@
OUTPUT_FORMAT("elf32-littlearm")
OUTPUT_ARCH(arm)
MEMORY
{
DDR_MEM(rwx): ORIGIN = 0x20100800, LENGTH = 0x100000
STACK_MEM(rw): ORIGIN = 0x20000000, LENGTH = 0x00100000
}
ENTRY(reset_vector_entry)
SECTIONS
{
.text : AT (ORIGIN(DDR_MEM)) {
_start_text = .;
*(.iv)
*(.text)
*(.rodata)
*(.rodata*)
. = ALIGN(4);
*(.glue_7)
. = ALIGN(4);
*(.eh_frame)
. = ALIGN(4);
_end_text = . ;
}
/* collect all initialized .data sections */
/* .data : AT ( ADDR (.text) + SIZEOF (.text) SIZEOF (.ARM.*) { */
. = ALIGN(4);
.dummy : {
_edummy = .;
}
.data : AT (LOADADDR(.dummy)) {
_start_data = .;
*(.vectors)
*(.data)
_end_data = .;
}
/* collect all uninitialized .bss sections */
.bss (NOLOAD) : {
. = ALIGN(4);
_start_bss = .;
*(.bss)
_end_bss = .;
}
}
_romsize = _end_data - _start_text;
_sramsize = _end_bss - _start_text;
END_STACK = _start_text;
_stack_top = ORIGIN(STACK_MEM) + LENGTH(STACK_MEM);
end = .; /* define a global symbol marking the end of application */

View File

@ -36,6 +36,7 @@ ifeq ($(HASH),SHA3_384)
endif
ifeq ($(TARGET),ti_hercules)
APP_OBJS:=app_$(TARGET).o ../test-app/libwolfboot.o
CFLAGS+=-I"../include"
@ -144,6 +145,11 @@ ifeq ($(TARGET),stm32c0)
LSCRIPT_TEMPLATE=ARM-stm32c0.ld
endif
ifeq ($(TARGET),sama5d3)
APP_OBJS+=./boot_arm32_start.o
LSCRIPT_TEMPLATE:=$(ARCH)-$(TARGET).ld
endif
ifeq ($(TARGET),stm32l4)
APP_OBJS+=$(STM32CUBE)/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash.o
APP_OBJS+=$(STM32CUBE)/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_flash_ex.o

View File

@ -0,0 +1,66 @@
/* app_sama5d3.c
*
* Test bare-metal boot application
*
* Copyright (C) 2024 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 3 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 <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <hal/sama5d3.h>
#include "wolfboot/wolfboot.h"
#ifdef TARGET_sama5d3
/* Blue LED is PE23, Red LED is PE24 */
#define BLUE_LED_PIN 23
#define RED_LED_PIN 24
void led_init(uint32_t pin)
{
uint32_t mask = 1U << pin;
GPIOE_MDDR |= mask;
GPIOE_PER |= mask;
GPIOE_IDR |= mask;
GPIOE_PPUDR |= mask;
GPIOE_CODR |= mask;
}
void led_put(uint32_t pin, int val)
{
uint32_t mask = 1U << pin;
if (val)
GPIOE_SODR |= mask;
else
GPIOE_CODR |= mask;
}
volatile uint32_t time_elapsed = 0;
void main(void) {
/* Wait for reboot */
led_init(RED_LED_PIN);
led_put(RED_LED_PIN, 1);
while(1)
;
}
#endif /** TARGET_sama5d3 **/

View File

@ -0,0 +1,99 @@
/**
* Arm32 (32bit Cortex-A) boot up
* Copyright (C) 2024 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 3 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
*/
.section start
.text
/* startup entry point */
.globl reset_vector_entry
.align 4
.section .iv
reset_vector_entry:
/* Exception vectors (should be a branch to be detected as a valid code by the rom */
_exception_vectors:
b isr_reset /* reset */
b isr_empty /* Undefined Instruction */
b isr_swi /* Software Interrupt */
b isr_pabt /* Prefetch Abort */
b dabt_vector /* Data Abort */
.word _romsize /* Size of the binary for ROMCode loading */
b isr_irq /* IRQ : read the AIC */
b isr_fiq /* FIQ */
isr_empty:
b isr_empty
isr_swi:
b isr_swi
isr_pabt:
b isr_pabt
dabt_vector:
subs pc, r14, #4 /* return */
nop
isr_rsvd:
b isr_rsvd
isr_irq:
b isr_irq
isr_fiq:
b isr_fiq
/* Reset handler procedure. Prepare the memory and call main() */
isr_reset:
/* Initialize the stack pointer */
ldr sp,=_stack_top
/* Save BootROM supplied boot source information to stack */
push {r4}
/* Copy the data section */
ldr r2, =_lp_data
ldmia r2, {r1, r3, r4}
1:
cmp r3, r4
ldrcc r2, [r1], #4
strcc r2, [r3], #4
bcc 1b
/* Zero bss area */
adr r2, _lp_bss
ldmia r2, {r3, r4}
mov r2, #0
1:
cmp r3, r4
strcc r2, [r3], #4
bcc 1b
/* Jump to main() */
ldr r4, = main
mov lr, pc
bx r4
/* main() should never return */
_panic:
b _panic
.align
_lp_data:
.word _start_data
.word _end_data
_lp_bss:
.word _start_bss
.word _end_bss