diff --git a/CMakeLists.txt b/CMakeLists.txt index 210bedf49c..b389418185 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -394,6 +394,7 @@ if(NOT DEFINED ARM_TARGETS) nrf52840 nrf5340 nrf5340_net + nrf54lm20 rp2350 sama5d3 same51 diff --git a/Makefile b/Makefile index bb62d3d320..3ab04a1acf 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ BIG_ENDIAN?=0 USE_GCC?=1 USE_GCC_HEADLESS?=1 FLASH_OTP_KEYSTORE?=0 +SUPPORT_DEV_BOARD?=0 BOOTLOADER_PARTITION_SIZE?=$$(( $(WOLFBOOT_PARTITION_BOOT_ADDRESS) - $(ARCH_FLASH_OFFSET))) OBJS:= \ @@ -163,6 +164,12 @@ include arch.mk # Parse config options include options.mk +ifeq ($(SUPPORT_DEV_BOARD),1) + ifeq ($(TARGET),nrf54lm20) + OBJS+=./hal/nrf54lm20_dk.o + endif +endif + OBJS+=$(WOLFCRYPT_OBJS) OBJS+=$(PUBLIC_KEY_OBJS) OBJS+=$(WOLFHSM_OBJS) diff --git a/config/examples/nrf54lm20.config b/config/examples/nrf54lm20.config new file mode 100644 index 0000000000..03d1180326 --- /dev/null +++ b/config/examples/nrf54lm20.config @@ -0,0 +1,64 @@ +ARCH?=ARM +TZEN?=0 +TARGET?=nrf54lm20 +SIGN?=ECC384 +HASH?=SHA384 +WOLFBOOT_VERSION?=1 +VTOR?=1 +CORTEX_M0?=0 +CORTEX_M33?=1 +NO_ASM?=0 +NO_MPU=1 +ALLOW_DOWNGRADE?=0 +NVM_FLASH_WRITEONCE?=0 +DELTA_UPDATES?=1 +SUPPORT_DEV_BOARD?=1 + +SPMATH?=1 +RAM_CODE?=1 + +DUALBANK_SWAP?=0 +FLAGS_HOME=0 +DISABLE_BACKUP=0 +EXT_FLASH?=0 +SPI_FLASH?=0 +QSPI_FLASH?=0 +UART_FLASH?=0 + +# Flash is 4KB pages +WOLFBOOT_SECTOR_SIZE?=0x1000 + +# Reserve the first 64KB of internal flash for wolfBoot itself +WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x10000 + +# Application partition spans the remainder of the 2MB internal flash +# (2048K - 64K - 4K) / 2 = 990K = 0xF7800 +WOLFBOOT_PARTITION_SIZE?=0xF7800 + +# Flash offset for application update image +# (64K + 990K) = 1054K = 0x107800 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x107800 + +# Flash offset for swap area +# (2048K - 4K) = 2044K = 0x1FF000 +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x1FF000 + +V?=0 +DEBUG?=0 +DEBUG_UART?=1 +USE_GCC=1 +OPTIMIZATION_LEVEL=2 + +# Use larger block size for swapping sectors (performance improvement) +CFLAGS_EXTRA+=-DFLASHBUFFER_SIZE=0x1000 + +# Map debug UART to DK connector (override as needed) +#CFLAGS_EXTRA+=-DUART_PORT=0 -DUART_PIN=20 + +# SPI flash hookup for the DK radio shield +#CFLAGS_EXTRA+=-DSPI_CS_PORT=0 -DSPI_CS_PIN=25 +#CFLAGS_EXTRA+=-DSPI_SCK_PORT=0 -DSPI_SCK_PIN=29 +#CFLAGS_EXTRA+=-DSPI_MOSI_PORT=0 -DSPI_MOSI_PIN=28 +#CFLAGS_EXTRA+=-DSPI_MISO_PORT=0 -DSPI_MISO_PIN=27 + +#CFLAGS_EXTRA+=-DDEBUG_FLASH diff --git a/hal/nrf54lm20.c b/hal/nrf54lm20.c new file mode 100644 index 0000000000..9badd02e49 --- /dev/null +++ b/hal/nrf54lm20.c @@ -0,0 +1,496 @@ +/* nrf54lm20.c + * + * Copyright (C) 2025 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 + */ + +#ifdef TARGET_nrf54lm20 + +#include +#include +#include + +#include "hal.h" +#include "image.h" +#include "nrf54lm20.h" +#include "printf.h" +#include "wolfboot/wolfboot.h" + +#ifndef DEBUG_UART +#define DEBUG_UART 1 +#endif + +/* UART */ + +#ifdef DEBUG_UART + +#define UART_WRITE_BUF_SIZE 128 + +void sleep_us(uint32_t usec); + +static void uart_init_device(int device, uint32_t bitrate, uint8_t data, char parity, uint8_t stop) +{ + int port = UART_PORT_NUM(device); + int pinTx = UART_PIN_NUM_TX(device); + int pinRx = UART_PIN_NUM_RX(device); + + UART_ENABLE(device) = UART_ENABLE_ENABLE_Disabled; + + /* Configure TX pin */ + GPIO_PIN_CNF(device, pinTx) = (GPIO_CNF_OUT | GPIO_CNF_STD_DRIVE_0 | GPIO_CNF_MCUSEL(0)); + /* Configure RX pin */ + GPIO_PIN_CNF(device, pinRx) = (GPIO_CNF_IN | GPIO_CNF_STD_DRIVE_0 | GPIO_CNF_MCUSEL(0)); + + UART_PSEL_TXD(device) = ((pinTx << UART_PSEL_TXD_PIN_Pos) & UART_PSEL_TXD_PIN_Msk) | + ((port << UART_PSEL_TXD_PORT_Pos) & UART_PSEL_TXD_PORT_Msk); + UART_PSEL_RXD(device) = ((pinRx << UART_PSEL_RXD_PIN_Pos) & UART_PSEL_RXD_PIN_Msk) | + ((port << UART_PSEL_RXD_PORT_Pos) & UART_PSEL_RXD_PORT_Msk); + UART_PSEL_CTS(device) = UART_PSEL_CTS_CONNECT_Disconnected; + UART_PSEL_RTS(device) = UART_PSEL_RTS_CONNECT_Disconnected; + UART_BAUDRATE(device) = UART_BAUDRATE_BAUDRATE_Baud115200; + UART_CONFIG(device) = 0; /* 8N1, no HW flow control */ + + UART_ENABLE(device) = UART_ENABLE_ENABLE_Enabled; +} + +void uart_write_raw(int device, const char* buffer, unsigned int sz) +{ + /* EasyDMA requires a RAM buffer */ + static uint8_t uartTxBuf[UART_WRITE_BUF_SIZE]; + + while (sz > 0) { + /* + * loop until all bytes written, + * but only write UART_WRITE_BUF_SIZE max chars at once + */ + unsigned int xfer = sz; + if (xfer > sizeof(uartTxBuf)) + xfer = sizeof(uartTxBuf); + memcpy(uartTxBuf, buffer, xfer); + + UART_EVENTS_DMA_TX_END(device) = 0; + UART_EVENTS_DMA_TX_BUSERROR(device) = 0; + + UART_DMA_TX_PTR(device) = (uint32_t)uartTxBuf; + UART_DMA_TX_MAXCNT(device) = xfer; + UART_TASKS_DMA_TX_START(device) = UART_TASKS_DMA_TX_START_START_Trigger; + + /* Avoid an infinite wait: break on end, bus error, or timeout */ + uint32_t guard = 0; + uint32_t maxGuard = xfer; // num char times + while((UART_EVENTS_DMA_TX_END(device) == 0) && (UART_EVENTS_DMA_TX_BUSERROR(device) == 0)) + { + if (guard > maxGuard) { + UART_TASKS_DMA_TX_STOP(device) = UART_TASKS_DMA_TX_STOP_STOP_Trigger; + break; + } + ++guard; + sleep_us(100); /* at 115200, a char takes ~ 86us, round up to 100 */ + } + + sz -= xfer; + buffer += xfer; + } +} + +void uart_write_device(int device, const char* buf, unsigned int sz) +{ + static char buffer[UART_WRITE_BUF_SIZE]; + int bufsz = 0; + + for(int i=0; i<(int)sz && bufsz < UART_WRITE_BUF_SIZE; i++) + { + char ch = (char) buf[i]; + if(ch == '\r') + continue; + if(ch == '\n') + buffer[bufsz++] = '\r'; + buffer[bufsz++] = ch; + } + uart_write_raw(device, buffer, bufsz); +} + +void uart_write(const char* buf, unsigned int sz) +{ + uart_write_device(DEVICE_MONITOR, buf, sz); +} + +#endif /* DEBUG_UART */ + +#if (defined DEBUG_UART || UART_FLASH) +#define UART_RX_TIMEOUT 1000000UL +int uart_read(int device, uint8_t* buf, unsigned int sz) +{ + if ((buf == NULL) || (sz == 0)) + return -1; + + UART_EVENTS_DMA_RX_END(device) = 0; + UART_EVENTS_DMA_RX_BUSERROR(device) = 0; + + UART_DMA_RX_PTR(device) = (uint32_t)buf; + UART_DMA_RX_MAXCNT(device) = sz; + + UART_TASKS_DMA_RX_START(device) = UART_TASKS_DMA_RX_START_START_Trigger; + + for (uint32_t guard = 0; UART_EVENTS_DMA_RX_END(device) == 0; guard++) { + if (UART_EVENTS_DMA_RX_BUSERROR(device) != 0) { + UART_TASKS_DMA_RX_STOP(device) = UART_TASKS_DMA_RX_STOP_STOP_Trigger; + return -1; + } + if (guard > UART_RX_TIMEOUT) { + UART_TASKS_DMA_RX_STOP(device) = UART_TASKS_DMA_RX_STOP_STOP_Trigger; + return 0; + } + } + + UART_TASKS_DMA_RX_STOP(device) = UART_TASKS_DMA_RX_STOP_STOP_Trigger; + return (int)UART_DMA_RX_AMOUNT(device); +} +#endif /* DEBUG_UART || UART_FLASH */ + +static void RAMFUNCTION flash_wait_ready(void) +{ + while ((RRAMC_READY & RRAMC_READY_READY_Msk) == 0U) + ; +} + +static void RAMFUNCTION flash_wait_ready_next(void) +{ + while ((RRAMC_READYNEXT & RRAMC_READYNEXT_READYNEXT_Msk) == 0U) + ; +} + +static void RAMFUNCTION flash_wait_buf_empty(void) +{ + while ((RRAMC_BUFSTATUS_WRITEBUFEMPTY & + RRAMC_BUFSTATUS_WRITEBUFEMPTY_EMPTY_Msk) == 0U) + ; +} + +static void RAMFUNCTION flash_commit_writebuf(void) +{ + if ((RRAMC_BUFSTATUS_WRITEBUFEMPTY & + RRAMC_BUFSTATUS_WRITEBUFEMPTY_EMPTY_Msk) == 0U) { + RRAMC_TASKS_COMMITWRITEBUF = + RRAMC_TASKS_COMMITWRITEBUF_TASKS_COMMITWRITEBUF_Trigger; + flash_wait_ready(); + flash_wait_buf_empty(); + } +} + +static void RAMFUNCTION flash_write_enable(int enable) +{ + uint32_t cfg = RRAMC_CONFIG; + if (enable != 0) + cfg |= RRAMC_CONFIG_WEN_Msk; + else + cfg &= ~RRAMC_CONFIG_WEN_Msk; + RRAMC_CONFIG = cfg; + flash_wait_ready(); +} + +static int RAMFUNCTION flash_program_range(uint32_t address, + const uint8_t *data, int len) +{ + int i = 0; + + while (i < len) { + flash_wait_ready_next(); + + if ((((address + i) & 0x3U) == 0U) && + ((((uintptr_t)(data + i)) & 0x3U) == 0U) && + (len - i) >= 4) { + const uint32_t *src = (const uint32_t *)(data + i); + volatile uint32_t *dst = (volatile uint32_t *)(address + i); + *dst = *src; + i += 4; + } + else { + uint32_t word; + volatile uint32_t *dst = + (volatile uint32_t *)((address + i) & ~0x3U); + int offset = (int)((address + i) & 0x3U); + + word = *dst; + ((uint8_t *)&word)[offset] = data[i]; + *dst = word; + i++; + } + } + + return 0; +} + +int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len) +{ + flash_write_enable(1); + flash_program_range(address, data, len); + flash_commit_writebuf(); + flash_write_enable(0); + return 0; +} + +int RAMFUNCTION hal_flash_erase(uint32_t address, int len) +{ + uint32_t end = address + (uint32_t)len; + uint8_t blank[64]; + + memset(blank, 0xFF, sizeof(blank)); + + flash_write_enable(1); + while (address < end) { + int chunk = (int)(end - address); + if (chunk > (int)sizeof(blank)) + chunk = (int)sizeof(blank); + flash_program_range(address, blank, chunk); + address += (uint32_t)chunk; + } + flash_commit_writebuf(); + flash_write_enable(0); + return 0; +} + +void RAMFUNCTION hal_flash_unlock(void) +{ + flash_write_enable(1); +} + +void RAMFUNCTION hal_flash_lock(void) +{ + flash_write_enable(0); +} + +#if (UART_FLASH) +int uart_tx(const uint8_t c) +{ + + uart_write((const char *)&c, 1); + return 0; +} + +int uart_rx(uint8_t *c) +{ + return uart_read(DEVICE_DOWNLOAD, c, 1); +} + +int uart_init(uint32_t bitrate, uint8_t data, char parity, uint8_t stop) +{ + uart_init_device(DEVICE_DOWNLOAD, bitrate, data, parity, stop); + return 0; +} +#else +/* NOTE: this is defined differently when UART_FLASH is not defined */ +void uart_init(void) +{ + uart_init_device(DEVICE_DOWNLOAD, 115200, 8, 'N', 1); +} +#endif + +static uintptr_t ext_flash_addr_calc(uintptr_t address) +{ + /* offset external flash addresses by the update partition address */ + address -= WOLFBOOT_PARTITION_UPDATE_ADDRESS; + return address; +} + +int ext_flash_write(uintptr_t address, const uint8_t *data, int len) +{ +#ifdef DEBUG_FLASH + uintptr_t addr = ext_flash_addr_calc(address); + wolfBoot_printf("Ext Write: Len %d, Addr 0x%x (off 0x%x) -> 0x%x\n", + len, address, addr, data); +#endif + return 0; +} + +int ext_flash_read(uintptr_t address, uint8_t *data, int len) +{ +#ifdef DEBUG_FLASH + uintptr_t addr = ext_flash_addr_calc(address); + wolfBoot_printf("Ext Read: Len %d, Addr 0x%x (off 0x%x) -> %p\n", + len, address, addr, data); +#endif + memset(data, FLASH_BYTE_ERASED, len); + return len; +} + +int ext_flash_erase(uintptr_t address, int len) +{ +#ifdef DEBUG_FLASH + uintptr_t addr = ext_flash_addr_calc(address); + wolfBoot_printf("Ext Erase: Len %d, Addr 0x%x (off 0x%x)\n", + len, address, addr); +#endif + return 0; +} + +void ext_flash_lock(void) +{ + /* no op */ +} + +void ext_flash_unlock(void) +{ + /* no op */ +} + +static void high_freq_clock_init(void) +{ + /* Start the HFXO and wait until it is running */ + CLOCK_EVENTS_XOSTARTED = 0; + CLOCK_TASKS_XOSTART = CLOCK_TASKS_XOSTART_TASKS_XOSTART_Trigger; + + while ((CLOCK_EVENTS_XOSTARTED == 0) || + ((CLOCK_XO_STAT & CLOCK_XO_STAT_STATE_Msk) == + (CLOCK_XO_STAT_STATE_NotRunning << CLOCK_XO_STAT_STATE_Pos))) { + /* wait */ + } +} + +static void low_freq_clock_init(void) +{ + /* Configure the 32.768 kHz crystal load caps using factory trim when present */ + uint32_t intcap = OSCILLATORS_XOSC32KI_INTCAP_ResetValue & + OSCILLATORS_XOSC32KI_INTCAP_VAL_Msk; + + if (FICR_XOSC32KTRIM != FICR_XOSC32KTRIM_ResetValue) { + uint32_t trim = (FICR_XOSC32KTRIM & FICR_XOSC32KTRIM_OFFSET_Msk) >> + FICR_XOSC32KTRIM_OFFSET_Pos; + intcap = trim & (OSCILLATORS_XOSC32KI_INTCAP_VAL_Msk >> + OSCILLATORS_XOSC32KI_INTCAP_VAL_Pos); + } + + OSCILLATORS_XOSC32KI_INTCAP = + (intcap << OSCILLATORS_XOSC32KI_INTCAP_VAL_Pos) & + OSCILLATORS_XOSC32KI_INTCAP_VAL_Msk; + + /* Start the LFCLK from the external LFXO and wait until it is running */ + CLOCK_EVENTS_LFCLKSTARTED = 0; + CLOCK_LFCLK_SRC = CLOCK_LFCLK_SRC_SRC_LFXO; + CLOCK_TASKS_LFCLKSTART = CLOCK_TASKS_LFCLKSTART_TASKS_LFCLKSTART_Trigger; + + while ((CLOCK_EVENTS_LFCLKSTARTED == 0) || + ((CLOCK_LFCLK_STAT & CLOCK_LFCLK_STAT_SRC_Msk) != + (CLOCK_LFCLK_STAT_SRC_LFXO << CLOCK_LFCLK_STAT_SRC_Pos)) || + ((CLOCK_LFCLK_STAT & CLOCK_LFCLK_STAT_STATE_Msk) == + (CLOCK_LFCLK_STAT_STATE_NotRunning << CLOCK_LFCLK_STAT_STATE_Pos))) { + /* wait */ + } +} + +static void clock_init(void) +{ + high_freq_clock_init(); + low_freq_clock_init(); +} + +static void clock_deinit(void) +{ +} + +static void grtc_counter_init(void) +{ + static bool grtc_started; + if (!grtc_started) { + GRTC_MODE |= (GRTC_MODE_AUTOEN_Msk | GRTC_MODE_SYSCOUNTEREN_Msk); + GRTC_TASKS_START = GRTC_TASKS_START_TASKS_START_Trigger; + GRTC_SYSCOUNTER_ACTIVE(0) = GRTC_SYSCOUNTER_ACTIVE_ACTIVE_Active; + while ((GRTC_STATUS_LFTIMER & GRTC_STATUS_LFTIMER_READY_Msk) == 0U) + ; + grtc_started = true; + } +} + +static uint64_t grtc_counter_read_us(void) +{ + const uint32_t idx = 0U; + uint32_t high1, high2, low; + + while (1) { + high1 = (GRTC_SYSCOUNTERH(idx) & GRTC_SYSCOUNTER_SYSCOUNTERH_VALUE_Msk) >> + GRTC_SYSCOUNTER_SYSCOUNTERH_VALUE_Pos; + low = GRTC_SYSCOUNTERL(idx); + high2 = (GRTC_SYSCOUNTERH(idx) & GRTC_SYSCOUNTER_SYSCOUNTERH_VALUE_Msk) >> + GRTC_SYSCOUNTER_SYSCOUNTERH_VALUE_Pos; + if (high1 == high2) + break; + } + + return (((uint64_t)high2 << 32) | (uint64_t)low); +} + +void sleep_us(uint32_t usec) +{ + if (usec == 0U) + return; + + uint64_t start = grtc_counter_read_us(); + while (1) { + uint64_t now = grtc_counter_read_us(); + if (((now - start) & GRTC_COUNTER_MASK) >= (uint64_t)usec) + break; + } +} + +void sleep_ms(uint32_t msec) +{ + sleep_us(msec * 1000); +} + +void hal_monitor(void) +{ +#if (USE_MONITOR) + monitor_loop(); +#endif +} + +void hal_init(void) +{ +#ifdef DEBUG_UART + const char* bootStr = "wolfBoot HAL Init\n"; +#endif + + clock_init(); + grtc_counter_init(); + +#if USE_PMIC_LED + if (!npm1300_configure_led_power()) + pmic_led_power_control(true); +#endif + +#ifdef DEBUG_UART + uart_init_device(DEVICE_MONITOR, 115200, 8, 'N', 1); + uart_write(bootStr, strlen(bootStr)); +#endif +} + +/* enable write protection for the region of flash specified */ +static int hal_flash_protect(uint32_t start, uint32_t len) +{ + return 0; +} + +void hal_prepare_boot(void) +{ + /* Write protect bootloader region of flash */ + hal_flash_protect(WOLFBOOT_ORIGIN, BOOTLOADER_PARTITION_SIZE); + + clock_deinit(); +} + +#endif /* TARGET_nrf54lm20 */ diff --git a/hal/nrf54lm20.h b/hal/nrf54lm20.h new file mode 100644 index 0000000000..d3a7b90354 --- /dev/null +++ b/hal/nrf54lm20.h @@ -0,0 +1,560 @@ +/* nrf54lm20.h + * + * Copyright (C) 2025 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 _HAL_NRF54LM20_H_ +#define _HAL_NRF54LM20_H_ + +#include +#include +#include + +#if (SUPPORT_DEV_BOARD) +#define USE_PMIC_LED 1 +#define USE_MONITOR 1 +#endif + +#if (USE_MONITOR) +extern void monitor_loop(void); +extern void monitor_write(const char* s); +extern void monitor_write_uint(uint32_t value); +extern void uart_write_raw(int device, const char* c, unsigned int sz); +#endif + +#if (USE_PMIC_LED) +extern void pmic_led_power_control(bool enable); +extern int npm1300_configure_led_power(void); +extern void board_status_led_blink(int numLoops); +#endif + +void uart_write_device(int device, const char* buf, unsigned int sz); + +extern void sleep_ms(uint32_t msec); + +// NO! #define NRF_TRUSTZONE_NONSECURE + +/* + * The nRF54LM20 memory map is not upstream in wolfBoot yet. + * The defaults below follow the dev-kit documentation and match the + * assumptions captured in docs/Targets.md. They can be overridden from + * the build system by defining the corresponding symbols. + */ +#ifndef CPU_CLOCK +#define CPU_CLOCK 160000000UL /* 160MHz default HFXO */ +#endif + +#ifndef FLASH_BASE_ADDR +#define FLASH_BASE_ADDR (0x00000000UL) +#endif +#ifndef FLASH_SIZE +#define FLASH_SIZE (2UL * 1024UL * 1024UL) /* 2MB on the DK */ +#endif +#ifndef FLASH_PAGE_SIZE +#define FLASH_PAGE_SIZE (0x1000UL) /* 4KB granularity */ +#endif +#define FLASH_END (FLASH_BASE_ADDR + FLASH_SIZE) + +/* Assembly helpers */ +#define DMB() __asm__ volatile ("dmb") +#define DSB() __asm__ volatile ("dsb") +#define ISB() __asm__ volatile ("isb") +#define NOP() __asm__ volatile ("nop") + +/* PSEL Port (bit 5) - used across UART/SPI GPIO muxing */ +#define PSEL_PORT(n) (((n) & 0x7) << 5) + + +#ifdef NRF_TRUSTZONE_NONSECURE + #define CLOCK_BASE_DEFAULT (0x4010E000UL) + #define OSCILLATORS_BASE_DEFAULT (0x40120000UL) +#else + #define CLOCK_BASE_DEFAULT (0x5010E000UL) + #define OSCILLATORS_BASE_DEFAULT (0x50120000UL) +#endif + +#define CLOCK_BASE CLOCK_BASE_DEFAULT +#define OSCILLATORS_BASE OSCILLATORS_BASE_DEFAULT +#define FICR_BASE (0x00FFC000UL) + +/* Clock control registers */ +#define CLOCK_TASKS_XOSTART *((volatile uint32_t *)(CLOCK_BASE + 0x000)) +#define CLOCK_TASKS_LFCLKSTART *((volatile uint32_t *)(CLOCK_BASE + 0x010)) +#define CLOCK_EVENTS_XOSTARTED *((volatile uint32_t *)(CLOCK_BASE + 0x100)) +#define CLOCK_EVENTS_LFCLKSTARTED *((volatile uint32_t *)(CLOCK_BASE + 0x108)) +#define CLOCK_XO_STAT *((volatile uint32_t *)(CLOCK_BASE + 0x40C)) +#define CLOCK_LFCLK_SRC *((volatile uint32_t *)(CLOCK_BASE + 0x440)) +#define CLOCK_LFCLK_STAT *((volatile uint32_t *)(CLOCK_BASE + 0x44C)) + +#define CLOCK_TASKS_XOSTART_TASKS_XOSTART_Trigger 0x1UL +#define CLOCK_TASKS_LFCLKSTART_TASKS_LFCLKSTART_Trigger 0x1UL + +#define CLOCK_XO_STAT_STATE_Pos 16UL +#define CLOCK_XO_STAT_STATE_Msk (0x1UL << CLOCK_XO_STAT_STATE_Pos) +#define CLOCK_XO_STAT_STATE_NotRunning 0x0UL +#define CLOCK_XO_STAT_STATE_Running 0x1UL + +#define CLOCK_LFCLK_SRC_SRC_Pos 0UL +#define CLOCK_LFCLK_SRC_SRC_Msk (0x3UL << CLOCK_LFCLK_SRC_SRC_Pos) +#define CLOCK_LFCLK_SRC_SRC_LFRC 0x0UL +#define CLOCK_LFCLK_SRC_SRC_LFXO 0x1UL +#define CLOCK_LFCLK_SRC_SRC_LFSYNT 0x2UL + +#define CLOCK_LFCLK_STAT_SRC_Pos 0UL +#define CLOCK_LFCLK_STAT_SRC_Msk (0x3UL << CLOCK_LFCLK_STAT_SRC_Pos) +#define CLOCK_LFCLK_STAT_SRC_LFRC 0x0UL +#define CLOCK_LFCLK_STAT_SRC_LFXO 0x1UL +#define CLOCK_LFCLK_STAT_SRC_LFSYNT 0x2UL + +#define CLOCK_LFCLK_STAT_STATE_Pos 16UL +#define CLOCK_LFCLK_STAT_STATE_Msk (0x1UL << CLOCK_LFCLK_STAT_STATE_Pos) +#define CLOCK_LFCLK_STAT_STATE_NotRunning 0x0UL +#define CLOCK_LFCLK_STAT_STATE_Running 0x1UL + +/* LFCLK source and oscillator trims */ +#define OSCILLATORS_XOSC32KI_INTCAP *((volatile uint32_t *)(OSCILLATORS_BASE + 0x904)) +#define OSCILLATORS_XOSC32KI_INTCAP_ResetValue 0x00000017UL +#define OSCILLATORS_XOSC32KI_INTCAP_VAL_Pos 0UL +#define OSCILLATORS_XOSC32KI_INTCAP_VAL_Msk (0x1FUL << OSCILLATORS_XOSC32KI_INTCAP_VAL_Pos) + +#define FICR_XOSC32KTRIM *((volatile uint32_t *)(FICR_BASE + 0x624)) +#define FICR_XOSC32KTRIM_ResetValue 0xFFFFFFFFUL +#define FICR_XOSC32KTRIM_OFFSET_Pos 16UL +#define FICR_XOSC32KTRIM_OFFSET_Msk (0x3FFUL << FICR_XOSC32KTRIM_OFFSET_Pos) + +/* RRAM controller */ +#define RRAMC_BASE_DEFAULT (0x5004E000UL) +#define RRAMC_BASE RRAMC_BASE_DEFAULT + +#define RRAMC_TASKS_COMMITWRITEBUF *((volatile uint32_t *)(RRAMC_BASE + 0x008)) +#define RRAMC_READY *((volatile uint32_t *)(RRAMC_BASE + 0x400)) +#define RRAMC_READYNEXT *((volatile uint32_t *)(RRAMC_BASE + 0x404)) +#define RRAMC_BUFSTATUS_WRITEBUFEMPTY *((volatile uint32_t *)(RRAMC_BASE + 0x418)) +#define RRAMC_CONFIG *((volatile uint32_t *)(RRAMC_BASE + 0x500)) + +#define RRAMC_TASKS_COMMITWRITEBUF_TASKS_COMMITWRITEBUF_Trigger 0x1UL + +#define RRAMC_READY_READY_Pos 0UL +#define RRAMC_READY_READY_Msk (0x1UL << RRAMC_READY_READY_Pos) + +#define RRAMC_READYNEXT_READYNEXT_Pos 0UL +#define RRAMC_READYNEXT_READYNEXT_Msk (0x1UL << RRAMC_READYNEXT_READYNEXT_Pos) + +#define RRAMC_BUFSTATUS_WRITEBUFEMPTY_EMPTY_Pos 0UL +#define RRAMC_BUFSTATUS_WRITEBUFEMPTY_EMPTY_Msk \ + (0x1UL << RRAMC_BUFSTATUS_WRITEBUFEMPTY_EMPTY_Pos) + +#define RRAMC_CONFIG_WEN_Pos 0UL +#define RRAMC_CONFIG_WEN_Msk (0x1UL << RRAMC_CONFIG_WEN_Pos) + +/* TWIM used for PMIC access */ +#ifdef NRF_TRUSTZONE_NONSECURE + #define TWIM20_BASE_DEFAULT (0x400C6000UL) +#else + #define TWIM20_BASE_DEFAULT (0x500C6000UL) +#endif + +#define PMIC_TWIM_BASE TWIM20_BASE_DEFAULT + +#define TWIM_TASKS_STOP(base) (*((volatile uint32_t *)((base) + 0x004))) +#define TWIM_TASKS_DMA_RX_START(base) (*((volatile uint32_t *)((base) + 0x028))) +#define TWIM_TASKS_DMA_TX_START(base) (*((volatile uint32_t *)((base) + 0x050))) +#define TWIM_EVENTS_STOPPED(base) (*((volatile uint32_t *)((base) + 0x104))) +#define TWIM_EVENTS_ERROR(base) (*((volatile uint32_t *)((base) + 0x114))) +#define TWIM_EVENTS_LASTRX(base) (*((volatile uint32_t *)((base) + 0x134))) +#define TWIM_EVENTS_LASTTX(base) (*((volatile uint32_t *)((base) + 0x138))) +#define TWIM_EVENTS_DMA_RX_END(base) (*((volatile uint32_t *)((base) + 0x14C))) +#define TWIM_EVENTS_DMA_TX_END(base) (*((volatile uint32_t *)((base) + 0x168))) +#define TWIM_SHORTS_REG(base) (*((volatile uint32_t *)((base) + 0x200))) +#define TWIM_ERRORSRC_REG(base) (*((volatile uint32_t *)((base) + 0x4C4))) +#define TWIM_ENABLE_REG(base) (*((volatile uint32_t *)((base) + 0x500))) +#define TWIM_FREQUENCY_REG(base) (*((volatile uint32_t *)((base) + 0x524))) +#define TWIM_ADDRESS_REG(base) (*((volatile uint32_t *)((base) + 0x588))) +#define TWIM_PSEL_SCL_REG(base) (*((volatile uint32_t *)((base) + 0x600))) +#define TWIM_PSEL_SDA_REG(base) (*((volatile uint32_t *)((base) + 0x604))) +#define TWIM_DMA_RX_PTR(base) (*((volatile uint32_t *)((base) + 0x704))) +#define TWIM_DMA_RX_MAXCNT(base) (*((volatile uint32_t *)((base) + 0x708))) +#define TWIM_DMA_RX_TERMINATE(base) (*((volatile uint32_t *)((base) + 0x71C))) +#define TWIM_DMA_TX_PTR(base) (*((volatile uint32_t *)((base) + 0x73C))) +#define TWIM_DMA_TX_MAXCNT(base) (*((volatile uint32_t *)((base) + 0x740))) +#define TWIM_DMA_TX_TERMINATE(base) (*((volatile uint32_t *)((base) + 0x754))) + +#define TWIM_TASKS_STOP_TASKS_STOP_Trigger 0x1UL +#define TWIM_TASKS_DMA_RX_START_START_Trigger 0x1UL +#define TWIM_TASKS_DMA_TX_START_START_Trigger 0x1UL +#define TWIM_ENABLE_ENABLE_Disabled 0x0UL +#define TWIM_ENABLE_ENABLE_Enabled 0x6UL +#define TWIM_FREQUENCY_FREQUENCY_K100 0x01980000UL +#define TWIM_DMA_RX_TERMINATEONBUSERROR_ENABLE_Enabled 0x1UL +#define TWIM_DMA_TX_TERMINATEONBUSERROR_ENABLE_Enabled 0x1UL +#define TWIM_SHORTS_LASTTX_DMA_RX_START_Msk (0x1UL << 7) +#define TWIM_SHORTS_LASTTX_STOP_Msk (0x1UL << 9) +#define TWIM_SHORTS_LASTRX_STOP_Msk (0x1UL << 12) + +/* Global RTC (GRTC) */ +#ifdef NRF_TRUSTZONE_NONSECURE + #define GRTC_BASE_DEFAULT (0x400E2000UL) +#else + #define GRTC_BASE_DEFAULT (0x500E2000UL) +#endif +#define GRTC_BASE GRTC_BASE_DEFAULT +#define GRTC_TASKS_CAPTURE(n) (*((volatile uint32_t *)(GRTC_BASE + 0x000 + ((n) * 0x4)))) +#define GRTC_TASKS_START (*((volatile uint32_t *)(GRTC_BASE + 0x060))) +#define GRTC_TASKS_STOP (*((volatile uint32_t *)(GRTC_BASE + 0x064))) +#define GRTC_TASKS_CLEAR (*((volatile uint32_t *)(GRTC_BASE + 0x068))) +#define GRTC_EVENTS_COMPARE(n) (*((volatile uint32_t *)(GRTC_BASE + 0x100 + ((n) * 0x4)))) +#define GRTC_CC_CCL(n) (*((volatile uint32_t *)(GRTC_BASE + 0x520 + ((n) * 0x10)))) +#define GRTC_CC_CCH(n) (*((volatile uint32_t *)(GRTC_BASE + 0x524 + ((n) * 0x10)))) +#define GRTC_CC_CCADD(n) (*((volatile uint32_t *)(GRTC_BASE + 0x528 + ((n) * 0x10)))) +#define GRTC_CC_CCEN(n) (*((volatile uint32_t *)(GRTC_BASE + 0x52C + ((n) * 0x10)))) +#define GRTC_EVTEN (*((volatile uint32_t *)(GRTC_BASE + 0x400))) +#define GRTC_EVTENSET (*((volatile uint32_t *)(GRTC_BASE + 0x404))) +#define GRTC_EVTENCLR (*((volatile uint32_t *)(GRTC_BASE + 0x408))) +#define GRTC_SYSCOUNTERL(n) (*((volatile uint32_t *)(GRTC_BASE + 0x720 + ((n) * 0x10)))) +#define GRTC_SYSCOUNTERH(n) (*((volatile uint32_t *)(GRTC_BASE + 0x724 + ((n) * 0x10)))) +#define GRTC_SYSCOUNTER_ACTIVE(n) (*((volatile uint32_t *)(GRTC_BASE + 0x728 + ((n) * 0x10)))) +#define GRTC_STATUS_LFTIMER (*((volatile uint32_t *)(GRTC_BASE + 0x6B0))) +#define GRTC_MODE (*((volatile uint32_t *)(GRTC_BASE + 0x510))) + +#define GRTC_EVTEN_COMPARE_Msk(idx) (1UL << (idx)) + +#define GRTC_TASKS_START_TASKS_START_Trigger 0x1UL +#define GRTC_TASKS_CAPTURE_TASKS_CAPTURE_Trigger 0x1UL +#define GRTC_CC_CCADD_VALUE_Pos 0UL +#define GRTC_CC_CCADD_VALUE_Msk (0x7FFFFFFFUL << GRTC_CC_CCADD_VALUE_Pos) +#define GRTC_CC_CCADD_REFERENCE_Pos 31UL +#define GRTC_CC_CCADD_REFERENCE_CC (0x1UL << GRTC_CC_CCADD_REFERENCE_Pos) +#define GRTC_CC_CCEN_ACTIVE_Pos 0UL +#define GRTC_CC_CCEN_ACTIVE_Msk (0x1UL << GRTC_CC_CCEN_ACTIVE_Pos) +#define GRTC_CC_CCEN_ACTIVE_Enable (0x1UL << GRTC_CC_CCEN_ACTIVE_Pos) +#define GRTC_CC_CCH_CCH_Pos 0UL +#define GRTC_CC_CCH_CCH_Msk (0xFFFFFUL << GRTC_CC_CCH_CCH_Pos) +#define GRTC_SYSCOUNTER_SYSCOUNTERH_VALUE_Pos 0UL +#define GRTC_SYSCOUNTER_SYSCOUNTERH_VALUE_Msk (0xFFFFFUL << GRTC_SYSCOUNTER_SYSCOUNTERH_VALUE_Pos) +#define GRTC_SYSCOUNTER_ACTIVE_ACTIVE_Pos 0UL +#define GRTC_SYSCOUNTER_ACTIVE_ACTIVE_Msk (0x1UL << GRTC_SYSCOUNTER_ACTIVE_ACTIVE_Pos) +#define GRTC_SYSCOUNTER_ACTIVE_ACTIVE_Active (0x1UL << GRTC_SYSCOUNTER_ACTIVE_ACTIVE_Pos) +#define GRTC_STATUS_LFTIMER_READY_Pos 0UL +#define GRTC_STATUS_LFTIMER_READY_Msk (0x1UL << GRTC_STATUS_LFTIMER_READY_Pos) +#define GRTC_MODE_AUTOEN_Pos 0UL +#define GRTC_MODE_AUTOEN_Msk (0x1UL << GRTC_MODE_AUTOEN_Pos) +#define GRTC_MODE_SYSCOUNTEREN_Pos 1UL +#define GRTC_MODE_SYSCOUNTEREN_Msk (0x1UL << GRTC_MODE_SYSCOUNTEREN_Pos) +#define GRTC_COUNTER_MASK ((1ULL << 52) - 1ULL) + +/* GPIO */ +#ifdef NRF_TRUSTZONE_NONSECURE + #define GPIO_P0_NS_BASE (0x4010A000UL) + #define GPIO_P1_NS_BASE (0x400D8200UL) + #define GPIO_P2_NS_BASE (0x40050400UL) + #define GPIO_P3_NS_BASE (0x400D8600UL) +#else + #define GPIO_P0_S_BASE (0x5010A000UL) + #define GPIO_P1_S_BASE (0x500D8200UL) + #define GPIO_P2_S_BASE (0x50050400UL) + #define GPIO_P3_S_BASE (0x500D8600UL) +#endif + +/* GPIO configuration */ +#ifdef NRF_TRUSTZONE_NONSECURE + #define GPIO_PORT0_BASE_DEFAULT GPIO_P0_NS_BASE + #define GPIO_PORT1_BASE_DEFAULT GPIO_P1_NS_BASE + #define GPIO_PORT2_BASE_DEFAULT GPIO_P2_NS_BASE + #define GPIO_PORT3_BASE_DEFAULT GPIO_P3_NS_BASE +#else + #define GPIO_PORT0_BASE_DEFAULT GPIO_P0_S_BASE + #define GPIO_PORT1_BASE_DEFAULT GPIO_P1_S_BASE + #define GPIO_PORT2_BASE_DEFAULT GPIO_P2_S_BASE + #define GPIO_PORT3_BASE_DEFAULT GPIO_P3_S_BASE +#endif + +#define GPIO0_BASE GPIO_PORT0_BASE_DEFAULT +#define GPIO1_BASE GPIO_PORT1_BASE_DEFAULT +#define GPIO2_BASE GPIO_PORT2_BASE_DEFAULT +#define GPIO3_BASE GPIO_PORT3_BASE_DEFAULT + +static inline uintptr_t hal_gpio_port_base(unsigned int port) +{ + switch (port) { + case 0: + return (uintptr_t)GPIO0_BASE; + case 1: + return (uintptr_t)GPIO1_BASE; + case 2: + return (uintptr_t)GPIO2_BASE; + case 3: + return (uintptr_t)GPIO3_BASE; + default: + return (uintptr_t)GPIO0_BASE; + } +} + +#define GPIO_BASE(n) hal_gpio_port_base((unsigned int)(n)) +#define GPIO_OUT(n) *((volatile uint32_t *)(GPIO_BASE(n) + 0x000)) +#define GPIO_OUTSET(n) *((volatile uint32_t *)(GPIO_BASE(n) + 0x004)) +#define GPIO_OUTCLR(n) *((volatile uint32_t *)(GPIO_BASE(n) + 0x008)) +#define GPIO_DIRSET(n) *((volatile uint32_t *)(GPIO_BASE(n) + 0x014)) +#define GPIO_DIRCLR(n) *((volatile uint32_t *)(GPIO_BASE(n) + 0x018)) +#define GPIO_PIN_CNF(n, p) *((volatile uint32_t *)(GPIO_BASE(n) + 0x080 + ((p) * 0x4))) + +#define GPIO_CNF_IN 0 // input +#define GPIO_CNF_OUT 1 // output +#define GPIO_CNF_IN_DIS 2 // input, disconnect input buffer +#define GPIO_CNF_OUT_DIS 3 // output, disconnect input buffer +#define GPIO_CNF_PULL_DIS 0 +#define GPIO_CNF_PULL_UP (3UL << 2) +#define GPIO_CNF_PULL_DOWN (1UL << 2) +#define GPIO_CNF_STD_DRIVE_0 0 +#define GPIO_CNF_HIGH_DRIVE_0 (1UL << 8) // High drive +#define GPIO_CNF_EXTRA_HIGH_DRIVE_0 (3UL << 8) // Extra-High drive +#define GPIO_CNF_STD_DRIVE_1 0 +#define GPIO_CNF_HIGH_DRIVE_1 (1UL << 10) // High drive +#define GPIO_CNF_EXTRA_HIGH_DRIVE_1 (3UL << 10) // Extra-High drive +#define GPIO_CNF_SENSE_NONE 0 +#define GPIO_CNF_MCUSEL(n) (((n) & 0x7) << 28) + + +/* UART */ + +// UART Device P0 P1 P2 P3 +// ----------------------------------- +// NRF_UARTE00 XX <-- has dedicated pins on P2 +// NRF_UARTE20 XX XX +// NRF_UARTE21 XX XX +// NRF_UARTE22 XX XX +// NRF_UARTE23 XX XX +// NRF_UARTE24 XX XX +// NRF_UARTE30 XX + +#define UARTE20_S_BASE 0x500C6000UL // monitor +#define UARTE30_S_BASE 0x50104000UL // download + +#define DEVICE_MONITOR 1 +#define DEVICE_DOWNLOAD 2 + +// setup for DK board +#define PORT_MONITOR 1 +#define PIN_TX_MONITOR 11 +#define PIN_RX_MONITOR 12 +#define BASE_ADDR_MONITOR UARTE20_S_BASE + +// setup for DK board +#define PORT_DOWNLOAD 0 +#define PIN_TX_DOWNLOAD 6 +#define PIN_RX_DOWNLOAD 7 +#define BASE_ADDR_DOWNLOAD UARTE30_S_BASE + +static inline uintptr_t hal_uart_port_base(int device) +{ + switch (device) { + case DEVICE_DOWNLOAD: + return (uintptr_t) BASE_ADDR_DOWNLOAD; + case DEVICE_MONITOR: + default: + return (uintptr_t) BASE_ADDR_MONITOR; + } +} + +static inline int hal_uart_port_num(int device) +{ + switch (device) { + case DEVICE_DOWNLOAD: + return (int) PORT_DOWNLOAD; + case DEVICE_MONITOR: + default: + return (int) PORT_MONITOR; + } +} + +static inline int hal_uart_pin_num_tx(int device) +{ + switch (device) { + case DEVICE_DOWNLOAD: + return (int) PIN_TX_DOWNLOAD; + case DEVICE_MONITOR: + default: + return (int) PIN_TX_MONITOR; + } +} + +static inline int hal_uart_pin_num_rx(int device) +{ + switch (device) { + case DEVICE_DOWNLOAD: + return (int) PIN_RX_DOWNLOAD; + case DEVICE_MONITOR: + default: + return (int) PIN_RX_MONITOR; + } +} + +/* UART Addressing */ +#define UART_PORT_NUM(n) hal_uart_port_num((unsigned int)(n)) +#define UART_PIN_NUM_TX(n) hal_uart_pin_num_tx((unsigned int)(n)) +#define UART_PIN_NUM_RX(n) hal_uart_pin_num_rx((unsigned int)(n)) +#define UART_BASE(n) hal_uart_port_base((unsigned int)(n)) + +#define UART_PSEL_TXD(n) *((volatile uint32_t *)(UART_BASE(n) + 0x604 + 0x000)) +#define UART_PSEL_CTS(n) *((volatile uint32_t *)(UART_BASE(n) + 0x604 + 0x004)) +#define UART_PSEL_RXD(n) *((volatile uint32_t *)(UART_BASE(n) + 0x604 + 0x008)) +#define UART_PSEL_RTS(n) *((volatile uint32_t *)(UART_BASE(n) + 0x604 + 0x00C)) +#define UART_ENABLE(n) *((volatile uint32_t *)(UART_BASE(n) + 0x500)) +#define UART_BAUDRATE(n) *((volatile uint32_t *)(UART_BASE(n) + 0x524)) +#define UART_CONFIG(n) *((volatile uint32_t *)(UART_BASE(n) + 0x56C)) + +#define UART_DMA_TX_PTR(n) *((volatile uint32_t *)(UART_BASE(n) + 0x700 + 0x038 + 0x004)) +#define UART_DMA_TX_MAXCNT(n) *((volatile uint32_t *)(UART_BASE(n) + 0x700 + 0x038 + 0x008)) + +#define UART_DMA_RX_PTR(n) *((volatile uint32_t *)(UART_BASE(n) + 0x700 + 0x000 + 0x004)) +#define UART_DMA_RX_MAXCNT(n) *((volatile uint32_t *)(UART_BASE(n) + 0x700 + 0x000 + 0x008)) +#define UART_DMA_RX_AMOUNT(n) *((volatile uint32_t *)(UART_BASE(n) + 0x700 + 0x000 + 0x00C)) + +#define UART_EVENTS_DMA_TX_END(n) *((volatile uint32_t *)(UART_BASE(n) + 0x14C + 0x01C + 0x000)) +#define UART_EVENTS_DMA_TX_BUSERROR(n) *((volatile uint32_t *)(UART_BASE(n) + 0x14C + 0x01C + 0x008)) +#define UART_EVENTS_DMA_RX_END(n) *((volatile uint32_t *)(UART_BASE(n) + 0x14C + 0x000 + 0x000)) +#define UART_EVENTS_DMA_RX_BUSERROR(n) *((volatile uint32_t *)(UART_BASE(n) + 0x14C + 0x000 + 0x008)) + +#define UART_TASKS_DMA_TX_START(n) *((volatile uint32_t *)(UART_BASE(n) + 0x028 + 0x028 + 0x000)) +#define UART_TASKS_DMA_TX_STOP(n) *((volatile uint32_t *)(UART_BASE(n) + 0x028 + 0x028 + 0x004)) + +#define UART_TASKS_DMA_RX_START(n) *((volatile uint32_t *)(UART_BASE(n) + 0x028 + 0x000 + 0x000)) +#define UART_TASKS_DMA_RX_STOP(n) *((volatile uint32_t *)(UART_BASE(n) + 0x028 + 0x000 + 0x004)) + +/* UART Settings */ +#define UART_ENABLE_ENABLE_Enabled 0x8UL +#define UART_ENABLE_ENABLE_Disabled 0x0UL + +#define UART_PSEL_TXD_PIN_Pos 0UL +#define UART_PSEL_TXD_PIN_Msk (0x1FUL << UART_PSEL_TXD_PIN_Pos) +#define UART_PSEL_TXD_PORT_Pos 5UL +#define UART_PSEL_TXD_PORT_Msk (0x7UL << UART_PSEL_TXD_PORT_Pos) + +#define UART_PSEL_RXD_PIN_Pos 0UL +#define UART_PSEL_RXD_PIN_Msk (0x1FUL << UART_PSEL_RXD_PIN_Pos) +#define UART_PSEL_RXD_PORT_Pos 0x5UL +#define UART_PSEL_RXD_PORT_Msk (0x7UL << UART_PSEL_RXD_PORT_Pos) + +#define UART_PSEL_CTS_CONNECT_Disconnected 0x1UL +#define UART_PSEL_RTS_CONNECT_Disconnected 0x1UL + +#define UART_TASKS_DMA_TX_START_START_Trigger 0x1UL +#define UART_TASKS_DMA_TX_STOP_STOP_Trigger 0x1UL + +#define UART_TASKS_DMA_RX_START_START_Trigger 0x1UL +#define UART_TASKS_DMA_RX_STOP_STOP_Trigger 0x1UL + +#define UART_BAUDRATE_BAUDRATE_Baud115200 0x01D60000UL + +#define BAUD_115200 UART_BAUDRATE_BAUDRATE_Baud115200 + +/* Nordic PMIC */ +#define PMIC_TWIM_PORT 1 +#define PMIC_TWIM_SDA_PIN 2 +#define PMIC_TWIM_SCL_PIN 3 +#define PMIC_TWIM_TIMEOUT 1000000UL +#define PMIC_REG_PAYLOAD_MAX 8U +#define PMIC_I2C_ADDRESS 0x6BU // from pdf p122 (110 1011) + +#define LED_PWR_CTRL_PORT 1 +#define LED_PWR_CTRL_PIN 13 + +#define NPM1300_REG_TASK_LDSW2_SET 0x0802U +#define NPM1300_REG_TASK_LDSW2_CLR 0x0803U +#define NPM1300_REG_LDSW2_GPISEL 0x0806U +#define NPM1300_REG_LDSWCONFIG 0x0807U +#define NPM1300_REG_LDSW2LDOSEL 0x0809U +#define NPM1300_REG_GPIOMODE(n) (0x0600U + (uint16_t)(n)) +#define NPM1300_REG_GPIOPUEN(n) (0x060AU + (uint16_t)(n)) +#define NPM1300_REG_GPIOPDEN(n) (0x060FU + (uint16_t)(n)) + +/* SPIM */ +#ifdef NRF_TRUSTZONE_NONSECURE + #define SPIM00_BASE_DEFAULT (0x4004D000UL) +#else + #define SPIM00_BASE_DEFAULT (0x5004D000UL) +#endif + +#define SPI_BASE SPIM00_BASE_DEFAULT + +#define SPI_TASKS_START (*((volatile uint32_t *)(SPI_BASE + 0x000))) +#define SPI_TASKS_STOP (*((volatile uint32_t *)(SPI_BASE + 0x004))) + +#define SPI_EVENTS_STARTED (*((volatile uint32_t *)(SPI_BASE + 0x100))) +#define SPI_EVENTS_STOPPED (*((volatile uint32_t *)(SPI_BASE + 0x104))) +#define SPI_EVENTS_END (*((volatile uint32_t *)(SPI_BASE + 0x108))) + +#define SPI_EVENTS_DMA_RX_END (*((volatile uint32_t *)(SPI_BASE + 0x14C + 0x000))) +#define SPI_EVENTS_DMA_RX_READY (*((volatile uint32_t *)(SPI_BASE + 0x14C + 0x004))) +#define SPI_EVENTS_DMA_RX_BUSERROR (*((volatile uint32_t *)(SPI_BASE + 0x14C + 0x008))) +#define SPI_EVENTS_DMA_TX_END (*((volatile uint32_t *)(SPI_BASE + 0x14C + 0x01C))) +#define SPI_EVENTS_DMA_TX_READY (*((volatile uint32_t *)(SPI_BASE + 0x14C + 0x020))) +#define SPI_EVENTS_DMA_TX_BUSERROR (*((volatile uint32_t *)(SPI_BASE + 0x14C + 0x024))) + +#define SPI_ENABLE_REG (*((volatile uint32_t *)(SPI_BASE + 0x500))) +#define SPI_PRESCALER_REG (*((volatile uint32_t *)(SPI_BASE + 0x52C))) +#define SPI_CONFIG_REG (*((volatile uint32_t *)(SPI_BASE + 0x554))) +#define SPI_IFTIMING_RXDELAY (*((volatile uint32_t *)(SPI_BASE + 0x5AC))) +#define SPI_IFTIMING_CSNDUR (*((volatile uint32_t *)(SPI_BASE + 0x5B0))) + +#define SPI_PSEL_SCK (*((volatile uint32_t *)(SPI_BASE + 0x600))) +#define SPI_PSEL_MOSI (*((volatile uint32_t *)(SPI_BASE + 0x604))) +#define SPI_PSEL_MISO (*((volatile uint32_t *)(SPI_BASE + 0x608))) +#define SPI_PSEL_CSN (*((volatile uint32_t *)(SPI_BASE + 0x610))) + +#define SPI_DMA_RX_PTR (*((volatile uint32_t *)(SPI_BASE + 0x704))) +#define SPI_DMA_RX_MAXCNT (*((volatile uint32_t *)(SPI_BASE + 0x708))) +#define SPI_DMA_RX_LIST (*((volatile uint32_t *)(SPI_BASE + 0x714))) + +#define SPI_DMA_TX_PTR (*((volatile uint32_t *)(SPI_BASE + 0x73C))) +#define SPI_DMA_TX_MAXCNT (*((volatile uint32_t *)(SPI_BASE + 0x740))) +#define SPI_DMA_TX_LIST (*((volatile uint32_t *)(SPI_BASE + 0x74C))) + +#define SPIM_TASKS_START_TASKS_START_Pos 0UL +#define SPIM_TASKS_START_TASKS_START_Msk \ + (0x1UL << SPIM_TASKS_START_TASKS_START_Pos) +#define SPIM_TASKS_START_TASKS_START_Trigger 0x1UL + +#define SPIM_TASKS_STOP_TASKS_STOP_Pos 0UL +#define SPIM_TASKS_STOP_TASKS_STOP_Msk \ + (0x1UL << SPIM_TASKS_STOP_TASKS_STOP_Pos) +#define SPIM_TASKS_STOP_TASKS_STOP_Trigger 0x1UL + +#define SPIM_ENABLE_ENABLE_Pos 0UL +#define SPIM_ENABLE_ENABLE_Msk (0xFUL << SPIM_ENABLE_ENABLE_Pos) +#define SPIM_ENABLE_ENABLE_Disabled 0x0UL +#define SPIM_ENABLE_ENABLE_Enabled 0x7UL + +#define SPIM_CONFIG_ORDER_Pos 0UL +#define SPIM_CONFIG_ORDER_Msk (0x1UL << SPIM_CONFIG_ORDER_Pos) +#define SPIM_CONFIG_ORDER_MsbFirst 0x0UL +#define SPIM_CONFIG_ORDER_LsbFirst 0x1UL + +#define SPIM_CONFIG_CPHA_Pos 1UL +#define SPIM_CONFIG_CPHA_Msk (0x1UL << SPIM_CONFIG_CPHA_Pos) +#define SPIM_CONFIG_CPHA_Leading 0x0UL +#define SPIM_CONFIG_CPHA_Trailing 0x1UL + +#define SPIM_CONFIG_CPOL_Pos 2UL +#define SPIM_CONFIG_CPOL_Msk (0x1UL << SPIM_CONFIG_CPOL_Pos) +#define SPIM_CONFIG_CPOL_ActiveHigh 0x0UL +#define SPIM_CONFIG_CPOL_ActiveLow 0x1UL + +#define SPI_PRESCALER_DIV 0x08UL + +#endif /* _HAL_NRF54LM20_H_ */ diff --git a/hal/nrf54lm20.ld b/hal/nrf54lm20.ld new file mode 100644 index 0000000000..d4af3f890e --- /dev/null +++ b/hal/nrf54lm20.ld @@ -0,0 +1,52 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = @ARCH_FLASH_OFFSET@, LENGTH = @BOOTLOADER_PARTITION_SIZE@ + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256K +} + +SECTIONS +{ + .text : + { + _start_text = .; + KEEP(*(.isr_vector)) + *(.boot*) + *(.text*) + *(.rodata*) + *(.init*) + *(.fini*) + . = ALIGN(4); + _end_text = .; + } > FLASH + + .edidx : + { + . = ALIGN(4); + *(.ARM.exidx*) + } > FLASH + + _stored_data = .; + + .data : AT (_stored_data) + { + _start_data = .; + KEEP(*(.data*)) + . = ALIGN(4); + _end_data = .; + } > RAM + + .bss (NOLOAD) : + { + _start_bss = .; + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + _end_bss = .; + __bss_end__ = .; + _end = .; + } > RAM + . = ALIGN(4); +} + +END_STACK = ORIGIN(RAM) + LENGTH(RAM); diff --git a/hal/nrf54lm20_dk.c b/hal/nrf54lm20_dk.c new file mode 100644 index 0000000000..7e1f085ca1 --- /dev/null +++ b/hal/nrf54lm20_dk.c @@ -0,0 +1,572 @@ +/* nrf54lm20_dk.c + * + * Copyright (C) 2025 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 + */ + +#ifdef TARGET_nrf54lm20 + +#include +#include +#include + +#include "hal.h" +#include "image.h" +#include "nrf54lm20.h" +#include "printf.h" +#include "wolfboot/wolfboot.h" + +#define FLASH_TEST_SECTOR WOLFBOOT_PARTITION_SWAP_ADDRESS +#define FLASH_TEST_SECTOR_SIZE FLASH_PAGE_SIZE + +#if USE_PMIC_LED +static bool pmic_led_power_ready; + +static void led_power_gpio_init(void) +{ + const uint32_t mask = (1U << LED_PWR_CTRL_PIN); + + GPIO_PIN_CNF(LED_PWR_CTRL_PORT, LED_PWR_CTRL_PIN) = + (GPIO_CNF_OUT | GPIO_CNF_STD_DRIVE_0); + GPIO_DIRSET(LED_PWR_CTRL_PORT) = mask; + GPIO_OUTCLR(LED_PWR_CTRL_PORT) = mask; +} + +static void led_power_gpio_set(bool enable) +{ + const uint32_t mask = (1U << LED_PWR_CTRL_PIN); + if (enable) + GPIO_OUTSET(LED_PWR_CTRL_PORT) = mask; + else + GPIO_OUTCLR(LED_PWR_CTRL_PORT) = mask; +} + +static void pmic_twi_init(void) +{ + static int initialized; + if (initialized) + return; + + const uintptr_t twim = PMIC_TWIM_BASE; + const uint32_t scl_mask = (1U << PMIC_TWIM_SCL_PIN); + const uint32_t sda_mask = (1U << PMIC_TWIM_SDA_PIN); + const uint32_t line_mask = scl_mask | sda_mask; + + GPIO_PIN_CNF(PMIC_TWIM_PORT, PMIC_TWIM_SCL_PIN) = + (GPIO_CNF_OUT | GPIO_CNF_STD_DRIVE_0 | GPIO_CNF_PULL_UP); + GPIO_PIN_CNF(PMIC_TWIM_PORT, PMIC_TWIM_SDA_PIN) = + (GPIO_CNF_OUT | GPIO_CNF_STD_DRIVE_0 | GPIO_CNF_PULL_UP); + GPIO_DIRSET(PMIC_TWIM_PORT) = line_mask; + GPIO_OUTSET(PMIC_TWIM_PORT) = line_mask; + + TWIM_ENABLE_REG(twim) = TWIM_ENABLE_ENABLE_Disabled; + TWIM_PSEL_SCL_REG(twim) = (PSEL_PORT(PMIC_TWIM_PORT) | PMIC_TWIM_SCL_PIN); + TWIM_PSEL_SDA_REG(twim) = (PSEL_PORT(PMIC_TWIM_PORT) | PMIC_TWIM_SDA_PIN); + TWIM_FREQUENCY_REG(twim) = TWIM_FREQUENCY_FREQUENCY_K100; + TWIM_ADDRESS_REG(twim) = PMIC_I2C_ADDRESS; + TWIM_DMA_RX_TERMINATE(twim) = TWIM_DMA_RX_TERMINATEONBUSERROR_ENABLE_Enabled; + TWIM_DMA_TX_TERMINATE(twim) = TWIM_DMA_TX_TERMINATEONBUSERROR_ENABLE_Enabled; + TWIM_ENABLE_REG(twim) = TWIM_ENABLE_ENABLE_Enabled; + + initialized = 1; +} + +static int pmic_twi_wait_stopped(void) +{ + const uintptr_t twim = PMIC_TWIM_BASE; + + for (uint32_t guard = 0; guard < PMIC_TWIM_TIMEOUT; guard++) { + if (TWIM_EVENTS_STOPPED(twim) != 0U) { + TWIM_EVENTS_STOPPED(twim) = 0; + TWIM_EVENTS_ERROR(twim) = 0; + return 0; + } + if (TWIM_EVENTS_ERROR(twim) != 0U) { + uint32_t err = TWIM_ERRORSRC_REG(twim); + TWIM_ERRORSRC_REG(twim) = err; + TWIM_EVENTS_ERROR(twim) = 0; + TWIM_TASKS_STOP(twim) = TWIM_TASKS_STOP_TASKS_STOP_Trigger; + return -1; + } + } + + TWIM_TASKS_STOP(twim) = TWIM_TASKS_STOP_TASKS_STOP_Trigger; + return -1; +} + +static int pmic_twi_xfer(const uint8_t* tx, size_t tx_len, + uint8_t* rx, size_t rx_len) +{ + const uintptr_t twim = PMIC_TWIM_BASE; + + if (((tx_len > 0U) && (tx == NULL)) || + ((rx_len > 0U) && (rx == NULL)) || + ((tx_len == 0U) && (rx_len == 0U))) + return -1; + + TWIM_EVENTS_STOPPED(twim) = 0; + TWIM_EVENTS_ERROR(twim) = 0; + TWIM_EVENTS_LASTTX(twim) = 0; + TWIM_EVENTS_LASTRX(twim) = 0; + TWIM_EVENTS_DMA_TX_END(twim) = 0; + TWIM_EVENTS_DMA_RX_END(twim) = 0; + TWIM_SHORTS_REG(twim) = 0; + + if (tx_len > 0U) { + TWIM_DMA_TX_PTR(twim) = (uint32_t)tx; + TWIM_DMA_TX_MAXCNT(twim) = (uint32_t)tx_len; + } + if (rx_len > 0U) { + TWIM_DMA_RX_PTR(twim) = (uint32_t)rx; + TWIM_DMA_RX_MAXCNT(twim) = (uint32_t)rx_len; + } + + if ((tx_len > 0U) && (rx_len > 0U)) { + TWIM_SHORTS_REG(twim) = (TWIM_SHORTS_LASTTX_DMA_RX_START_Msk | + TWIM_SHORTS_LASTRX_STOP_Msk); + TWIM_TASKS_DMA_TX_START(twim) = TWIM_TASKS_DMA_TX_START_START_Trigger; + } + else if (rx_len > 0U) { + TWIM_SHORTS_REG(twim) = TWIM_SHORTS_LASTRX_STOP_Msk; + TWIM_TASKS_DMA_RX_START(twim) = TWIM_TASKS_DMA_RX_START_START_Trigger; + } + else { + TWIM_SHORTS_REG(twim) = TWIM_SHORTS_LASTTX_STOP_Msk; + TWIM_TASKS_DMA_TX_START(twim) = TWIM_TASKS_DMA_TX_START_START_Trigger; + } + + if (pmic_twi_wait_stopped() != 0) { + TWIM_SHORTS_REG(twim) = 0; + return -1; + } + + TWIM_SHORTS_REG(twim) = 0; + return 0; +} + +static int npm1300_reg_write(uint16_t reg, const uint8_t* data, size_t len) +{ + uint8_t frame[2U + PMIC_REG_PAYLOAD_MAX]; + + if ((data == NULL) || (len == 0U) || (len > PMIC_REG_PAYLOAD_MAX)) + return -1; + + frame[0] = (uint8_t)((reg >> 8) & 0xFFU); + frame[1] = (uint8_t)(reg & 0xFFU); + memcpy(&frame[2], data, len); + return pmic_twi_xfer(frame, len + 2U, NULL, 0); +} + +static int npm1300_reg_write_u8(uint16_t reg, uint8_t value) +{ + return npm1300_reg_write(reg, &value, 1U); +} + +void pmic_led_power_control(bool enable) +{ + if (!pmic_led_power_ready) + return; + + led_power_gpio_set(enable); + if (enable) + (void)npm1300_reg_write_u8(NPM1300_REG_TASK_LDSW2_SET, 0x01); + else + (void)npm1300_reg_write_u8(NPM1300_REG_TASK_LDSW2_CLR, 0x01); +} + +int npm1300_configure_led_power(void) +{ + int ret; + + pmic_led_power_ready = false; + pmic_twi_init(); + led_power_gpio_init(); + + ret = npm1300_reg_write_u8(NPM1300_REG_LDSW2LDOSEL, 0x00); + if (ret != 0) + return ret; + + /* Soft-start load switch 2 at 50mA to drive the LED rail reliably */ + ret = npm1300_reg_write_u8(NPM1300_REG_LDSWCONFIG, (uint8_t)(3U << 4)); + if (ret != 0) + return ret; + + ret = npm1300_reg_write_u8(NPM1300_REG_GPIOMODE(1), 0x00); + if (ret != 0) + return ret; + + ret = npm1300_reg_write_u8(NPM1300_REG_GPIOPUEN(1), 0x00); + if (ret != 0) + return ret; + + ret = npm1300_reg_write_u8(NPM1300_REG_GPIOPDEN(1), 0x00); + if (ret != 0) + return ret; + + ret = npm1300_reg_write_u8(NPM1300_REG_LDSW2_GPISEL, 0x02); + if (ret != 0) + return ret; + + /* Ensure the LED rail starts in the OFF state. */ + (void)npm1300_reg_write_u8(NPM1300_REG_TASK_LDSW2_CLR, 0x01); + + pmic_led_power_ready = true; + return 0; +} + +static void get_led_port_pin(int lednum, int *port, int *pin) +{ + switch(lednum) + { + case 0: *port = 1; *pin = 22; break; + case 1: *port = 1; *pin = 25; break; + case 2: *port = 1; *pin = 27; break; + case 3: *port = 1; *pin = 28; break; + default: *port = 1; *pin = 22; break; + } +} + +void board_status_led_blink(int numLoops) +{ + int port, pin; + + const uint32_t toggle_delay_ms = 500U; + const int led_flash_loops = numLoops; + + // setup GPIOs + for(int i=0; i<4; i++) + { + get_led_port_pin(i, &port, &pin); + GPIO_PIN_CNF(port, pin) = (GPIO_CNF_OUT | GPIO_CNF_STD_DRIVE_0 | GPIO_CNF_STD_DRIVE_1); + GPIO_DIRSET(port) = 1U << pin; + GPIO_OUTCLR(port) = 1U << pin; + } + + for(int i=0; i 0) + { + if(bits >= 4) + bits -= 4; + output[nybble++] = hexascii[((value >> bits) & 0x0F)]; + } + output[nybble] = 0; +} + +int scan_decimal(char *str) +{ + int value = 0; + + while(*str != 0) + { + char ch = *str++; + value *= 10; + if(ch >= '0' && ch <= '9') + value += (uint32_t)(ch - '0'); + } + + return value; +} + +uint32_t scan_hexadecimal(char *str) +{ + uint32_t value = 0; + + while(*str != 0) + { + char ch = *str++; + value *= 16; + if(ch >= '0' && ch <= '9') + value += (uint32_t)(ch - '0'); + else if(ch >= 'a' && ch <= 'f') + value += (uint32_t)(ch - 'a' + 10); + else if(ch >= 'A' && ch <= 'F') + value += (uint32_t)(ch - 'A' + 10); + } + + return value; +} + +void flash_dump(uint32_t address, int length) +{ + uint32_t addr = address; + uint8_t byte = 0; + char buffer[10]; + char text[16+1]; + + monitor_write("\n"); + length = length % 16 == 0 ? length/16 : length/16+1; + length = length == 0 ? 16 : length; + for(int i=0; i= 32 && byte < 127) + text[j] = byte; + else + text[j] = '.'; + bits_to_hexascii(8, byte, buffer); + monitor_write(buffer); + monitor_write(" "); + ++addr; + } + text[16] = 0; + monitor_write(" : "); + monitor_write(text); + monitor_write("\n"); + } +} + +static const char test_data[] = "This is some test data. Can you read it?"; + +void flash_test(void) +{ + uint32_t address = FLASH_TEST_SECTOR; + + int rc = 0; + rc = hal_flash_erase(address, FLASH_TEST_SECTOR_SIZE); + rc = hal_flash_write(address, (const uint8_t *)test_data, sizeof(test_data)); + (void)rc; +} + +void flash_erase(void) +{ + uint32_t address = FLASH_TEST_SECTOR; + + int rc = hal_flash_erase(address, FLASH_TEST_SECTOR_SIZE); + (void)rc; +} + +void flash_show(void) +{ + uint32_t address = FLASH_TEST_SECTOR; + int length = 256; + + flash_dump(address, length); +} + +static int parse_command_line( char *cmdline, int *argc, char *argv[] ) +{ + char *cp; + int cnt; + + cnt = 0; + + cp = strtok( cmdline, " \t" ); + + do + { + if( cp ) + argv[cnt++] = cp; + else + break; + cp = strtok( NULL, " \t" ); + + } while( cnt < MAX_CLI_PARAMS ); + + *argc = cnt; + + return cnt; +} + +void monitor_write(const char* s) +{ + if (s != NULL) + uart_write(s, (unsigned int)strlen(s)); +} + +void monitor_write_uint(uint32_t value) +{ + char tmp[12]; + int pos = (int)sizeof(tmp) - 1; + tmp[pos--] = '\0'; + do { + tmp[pos--] = (char)('0' + (value % 10U)); + value /= 10U; + } while (value != 0U && pos >= 0); + monitor_write(&tmp[pos + 1]); +} + +static int argc; +static char *argv[MAX_CLI_PARAMS]; + +static int monitor_handle_command(char* line) +{ + if ((line == NULL) || (*line == '\0')) + return 0; + + parse_command_line( line, &argc, argv ); + char *cmd = argv[0]; + char *arg1 = argv[1]; + char *arg2 = argv[2]; + + if (strcmp(cmd, "help") == 0) { + monitor_write("\nCommands:\n"); + monitor_write(" help - show this message\n"); + monitor_write(" version - print current firmware version\n"); +#if USE_PMIC_LED + monitor_write(" led [count] - flash LEDs\n"); +#endif + monitor_write(" dump [len] - dump flash\n"); + monitor_write(" flash - flash commands:\n"); + monitor_write(" write - write test block to flash\n"); + monitor_write(" erase - erase test block in flash\n"); + monitor_write(" show - show test block in flash\n"); + + monitor_write(" reboot - restart the system\n"); + monitor_write(" exit - return to code that started the monitor\n"); + } + else if (strcmp(cmd, "flash") == 0) { + if(argc >= 2) { + if(strcmp(arg1, "write")==0) + flash_test(); + else if(strcmp(arg1, "erase")==0) + flash_erase(); + else if(strcmp(arg1, "show")==0) + flash_show(); + } + } + else if (strcmp(cmd, "dump") == 0) { + uint32_t addr = 0; + int len = 0; + if(argc >= 2) { + addr = scan_hexadecimal(arg1); + if(argc == 3) + len = scan_decimal(arg2); + flash_dump(addr, len); + } + } + else if (strcmp(cmd, "version") == 0) { + monitor_write("\nFirmware version: "); + monitor_write_uint(wolfBoot_current_firmware_version()); + monitor_write("\n"); + } + else if (strcmp(cmd, "reboot") == 0) { + monitor_write("\nRebooting...\n"); + arch_reboot(); + } +#if USE_PMIC_LED + else if (strcmp(cmd, "led") == 0) { + int count = 1; + if(argc == 2) { + count = scan_decimal(arg1); + } + monitor_write("\nLED test..."); + board_status_led_blink(count); + monitor_write("\n"); + } +#endif + else if (strcmp(cmd, "exit") == 0) { + monitor_write("\n"); + return 1; + } + else { + monitor_write("\nUnknown command. Type 'help'.\n"); + } + + return 0; +} + +void monitor_loop(void) +{ + static const char* prompt = "\nwolfBoot> "; + uint8_t ch; + uint8_t chBuf[2]; + char line[128]; + unsigned int idx = 0; + + chBuf[1] = 0; + + monitor_write("\nwolfBoot monitor ready. Type 'help' for commands.\n"); + + for (;;) { + monitor_write(prompt); + idx = 0; + memset(line, 0, sizeof(line)); + + while (1) { + int ret = uart_read(DEVICE_MONITOR, &ch, 1); + if (ret <= 0) + continue; + + // echo + chBuf[0] = ch; + monitor_write((const char *)chBuf); + + if ((ch == '\r') || (ch == '\n')) { + if(monitor_handle_command(line)) + return; // exit was requested + break; + } + else if ((ch == 0x08 || ch == 0x7F) && idx > 0) { + idx--; + line[idx] = '\0'; + if(ch == 0x08) { + monitor_write((const char *)" "); + chBuf[0] = ch; + monitor_write((const char *)chBuf); + } + } + else if ((ch >= 0x20) && (ch <= 0x7E)) { + if (idx < (sizeof(line) - 1U)) { + line[idx++] = (char)ch; + line[idx] = '\0'; + } + } + } + } +} +#endif /* USE_MONITOR */ + +#endif /* TARGET_nrf54lm20 */ diff --git a/hal/spi/spi_drv_nrf54lm20.c b/hal/spi/spi_drv_nrf54lm20.c new file mode 100644 index 0000000000..2f7271ea9c --- /dev/null +++ b/hal/spi/spi_drv_nrf54lm20.c @@ -0,0 +1,164 @@ +/* spi_drv_nrf54lm20.c + * + * Driver for the SPI back-end of the SPI_FLASH module. + * + * Pinout: see spi_drv_nrf54lm20.h + * + * Copyright (C) 2025 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 "spi_drv.h" + +#ifdef TARGET_nrf54lm20 + +#if defined(SPI_FLASH) || defined(WOLFBOOT_TPM) + +#include "hal/nrf54lm20.h" +#include "hal/spi/spi_drv_nrf54lm20.h" + +static uint8_t spi_tx_byte; +static volatile uint8_t spi_rx_byte; +static volatile uint8_t spi_rx_ready; + +static inline void spim_clear_events(void) +{ + SPI_EVENTS_STARTED = 0; + SPI_EVENTS_STOPPED = 0; + SPI_EVENTS_END = 0; + SPI_EVENTS_DMA_RX_END = 0; + SPI_EVENTS_DMA_RX_READY = 0; + SPI_EVENTS_DMA_RX_BUSERROR = 0; + SPI_EVENTS_DMA_TX_END = 0; + SPI_EVENTS_DMA_TX_READY = 0; + SPI_EVENTS_DMA_TX_BUSERROR = 0; +} + +void RAMFUNCTION spi_cs_off(uint32_t base, int pin) +{ + uint32_t mask = (1U << pin); + GPIO_OUTSET(base) = mask; +} + +void RAMFUNCTION spi_cs_on(uint32_t base, int pin) +{ + uint32_t mask = (1U << pin); + GPIO_OUTCLR(base) = mask; +} + +uint8_t RAMFUNCTION spi_read(void) +{ + while (!spi_rx_ready) + ; + spi_rx_ready = 0; + return spi_rx_byte; +} + +void RAMFUNCTION spi_write(const char byte) +{ + spi_tx_byte = (uint8_t)byte; + spi_rx_ready = 0; + + spim_clear_events(); + + SPI_DMA_RX_PTR = (uint32_t)&spi_rx_byte; + SPI_DMA_RX_MAXCNT = 1; + SPI_DMA_RX_LIST = 0; + + SPI_DMA_TX_PTR = (uint32_t)&spi_tx_byte; + SPI_DMA_TX_MAXCNT = 1; + SPI_DMA_TX_LIST = 0; + + SPI_TASKS_START = SPIM_TASKS_START_TASKS_START_Trigger; + while (SPI_EVENTS_END == 0) + ; + SPI_TASKS_STOP = SPIM_TASKS_STOP_TASKS_STOP_Trigger; + while (SPI_EVENTS_STOPPED == 0) + ; + SPI_EVENTS_STOPPED = 0; + spi_rx_ready = 1; +} + + +void spi_init(int polarity, int phase) +{ + static int initialized = 0; + if (!initialized) { + initialized++; + GPIO_PIN_CNF(SPI_CS_PORT, SPI_CS_PIN) = + (GPIO_CNF_OUT | GPIO_CNF_HIGH_DRIVE_0); + GPIO_PIN_CNF(SPI_SCK_PORT, SPI_SCK_PIN) = + (GPIO_CNF_OUT | GPIO_CNF_HIGH_DRIVE_0); + GPIO_PIN_CNF(SPI_MOSI_PORT, SPI_MOSI_PIN) = + (GPIO_CNF_OUT | GPIO_CNF_HIGH_DRIVE_0); + GPIO_PIN_CNF(SPI_MISO_PORT, SPI_MISO_PIN) = + (GPIO_CNF_IN | GPIO_CNF_PULL_UP); + + GPIO_OUTSET(SPI_CS_PORT) = (1 << SPI_CS_PIN); + GPIO_OUTCLR(SPI_SCK_PORT) = (1 << SPI_SCK_PIN); + GPIO_OUTCLR(SPI_MOSI_PORT) = (1 << SPI_MOSI_PIN); + + SPI_ENABLE_REG = SPIM_ENABLE_ENABLE_Disabled; + SPI_PSEL_MISO = (PSEL_PORT(SPI_MISO_PORT) | SPI_MISO_PIN); + SPI_PSEL_MOSI = (PSEL_PORT(SPI_MOSI_PORT) | SPI_MOSI_PIN); + SPI_PSEL_SCK = (PSEL_PORT(SPI_SCK_PORT) | SPI_SCK_PIN); + SPI_PSEL_CSN = 0xFFFFFFFFUL; /* manual CS */ + + SPI_PRESCALER_REG = SPI_PRESCALER_DIV; + + uint32_t cfg = (SPIM_CONFIG_ORDER_MsbFirst << SPIM_CONFIG_ORDER_Pos); + if (phase) + cfg |= (SPIM_CONFIG_CPHA_Trailing << SPIM_CONFIG_CPHA_Pos); + if (polarity) + cfg |= (SPIM_CONFIG_CPOL_ActiveLow << SPIM_CONFIG_CPOL_Pos); + SPI_CONFIG_REG = cfg; + + SPI_IFTIMING_RXDELAY = 0; + SPI_IFTIMING_CSNDUR = 2; + SPI_DMA_RX_LIST = 0; + SPI_DMA_TX_LIST = 0; + + SPI_ENABLE_REG = SPIM_ENABLE_ENABLE_Enabled; + } + (void)polarity; + (void)phase; +} + +void spi_release(void) +{ + +} + +#ifdef WOLFBOOT_TPM +int spi_xfer(int cs, const uint8_t* tx, uint8_t* rx, uint32_t sz, int flags) +{ + uint32_t i; + spi_cs_on(SPI_CS_TPM_PIO_BASE, cs); + for (i = 0; i < sz; i++) { + spi_write((const char)tx[i]); + rx[i] = spi_read(); + } + if (!(flags & SPI_XFER_FLAG_CONTINUE)) { + spi_cs_off(SPI_CS_TPM_PIO_BASE, cs); + } + return 0; +} +#endif /* WOLFBOOT_TPM */ + +#endif /* SPI_FLASH || WOLFBOOT_TPM */ +#endif /* TARGET_ */ diff --git a/hal/spi/spi_drv_nrf54lm20.h b/hal/spi/spi_drv_nrf54lm20.h new file mode 100644 index 0000000000..16987052af --- /dev/null +++ b/hal/spi/spi_drv_nrf54lm20.h @@ -0,0 +1,54 @@ +/* spi_drv_nrf54lm20.h + * + * 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 SPI_DRV_NRF54LM20_H_INCLUDED +#define SPI_DRV_NRF54LM20_H_INCLUDED + +#include + +#include "hal/nrf54lm20.h" + +/* Default pin-mux matches the nRF54LM20 DK */ +#ifndef SPI_CS_PORT + #define SPI_CS_PORT 0 +#endif +#ifndef SPI_CS_PIN + #define SPI_CS_PIN 25 +#endif +#ifndef SPI_SCK_PORT + #define SPI_SCK_PORT 0 +#endif +#ifndef SPI_SCK_PIN + #define SPI_SCK_PIN 29 +#endif +#ifndef SPI_MOSI_PORT + #define SPI_MOSI_PORT 0 +#endif +#ifndef SPI_MOSI_PIN + #define SPI_MOSI_PIN 28 +#endif +#ifndef SPI_MISO_PORT + #define SPI_MISO_PORT 0 +#endif +#ifndef SPI_MISO_PIN + #define SPI_MISO_PIN 27 +#endif + +#define SPI_CS_FLASH SPI_CS_PIN +#define SPI_CS_PIO_BASE SPI_CS_PORT + +#endif /* SPI_DRV_NRF54LM20_H_INCLUDED */ diff --git a/include/loader.h b/include/loader.h index 167d9b0e5b..355aca5436 100644 --- a/include/loader.h +++ b/include/loader.h @@ -52,6 +52,9 @@ extern "C" { #define ML_DSA_IMAGE_SIGNATURE_SIZE (3309) #endif +#ifdef TARGET_nrf54lm20 +extern void hal_monitor(void); +#endif void wolfBoot_start(void); @@ -84,6 +87,10 @@ static inline void wolfBoot_panic(void) #include "printf.h" static inline void wolfBoot_panic(void) { +#ifdef TARGET_nrf54lm20 + hal_monitor(); +#endif + wolfBoot_printf("wolfBoot: PANIC!\n"); #ifdef WOLFBOOT_FSP extern void panic(void); diff --git a/include/spi_drv.h b/include/spi_drv.h index 77f40e95b3..b4339bff88 100644 --- a/include/spi_drv.h +++ b/include/spi_drv.h @@ -56,6 +56,10 @@ #include "hal/spi/spi_drv_nrf52.h" #endif +#if defined(TARGET_nrf54lm20) +#include "hal/spi/spi_drv_nrf54lm20.h" +#endif + #if defined(TARGET_nrf5340) #include "hal/spi/spi_drv_nrf5340.h" #endif diff --git a/options.mk b/options.mk index d55dd160c4..9797a15fe7 100644 --- a/options.mk +++ b/options.mk @@ -1145,3 +1145,7 @@ endif ifeq ($(TZEN),1) CFLAGS+=-DTZEN endif + +ifeq ($(SUPPORT_DEV_BOARD),1) + CFLAGS += -DSUPPORT_DEV_BOARD=1 +endif diff --git a/test-app/Makefile b/test-app/Makefile index 135dbfd5ac..3c594d58ec 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -245,6 +245,10 @@ ifeq ($(TARGET),nrf5340_net) LSCRIPT_TEMPLATE=ARM-nrf5340_net.ld endif +ifeq ($(TARGET),nrf54lm20) + APP_OBJS+=../hal/nrf54lm20_dk.o +endif + ifeq ($(TARGET),ti_hercules) LSCRIPT_TEMPLATE=ARM-r5be.ld # Override linker flags diff --git a/test-app/app_nrf54lm20.c b/test-app/app_nrf54lm20.c new file mode 100644 index 0000000000..a7f0451c14 --- /dev/null +++ b/test-app/app_nrf54lm20.c @@ -0,0 +1,74 @@ +/* app_nrf54lm20.c + * + * Basic smoke test for the nRF54LM20 target. + */ + +#include +#include + +#include "target.h" +#include "wolfboot/wolfboot.h" +#include "hal/nrf54lm20.h" +#include "printf.h" + +#ifndef TEST_LED_PORT + #define TEST_LED_PORT 0 +#endif +#ifndef TEST_LED_PIN + #define TEST_LED_PIN 6 +#endif + +extern void hal_init(void); +extern void wolfBoot_panic(void); + +#ifdef RAM_CODE + +#define AIRCR *(volatile uint32_t *)(0xE000ED0C) +#define AIRCR_VKEY (0x05FA << 16) +#define AIRCR_SYSRESETREQ (1 << 2) + +#define WEAKFUNCTION __attribute__((weak)) + +void WEAKFUNCTION RAMFUNCTION arch_reboot(void) +{ + AIRCR = AIRCR_SYSRESETREQ | AIRCR_VKEY; + while(1) + ; + wolfBoot_panic(); + +} +#endif + +static void led_toggle(void) +{ + uint32_t mask = (1U << TEST_LED_PIN); + if (GPIO_OUT(TEST_LED_PORT) & mask) + GPIO_OUTCLR(TEST_LED_PORT) = mask; + else + GPIO_OUTSET(TEST_LED_PORT) = mask; +} + +void main(void) +{ + uint32_t version = wolfBoot_current_firmware_version(); + uint8_t version_bytes[sizeof(version)]; + memcpy(version_bytes, &version, sizeof(version)); + + hal_init(); + + GPIO_PIN_CNF(TEST_LED_PORT, TEST_LED_PIN) = + (GPIO_CNF_OUT | GPIO_CNF_HIGH_DRIVE_0); + GPIO_OUTCLR(TEST_LED_PORT) = (1U << TEST_LED_PIN); + + uart_init(); + uart_write("*", 1); + for (int i = (int)(sizeof(version_bytes) - 1); i >= 0; i--) { + uart_write((const char*)&version_bytes[i], 1); + } + + for (;;) { + led_toggle(); + for (volatile uint32_t n = 0; n < 1000000UL; n++) + NOP(); + } +}