STM32L4: Add workaround of data cache corruption on RWW.

Author: Gregory Nutt <gnutt@nuttx.org>

    Run .c modified by the PR through tools/nxstyle and correct all reporting coding style problems noted in the file.

Author: Satoshi Togawa <togawa@develcb210.centurysys.co.jp>

    STM32L4: Add workaround of data cache corruption on RWW.

    Some STM32L4 chips has eratta "Data cache might be corrupted during Flash Read While Write operation". This is also in STM32, and arch/arm/src/stm32/stm32f20xxf40xx_flash.c has workaround.

    To enable this workaround, define CONFIG_STM32L4_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW.
This commit is contained in:
Satoshi Togawa 2020-01-26 08:57:12 -06:00 committed by Gregory Nutt
parent cf756061f4
commit 705ac84432
2 changed files with 67 additions and 21 deletions

View File

@ -1657,6 +1657,15 @@ config STM32L4_FLASH_PREFETCH
---help---
Enable FLASH prefetch
config STM32L4_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW
bool "Workaround for FLASH data cache corruption"
default n
depends on STM32L4_STM32L475XX || STM32L4_STM32L476XX || STM32L4_STM32L486XX || STM32L4_STM32L496XX || STM32L4_STM32L4A6XX
---help---
Enable the workaround to fix flash data cache corruption when reading
from one flash bank while writing on other flash bank. See your STM32
errata to check if your STM32 is affected by this problem.
config STM32L4_DISABLE_IDLE_SLEEP_DURING_DEBUG
bool "Disable IDLE Sleep (WFI) in debug mode"
default n

View File

@ -1,4 +1,4 @@
/************************************************************************************
/****************************************************************************
* arch/arm/src/stm32l4/stm32l4_flash.c
*
* Copyright (C) 2011 Uros Platise. All rights reserved.
@ -33,10 +33,10 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
************************************************************************************/
****************************************************************************/
/* Provides standard flash access functions, to be used by the flash mtd driver.
* The interface is defined in the include/nuttx/progmem.h
/* 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
@ -44,9 +44,9 @@
* - Low Power Modes are not permitted during write/erase
*/
/************************************************************************************
/****************************************************************************
* Included Files
************************************************************************************/
****************************************************************************/
#include <nuttx/config.h>
#include <nuttx/arch.h>
@ -72,9 +72,9 @@
# warning "Flash Configuration has been overridden - make sure it is correct"
#endif
/************************************************************************************
/****************************************************************************
* Pre-processor Definitions
************************************************************************************/
****************************************************************************/
#define FLASH_KEY1 0x45670123
#define FLASH_KEY2 0xCDEF89AB
@ -107,16 +107,16 @@
# define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
/************************************************************************************
/****************************************************************************
* Private Data
************************************************************************************/
****************************************************************************/
static sem_t g_sem = SEM_INITIALIZER(1);
static uint32_t g_page_buffer[FLASH_PAGE_WORDS];
/************************************************************************************
/****************************************************************************
* Private Functions
************************************************************************************/
****************************************************************************/
static inline void sem_lock(void)
{
@ -187,9 +187,27 @@ static inline void flash_erase(size_t page)
modifyreg32(STM32L4_FLASH_CR, FLASH_CR_PAGE_ERASE, 0);
}
/************************************************************************************
#if defined(CONFIG_STM32L4_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW)
static void data_cache_disable(void)
{
modifyreg32(STM32L4_FLASH_ACR, FLASH_ACR_DCEN, 0);
}
static void data_cache_enable(void)
{
/* Reset data cache */
modifyreg32(STM32L4_FLASH_ACR, 0, FLASH_ACR_DCRST);
/* Enable data cache */
modifyreg32(STM32L4_FLASH_ACR, 0, FLASH_ACR_DCEN);
}
#endif /* defined(CONFIG_STM32L4_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) */
/****************************************************************************
* Public Functions
************************************************************************************/
****************************************************************************/
void stm32l4_flash_unlock(void)
{
@ -370,6 +388,7 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t buflen)
size_t xfrsize;
size_t offset;
size_t page;
bool set_pg_bit = false;
int i;
int ret = OK;
@ -447,7 +466,12 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t buflen)
/* Write the page. Must be with double-words. */
#if defined(CONFIG_STM32L4_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW)
data_cache_disable();
#endif
modifyreg32(STM32L4_FLASH_CR, 0, FLASH_CR_PG);
set_pg_bit = true;
for (i = 0; i < FLASH_PAGE_WORDS; i += 2)
{
@ -463,20 +487,24 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t buflen)
if (getreg32(STM32L4_FLASH_SR) & FLASH_SR_WRITE_PROTECTION_ERROR)
{
modifyreg32(STM32L4_FLASH_CR, FLASH_CR_PG, 0);
ret = -EROFS;
goto out;
}
if (getreg32(dest-1) != *(src-1) || getreg32(dest-2) != *(src-2))
if (getreg32(dest -1) != *(src - 1) ||
getreg32(dest - 2) != *(src - 2))
{
modifyreg32(STM32L4_FLASH_CR, FLASH_CR_PG, 0);
ret = -EIO;
goto out;
}
}
modifyreg32(STM32L4_FLASH_CR, FLASH_CR_PG, 0);
set_pg_bit = false;
#if defined(CONFIG_STM32L4_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW)
data_cache_enable();
#endif
/* Adjust pointers and counts for the next time through the loop */
@ -489,14 +517,23 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t buflen)
}
out:
/* If there was an error, clear all error flags in status
* register (rc_w1 register so do this by writing the
* error bits).
if (set_pg_bit)
{
modifyreg32(STM32L4_FLASH_CR, FLASH_CR_PG, 0);
#if defined(CONFIG_STM32L4_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%x\n", ret, getreg32(STM32L4_FLASH_SR));
ferr("flash write error: %d, status: 0x%x\n",
ret, getreg32(STM32L4_FLASH_SR));
modifyreg32(STM32L4_FLASH_SR, 0, FLASH_SR_ALLERRS);
}