diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index 7196278c78536..9d5c74fc8c921 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -1279,6 +1279,13 @@ config STM32_FLASH_CONFIG_I endchoice +config STM32_PROGMEM + bool "Flash progmem support" + default n + ---help--- + Add progmem support, start block and end block options are provided to + obtain an uniform flash memory mapping. + # This is really 15XX/16XX, but we treat the two the same. config STM32_STM32L15XX bool diff --git a/arch/arm/src/stm32/hardware/stm32_flash.h b/arch/arm/src/stm32/hardware/stm32_flash.h index 2e2b02fd25217..f0774ac8ed30d 100644 --- a/arch/arm/src/stm32/hardware/stm32_flash.h +++ b/arch/arm/src/stm32/hardware/stm32_flash.h @@ -178,17 +178,37 @@ /* Define the Valid Configuration the G4 */ # elif defined(CONFIG_STM32_STM32G4XXX) -# if defined(CONFIG_STM32_FLASH_CONFIG_B) -# define STM32_FLASH_NPAGES 32 -# define STM32_FLASH_PAGESIZE 4096 - -# elif defined(CONFIG_STM32_FLASH_CONFIG_C) -# define STM32_FLASH_NPAGES 64 -# define STM32_FLASH_PAGESIZE 4096 - -# elif defined(CONFIG_STM32_FLASH_CONFIG_E) -# define STM32_FLASH_NPAGES 128 -# define STM32_FLASH_PAGESIZE 4096 +# if defined(CONFIG_STM32_STM32G43XX) +# if defined(CONFIG_STM32_FLASH_CONFIG_6) +# define STM32_FLASH_NPAGES 16 +# define STM32_FLASH_PAGESIZE 2048 + +# elif defined(CONFIG_STM32_FLASH_CONFIG_8) +# define STM32_FLASH_NPAGES 32 +# define STM32_FLASH_PAGESIZE 2048 + +# elif defined(CONFIG_STM32_FLASH_CONFIG_B) +# define STM32_FLASH_NPAGES 64 +# define STM32_FLASH_PAGESIZE 2048 +# endif +# elif defined(CONFIG_STM32_STM32G47XX) || defined(CONFIG_STM32_STM32G48XX) +# if defined(CONFIG_STM32_FLASH_CONFIG_B) +# define STM32_FLASH_SIZE 32 * 4096 + +# elif defined(CONFIG_STM32_FLASH_CONFIG_C) +# define STM32_FLASH_SIZE 64 * 4096 + +# elif defined(CONFIG_STM32_FLASH_CONFIG_E) +# define STM32_FLASH_SIZE 128 * 4096 +# endif +# elif defined(CONFIG_STM32_STM32G49XX) +# elif defined(CONFIG_STM32_FLASH_CONFIG_C) +# define STM32_FLASH_NPAGES 128 +# define STM32_FLASH_PAGESIZE 2048 + +# elif defined(CONFIG_STM32_FLASH_CONFIG_E) +# define STM32_FLASH_NPAGES 256 +# define STM32_FLASH_PAGESIZE 2048 # endif /* Define the Valid Configuration the F1 and F3 */ @@ -261,7 +281,7 @@ #elif defined(CONFIG_STM32_STM32G4XXX) # define STM32_FLASH_PDKEYR_OFFSET 0x0004 # define STM32_FLASH_KEYR_OFFSET 0x0008 -# define STM32_FLASH_OPT_KEYR_OFFSET 0x000c +# define STM32_FLASH_OPTKEYR_OFFSET 0x000c # define STM32_FLASH_SR_OFFSET 0x0010 # define STM32_FLASH_CR_OFFSET 0x0014 # define STM32_FLASH_ECCR_OFFSET 0x0018 @@ -324,7 +344,7 @@ #elif defined(CONFIG_STM32_STM32G4XXX) # define STM32_FLASH_PDKEYR (STM32_FLASHIF_BASE+STM32_FLASH_PDKEYR_OFFSET) # define STM32_FLASH_KEYR (STM32_FLASHIF_BASE+STM32_FLASH_KEYR_OFFSET) -# define STM32_FLASH_OPT_KEYR (STM32_FLASHIF_BASE+STM32_FLASH_OPT_KEYR_OFFSET) +# define STM32_FLASH_OPTKEYR (STM32_FLASHIF_BASE+STM32_FLASH_OPTKEYR_OFFSET) # define STM32_FLASH_SR (STM32_FLASHIF_BASE+STM32_FLASH_SR_OFFSET) # define STM32_FLASH_CR (STM32_FLASHIF_BASE+STM32_FLASH_CR_OFFSET) # define STM32_FLASH_ECCR (STM32_FLASHIF_BASE+STM32_FLASH_ECCR_OFFSET) @@ -538,10 +558,18 @@ # define FLASH_CR_PER (1 << 1) # define FLASH_CR_MER1 (1 << 2) # define FLASH_CR_PNB_SHIFT (3) -# define FLASH_CR_PNB_MASK (0x7f << FLASH_CR_PNB_SHIFT) +# if defined(CONFIG_STM32_STM32G43XX) +# define FLASH_CR_PNB_MASK (0x3f << FLASH_CR_PNB_SHIFT) +# elif defined(CONFIG_STM32_STM32G47XX) || defined (CONFIG_STM32_STM32G48XX) +# define FLASH_CR_PNB_MASK (0x7f << FLASH_CR_PNB_SHIFT) +# elif defined(CONFIG_STM32_STM32G49XX) +# define FLASH_CR_PNB_MASK (0xff << FLASH_CR_PNB_SHIFT) +# endif # define FLASH_CR_PNB(n) (((n) << FLASH_CR_PNB_SHIFT) & FLASH_CR_PNB_MASK) -# define FLASH_CR_BKER (1 << 11) -# define FLASH_CR_MER2 (1 << 15) +# if defined(CONFIG_STM32_STM32G47XX) || defined (CONFIG_STM32_STM32G48XX) +# define FLASH_CR_BKER (1 << 11) +# define FLASH_CR_MER2 (1 << 15) +# endif # define FLASH_CR_START (1 << 16) # define FLASH_CR_OPTSTRT (1 << 17) # define FLASH_CR_FSTPG (1 << 18) @@ -550,7 +578,9 @@ # define FLASH_CR_RDERRIE (1 << 26) # define FLASH_CR_OBL_LAUNCH (1 << 27) # define FLASH_CR_SEC_PROT1 (1 << 28) -# define FLASH_CR_SEC_PROT2 (1 << 29) +# if defined(CONFIG_STM32_STM32G47XX) || defined (CONFIG_STM32_STM32G48XX) +# define FLASH_CR_SEC_PROT2 (1 << 29) +# endif # define FLASH_CR_OPTLOCK (1 << 30) # define FLASH_CR_LOCK (1 << 31) #endif @@ -568,8 +598,10 @@ # define FLASH_ECCR_BK_ECC (1 << 21) # define FLASH_ECCR_SYSF_ECC (1 << 22) # define FLASH_ECCR_ECCIE (1 << 24) -# define FLASH_ECCR_ECCC2 (1 << 28) -# define FLASH_ECCR_ECCD2 (1 << 29) +# if defined(CONFIG_STM32_STM32G47XX) || defined (CONFIG_STM32_STM32G48XX) +# define FLASH_ECCR_ECCC2 (1 << 28) +# define FLASH_ECCR_ECCD2 (1 << 29) +# endif # define FLASH_ECCR_ECCC (1 << 30) # define FLASH_ECCR_ECCD (1 << 31) #endif @@ -633,7 +665,11 @@ # define FLASH_OPTR_IWDG_STDBY (1 << 18) # define FLASH_OPTR_WWDG_SW (1 << 19) # define FLASH_OPTR_BFB2 (1 << 20) -# define FLASH_OPTR_DBANK (1 << 22) +# if defined(CONFIG_STM32_STM32G47XX) || defined (CONFIG_STM32_STM32G48XX) +# define FLASH_OPTR_DBANK (1 << 22) +# elif defined (CONFIG_STM32_STM32G49XX) +# define FLASH_OPTR_PB4_PUPEN (1 << 22) +# endif # define FLASH_OPTR_NBOOT1 (1 << 23) # define FLASH_OPTR_SRAM_PE (1 << 24) # define FLASH_OPTR_CCMSRAM_RST (1 << 25) diff --git a/arch/arm/src/stm32/stm32_flash.c b/arch/arm/src/stm32/stm32_flash.c index b9c0a40a0dab5..2a49f5f56c8e7 100644 --- a/arch/arm/src/stm32/stm32_flash.c +++ b/arch/arm/src/stm32/stm32_flash.c @@ -36,6 +36,8 @@ # include "stm32f10xxf30xx_flash.c" #elif defined(CONFIG_STM32_STM32F20XX) || defined (CONFIG_STM32_STM32F4XXX) # include "stm32f20xxf40xx_flash.c" +#elif defined(CONFIG_STM32_STM32G4XXX) +# include "stm32g4xxx_flash.c" #else # warning "No FLASH support for the selected part" #endif diff --git a/arch/arm/src/stm32/stm32_flash.h b/arch/arm/src/stm32/stm32_flash.h index 030990db71361..8477cece6562a 100644 --- a/arch/arm/src/stm32/stm32_flash.h +++ b/arch/arm/src/stm32/stm32_flash.h @@ -35,6 +35,28 @@ * Public Function Prototypes ****************************************************************************/ +int stm32_flash_lock(void); +int stm32_flash_unlock(void); + +/**************************************************************************** + * Name: stm32_flash_user_optbytes + * + * Description: + * Modify the contents of the user option bytes (USR OPT) on the flash. + * This does not set OBL_LAUNCH so new options take effect only after + * next power reset. + * + * Input Parameters: + * clrbits - Bits in the option bytes to be cleared + * setbits - Bits in the option bytes to be set + * + * Returned Value: + * Option bytes after operation is completed + * + ****************************************************************************/ + +uint32_t stm32_flash_users_optbytes(uint32_t clrbits, uint32_t setbits); + /**************************************************************************** * Name: stm32_eeprom_size * diff --git a/arch/arm/src/stm32/stm32g4xxx_flash.c b/arch/arm/src/stm32/stm32g4xxx_flash.c new file mode 100644 index 0000000000000..67a8b11978376 --- /dev/null +++ b/arch/arm/src/stm32/stm32g4xxx_flash.c @@ -0,0 +1,619 @@ +/**************************************************************************** + * arch/arm/src/stm32/stm32g4xxx_flash.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* Provides standard flash access functions, to be used by the flash mtd + * driver. The interface is defined in the include/nuttx/progmem.h + * + * Notes about this implementation: + * - HSI16 is automatically turned ON by MCU, if not enabled beforehand + * - Only Standard Programming is supported, no Fast Programming. + * - Low Power Modes are not permitted during write/erase + */ + +/* Differences vs STM32L4 (used as template): + * 1. FLASH_CR - Bits (29:28) (SEC_PROT2, SEC_PROT1) added. + * 2. FLASH_ECCR - Bits (29:28) (ECCD2, ECCC2) added. + * Note: Bits are set by hardware. Nothing to do + * 3. FLASH_OPTR - + * a. DUALBANK moved from bit 21 to 22. + * b. NRST_MODE added - Bits 29:28 + * c. IRHEN added - Bit 30 + * 4. FLASH_SEC1R - (New) Secure Area Bank 1 Register + * a. BOOT_LOCK - Forces boot from user flash area + * b. SEC_SIZE1[7:0] - Starts at 0x80000000, size = SEC_SIZE1 * page_size + * 5. FLASH_SEC2R - (New) Secure Area Bank 2 Register + * a. BOOT_LOCK - Forces boot from user flash area + * b. SEC_SIZE1[7:0] - Starts at 0x80000000, size = SEC_SIZE1 * page_size + * 6. FLASH_PAGE_SIZE - The page size of the STM32G47XX and STM32G48XX + * is dependent on the DBANK bit. If Dual Banks are used, the page size + * is 2K. If a single bank is used, the page size is 4K. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "stm32_rcc.h" +#include "stm32_waste.h" +#include "stm32_flash.h" +#include "arm_internal.h" + +#if !(defined(CONFIG_STM32_STM32G43XX) || defined(CONFIG_STM32_STM32G47XX) || \ + defined(CONFIG_STM32_STM32G48XX) || defined(CONFIG_STM32_STM32G49XX)) +# error "Unrecognized STM32 chip" +#endif + +#if !defined(CONFIG_STM32_FLASH_CONFIG_DEFAULT) +# warning "Flash Configuration has been overridden - make sure it is correct" +#endif + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define FLASH_KEY1 0x45670123 +#define FLASH_KEY2 0xCDEF89AB +#define FLASH_ERASEDVALUE 0xffu + +#define OPTBYTES_KEY1 0x08192A3B +#define OPTBYTES_KEY2 0x4C5D6E7F + +#define FLASH_CR_PAGE_ERASE FLASH_CR_PER +#define FLASH_SR_WRITE_PROTECTION_ERROR FLASH_SR_WRPERR + +/* All errors for Standard Programming, not for other operations. */ + +#define FLASH_SR_ALLERRS (FLASH_SR_PGSERR | FLASH_SR_SIZERR | \ + FLASH_SR_PGAERR | FLASH_SR_WRPERR | \ + FLASH_SR_PROGERR) + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static mutex_t g_lock = NXMUTEX_INITIALIZER; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static uint32_t get_flash_page_size(void) +{ +#if defined(CONFIG_STM32_STM32G47XX) || defined(CONFIG_STM32_STM32G48XX) + if (getreg32(STM32_FLASH_OPTR) & FLASH_OPTR_DBANK) + { + return 2048; + } + else + { + return 4096; + } +#else + return STM32_FLASH_PAGESIZE; +#endif +} + +static uint32_t get_flash_npages(void) +{ +#if defined(CONFIG_STM32_STM32G47XX) || defined(CONFIG_STM32_STM32G48XX) + if (getreg32(STM32_FLASH_OPTR) & FLASH_OPTR_DBANK) + { + return STM32_FLASH_SIZE / 2048; + } + else + { + return STM32_FLASH_SIZE / 4096; + } +#else + return STM32_FLASH_NPAGES; +#endif +} + +static void flash_unlock(void) +{ + while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY) + { + stm32_waste(); + } + + if (getreg32(STM32_FLASH_CR) & FLASH_CR_LOCK) + { + /* Unlock sequence */ + + putreg32(FLASH_KEY1, STM32_FLASH_KEYR); + putreg32(FLASH_KEY2, STM32_FLASH_KEYR); + } +} + +static void flash_lock(void) +{ + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_LOCK); +} + +static void flash_optbytes_unlock(void) +{ + flash_unlock(); + + if (getreg32(STM32_FLASH_CR) & FLASH_CR_OPTLOCK) + { + /* Unlock Option Bytes sequence */ + + putreg32(OPTBYTES_KEY1, STM32_FLASH_OPTKEYR); + putreg32(OPTBYTES_KEY2, STM32_FLASH_OPTKEYR); + } +} + +static inline void flash_optbytes_lock(void) +{ + /* We don't need to set OPTLOCK here as it is automatically + * set by MCU when flash_lock() sets LOCK. + */ + + flash_lock(); +} + +static inline void flash_erase(size_t page) +{ + finfo("erase page %u\n", page); + + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_PAGE_ERASE); + + /* DBANK=0, Page range 0 to 128 + * DBANK=1, Page range 0 to 255 + */ + + modifyreg32(STM32_FLASH_CR, FLASH_CR_PNB_MASK, + FLASH_CR_PNB(page)); + +#if (defined(CONFIG_STM32_STM32G47XX) || \ + defined(CONFIG_STM32_STM32G48XX)) + + if (getreg32(STM32_FLASH_OPTR) & FLASH_OPTR_DBANK) + { + if (page <= 0x7f) + { + /* Select bank 1 */ + + modifyreg32(STM32_FLASH_CR, FLASH_CR_BKER, 0); + } + else + { + /* Select bank 2 */ + + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_BKER); + } + } +#endif + + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_START); + + while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY) + { + stm32_waste(); + } + + modifyreg32(STM32_FLASH_CR, FLASH_CR_PAGE_ERASE, 0); +} + +#if defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) +static void data_cache_disable(void) +{ + modifyreg32(STM32_FLASH_ACR, FLASH_ACR_DCEN, 0); +} + +static void data_cache_enable(void) +{ + /* Reset data cache */ + + modifyreg32(STM32_FLASH_ACR, 0, FLASH_ACR_DCRST); + + /* Enable data cache */ + + modifyreg32(STM32_FLASH_ACR, 0, FLASH_ACR_DCEN); +} +#endif /* defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) */ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +int stm32_flash_unlock(void) +{ + int ret; + + ret = nxmutex_lock(&g_lock); + if (ret < 0) + { + return ret; + } + + flash_unlock(); + nxmutex_unlock(&g_lock); + + return ret; +} + +int stm32_flash_lock(void) +{ + int ret; + + ret = nxmutex_lock(&g_lock); + if (ret < 0) + { + return ret; + } + + flash_lock(); + nxmutex_unlock(&g_lock); + + return ret; +} + +uint32_t stm32_flash_user_optbytes(uint32_t clrbits, uint32_t setbits) +{ + uint32_t regval; + int ret; + + /* To avoid accidents, do not allow setting RDP via this function. + * Remove these asserts if want to enable changing the protection level. + * WARNING: level 2 protection is permanent! + */ + + DEBUGASSERT((clrbits & FLASH_OPTR_RDP_MASK) == 0); + DEBUGASSERT((setbits & FLASH_OPTR_RDP_MASK) == 0); + + ret = nxmutex_lock(&g_lock); + if (ret < 0) + { + return 0; + } + + flash_optbytes_unlock(); + + /* Modify Option Bytes in register. */ + + regval = getreg32(STM32_FLASH_OPTR); + + finfo("Flash option bytes before: 0x%" PRIx32 "\n", regval); + + regval = (regval & ~clrbits) | setbits; + + putreg32(regval, STM32_FLASH_OPTR); + + finfo("Flash option bytes after: 0x%" PRIx32 "\n", regval); + + /* Start Option Bytes programming and wait for completion. */ + + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_OPTSTRT); + + while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY) + { + stm32_waste(); + } + + flash_optbytes_lock(); + nxmutex_unlock(&g_lock); + + return regval; +} + +size_t up_progmem_pagesize(size_t page) +{ + return get_flash_page_size(); +} + +size_t up_progmem_erasesize(size_t block) +{ + return get_flash_page_size(); +} + +ssize_t up_progmem_getpage(size_t addr) +{ + if (addr >= STM32_FLASH_BASE) + { + addr -= STM32_FLASH_BASE; + } + + if (addr >= STM32_FLASH_SIZE) + { + return -EFAULT; + } + + return addr / get_flash_page_size(); +} + +size_t up_progmem_getaddress(size_t page) +{ + if (page >= get_flash_npages()) + { + return SIZE_MAX; + } + + return page * get_flash_page_size() + STM32_FLASH_BASE; +} + +size_t up_progmem_neraseblocks(void) +{ + return get_flash_npages(); +} + +bool up_progmem_isuniform(void) +{ + return true; +} + +ssize_t up_progmem_eraseblock(size_t block) +{ + int ret; + + if (block >= get_flash_npages()) + { + return -EFAULT; + } + + /* Erase single block */ + + ret = nxmutex_lock(&g_lock); + if (ret < 0) + { + return (ssize_t)ret; + } + + flash_unlock(); + + flash_erase(block); + + flash_lock(); + nxmutex_unlock(&g_lock); + + /* Verify */ + + if (up_progmem_ispageerased(block) == 0) + { + return up_progmem_erasesize(block); + } + else + { + return -EIO; + } +} + +ssize_t up_progmem_ispageerased(size_t page) +{ + size_t addr; + size_t count; + size_t bwritten = 0; + + if (page >= get_flash_npages()) + { + return -EFAULT; + } + + /* Verify */ + + for (addr = up_progmem_getaddress(page), count = up_progmem_pagesize(page); + count; count--, addr++) + { + if (getreg8(addr) != FLASH_ERASEDVALUE) + { + bwritten++; + } + } + + return bwritten; +} + +ssize_t up_progmem_write(size_t addr, const void *buf, size_t buflen) +{ + uint32_t *dest; + const uint32_t *src; + size_t written; + size_t xfrsize; + size_t offset; + size_t page; + bool set_pg_bit = false; + int i; + int ret = OK; + const uint32_t flash_page_size = get_flash_page_size(); + const uint32_t flash_page_words = flash_page_size / 4; + const uint32_t flash_page_mask = flash_page_size - 1; + uint32_t *page_buffer = NULL; + + /* Check for valid address range. */ + + offset = addr; + if (addr >= STM32_FLASH_BASE) + { + offset -= STM32_FLASH_BASE; + } + + if (offset + buflen > STM32_FLASH_SIZE) + { + return -EFAULT; + } + + /* Get the page number corresponding to the flash offset and the byte + * offset into the page. Align write destination to page boundary. + */ + + if (flash_page_size == 2048) + { + page = ((uint32_t)offset >> 11); + } + else if (flash_page_size == 4096) + { + page = ((uint32_t)offset >> 12); + } + + offset &= flash_page_mask; + + dest = (uint32_t *)((uint8_t *)addr - offset); + written = 0; + + ret = nxmutex_lock(&g_lock); + if (ret < 0) + { + return (ssize_t)ret; + } + + /* Get flash ready and begin flashing. */ + + flash_unlock(); + + /* Loop until all of the data has been written */ + + while (buflen > 0) + { + /* How much can we write into this page? */ + + xfrsize = MIN((size_t) flash_page_size - offset, buflen); + + /* Do we need to use the intermediate buffer? */ + + if (offset == 0 && xfrsize == flash_page_size) + { + /* No, we can take the data directly from the user buffer */ + + src = (const uint32_t *)buf; + } + else + { + /* Yes, copy data into the page buffer */ + + page_buffer = malloc(flash_page_size); + + if (offset > 0) + { + memcpy(page_buffer, dest, offset); + } + + memcpy((uint8_t *)page_buffer + offset, buf, xfrsize); + + if (offset + xfrsize < flash_page_size) + { + memcpy((uint8_t *)page_buffer + offset + xfrsize, + (const uint8_t *)dest + offset + xfrsize, + flash_page_size - offset - xfrsize); + } + + src = page_buffer; + } + + /* Erase the page. Unlike most flash chips, STM32 is unable to + * write back existing data read from page without erase. + */ + + flash_erase(page); + + /* Write the page. Must be with double-words. */ + +#if defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) + data_cache_disable(); +#endif + + modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_PG); + set_pg_bit = true; + + for (i = 0; i < flash_page_words; i += 2) + { + *dest++ = *src++; + *dest++ = *src++; + + while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY) + { + stm32_waste(); + } + + /* Verify */ + + if (getreg32(STM32_FLASH_SR) & FLASH_SR_WRITE_PROTECTION_ERROR) + { + ret = -EROFS; + goto out; + } + + if (getreg32(dest -1) != *(src - 1) || + getreg32(dest - 2) != *(src - 2)) + { + ret = -EIO; + goto out; + } + } + + modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0); + set_pg_bit = false; + +#if defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) + data_cache_enable(); +#endif + + /* Adjust pointers and counts for the next time through the loop */ + + written += xfrsize; + addr += xfrsize; + dest = (uint32_t *)addr; + buf = (void *)((uintptr_t)buf + xfrsize); + buflen -= xfrsize; + page++; + } + +out: + if (set_pg_bit) + { + modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0); +#if defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) + data_cache_enable(); +#endif + } + + /* If there was an error, clear all error flags in status register (rc_w1 + * register so do this by writing the error bits). + */ + + if (ret != OK) + { + ferr("flash write error: %d, status: 0x%" PRIx32 "\n", + ret, getreg32(STM32_FLASH_SR)); + + modifyreg32(STM32_FLASH_SR, 0, FLASH_SR_ALLERRS); + } + + free(page_buffer); + flash_lock(); + nxmutex_unlock(&g_lock); + return (ret == OK) ? written : ret; +} + +uint8_t up_progmem_erasestate(void) +{ + return FLASH_ERASEDVALUE; +} diff --git a/boards/arm/stm32/nucleo-g474re/configs/lpuartnsh/defconfig b/boards/arm/stm32/nucleo-g474re/configs/lpuartnsh/defconfig index 65b7c91e6e489..d9c2a762d2c28 100644 --- a/boards/arm/stm32/nucleo-g474re/configs/lpuartnsh/defconfig +++ b/boards/arm/stm32/nucleo-g474re/configs/lpuartnsh/defconfig @@ -39,6 +39,7 @@ CONFIG_SCHED_WAITPID=y CONFIG_STM32_DMA1=y CONFIG_STM32_DMA2=y CONFIG_STM32_DMAMUX1=y +CONFIG_STM32_FLASH_CONFIG_E=y CONFIG_STM32_LPUART1=y CONFIG_STM32_USART3=y CONFIG_SYSTEM_NSH=y