wolfBoot/hal/lpc55s69.c

333 lines
9.5 KiB
C

/* lpc55s69.c
*
* Copyright (C) 2026 wolfSSL Inc.
*
* This file is part of wolfBoot.
*
* wolfBoot is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
#include <stdint.h>
#include <string.h>
#include <target.h>
#include "fsl_common.h"
#include "image.h"
#include "clock_config.h"
#include "fsl_clock.h"
#include "fsl_iap.h"
#include "fsl_iocon.h"
#include "fsl_reset.h"
#include "fsl_rng.h"
#include "fsl_usart.h"
#include "loader.h"
#ifdef TZEN
#include "hal/armv8m_tz.h"
#endif
static flash_config_t pflash;
static const uint32_t pflash_page_size = 512U;
uint32_t SystemCoreClock; /* set in clock_config.c */
#ifdef TZEN
static void hal_sau_init(void)
{
/* Non-secure callable area */
sau_init_region(0, WOLFBOOT_NSC_ADDRESS,
WOLFBOOT_NSC_ADDRESS + WOLFBOOT_NSC_SIZE - 1, 1);
/* Non-secure: application flash area (boot+update partition) */
sau_init_region(1, WOLFBOOT_PARTITION_BOOT_ADDRESS,
WOLFBOOT_PARTITION_BOOT_ADDRESS + (WOLFBOOT_PARTITION_SIZE * 2) - 1,
0);
/* Non-secure RAM */
sau_init_region(2, 0x20020000, 0x20027FFF, 0);
/* Peripherals */
sau_init_region(3, 0x40000000, 0x4003FFFF, 0);
sau_init_region(4, 0x40080000, 0x400AFFFF, 0);
sau_init_region(5, 0x40100000, 0x4010FFFF, 0);
/* Enable SAU */
SAU_CTRL = SAU_INIT_CTRL_ENABLE;
/* Enable securefault handler */
SCB_SHCSR |= SCB_SHCSR_SECUREFAULT_EN;
}
static void periph_unsecure(void)
{
#ifdef WOLFSSL_NXP_RNG_1
CLOCK_EnableClock(kCLOCK_Rng);
RESET_PeripheralReset(kRNG_RST_SHIFT_RSTn);
#endif
CLOCK_EnableClock(kCLOCK_Iocon);
CLOCK_EnableClock(kCLOCK_Gpio1);
}
#endif
static void hal_flash_fix_ecc(void)
{
uint8_t page_buf[512];
uint32_t addr;
uint32_t start = WOLFBOOT_PARTITION_BOOT_ADDRESS;
uint32_t end = WOLFBOOT_PARTITION_SWAP_ADDRESS + WOLFBOOT_SECTOR_SIZE;
memset(page_buf, 0xFF, sizeof(page_buf));
for (addr = start; addr < end; addr += pflash_page_size) {
if (FLASH_VerifyErase(&pflash, addr, pflash_page_size)
== kStatus_FLASH_Success) {
FLASH_Program(&pflash, addr, page_buf, pflash_page_size);
}
}
}
extern int wc_hashcrypt_init(void);
extern int wc_casper_init(void);
void hal_init(void)
{
#ifdef __WOLFBOOT
/* lpc55s69 must run < 100 MHz for flash write/erase to work */
BOARD_BootClockFROHF96M();
// BOARD_BootClockPLL150M();
# ifdef DEBUG_UART
uart_init();
uart_write("lpc55s69 init\n", 14);
# endif
# ifdef WOLFSSL_NXP_HASHCRYPT
CLOCK_EnableClock(kCLOCK_HashCrypt);
wc_hashcrypt_init();
# endif
# ifdef WOLFSSL_NXP_CASPER
CLOCK_EnableClock(kCLOCK_Casper);
wc_casper_init();
# endif
#endif /* __WOLFBOOT */
#if defined(__WOLFBOOT) || !defined(TZEN)
memset(&pflash, 0, sizeof(pflash));
FLASH_Init(&pflash);
hal_flash_fix_ecc();
#endif
#if defined(TZEN) && !defined(NONSECURE_APP)
hal_sau_init();
#endif
}
#ifdef __WOLFBOOT
/* Assert hook needed by SDK assert() macro. */
void __assert_func(const char *a, int b, const char *c, const char *d)
{
(void)a;
(void)b;
(void)c;
(void)d;
while (1) {
}
}
void hal_prepare_boot(void)
{
#ifdef TZEN
periph_unsecure();
#endif
}
#endif
int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
{
uint8_t page_buf[512];
uint32_t page_addr;
uint32_t offset;
uint32_t chunk;
while (len > 0) {
page_addr = address & ~(pflash_page_size - 1);
offset = address - page_addr;
chunk = pflash_page_size - offset;
if ((uint32_t)len < chunk)
chunk = (uint32_t)len;
if (FLASH_VerifyErase(&pflash, page_addr, pflash_page_size)
== kStatus_FLASH_Success) {
memset(page_buf, 0xFF, pflash_page_size);
} else {
memcpy(page_buf, (void *)page_addr, pflash_page_size);
if (FLASH_Erase(&pflash, page_addr, pflash_page_size,
kFLASH_ApiEraseKey) != kStatus_FLASH_Success)
return -1;
}
memcpy(page_buf + offset, data, chunk);
if (FLASH_Program(&pflash, page_addr, page_buf, pflash_page_size)
!= kStatus_FLASH_Success)
return -1;
address += chunk;
data += chunk;
len -= (int)chunk;
}
return 0;
}
void RAMFUNCTION hal_flash_unlock(void)
{
}
void RAMFUNCTION hal_flash_lock(void)
{
}
int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
{
uint8_t page_buf[512];
uint32_t pos;
if (address % pflash_page_size != 0 || len % pflash_page_size != 0)
return -1;
memset(page_buf, 0xFF, sizeof(page_buf));
for (pos = address; pos < address + (uint32_t)len; pos += pflash_page_size) {
if (FLASH_Erase(&pflash, pos, pflash_page_size, kFLASH_ApiEraseKey)
!= kStatus_FLASH_Success)
return -1;
if (FLASH_Program(&pflash, pos, page_buf, pflash_page_size)
!= kStatus_FLASH_Success)
return -1;
}
return 0;
}
#ifdef WOLFCRYPT_SECURE_MODE
void hal_trng_init(void)
{
#ifdef WOLFSSL_NXP_RNG_1
# ifdef __WOLFBOOT
CLOCK_EnableClock(kCLOCK_Rng);
RESET_PeripheralReset(kRNG_RST_SHIFT_RSTn);
# endif
RNG_Init(RNG);
#endif
}
void hal_trng_fini(void)
{
}
int hal_trng_get_entropy(unsigned char *out, unsigned int len)
{
#ifdef WOLFSSL_NXP_RNG_1
if (RNG_GetRandomData(RNG, out, len) == kStatus_Success)
return 0;
#endif
return -1;
}
#endif
#define IOCON_PIO_DIGITAL_EN 0x0100u /*!<@brief Enables digital function */
#define IOCON_PIO_FUNC1 0x01u /*!<@brief Selects pin function 1 */
#define IOCON_PIO_INV_DI 0x00u /*!<@brief Input function is not inverted */
#define IOCON_PIO_MODE_INACT 0x00u /*!<@brief No addition pin function */
#define IOCON_PIO_OPENDRAIN_DI 0x00u /*!<@brief Open drain is disabled */
#define IOCON_PIO_SLEW_STANDARD 0x00u /*!<@brief Standard mode, output slew rate control is enabled */
#ifdef DEBUG_UART
void uart_init(void)
{
CLOCK_EnableClock(kCLOCK_Iocon);
const uint32_t port0_pin29_config = (/* Pin is configured as FC0_RXD_SDA_MOSI_DATA */
IOCON_PIO_FUNC1 |
/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Standard mode, output slew rate control is enabled */
IOCON_PIO_SLEW_STANDARD |
/* Input function is not inverted */
IOCON_PIO_INV_DI |
/* Enables digital function */
IOCON_PIO_DIGITAL_EN |
/* Open drain is disabled */
IOCON_PIO_OPENDRAIN_DI);
/* PORT0 PIN29 (coords: 92) is configured as FC0_RXD_SDA_MOSI_DATA */
IOCON_PinMuxSet(IOCON, 0U, 29U, port0_pin29_config);
const uint32_t port0_pin30_config = (/* Pin is configured as FC0_TXD_SCL_MISO_WS */
IOCON_PIO_FUNC1 |
/* No addition pin function */
IOCON_PIO_MODE_INACT |
/* Standard mode, output slew rate control is enabled */
IOCON_PIO_SLEW_STANDARD |
/* Input function is not inverted */
IOCON_PIO_INV_DI |
/* Enables digital function */
IOCON_PIO_DIGITAL_EN |
/* Open drain is disabled */
IOCON_PIO_OPENDRAIN_DI);
/* PORT0 PIN30 (coords: 94) is configured as FC0_TXD_SCL_MISO_WS */
IOCON_PinMuxSet(IOCON, 0U, 30U, port0_pin30_config);
/* attach 12 MHz clock to FLEXCOMM0 (debug console) */
CLOCK_AttachClk(kFRO12M_to_FLEXCOMM0);
CLOCK_EnableClock(kCLOCK_FlexComm0);
RESET_ClearPeripheralReset(kFC0_RST_SHIFT_RSTn);
usart_config_t config;
USART_GetDefaultConfig(&config);
config.baudRate_Bps = 115200U;
config.enableTx = true;
config.enableRx = true;
(void)USART_Init(USART0, &config, 12000000U);
}
void uart_write(const char *buf, unsigned int sz)
{
const char *line;
unsigned int line_sz;
while (sz > 0)
{
line = memchr(buf, '\n', sz);
if (line == NULL) {
(void)USART_WriteBlocking(USART0, (const uint8_t *)buf, sz);
break;
}
line_sz = (unsigned int)(line - buf);
if (line_sz > sz - 1U) {
line_sz = sz - 1U;
}
(void)USART_WriteBlocking(USART0, (const uint8_t *)buf, line_sz);
(void)USART_WriteBlocking(USART0, (const uint8_t *)"\r\n", 2U);
buf = line + 1;
sz -= line_sz + 1U;
}
}
#endif