/* stm32h5.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 2 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 "hal.h" #include "hal/stm32h5.h" #define PLL_SRC_HSE 1 #if TZ_SECURE() static int is_flash_nonsecure(uint32_t address) { uint32_t in_bank_offset = address & 0x000FFFFF; #ifdef DUALBANK_SWAP if (in_bank_offset >= (WOLFBOOT_PARTITION_BOOT_ADDRESS - FLASHMEM_ADDRESS_SPACE)) return 1; else return 0; #else if (address >= WOLFBOOT_PARTITION_BOOT_ADDRESS) return 1; else return 0; #endif } #endif static void RAMFUNCTION flash_set_waitstates(unsigned int waitstates) { uint32_t reg = FLASH_ACR; if ((reg & FLASH_ACR_LATENCY_MASK) < waitstates) do { FLASH_ACR = (reg & ~(FLASH_ACR_LATENCY_MASK | (FLASH_ACR_WRHIGHFREQ_MASK << FLASH_ACR_WRHIGHFREQ_SHIFT))) | waitstates | (0x02 << FLASH_ACR_WRHIGHFREQ_SHIFT) ; } while ((FLASH_ACR & FLASH_ACR_LATENCY_MASK) != waitstates); } void RAMFUNCTION hal_flash_wait_complete(uint8_t bank) { while ((FLASH_SR & FLASH_SR_BSY) == FLASH_SR_BSY) ; #if (TZ_SECURE()) while ((FLASH_NS_SR & FLASH_SR_BSY) == FLASH_SR_BSY) ; #endif } static void RAMFUNCTION hal_flash_wait_buffer_empty(uint8_t bank) { while ((FLASH_SR & FLASH_SR_DBNE) == FLASH_SR_DBNE) ; #if (TZ_SECURE()) while ((FLASH_NS_SR & FLASH_SR_DBNE) == FLASH_SR_DBNE) ; #endif } void RAMFUNCTION hal_flash_clear_errors(uint8_t bank) { FLASH_CCR |= ( FLASH_CCR_CLR_WBNE | FLASH_CCR_CLR_DBNE | FLASH_CCR_CLR_INCE| FLASH_CCR_CLR_PGSE | FLASH_CCR_CLR_OPTE | FLASH_CCR_CLR_OPTWE | FLASH_CCR_CLR_WRPE | FLASH_CCR_CLR_EOP); } int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len) { int i = 0; uint32_t *src, *dst; uint32_t dword[2]; uint32_t off = 0; uint32_t una_len = 0; hal_flash_clear_errors(0); src = (uint32_t *)data; dst = (uint32_t *)address; #if (TZ_SECURE()) if (is_flash_nonsecure(address)) { hal_tz_claim_nonsecure_area(address, len); } else if (((uint32_t)dst & 0x0F000000) == 0x08000000) { /* Convert into secure address space */ dst = (uint32_t *)((address & (~FLASHMEM_ADDRESS_SPACE)) | FLASH_SECURE_MMAP_BASE); } #endif while (i < len) { dword[0] = src[i >> 2]; if (len > i + 1) dword[1] = src[(i >> 2) + 1]; else dword[1] = 0xFFFFFFFF; FLASH_CR |= FLASH_CR_PG; dst[i >> 2] = dword[0]; ISB(); dst[(i >> 2) + 1] = dword[1]; ISB(); hal_flash_wait_complete(0); if ((FLASH_SR & FLASH_SR_EOP) != 0) FLASH_SR |= FLASH_SR_EOP; FLASH_CR &= ~FLASH_CR_PG; i+=8; } #if (TZ_SECURE()) if (is_flash_nonsecure(address)) { hal_tz_release_nonsecure_area(); } #endif return 0; } void RAMFUNCTION hal_flash_unlock(void) { hal_flash_wait_complete(0); if ((FLASH_CR & FLASH_CR_LOCK) != 0) { FLASH_KEYR = FLASH_KEY1; DMB(); FLASH_KEYR = FLASH_KEY2; DMB(); while ((FLASH_CR & FLASH_CR_LOCK) != 0) ; } } void RAMFUNCTION hal_flash_lock(void) { hal_flash_wait_complete(0); if ((FLASH_CR & FLASH_CR_LOCK) == 0) FLASH_CR |= FLASH_CR_LOCK; } void RAMFUNCTION hal_flash_opt_unlock(void) { hal_flash_wait_complete(0); if ((FLASH_OPTCR & FLASH_OPTCR_OPTLOCK) != 0) { FLASH_OPTKEYR = FLASH_OPTKEY1; DMB(); FLASH_OPTKEYR = FLASH_OPTKEY2; DMB(); while ((FLASH_CR & FLASH_CR_LOCK) != 0) ; } } void RAMFUNCTION hal_flash_opt_lock(void) { FLASH_OPTCR |= FLASH_OPTCR_OPTSTRT; hal_flash_wait_complete(0); if ((FLASH_OPTCR & FLASH_OPTCR_OPTLOCK) == 0) FLASH_OPTCR |= FLASH_OPTCR_OPTLOCK; } int RAMFUNCTION hal_flash_erase(uint32_t address, int len) { uint32_t end_address; uint32_t p; hal_flash_clear_errors(0); if (len == 0) return -1; if (address < 0x08000000) return -1; end_address = address + len - 1; for (p = address; p < end_address; p += FLASH_PAGE_SIZE) { uint32_t reg; uint32_t base; uint32_t bnksel = 0; base = FLASHMEM_ADDRESS_SPACE; reg = FLASH_CR & (~((FLASH_CR_PNB_MASK << FLASH_CR_PNB_SHIFT) | FLASH_CR_BER)); if(p >= (FLASH_BANK2_BASE) && (p <= (FLASH_TOP) )) { base = FLASH_BANK2_BASE; bnksel = 1; } #if TZ_SECURE() /* When in secure mode, skip erasing non-secure pages: will be erased upon claim */ if (is_flash_nonsecure(address)) { return 0; } #endif /* Check for swapped banks to invert bnksel */ if ((FLASH_OPTSR_CUR & FLASH_OPTSR_SWAP_BANK) >> 31) bnksel = !bnksel; reg |= ((((p - base) >> 13) << FLASH_CR_PNB_SHIFT) | FLASH_CR_SER | (bnksel << 31)); FLASH_CR = reg; ISB(); FLASH_CR |= FLASH_CR_STRT; hal_flash_wait_complete(0); } /* If the erase operation is completed, disable the associated bits */ FLASH_CR &= ~FLASH_CR_SER ; return 0; } static void clock_pll_off(void) { uint32_t reg32; /* Select HSI as SYSCLK source. */ RCC_CFGR1 &= ~(0x07 << RCC_CFGR1_SW_SHIFT); DMB(); /* Turn off PLL1 */ RCC_PLL1CFGR &= ~RCC_PLLCFGR_PLL1PEN; DMB(); RCC_CR &= ~RCC_CR_PLL1ON; DMB(); /* Wait until PLL1 is disabled */ while ((RCC_CR & RCC_CR_PLL1RDY) != 0) ; /* Turn off PLL2 */ RCC_PLL2CFGR &= ~RCC_PLLCFGR_PLLPEN; DMB(); RCC_CR &= ~RCC_CR_PLL2ON; DMB(); /* Wait until PLL2 is disabled */ while ((RCC_CR & RCC_CR_PLL2RDY) != 0) ; } /*This implementation will setup MSI 48 MHz as PLL Source Mux, PLLCLK as System Clock Source*/ static void clock_pll_on(void) { uint32_t reg32; uint32_t plln, pllm, pllq, pllp, pllr, hpre, apb1pre, apb2pre, apb3pre, flash_waitstates; #if PLL_SRC_HSE pllm = 4; plln = 250; pllp = 2; pllq = 2; pllr = 2; #else pllm = 1; plln = 129; pllp = 2; pllq = 2; pllr = 2; #endif flash_waitstates = 5; /* Set voltage scaler */ reg32 = PWR_VOSCR & (~PWR_VOS_MASK); PWR_VOSCR = reg32 | PWR_VOS_SCALE_0; /* Wait until scale has changed */ while ((PWR_VOSSR & PWR_VOSRDY) == 0) ; /* Disable PLL1 */ RCC_CR &= ~RCC_CR_PLL1ON; /* Wait until PLL1 is disabled */ while ((RCC_CR & RCC_CR_PLL1RDY) != 0) ; /* Set flash wait states */ flash_set_waitstates(flash_waitstates); #if PLL_SRC_HSE /* PLL Oscillator configuration */ RCC_CR |= RCC_CR_HSEON | RCC_CR_HSEBYP; /* Wait until HSE is Ready */ while ((RCC_CR & RCC_CR_HSERDY) == 0) ; /* Configure PLL1 div/mul factors */ reg32 = RCC_PLL1CFGR; reg32 &= ~((0x3F << RCC_PLLCFGR_PLLM_SHIFT) | (0x03)); reg32 |= (pllm << RCC_PLLCFGR_PLLM_SHIFT) | RCC_PLLCFGR_PLLSRC_HSE; RCC_PLL1CFGR = reg32; #else RCC_CR |= RCC_CR_HSION; /* Wait until HSI is Ready */ while ((RCC_CR & RCC_CR_HSIRDY) == 0) ; RCC_CR |= RCC_CR_CSION; /* Wait until CSI is Ready */ while ((RCC_CR & RCC_CR_HSIRDY) == 0) ; /* Configure PLL1 div/mul factors */ reg32 = RCC_PLL1CFGR; reg32 &= ~((0x3F << RCC_PLLCFGR_PLLM_SHIFT) | (0x03)); reg32 |= (pllm << RCC_PLLCFGR_PLLM_SHIFT) | RCC_PLLCFGR_PLLSRC_CSI; RCC_PLL1CFGR = reg32; #endif DMB(); RCC_PLL1DIVR = ((plln - 1) << RCC_PLLDIVR_DIVN_SHIFT) | ((pllp - 1) << RCC_PLLDIVR_DIVP_SHIFT) | ((pllq - 1) << RCC_PLLDIVR_DIVQ_SHIFT) | ((pllr - 1) << RCC_PLLDIVR_DIVR_SHIFT); DMB(); /* Disable Fractional PLL */ RCC_PLL1CFGR &= ~RCC_PLLCFGR_PLLFRACEN; DMB(); /* Configure Fractional PLL factor */ RCC_PLL1FRACR = 0x00000000; DMB(); /* Enable Fractional PLL */ RCC_PLL1CFGR |= RCC_PLLCFGR_PLLFRACEN; DMB(); /* Select PLL1 Input frequency range: VCI */ RCC_PLL1CFGR |= RCC_PLLCFGR_RGE_2_4 << RCC_PLLCFGR_PLLRGE_SHIFT; /* Select PLL1 Output frequency range: VCO = 0 */ RCC_PLL1CFGR &= ~RCC_PLLCFGR_PLLVCOSEL; DMB(); /* Enable PLL1 system clock out (DIV: P) */ RCC_PLL1CFGR |= RCC_PLLCFGR_PLL1PEN; /* Enable PLL1 */ RCC_CR |= RCC_CR_PLL1ON; /* Set up APB3, 2, 1 and AHB prescalers */ hpre = RCC_AHB_PRESCALER_DIV_NONE; apb1pre = RCC_APB_PRESCALER_DIV_NONE; apb2pre = RCC_APB_PRESCALER_DIV_NONE; apb3pre = RCC_APB_PRESCALER_DIV_NONE; reg32 = RCC_CFGR2; reg32 &= ~( (0x0F << RCC_CFGR2_HPRE_SHIFT) | (0x07 << RCC_CFGR2_PPRE1_SHIFT) | (0x07 << RCC_CFGR2_PPRE2_SHIFT) | (0x07 << RCC_CFGR2_PPRE3_SHIFT)); reg32 |= ((hpre) << RCC_CFGR2_HPRE_SHIFT) | ((apb1pre) << RCC_CFGR2_PPRE1_SHIFT) | ((apb2pre) << RCC_CFGR2_PPRE2_SHIFT) | ((apb3pre) << RCC_CFGR2_PPRE3_SHIFT); RCC_CFGR2 = reg32; DMB(); /* Wait until PLL1 is Ready */ while ((RCC_CR & RCC_CR_PLL1RDY) == 0) ; /* Set PLL as clock source */ reg32 = RCC_CFGR1 & (~RCC_CFGR1_SW_MASK); RCC_CFGR1 = reg32 | RCC_CFGR1_SW_PLL1; DMB(); /* Wait until selection of PLL as source is complete */ while ((RCC_CFGR1 & (RCC_CFGR1_SW_PLL1 << RCC_CFGR1_SWS_SHIFT)) == 0) ; /* Set PLL1 as system clock */ RCC_PLL1CFGR |= RCC_PLLCFGR_PLL1PEN; } #if (TZ_SECURE()) #define NVIC_ISER_BASE (0xE000E100) #define NVIC_ICER_BASE (0xE000E180) #define NVIC_IPRI_BASE (0xE000E400) #define NVIC_USART3_IRQ 60 /* Cortex M-33 has an extra register to set up non-secure interrupts */ #define NVIC_ITNS_BASE (0xE000E380) static void periph_unsecure(void) { uint32_t pin; volatile uint32_t reg; volatile uint32_t *nvic_itns; uint32_t nvic_reg_pos, nvic_reg_off; /*Enable clock for User LED GPIOs */ RCC_AHB2_CLOCK_ER|= LED_AHB2_ENABLE; /* Enable GPIO clock for accessing SECCFGR registers */ RCC_AHB2_CLOCK_ER |= GPIOA_AHB2_CLOCK_ER; RCC_AHB2_CLOCK_ER |= GPIOB_AHB2_CLOCK_ER; RCC_AHB2_CLOCK_ER |= GPIOC_AHB2_CLOCK_ER; RCC_AHB2_CLOCK_ER |= GPIOD_AHB2_CLOCK_ER; /* Enable clock for LPUART1 */ RCC_APB2_CLOCK_ER |= UART1_APB2_CLOCK_ER_VAL; /* Enable clock for USART3 */ RCC_APB1L_CLOCK_ER |= UART3_APB1L_CLOCK_ER_VAL; PWR_CR2 |= PWR_CR2_IOSV; /*Un-secure User LED GPIO pins */ GPIO_SECCFGR(GPIOG_BASE) &= ~(1 << 4); GPIO_SECCFGR(GPIOB_BASE) &= ~(1 << 0); GPIO_SECCFGR(GPIOF_BASE) &= ~(1 << 4); /* Unsecure LPUART1 */ GPIO_SECCFGR(GPIOB_BASE) &= ~(1<> 31; hal_flash_clear_errors(0); hal_flash_unlock(); hal_flash_opt_unlock(); if (cur_opts) FLASH_OPTSR_PRG &= ~(FLASH_OPTSR_SWAP_BANK); else FLASH_OPTSR_PRG |= FLASH_OPTSR_SWAP_BANK; FLASH_OPTCR |= FLASH_OPTCR_OPTSTRT; DMB(); hal_flash_opt_lock(); hal_flash_lock(); stm32h5_reboot(); } #define BOOTLOADER_COPY_MEM_SIZE 0x1000 static uint8_t bootloader_copy_mem[BOOTLOADER_COPY_MEM_SIZE]; static void fork_bootloader(void) { uint32_t data = (uint32_t) FLASHMEM_ADDRESS_SPACE; uint32_t dst = FLASH_BANK2_BASE; uint32_t r = 0, w = 0; int i; #if TZ_SECURE() data = (uint32_t)((data & (~FLASHMEM_ADDRESS_SPACE)) | FLASH_SECURE_MMAP_BASE); dst = (uint32_t)((dst & (~FLASHMEM_ADDRESS_SPACE)) | FLASH_SECURE_MMAP_BASE); #endif /* Return if content already matches */ if (memcmp((void *)data, (const char*)dst, BOOTLOADER_SIZE) == 0) return; hal_flash_unlock(); /* Mass-erase second block */ hal_flash_erase(dst, BOOTLOADER_SIZE); /* Read the wolfBoot image in RAM */ for (i = 0; i < BOOTLOADER_SIZE; i += BOOTLOADER_COPY_MEM_SIZE) { memcpy(bootloader_copy_mem, (void*)(data + i), BOOTLOADER_COPY_MEM_SIZE); hal_flash_write(dst + i, bootloader_copy_mem, BOOTLOADER_COPY_MEM_SIZE); } hal_flash_lock(); } #endif #include "uart_drv.h" void hal_init(void) { clock_pll_on(); #if TZ_SECURE() hal_gtzc_init(); hal_tz_sau_init(); #endif #if defined(DUALBANK_SWAP) && defined(__WOLFBOOT) fork_bootloader(); #endif } void hal_prepare_boot(void) { /* Keep clock settings when staging a NS-application */ #if (TZ_SECURE()) periph_unsecure(); #else clock_pll_off(); #endif } #ifdef FLASH_OTP_KEYSTORE #define FLASH_OTP_BLOCK_SIZE (64) /* Public API */ int hal_flash_otp_set_readonly(uint32_t flashAddress, uint16_t length) { uint32_t start_block = (flashAddress - FLASH_OTP_BASE) / FLASH_OTP_BLOCK_SIZE; uint32_t count = length / FLASH_OTP_BLOCK_SIZE; uint32_t bmap = 0; unsigned int i; if (start_block + count > 32) return -1; if ((length % FLASH_OTP_BLOCK_SIZE) != 0) { count++; } /* Turn on the bits */ for (i = start_block; i < (start_block + count); i++) { bmap |= (1 << i); } /* Enable OTP write protection for the selected blocks */ while ((bmap & FLASH_OTPBLR_CUR) != bmap) { FLASH_OTPBLR_PRG |= bmap; ISB(); DSB(); } return 0; } int hal_flash_otp_write(uint32_t flashAddress, const void* data, uint16_t length) { volatile uint16_t tmp_msw, tmp_lsw; uint16_t *pdata = (uint16_t *)data; uint16_t idx = 0, len_align; uint16_t last_word; uint32_t blr_bitmap = 0; if (!(flashAddress >= FLASH_OTP_BASE && flashAddress <= FLASH_OTP_END)) { return -1; } /* Reject misaligned destination address */ if ((flashAddress & 0x01) != 0) { return -1; } hal_flash_wait_complete(0); hal_flash_wait_buffer_empty(0); hal_flash_unlock(); hal_flash_clear_errors(0); /* Truncate to 2B alignment */ length = (length / 2 * 2); while ((idx < length) && (flashAddress <= FLASH_OTP_END-1)) { hal_flash_wait_complete(0); /* Set PG bit */ FLASH_CR |= FLASH_CR_PG; /* Program an OTP word (16 bits) */ *(volatile uint16_t*)flashAddress = pdata[0]; /* Program a second OTP word (16 bits) */ *(volatile uint16_t*)(flashAddress + sizeof(uint16_t)) = pdata[1]; ISB(); DSB(); /* Wait until not busy */ while ((FLASH_SR & FLASH_SR_BSY) != 0) ; /* Read it back */ tmp_msw = *(volatile uint16_t*)flashAddress; tmp_lsw = *(volatile uint16_t*)(flashAddress + sizeof(uint16_t)); if ((tmp_msw != pdata[0]) || (tmp_lsw != pdata[1])) { /* Provisioning failed. OTP already programmed? */ while(1) ; } /* Clear PG bit */ FLASH_CR &= ~FLASH_CR_PG; /* Advance to next two words */ flashAddress += (2 * sizeof(uint16_t)); pdata += 2; idx += (2 * sizeof(uint16_t)); } hal_flash_lock(); return 0; } int hal_flash_otp_read(uint32_t flashAddress, void* data, uint32_t length) { uint16_t i; uint16_t *pdata = (uint16_t *)data; if (!(flashAddress >= FLASH_OTP_BASE && flashAddress <= FLASH_OTP_END)) { return -1; } for (i = 0; (i < length) && (flashAddress <= (FLASH_OTP_END-1)); i += sizeof(uint16_t)) { *pdata = *(volatile uint16_t*)flashAddress; flashAddress += sizeof(uint16_t); pdata++; } return 0; } #endif /* FLASH_OTP_KEYSTORE */