This is an automated email from the ASF dual-hosted git repository.

acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new df47241a2b STM32G4 Flash Driver
df47241a2b is described below

commit df47241a2bdb43d013571246253c78f934b8783f
Author: Kyle Wilson <kwil...@2g-eng.com>
AuthorDate: Mon Oct 7 08:28:30 2024 -0500

    STM32G4 Flash Driver
    
    Added a flash driver for the STM32G4 series. The primary change here is
    the addition of stm32g4xxx_flash.c. This file uses the STM32L4 flash
    driver as a template. The primary difference is the accounting for dual
    banks with different page sizes.
    
    Fixed error while building b-g474e-dpow1/buckboost. It was possible 
(technically) to have page be used uninitialzied. Changing the if statement to 
default to using a flash_page_size == 2048 fixes this issue.
---
 arch/arm/src/stm32/hardware/stm32_flash.h          |  76 ++-
 arch/arm/src/stm32/stm32_flash.c                   |   2 +
 arch/arm/src/stm32/stm32_flash.h                   |  22 +
 arch/arm/src/stm32/stm32g4xxx_flash.c              | 616 +++++++++++++++++++++
 .../nucleo-g474re/configs/lpuartnsh/defconfig      |   1 +
 5 files changed, 697 insertions(+), 20 deletions(-)

diff --git a/arch/arm/src/stm32/hardware/stm32_flash.h 
b/arch/arm/src/stm32/hardware/stm32_flash.h
index 2e2b02fd25..f0774ac8ed 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 b9c0a40a0d..2a49f5f56c 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 030990db71..8477cece65 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 0000000000..bb0d3681df
--- /dev/null
+++ b/arch/arm/src/stm32/stm32g4xxx_flash.c
@@ -0,0 +1,616 @@
+/****************************************************************************
+ * 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 <nuttx/config.h>
+#include <nuttx/arch.h>
+#include <nuttx/progmem.h>
+#include <nuttx/mutex.h>
+
+#include <assert.h>
+#include <debug.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <string.h>
+#include <sys/param.h>
+
+#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);
+
+  modifyreg32(STM32_FLASH_CR, FLASH_CR_PNB_MASK,
+              FLASH_CR_PNB(page));
+
+#if (defined(CONFIG_STM32_STM32G47XX) || \
+     defined(CONFIG_STM32_STM32G48XX))
+  uint32_t half_npages = get_flash_npages() / 2;
+
+  if (getreg32(STM32_FLASH_OPTR) & FLASH_OPTR_DBANK)
+    {
+      if (page < half_npages)
+        {
+          /* 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 == 4096)
+    {
+      page = ((uint32_t)offset >> 12);
+    }
+  else
+    {
+      page = ((uint32_t)offset >> 11);
+    }
+
+  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 65b7c91e6e..d9c2a762d2 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

Reply via email to