From 6b8702dd63c08ba0e70d19dd90f3535d9b38de09 Mon Sep 17 00:00:00 2001 From: Mattia Moffa Date: Thu, 9 Jul 2026 05:19:51 +0200 Subject: [PATCH] Add uart driver for stm32u5 --- hal/stm32u5.c | 47 ++++++++--- hal/stm32u5.h | 62 ++++++++++++++ hal/uart/uart_drv_stm32u5.c | 157 ++++++++++++++++++++++++++++++++++++ test-app/Makefile | 6 ++ 4 files changed, 262 insertions(+), 10 deletions(-) create mode 100644 hal/uart/uart_drv_stm32u5.c diff --git a/hal/stm32u5.c b/hal/stm32u5.c index fa8667ae..a8c0227a 100644 --- a/hal/stm32u5.c +++ b/hal/stm32u5.c @@ -24,6 +24,7 @@ #include #include "hal/stm32u5.h" #include "hal.h" +#include "uart_drv.h" static void RAMFUNCTION flash_set_waitstates(unsigned int waitstates) @@ -33,7 +34,7 @@ static void RAMFUNCTION flash_set_waitstates(unsigned int waitstates) FLASH_ACR = (reg & ~FLASH_ACR_LATENCY_MASK) | waitstates; } -static RAMFUNCTION void flash_wait_complete(uint8_t bank) +void RAMFUNCTION hal_flash_wait_complete(uint8_t bank) { while ((FLASH_NS_SR & (FLASH_SR_BSY | FLASH_SR_WDW)) != 0) ; @@ -44,7 +45,7 @@ static RAMFUNCTION void flash_wait_complete(uint8_t bank) } -static void RAMFUNCTION flash_clear_errors(uint8_t bank) +void RAMFUNCTION hal_flash_clear_errors(uint8_t bank) { FLASH_NS_SR |= (FLASH_SR_OPERR | FLASH_SR_PROGERR | FLASH_SR_WRPERR | @@ -68,7 +69,7 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len) uint32_t qword[4]; volatile uint32_t *sr, *cr; - flash_clear_errors(0); + hal_flash_clear_errors(0); src = (uint32_t*)data; dst = (uint32_t*)address; @@ -105,7 +106,7 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len) ISB(); dst[(i >> 2) + 3] = qword[3]; ISB(); - flash_wait_complete(0); + hal_flash_wait_complete(0); if ((*sr & FLASH_SR_EOP) != 0) *sr |= FLASH_SR_EOP; *cr &= ~FLASH_CR_PG; @@ -117,7 +118,7 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len) void RAMFUNCTION hal_flash_unlock(void) { - flash_wait_complete(0); + hal_flash_wait_complete(0); #if (TZ_SECURE()) if ((FLASH_CR & FLASH_CR_LOCK) != 0) { FLASH_KEYR = FLASH_KEY1; @@ -140,7 +141,7 @@ void RAMFUNCTION hal_flash_unlock(void) void RAMFUNCTION hal_flash_lock(void) { - flash_wait_complete(0); + hal_flash_wait_complete(0); #if (TZ_SECURE()) if ((FLASH_CR & FLASH_CR_LOCK) == 0) FLASH_CR |= FLASH_CR_LOCK; @@ -151,7 +152,7 @@ void RAMFUNCTION hal_flash_lock(void) void RAMFUNCTION hal_flash_opt_unlock(void) { - flash_wait_complete(0); + hal_flash_wait_complete(0); if ((FLASH_NS_CR & FLASH_CR_OPTLOCK) != 0) { FLASH_NS_OPTKEYR = FLASH_OPTKEY1; @@ -167,7 +168,7 @@ void RAMFUNCTION hal_flash_opt_lock(void) { FLASH_NS_CR |= FLASH_CR_OPTSTRT; - flash_wait_complete(0); + hal_flash_wait_complete(0); FLASH_NS_CR |= FLASH_CR_OBL_LAUNCH; if ((FLASH_NS_CR & FLASH_CR_OPTLOCK) == 0) FLASH_NS_CR |= FLASH_CR_OPTLOCK; @@ -179,7 +180,7 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len) uint32_t p; volatile uint32_t *cr = &FLASH_NS_CR; - flash_clear_errors(0); + hal_flash_clear_errors(0); if (len == 0) return -1; @@ -219,7 +220,7 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len) *cr = reg; DMB(); *cr |= FLASH_CR_STRT; - flash_wait_complete(0); + hal_flash_wait_complete(0); } /* If the erase operation is completed, disable the associated bits */ *cr &= ~FLASH_CR_PER ; @@ -500,6 +501,8 @@ static void led_unsecure() #define TZSC1_BASE 0x50032400u #define TZSC_SECCFGR1 (*(volatile uint32_t *)(TZSC1_BASE + 0x10u)) #define TZSC_SECCFGR1_USART3SEC (1u << 10) +#define TZSC_SECCFGR2 (*(volatile uint32_t *)(TZSC1_BASE + 0x14u)) +#define TZSC_SECCFGR2_USART1SEC (1u << 3) static void periph_unsecure(void) { @@ -522,6 +525,24 @@ static void periph_unsecure(void) DMB(); TZSC_SECCFGR1 = reg; } + + /* Enable clock for GPIO A (USART1 pins PA9/PA10) */ + RCC_AHB2ENR1_CLOCK_ER |= GPIOA_AHB2ENR1_CLOCK_ER; + + /* Enable clock for USART1 */ + RCC_APB2ENR |= UART1_APB2_CLOCK_ER_VAL; + + /* Unsecure USART1 pins (PA9 TX, PA10 RX) */ + GPIOA_SECCFGR &= ~(1u << UART1_TX_PIN); + GPIOA_SECCFGR &= ~(1u << UART1_RX_PIN); + + /* Unsecure USART1 peripheral in GTZC TZSC */ + reg = TZSC_SECCFGR2; + if (reg & TZSC_SECCFGR2_USART1SEC) { + reg &= ~TZSC_SECCFGR2_USART1SEC; + DMB(); + TZSC_SECCFGR2 = reg; + } } #endif @@ -554,6 +575,12 @@ void hal_init(void) fork_bootloader(); #endif clock_pll_on(0); + +#ifdef DEBUG_UART + uart_init(115200, 8, 'N', 1); + uart_write("wolfBoot Init\n", 14); +#endif + #if TZ_SECURE() hal_tz_sau_init(); hal_gtzc_init(); diff --git a/hal/stm32u5.h b/hal/stm32u5.h index e28cd86e..122efaac 100644 --- a/hal/stm32u5.h +++ b/hal/stm32u5.h @@ -277,6 +277,68 @@ #define RCC_AHB2_CLOCK_ER RCC_AHB2ENR1_CLOCK_ER +/* UART */ +#if (TZ_SECURE()) +#define UART1 (0x50013800) /* USART1 - RM0456 - Table 4 */ +#define GPIOA_BASE (0x52020000) +#else +#define UART1 (0x40013800) /* USART1 - RM0456 - Table 4 */ +#define GPIOA_BASE (0x42020000) +#endif + +#define UART_CR1(base) (*(volatile uint32_t *)((base) + 0x00)) +#define UART_CR2(base) (*(volatile uint32_t *)((base) + 0x04)) +#define UART_CR3(base) (*(volatile uint32_t *)((base) + 0x08)) +#define UART_BRR(base) (*(volatile uint32_t *)((base) + 0x0c)) +#define UART_ISR(base) (*(volatile uint32_t *)((base) + 0x1c)) +#define UART_ICR(base) (*(volatile uint32_t *)((base) + 0x20)) +#define UART_RDR(base) (*(volatile uint32_t *)((base) + 0x24)) +#define UART_TDR(base) (*(volatile uint32_t *)((base) + 0x28)) +#define UART_PRE(base) (*(volatile uint32_t *)((base) + 0x2C)) + +#define UART_CR1_UART_ENABLE (1 << 0) +#define UART_CR1_OVER8 (1 << 15) +#define UART_CR1_SYMBOL_LEN (1 << 12) +#define UART_CR1_PARITY_ENABLED (1 << 10) +#define UART_CR1_PARITY_ODD (1 << 9) +#define UART_CR1_TX_ENABLE (1 << 3) +#define UART_CR1_RX_ENABLE (1 << 2) +#define UART_CR2_STOPBITS (3 << 12) +#define UART_CR2_LINEN (1 << 14) +#define UART_CR2_CLKEN (1 << 11) +#define UART_CR3_HDSEL (1 << 3) +#define UART_CR3_SCEN (1 << 5) +#define UART_CR3_IREN (1 << 1) +#define UART_ISR_TX_EMPTY (1 << 7) +#define UART_ISR_TX_COMPLETE (1 << 6) +#define UART_ISR_RX_NOTEMPTY (1 << 5) +#define UART_EPE (1 << 0) /* Parity error */ +#define UART_EFE (1 << 1) /* Framing error */ +#define UART_ENE (1 << 2) /* Noise error */ +#define UART_ORE (1 << 3) /* Overrun error */ + +#define UART1_APB2_CLOCK_ER_VAL (1 << 14) /* RM0456 - RCC_APB2ENR - USART1EN */ +#define RCC_APB2ENR (*(volatile uint32_t *)(RCC_BASE + 0xA4)) /* RM0456 - Table 108 */ + +#define RCC_CCIPR1 (*(volatile uint32_t *)(RCC_BASE + 0xE0)) /* RM0456 - 11.8.46 */ +#define RCC_CCIPR1_USART1SEL_SHIFT (0) +#define RCC_CCIPR1_USART1SEL_MASK (0x3) +#define RCC_CCIPR1_USART1SEL_HSI16 (0x2) + +#define HSI16_FREQ (16000000) + +/* USART1 pin configuration: PA9 (TX) / PA10 (RX), AF7. + * Connected to the ST-LINK VCP on Nucleo-U575ZI-Q. */ +#define UART1_PIN_AF 7 +#define UART1_TX_PIN 9 +#define UART1_RX_PIN 10 + +#define GPIOA_AHB2ENR1_CLOCK_ER (1 << 0) +#define GPIOA_MODE (*(volatile uint32_t *)(GPIOA_BASE + 0x00)) +#define GPIOA_AFL (*(volatile uint32_t *)(GPIOA_BASE + 0x20)) +#define GPIOA_AFH (*(volatile uint32_t *)(GPIOA_BASE + 0x24)) +#define GPIOA_SECCFGR (*(volatile uint32_t *)(GPIOA_BASE + 0x30)) + /* Reset */ #define OPTR_SWAP_BANK (1 << 20) diff --git a/hal/uart/uart_drv_stm32u5.c b/hal/uart/uart_drv_stm32u5.c new file mode 100644 index 00000000..32c06622 --- /dev/null +++ b/hal/uart/uart_drv_stm32u5.c @@ -0,0 +1,157 @@ +/* uart_drv_stm32u5.c + * + * Driver for the back-end of the UART_FLASH module. + * + * Example implementation for stm32U5 + * using USART1 (PA9/PA10, ST-LINK VCP on B-U585I-IOT02A). + * + * + * 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 + */ + +#ifdef TARGET_stm32u5 + +#include +#include "hal/stm32u5.h" + +static void uart_pins_setup(void) +{ + uint32_t reg; + RCC_AHB2ENR1_CLOCK_ER |= GPIOA_AHB2ENR1_CLOCK_ER; + /* Set mode = AF */ + reg = GPIOA_MODE & ~(0x03 << (UART1_RX_PIN * 2)); + GPIOA_MODE = reg | (2 << (UART1_RX_PIN * 2)); + reg = GPIOA_MODE & ~(0x03 << (UART1_TX_PIN * 2)); + GPIOA_MODE = reg | (2 << (UART1_TX_PIN * 2)); + + /* Alternate function: use hi pins (9 and 10) */ + reg = GPIOA_AFH & ~(0xf << ((UART1_TX_PIN - 8) * 4)); + GPIOA_AFH = reg | (UART1_PIN_AF << ((UART1_TX_PIN - 8) * 4)); + reg = GPIOA_AFH & ~(0xf << ((UART1_RX_PIN - 8) * 4)); + GPIOA_AFH = reg | (UART1_PIN_AF << ((UART1_RX_PIN - 8) * 4)); +} + +static void uart_clear_errors(uint32_t base) +{ + UART_ICR(base) = UART_ISR(base) & (UART_ENE | UART_EPE | UART_ORE | UART_EFE); +} + +int uart_tx(const uint8_t c) +{ + volatile uint32_t reg; + do { + reg = UART_ISR(UART1); + if (reg & (UART_ENE | UART_EPE | UART_ORE | UART_EFE)) + uart_clear_errors(UART1); + } while ((reg & UART_ISR_TX_EMPTY) == 0); + UART_TDR(UART1) = c; + return 1; +} + +int uart_rx(uint8_t *c) +{ + volatile uint32_t reg; + reg = UART_ISR(UART1); + if (reg & (UART_ENE | UART_EPE | UART_ORE | UART_EFE)) + uart_clear_errors(UART1); + if (reg & UART_ISR_RX_NOTEMPTY) { + *c = (uint8_t)UART_RDR(UART1); + return 1; + } + return 0; +} + +int uart_init(uint32_t bitrate, uint8_t data, char parity, uint8_t stop) +{ + uint32_t reg; + + /* Enable USART1 peripheral clock */ + RCC_APB2ENR |= UART1_APB2_CLOCK_ER_VAL; + + /* If the UART is already running (e.g. left enabled by the secure + * bootloader), let the last frame finish shifting out before + * reconfiguring, or the character is cut mid-frame */ + if (UART_CR1(UART1) & UART_CR1_UART_ENABLE) { + while ((UART_ISR(UART1) & UART_ISR_TX_COMPLETE) == 0) {}; + } + + uart_pins_setup(); + + /* Use HSI16 as USART1 kernel clock, so the baud rate does not + * depend on the current SYSCLK/PLL configuration */ + RCC_CR |= RCC_CR_HSION; + while ((RCC_CR & RCC_CR_HSIRDY) == 0) {}; + reg = RCC_CCIPR1 & (~(RCC_CCIPR1_USART1SEL_MASK << RCC_CCIPR1_USART1SEL_SHIFT)); + RCC_CCIPR1 = reg | (RCC_CCIPR1_USART1SEL_HSI16 << RCC_CCIPR1_USART1SEL_SHIFT); + + /* Disable UART to configure BRR (only writable while disabled) */ + UART_CR1(UART1) &= ~UART_CR1_UART_ENABLE; + + /* Enable 16-bit oversampling */ + UART_CR1(UART1) &= ~UART_CR1_OVER8; + + /* Configure baud rate */ + UART_BRR(UART1) = (uint16_t)(HSI16_FREQ / bitrate); + + /* Configure data bits */ + if (data == 8) + UART_CR1(UART1) &= ~UART_CR1_SYMBOL_LEN; + else + UART_CR1(UART1) |= UART_CR1_SYMBOL_LEN; + + /* Configure parity */ + switch (parity) { + case 'O': + UART_CR1(UART1) |= UART_CR1_PARITY_ODD; + /* fall through to enable parity */ + /* FALL THROUGH */ + case 'E': + UART_CR1(UART1) |= UART_CR1_PARITY_ENABLED; + break; + default: + UART_CR1(UART1) &= ~(UART_CR1_PARITY_ENABLED | UART_CR1_PARITY_ODD); + } + /* Set stop bits */ + reg = UART_CR2(UART1) & ~UART_CR2_STOPBITS; + if (stop > 1) + UART_CR2(UART1) = reg | (2 << 12); + else + UART_CR2(UART1) = reg; + + /* Clear flags for async mode */ + UART_CR2(UART1) &= ~(UART_CR2_LINEN | UART_CR2_CLKEN); + UART_CR3(UART1) &= ~(UART_CR3_SCEN | UART_CR3_HDSEL | UART_CR3_IREN); + + /* Configure for RX+TX, turn on. */ + UART_CR1(UART1) |= UART_CR1_TX_ENABLE | UART_CR1_RX_ENABLE | UART_CR1_UART_ENABLE; + + return 0; +} + +#ifdef DEBUG_UART +void uart_write(const char *buf, unsigned int len) +{ + while (len--) { + uart_tx(*buf); + buf++; + } +} +#endif + +#endif /* TARGET_stm32u5 */ diff --git a/test-app/Makefile b/test-app/Makefile index e0ded2f7..f8058a34 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -654,6 +654,9 @@ ifeq ($(TARGET),stm32u5) endif CFLAGS+=-mcpu=cortex-m33 LDFLAGS+=-mcpu=cortex-m33 + ifeq ($(DEBUG_UART),1) + APP_OBJS+=../hal/uart/uart_drv_$(UART_TARGET)_ns.o + endif endif ifeq ($(TARGET),stm32u3) @@ -1382,6 +1385,9 @@ delta-extra-data: image.bin ../hal/spi/spi_drv_$(SPI_TARGET)_ns.o: ../hal/spi/spi_drv_$(SPI_TARGET).c FORCE $(Q)$(CC) $(CFLAGS) -c -o $(@) ../hal/spi/spi_drv_$(SPI_TARGET).c -DNONSECURE_APP +../hal/uart/uart_drv_$(UART_TARGET)_ns.o: ../hal/uart/uart_drv_$(UART_TARGET).c FORCE + $(Q)$(CC) $(CFLAGS) -c -o $(@) ../hal/uart/uart_drv_$(UART_TARGET).c -DNONSECURE_APP + board_$(BOARD).o: ../hal/boards/$(BOARD)/board.c @echo "\t[CC-$(ARCH)] $@" $(Q)$(CC) $(CFLAGS) -DDEBUG_UART -c $(OUTPUT_FLAG) $@ $<