diff --git a/.gdbinit b/.gdbinit index 676e54df9..e6d2cdfeb 100644 --- a/.gdbinit +++ b/.gdbinit @@ -1,5 +1,5 @@ -tar rem:3333 file wolfboot.elf +tar rem:3333 add-symbol-file test-app/image.elf foc c diff --git a/.github/workflows/test-configs.yml b/.github/workflows/test-configs.yml index 1df9275be..4760abd5d 100644 --- a/.github/workflows/test-configs.yml +++ b/.github/workflows/test-configs.yml @@ -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: diff --git a/Makefile b/Makefile index d803e91e0..2bc191e93 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/arch.mk b/arch.mk index 92dbe8319..0bc648df1 100644 --- a/arch.mk +++ b/arch.mk @@ -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 + # 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 # 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_CORTEX_M_ASM + MATH_OBJS += ./lib/wolfssl/wolfcrypt/src/sp_cortexm.o + endif + endif + else + 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_M0),1) - CFLAGS+=-mcpu=cortex-m0 - LDFLAGS+=-mcpu=cortex-m0 + 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_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 ($(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 diff --git a/config/examples/sama5d3.config b/config/examples/sama5d3.config new file mode 100644 index 000000000..f52f84794 --- /dev/null +++ b/config/examples/sama5d3.config @@ -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 diff --git a/docs/Targets.md b/docs/Targets.md index c100d4526..3c65c7615 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -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 diff --git a/hal/sama5d3.c b/hal/sama5d3.c new file mode 100644 index 000000000..804dc3d5a --- /dev/null +++ b/hal/sama5d3.c @@ -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 +#include +#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, "ient, &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, "ient, &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; +} + + diff --git a/hal/sama5d3.h b/hal/sama5d3.h new file mode 100644 index 000000000..40b99ab25 --- /dev/null +++ b/hal/sama5d3.h @@ -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 + +/* 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 diff --git a/hal/sama5d3.ld b/hal/sama5d3.ld new file mode 100644 index 000000000..c446f1683 --- /dev/null +++ b/hal/sama5d3.ld @@ -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 */ + + diff --git a/options.mk b/options.mk index 7184ed67c..584b65e3e 100644 --- a/options.mk +++ b/options.mk @@ -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 diff --git a/src/boot_arm32.c b/src/boot_arm32.c new file mode 100644 index 000000000..5502ff151 --- /dev/null +++ b/src/boot_arm32.c @@ -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 + +#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 diff --git a/src/boot_arm32_start.S b/src/boot_arm32_start.S new file mode 100644 index 000000000..57520ba7f --- /dev/null +++ b/src/boot_arm32_start.S @@ -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 + diff --git a/test-app/ARM-sama5d3.ld b/test-app/ARM-sama5d3.ld new file mode 100644 index 000000000..bd2808361 --- /dev/null +++ b/test-app/ARM-sama5d3.ld @@ -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 */ + diff --git a/test-app/Makefile b/test-app/Makefile index 7e095197f..47b8acae2 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -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 diff --git a/test-app/app_sama5d3.c b/test-app/app_sama5d3.c new file mode 100644 index 000000000..45de4d452 --- /dev/null +++ b/test-app/app_sama5d3.c @@ -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 +#include +#include +#include + +#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 **/ diff --git a/test-app/boot_arm32_start.S b/test-app/boot_arm32_start.S new file mode 100644 index 000000000..55a26462d --- /dev/null +++ b/test-app/boot_arm32_start.S @@ -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 +