Backport:stm32_flash changes from upsteam

PX4 contrib from <jose.souza@intel.com>

  1) stm32: Fix erase sector number for microcontrolers with
     more than 11 sectors

     Erase a sector from the second bank cause the bit 4 of SNB being set
     but never unsed, so trying to erase a sector from the first bank
     was acually eraseing a sector from the second bank.
  2) stm32: Make up_progmem thread safe

   Writing to a flash sector while starting the erase of other sector
   have a undefined behavior so lets add a [staticaly initalized]
   semaphore and syncronize access to Flash registers.

  3) Add workaround for flash data cache corruption on
     read-while-write

    This is a know hardware issue on some STM32 see the errata
    of your model and if you make use of both memory banks you
    should enable it.

  4) Greg's cleanup

  5) PX4 clean up

    stm32_flash:Need conditional on non F4 targets
This commit is contained in:
David Sidrane
2017-03-23 14:55:30 -10:00
committed by Julian Oes
parent 8810f70fdc
commit 5c6264ae35
3 changed files with 216 additions and 119 deletions
@@ -0,0 +1,216 @@
diff --git NuttX/nuttx/arch/arm/src/stm32/Kconfig NuttX/nuttx/arch/arm/src/stm32/Kconfig
index b6c0458..8ebf8df 100644
--- NuttX/nuttx/arch/arm/src/stm32/Kconfig
+++ NuttX/nuttx/arch/arm/src/stm32/Kconfig
@@ -2514,6 +2514,14 @@ config STM32_FLASH_PREFETCH
on F1 parts). Some early revisions of F4 parts do not support FLASH pre-fetch
properly and enabling this option may interfere with ADC accuracy.
+config STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW
+ bool "Workaround for FLASH data cache corruption"
+ default n
+ ---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.
+
choice
prompt "JTAG Configuration"
default STM32_JTAG_DISABLE
diff --git NuttX/nuttx/arch/arm/src/stm32/chip/stm32_flash.h NuttX/nuttx/arch/arm/src/stm32/chip/stm32_flash.h
index 70e6d62..82d8f09 100644
--- NuttX/nuttx/arch/arm/src/stm32/chip/stm32_flash.h
+++ NuttX/nuttx/arch/arm/src/stm32/chip/stm32_flash.h
@@ -322,10 +322,11 @@
# define FLASH_CR_SER (1 << 1) /* Bit 1: Sector Erase */
# define FLASH_CR_MER (1 << 2) /* Bit 2: Mass Erase sectors 0..11 */
# define FLASH_CR_SNB_SHIFT (3) /* Bits 3-6: Sector number */
-# define FLASH_CR_SNB_MASK (15 << FLASH_CR_SNB_SHIFT)
#if defined(CONFIG_STM32_STM32F427) || defined(CONFIG_STM32_STM32F429)
+# define FLASH_CR_SNB_MASK (31 << FLASH_CR_SNB_SHIFT)
# define FLASH_CR_SNB(n) (((n % 12) << FLASH_CR_SNB_SHIFT) | ((n / 12) << 7)) /* Sector n, n=0..23 */
#else
+# define FLASH_CR_SNB_MASK (15 << FLASH_CR_SNB_SHIFT)
# define FLASH_CR_SNB(n) ((n) << FLASH_CR_SNB_SHIFT) /* Sector n, n=0..11 */
#endif
# define FLASH_CR_PSIZE_SHIFT (8) /* Bits 8-9: Program size */
diff --git NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c
index 73f1419..3b4ebd8 100644
--- NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c
+++ NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c
@@ -47,6 +47,10 @@
#include <nuttx/config.h>
#include <nuttx/arch.h>
+
+#include <stdbool.h>
+#include <semaphore.h>
+#include <assert.h>
#include <errno.h>
#include "stm32_flash.h"
@@ -81,13 +85,29 @@
#endif
/************************************************************************************
- * Private Functions
+ * Private Data
************************************************************************************/
+static sem_t g_sem = SEM_INITIALIZER(1);
+
/************************************************************************************
- * Public Functions
+ * Private Functions
************************************************************************************/
-void stm32_flash_unlock(void)
+
+static void sem_lock(void)
+{
+ while (sem_wait(&g_sem) < 0)
+ {
+ DEBUGASSERT(errno == EINTR);
+ }
+}
+
+static inline void sem_unlock(void)
+{
+ sem_post(&g_sem);
+}
+
+static void flash_unlock(void)
{
while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY)
{
@@ -103,14 +123,48 @@ void stm32_flash_unlock(void)
}
}
-void stm32_flash_lock(void)
+static void flash_lock(void)
{
modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_LOCK);
}
+#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);
+}
-#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX)
+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
+
+/************************************************************************************
+ * Public Functions
+ ************************************************************************************/
+
+void stm32_flash_unlock(void)
+{
+ sem_lock();
+ flash_unlock();
+ sem_unlock();
+}
+
+void stm32_flash_lock(void)
+{
+ sem_lock();
+ flash_lock();
+ sem_unlock();
+}
+
+#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX)
size_t up_progmem_pagesize(size_t page)
{
return STM32_FLASH_PAGESIZE;
@@ -231,14 +285,18 @@ ssize_t up_progmem_erasepage(size_t page)
return -EFAULT;
}
- /* Get flash ready and begin erasing single page */
+ sem_lock();
+#if !defined(CONFIG_STM32_STM32F40XX)
if (!(getreg32(STM32_RCC_CR) & RCC_CR_HSION))
{
return -EPERM;
}
+#endif
+
+ /* Get flash ready and begin erasing single page */
- stm32_flash_unlock();
+ flash_unlock();
modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_PAGE_ERASE);
@@ -257,6 +315,7 @@ ssize_t up_progmem_erasepage(size_t page)
while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY) up_waste();
modifyreg32(STM32_FLASH_CR, FLASH_CR_PAGE_ERASE, 0);
+ sem_unlock();
/* Verify */
if (up_progmem_ispageerased(page) == 0)
@@ -318,14 +377,23 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t count)
return -EFAULT;
}
- /* Get flash ready and begin flashing */
+ sem_lock();
+#if !defined(CONFIG_STM32_STM32F40XX)
if (!(getreg32(STM32_RCC_CR) & RCC_CR_HSION))
{
+ sem_unlock();
return -EPERM;
}
+#endif
+
+ /* Get flash ready and begin flashing */
+
+ flash_unlock();
- stm32_flash_unlock();
+#if defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW)
+ data_cache_disable();
+#endif
modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_PG);
@@ -347,17 +415,25 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t count)
if (getreg32(STM32_FLASH_SR) & FLASH_SR_WRITE_PROTECTION_ERROR)
{
modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0);
+ sem_unlock();
return -EROFS;
}
if (getreg16(addr) != *hword)
{
modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0);
+ sem_unlock();
return -EIO;
}
}
modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0);
+
+#if defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW)
+ data_cache_enable();
+#endif
+
+ sem_unlock();
return written;
}
@@ -1,81 +0,0 @@
diff --git NuttX/nuttx/arch/arm/src/stm32/Kconfig NuttX/nuttx/arch/arm/src/stm32/Kconfig
index b6c0458649..d9fb0aeaa2 100644
--- NuttX/nuttx/arch/arm/src/stm32/Kconfig
+++ NuttX/nuttx/arch/arm/src/stm32/Kconfig
@@ -2514,6 +2514,12 @@ config STM32_FLASH_PREFETCH
on F1 parts). Some early revisions of F4 parts do not support FLASH pre-fetch
properly and enabling this option may interfere with ADC accuracy.
+config STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW
+ bool "Enable the workaround to fix flash data cache corruption when reading from one flash bank while writing on other flash bank"
+ default n
+ ---help---
+ See your STM32 errata to check if your STM32 is affected by this problem.
+
choice
prompt "JTAG Configuration"
default STM32_JTAG_DISABLE
diff --git NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c
index 73f1419506..fd0b05d624 100644
--- NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c
+++ NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c
@@ -294,6 +294,37 @@ ssize_t up_progmem_ispageerased(size_t page)
return bwritten;
}
+#if defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW)
+static void data_cache_disable(void)
+{
+ uint32_t value = getreg32(STM32_FLASH_ACR);
+
+ if (value & FLASH_ACR_DCEN)
+ {
+ value &= ~FLASH_ACR_DCEN;
+ putreg32(value, STM32_FLASH_ACR);
+ }
+}
+
+static void data_cache_enable(void)
+{
+ uint32_t value = getreg32(STM32_FLASH_ACR);
+ if (value & FLASH_ACR_DCEN)
+ {
+ return;
+ }
+
+ /* reset data cache */
+ value |= FLASH_ACR_DCRST;
+ putreg32(value, STM32_FLASH_ACR);
+
+ /* enable data cache */
+ value = getreg32(STM32_FLASH_ACR);
+ value |= FLASH_ACR_DCEN;
+ putreg32(value, STM32_FLASH_ACR);
+}
+#endif
+
ssize_t up_progmem_write(size_t addr, const void *buf, size_t count)
{
uint16_t *hword = (uint16_t *)buf;
@@ -327,6 +358,10 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t count)
stm32_flash_unlock();
+#if defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW)
+ data_cache_disable();
+#endif
+
modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_PG);
#if defined(CONFIG_STM32_STM32F40XX)
@@ -358,6 +393,10 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t count)
}
modifyreg32(STM32_FLASH_CR, FLASH_CR_PG, 0);
+
+#if defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW)
+ data_cache_enable();
+#endif
return written;
}
@@ -1,38 +0,0 @@
diff --git NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c
index 73f1419..9ac38a1 100644
--- NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c
+++ NuttX/nuttx/arch/arm/src/stm32/stm32_flash.c
@@ -231,12 +231,14 @@ ssize_t up_progmem_erasepage(size_t page)
return -EFAULT;
}
- /* Get flash ready and begin erasing single page */
-
+#if !defined(CONFIG_STM32_STM32F40XX)
if (!(getreg32(STM32_RCC_CR) & RCC_CR_HSION))
{
return -EPERM;
}
+#endif
+
+ /* Get flash ready and begin erasing single page */
stm32_flash_unlock();
@@ -318,12 +320,14 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t count)
return -EFAULT;
}
- /* Get flash ready and begin flashing */
-
+#if !defined(CONFIG_STM32_STM32F40XX)
if (!(getreg32(STM32_RCC_CR) & RCC_CR_HSION))
{
return -EPERM;
}
+#endif
+
+ /* Get flash ready and begin flashing */
stm32_flash_unlock();