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 3ab1b4b8fe3 arm/nrf54l: add RRAM progmem support
3ab1b4b8fe3 is described below

commit 3ab1b4b8fe3746f7007795401c353a94bfb2c9c7
Author: raiden00pl <[email protected]>
AuthorDate: Sun Sep 20 16:24:45 2026 +0200

    arm/nrf54l: add RRAM progmem support
    
    add RRAM progmem support
    
    Assisted-by: Codex:GPT-6
    Signed-off-by: raiden00pl <[email protected]>
---
 Documentation/platforms/arm/nrf54l/index.rst |   9 +-
 arch/arm/src/nrf54l/CMakeLists.txt           |   4 +
 arch/arm/src/nrf54l/Kconfig                  |   8 +
 arch/arm/src/nrf54l/Make.defs                |   4 +
 arch/arm/src/nrf54l/hardware/nrf54l_cache.h  |  88 +++++
 arch/arm/src/nrf54l/hardware/nrf54l_rramc.h  | 173 +++++++++
 arch/arm/src/nrf54l/nrf54l_flash.c           | 506 +++++++++++++++++++++++++++
 7 files changed, 791 insertions(+), 1 deletion(-)

diff --git a/Documentation/platforms/arm/nrf54l/index.rst 
b/Documentation/platforms/arm/nrf54l/index.rst
index 1be3d0a9ee3..c0438aaba93 100644
--- a/Documentation/platforms/arm/nrf54l/index.rst
+++ b/Documentation/platforms/arm/nrf54l/index.rst
@@ -20,7 +20,7 @@ GRTC        Yes     Counter and tickless scheduling
 PWM         No
 QDEC        No
 RADIO       No
-RRAMC       No
+RRAMC       Yes     Progmem erase/write interface
 SAADC       No
 SPIM        No
 TIMER       Yes
@@ -44,6 +44,13 @@ instance and compare channel zero for tickless scheduling. 
The GRTC is timed
 by LFCLK, so the LFCLK source selected with ``CONFIG_NRF54L_USE_LFCLK``
 determines the long-term accuracy of the system time.
 
+RRAMC
+-----
+
+``CONFIG_NRF54L_PROGMEM`` enables the progmem interface. RRAM supports
+overwriting either bit value; erase operations fill emulated 4 KiB blocks
+with ``0xff``. Writes require word-aligned addresses and lengths.
+
 TIMER
 -----
 
diff --git a/arch/arm/src/nrf54l/CMakeLists.txt 
b/arch/arm/src/nrf54l/CMakeLists.txt
index 484ffbcecbe..cc3b7f1d940 100644
--- a/arch/arm/src/nrf54l/CMakeLists.txt
+++ b/arch/arm/src/nrf54l/CMakeLists.txt
@@ -30,6 +30,10 @@ set(SRCS
     nrf54l_lowputc.c
     nrf54l_uid.c)
 
+if(CONFIG_NRF54L_PROGMEM)
+  list(APPEND SRCS nrf54l_flash.c)
+endif()
+
 if(CONFIG_NRF54L_SYSTIMER_SYSTICK)
   list(APPEND SRCS nrf54l_systick.c)
 endif()
diff --git a/arch/arm/src/nrf54l/Kconfig b/arch/arm/src/nrf54l/Kconfig
index b2dec2687eb..d124baee727 100644
--- a/arch/arm/src/nrf54l/Kconfig
+++ b/arch/arm/src/nrf54l/Kconfig
@@ -192,6 +192,14 @@ endchoice # System Timer Source
 
 endmenu # System Timer
 
+config NRF54L_PROGMEM
+       bool "RRAM program memory"
+       default n
+       select ARCH_HAVE_PROGMEM
+       ---help---
+               Enable the program memory interfaces in nuttx/progmem.h.
+               RRAM erase blocks are emulated as 4 KiB regions filled with 
0xff.
+
 config NRF54L_DEBUG_ACCESS
        bool "Keep firmware-controlled debug access open"
        default y
diff --git a/arch/arm/src/nrf54l/Make.defs b/arch/arm/src/nrf54l/Make.defs
index 3b45c3e33bd..31b12b75332 100644
--- a/arch/arm/src/nrf54l/Make.defs
+++ b/arch/arm/src/nrf54l/Make.defs
@@ -26,6 +26,10 @@ CHIP_CSRCS += nrf54l_start.c nrf54l_clockconfig.c 
nrf54l_oscconfig.c nrf54l_irq.
 CHIP_CSRCS += nrf54l_allocateheap.c nrf54l_gpio.c nrf54l_lowputc.c
 CHIP_CSRCS += nrf54l_uid.c
 
+ifeq ($(CONFIG_NRF54L_PROGMEM),y)
+CHIP_CSRCS += nrf54l_flash.c
+endif
+
 ifeq ($(CONFIG_NRF54L_SYSTIMER_SYSTICK),y)
 CHIP_CSRCS += nrf54l_systick.c
 endif
diff --git a/arch/arm/src/nrf54l/hardware/nrf54l_cache.h 
b/arch/arm/src/nrf54l/hardware/nrf54l_cache.h
new file mode 100644
index 00000000000..3ef030d00d3
--- /dev/null
+++ b/arch/arm/src/nrf54l/hardware/nrf54l_cache.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+ * arch/arm/src/nrf54l/hardware/nrf54l_cache.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_NRF54L_HARDWARE_NRF54L_CACHE_H
+#define __ARCH_ARM_SRC_NRF54L_HARDWARE_NRF54L_CACHE_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include "hardware/nrf54l_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register offsets *********************************************************/
+
+#define NRF54L_CACHE_TASKS_INVALIDATECACHE_OFFSET 0x008 /* Invalidate cache */
+#define NRF54L_CACHE_TASKS_INVALIDATELINE_OFFSET  0x014 /* Invalidate line */
+#define NRF54L_CACHE_TASKS_ERASE_OFFSET           0x020 /* Erase cache */
+#define NRF54L_CACHE_STATUS_OFFSET                0x400 /* Cache activity */
+#define NRF54L_CACHE_ENABLE_OFFSET                0x404 /* Enable cache */
+#define NRF54L_CACHE_LINEADDR_OFFSET              0x410 /* Line address */
+#define NRF54L_CACHE_PROFILING_ENABLE_OFFSET      0x414 /* Profiling enable */
+#define NRF54L_CACHE_PROFILING_HIT_OFFSET         0x418 /* Hit count */
+#define NRF54L_CACHE_PROFILING_MISS_OFFSET        0x41c /* Miss count */
+#define NRF54L_CACHE_PROFILING_LMISS_OFFSET       0x420 /* Line miss count */
+#define NRF54L_CACHE_PROFILING_READS_OFFSET       0x424 /* Read count */
+#define NRF54L_CACHE_PROFILING_WRITES_OFFSET      0x428 /* Write count */
+#define NRF54L_CACHE_DEBUGLOCK_OFFSET             0x430 /* Debug lock */
+#define NRF54L_CACHE_WRITELOCK_OFFSET             0x434 /* Update lock */
+
+/* Register addresses *******************************************************/
+
+#define NRF54L_ICACHE_TASKS_INVALIDATECACHE (NRF54L_ICACHE_BASE + 
NRF54L_CACHE_TASKS_INVALIDATECACHE_OFFSET)
+#define NRF54L_ICACHE_TASKS_INVALIDATELINE  (NRF54L_ICACHE_BASE + 
NRF54L_CACHE_TASKS_INVALIDATELINE_OFFSET)
+#define NRF54L_ICACHE_TASKS_ERASE           (NRF54L_ICACHE_BASE + 
NRF54L_CACHE_TASKS_ERASE_OFFSET)
+#define NRF54L_ICACHE_STATUS                (NRF54L_ICACHE_BASE + 
NRF54L_CACHE_STATUS_OFFSET)
+#define NRF54L_ICACHE_ENABLE                (NRF54L_ICACHE_BASE + 
NRF54L_CACHE_ENABLE_OFFSET)
+#define NRF54L_ICACHE_LINEADDR              (NRF54L_ICACHE_BASE + 
NRF54L_CACHE_LINEADDR_OFFSET)
+#define NRF54L_ICACHE_PROFILING_ENABLE      (NRF54L_ICACHE_BASE + 
NRF54L_CACHE_PROFILING_ENABLE_OFFSET)
+#define NRF54L_ICACHE_PROFILING_HIT         (NRF54L_ICACHE_BASE + 
NRF54L_CACHE_PROFILING_HIT_OFFSET)
+#define NRF54L_ICACHE_PROFILING_MISS        (NRF54L_ICACHE_BASE + 
NRF54L_CACHE_PROFILING_MISS_OFFSET)
+#define NRF54L_ICACHE_PROFILING_LMISS       (NRF54L_ICACHE_BASE + 
NRF54L_CACHE_PROFILING_LMISS_OFFSET)
+#define NRF54L_ICACHE_PROFILING_READS       (NRF54L_ICACHE_BASE + 
NRF54L_CACHE_PROFILING_READS_OFFSET)
+#define NRF54L_ICACHE_PROFILING_WRITES      (NRF54L_ICACHE_BASE + 
NRF54L_CACHE_PROFILING_WRITES_OFFSET)
+#define NRF54L_ICACHE_DEBUGLOCK             (NRF54L_ICACHE_BASE + 
NRF54L_CACHE_DEBUGLOCK_OFFSET)
+#define NRF54L_ICACHE_WRITELOCK             (NRF54L_ICACHE_BASE + 
NRF54L_CACHE_WRITELOCK_OFFSET)
+
+/* ENABLE register */
+
+#define CACHE_ENABLE_ENABLE        (1 << 0)  /* Enable cache */
+
+/* STATUS register */
+
+#define CACHE_STATUS_BUSY          (1 << 0)
+
+/* PROFILING.ENABLE register */
+
+#define CACHE_PROFILING_ENABLE     (1 << 0)
+
+/* DEBUGLOCK and WRITELOCK registers */
+
+#define CACHE_DEBUGLOCK_LOCK       (1 << 0)
+#define CACHE_WRITELOCK_LOCK       (1 << 0)
+
+#endif /* __ARCH_ARM_SRC_NRF54L_HARDWARE_NRF54L_CACHE_H */
diff --git a/arch/arm/src/nrf54l/hardware/nrf54l_rramc.h 
b/arch/arm/src/nrf54l/hardware/nrf54l_rramc.h
new file mode 100644
index 00000000000..0987ebf1c1b
--- /dev/null
+++ b/arch/arm/src/nrf54l/hardware/nrf54l_rramc.h
@@ -0,0 +1,173 @@
+/****************************************************************************
+ * arch/arm/src/nrf54l/hardware/nrf54l_rramc.h
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_NRF54L_HARDWARE_NRF54L_RRAMC_H
+#define __ARCH_ARM_SRC_NRF54L_HARDWARE_NRF54L_RRAMC_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+#include "hardware/nrf54l_memorymap.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register offsets *********************************************************/
+
+#define NRF54L_RRAMC_TASKS_WAKEUP_OFFSET         0x000             /* Wake 
RRAM from low power */
+#define NRF54L_RRAMC_TASKS_CLRWRITEBUF_OFFSET    0x004             /* Discard 
buffered writes */
+#define NRF54L_RRAMC_TASKS_COMMITWRITEBUF_OFFSET 0x008             /* Commit 
buffered writes to RRAM */
+#define NRF54L_RRAMC_SUB_WAKEUP_OFFSET           0x080             /* 
Subscribe to WAKEUP task */
+#define NRF54L_RRAMC_SUB_CLRWRITEBUF_OFFSET      0x084             /* 
Subscribe to CLRWRITEBUF task */
+#define NRF54L_RRAMC_SUB_COMMITWRITEBUF_OFFSET   0x088             /* 
Subscribe to COMMITWRITEBUF task */
+#define NRF54L_RRAMC_EVENTS_WOKENUP_OFFSET       0x100             /* RRAM 
wakeup completed */
+#define NRF54L_RRAMC_EVENTS_READY_OFFSET         0x104             /* RRAM 
ready */
+#define NRF54L_RRAMC_EVENTS_READYNEXT_OFFSET     0x108             /* Ready 
for next write */
+#define NRF54L_RRAMC_EVENTS_ACCESSERROR_OFFSET   0x10c             /* RRAM 
access error */
+#define NRF54L_RRAMC_PUB_WOKENUP_OFFSET          0x180             /* Publish 
WOKENUP event */
+#define NRF54L_RRAMC_INTEN_OFFSET                0x300             /* Enable 
or disable interrupts */
+#define NRF54L_RRAMC_INTENSET_OFFSET             0x304             /* Enable 
interrupts */
+#define NRF54L_RRAMC_INTENCLR_OFFSET             0x308             /* Disable 
interrupts */
+#define NRF54L_RRAMC_INTPEND_OFFSET              0x30c             /* Pending 
interrupts */
+#define NRF54L_RRAMC_READY_OFFSET                0x400             /* Ready 
flag */
+#define NRF54L_RRAMC_READYNEXT_OFFSET            0x404             /* Next 
write ready */
+#define NRF54L_RRAMC_ACCESSERRORADDR_OFFSET      0x408             /* Address 
of access error */
+#define NRF54L_RRAMC_WRITEBUFEMPTY_OFFSET        0x418             /* Write 
buffer empty status */
+#define NRF54L_RRAMC_ECC_ERRORADDR_OFFSET        0x420             /* Address 
of ECC error */
+#define NRF54L_RRAMC_CONFIG_OFFSET               0x500             /* Write 
enable and buffer configuration */
+#define NRF54L_RRAMC_READYNEXTTIMEOUT_OFFSET     0x50c             /* 
Next-write timeout */
+#define NRF54L_RRAMC_POWER_CONFIG_OFFSET         0x510             /* Power 
mode configuration */
+#define NRF54L_RRAMC_POWER_STANDBYCONFIG_OFFSET  0x514             /* Standby 
mode configuration */
+#define NRF54L_RRAMC_POWER_LOWPOWERCONFIG_OFFSET 0x518             /* 
Low-power mode configuration */
+#define NRF54L_RRAMC_ERASEALL_OFFSET             0x540             /* Erase 
all RRAM */
+#define NRF54L_RRAMC_REGION_ADDRESS_OFFSET(n)    (0x550 + (n) * 8) /* Region n 
start address */
+#define NRF54L_RRAMC_REGION_CONFIG_OFFSET(n)     (0x554 + (n) * 8) /* Region n 
configuration */
+
+/* Register addresses *******************************************************/
+
+#define NRF54L_RRAMC_TASKS_WAKEUP          (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_TASKS_WAKEUP_OFFSET)
+#define NRF54L_RRAMC_TASKS_CLRWRITEBUF     (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_TASKS_CLRWRITEBUF_OFFSET)
+#define NRF54L_RRAMC_TASKS_COMMITWRITEBUF  (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_TASKS_COMMITWRITEBUF_OFFSET)
+#define NRF54L_RRAMC_SUB_WAKEUP            (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_SUB_WAKEUP_OFFSET)
+#define NRF54L_RRAMC_SUB_CLRWRITEBUF       (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_SUB_CLRWRITEBUF_OFFSET)
+#define NRF54L_RRAMC_SUB_COMMITWRITEBUF    (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_SUB_COMMITWRITEBUF_OFFSET)
+#define NRF54L_RRAMC_EVENTS_WOKENUP        (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_EVENTS_WOKENUP_OFFSET)
+#define NRF54L_RRAMC_EVENTS_READY          (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_EVENTS_READY_OFFSET)
+#define NRF54L_RRAMC_EVENTS_READYNEXT      (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_EVENTS_READYNEXT_OFFSET)
+#define NRF54L_RRAMC_EVENTS_ACCESSERROR    (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_EVENTS_ACCESSERROR_OFFSET)
+#define NRF54L_RRAMC_PUB_WOKENUP           (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_PUB_WOKENUP_OFFSET)
+#define NRF54L_RRAMC_INTEN                 (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_INTEN_OFFSET)
+#define NRF54L_RRAMC_INTENSET              (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_INTENSET_OFFSET)
+#define NRF54L_RRAMC_INTENCLR              (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_INTENCLR_OFFSET)
+#define NRF54L_RRAMC_INTPEND               (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_INTPEND_OFFSET)
+#define NRF54L_RRAMC_READY                 (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_READY_OFFSET)
+#define NRF54L_RRAMC_READYNEXT             (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_READYNEXT_OFFSET)
+#define NRF54L_RRAMC_CONFIG                (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_CONFIG_OFFSET)
+#define NRF54L_RRAMC_ERASEALL              (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_ERASEALL_OFFSET)
+#define NRF54L_RRAMC_ACCESSERRORADDR       (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_ACCESSERRORADDR_OFFSET)
+#define NRF54L_RRAMC_WRITEBUFEMPTY         (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_WRITEBUFEMPTY_OFFSET)
+#define NRF54L_RRAMC_ECC_ERRORADDR         (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_ECC_ERRORADDR_OFFSET)
+#define NRF54L_RRAMC_READYNEXTTIMEOUT      (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_READYNEXTTIMEOUT_OFFSET)
+#define NRF54L_RRAMC_POWER_CONFIG          (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_POWER_CONFIG_OFFSET)
+#define NRF54L_RRAMC_POWER_STANDBYCONFIG   (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_POWER_STANDBYCONFIG_OFFSET)
+#define NRF54L_RRAMC_POWER_LOWPOWERCONFIG  (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_POWER_LOWPOWERCONFIG_OFFSET)
+#define NRF54L_RRAMC_REGION_ADDRESS(n)     (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_REGION_ADDRESS_OFFSET(n))
+#define NRF54L_RRAMC_REGION_CONFIG(n)      (NRF54L_RRAMC_BASE + 
NRF54L_RRAMC_REGION_CONFIG_OFFSET(n))
+
+/* Register bit definitions *************************************************/
+
+/* READY Register */
+
+#define RRAMC_READY_READY                 (1 << 0) /* RRAMC is ready */
+
+/* CONFIG Register */
+
+#define RRAMC_CONFIG_WEN                  (1 << 0)
+#define RRAMC_CONFIG_WRITEBUFSIZE_SHIFT   (8)
+#define RRAMC_CONFIG_WRITEBUFSIZE_MASK    (0x3f << 
RRAMC_CONFIG_WRITEBUFSIZE_SHIFT)
+#define RRAMC_CONFIG_WRITEBUFSIZE_32      (32 << 
RRAMC_CONFIG_WRITEBUFSIZE_SHIFT)
+
+/* SUBSCRIBE/PUBLISH Registers */
+
+#define RRAMC_SUBPUB_CHIDX_MASK           (0xff)
+#define RRAMC_SUBPUB_ENABLE               (0x80000000)
+
+/* INTEN/INTENSET/INTENCLR/INTPEND Registers */
+
+#define RRAMC_INT_WOKENUP                 (1 << 0)
+#define RRAMC_INT_READY                   (1 << 1)
+#define RRAMC_INT_READYNEXT               (1 << 2)
+#define RRAMC_INT_ACCESSERROR             (1 << 3)
+
+/* READYNEXT and BUFSTATUS.WRITEBUFEMPTY Registers */
+
+#define RRAMC_READYNEXT_READY             (1 << 0)
+#define RRAMC_WRITEBUFEMPTY_EMPTY         (1 << 0)
+
+/* POWER.CONFIG Register */
+
+#define RRAMC_POWER_ACCESSTIMEOUT_MASK    (0xffff)
+#define RRAMC_POWER_POF_ABORT             (1 << 16)
+
+/* POWER.STANDBYCONFIG Register */
+
+#define RRAMC_STANDBY_MODE_MASK           (3 << 0)
+#define RRAMC_STANDBY_NORMAL              (0 << 0)
+#define RRAMC_STANDBY_POWERDOWN           (2 << 0)
+#define RRAMC_STANDBY_STANDBY             (3 << 0)
+#ifdef CONFIG_ARCH_CHIP_NRF54L15
+#  define RRAMC_STANDBY_NAP               (1 << 0)
+#endif
+
+/* POWER.LOWPOWERCONFIG Register */
+
+#define RRAMC_LOWPOWER_MODE_MASK          (3 << 0)
+#define RRAMC_LOWPOWER_STANDBY            (1 << 0)
+#ifdef CONFIG_ARCH_CHIP_NRF54L15
+#  define RRAMC_LOWPOWER_POWERDOWN        (0 << 0)
+#  define RRAMC_LOWPOWER_NAP              (2 << 0)
+#  define RRAMC_LOWPOWER_POWEROFF         (3 << 0)
+#else
+#  define RRAMC_LOWPOWER_POWEROFF         (0 << 0)
+#endif
+
+/* REGION.CONFIG Register */
+
+#define RRAMC_REGION_READ                 (1 << 0)
+#define RRAMC_REGION_WRITE                (1 << 1)
+#define RRAMC_REGION_EXECUTE              (1 << 2)
+#define RRAMC_REGION_SECURE               (1 << 3)
+#define RRAMC_REGION_WRITEONCE            (1 << 12)
+#define RRAMC_REGION_LOCK                 (1 << 13)
+#define RRAMC_REGION_SIZE_SHIFT           (16)
+#ifdef CONFIG_ARCH_CHIP_NRF54L15
+#  define RRAMC_REGION_OWNER_SHIFT        (4)
+#  define RRAMC_REGION_OWNER_MASK         (0xf << RRAMC_REGION_OWNER_SHIFT)
+#  define RRAMC_REGION_SIZE_MASK          (0x1f << RRAMC_REGION_SIZE_SHIFT)
+#else
+#  define RRAMC_REGION_SIZE_MASK          (0x7f << RRAMC_REGION_SIZE_SHIFT)
+#endif
+
+#endif /* __ARCH_ARM_SRC_NRF54L_HARDWARE_NRF54L_RRAMC_H */
diff --git a/arch/arm/src/nrf54l/nrf54l_flash.c 
b/arch/arm/src/nrf54l/nrf54l_flash.c
new file mode 100644
index 00000000000..244c356d98a
--- /dev/null
+++ b/arch/arm/src/nrf54l/nrf54l_flash.c
@@ -0,0 +1,506 @@
+/****************************************************************************
+ * arch/arm/src/nrf54l/nrf54l_flash.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/progmem.h>
+#include <nuttx/mutex.h>
+#include <arch/barriers.h>
+
+#include "arm_internal.h"
+
+#include "hardware/nrf54l_ficr.h"
+#include "hardware/nrf54l_rramc.h"
+#include "hardware/nrf54l_cache.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Sizes and masks */
+
+#define NRF54L_FLASH_ERASEDVAL  (0xff)
+#define NRF54L_FLASH_PAGESIZE   (4096)
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static mutex_t g_flash_lock = NXMUTEX_INITIALIZER;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: nrf54l_get_flash_size
+ *
+ * Description:
+ *   Return the size of the RRAM array reported by the factory registers.
+ *
+ ****************************************************************************/
+
+static inline uint32_t nrf54l_get_flash_size(void)
+{
+  return getreg32(NRF54L_FICR_INFO_RRAM) * 1024;
+}
+
+/****************************************************************************
+ * Name: nrf54l_get_page_size
+ *
+ * Description:
+ *   RRAM has no page erase. Expose uniform 4 KiB blocks to progmem users.
+ *
+ ****************************************************************************/
+
+static inline uint32_t nrf54l_get_page_size(void)
+{
+  return NRF54L_FLASH_PAGESIZE;
+}
+
+/****************************************************************************
+ * Name: nrf54l_get_pages_num
+ *
+ * Description:
+ *   Return the number of emulated erase blocks.
+ *
+ ****************************************************************************/
+
+static inline uint32_t nrf54l_get_pages_num(void)
+{
+  return nrf54l_get_flash_size() / NRF54L_FLASH_PAGESIZE;
+}
+
+/****************************************************************************
+ * Name: nrf54l_flash_cache_bypass
+ *
+ * Description:
+ *   Disable the instruction cache while modifying executable memory.
+ *
+ ****************************************************************************/
+
+static uint32_t nrf54l_flash_cache_bypass(void)
+{
+  uint32_t enable = getreg32(NRF54L_ICACHE_ENABLE);
+
+  putreg32(0, NRF54L_ICACHE_ENABLE);
+  UP_MB();
+  return enable;
+}
+
+/****************************************************************************
+ * Name: nrf54l_flash_cache_restore
+ *
+ * Description:
+ *   Invalidate modified instructions and restore the previous cache state.
+ *
+ ****************************************************************************/
+
+static void nrf54l_flash_cache_restore(uint32_t enable)
+{
+  putreg32(1, NRF54L_ICACHE_TASKS_INVALIDATECACHE);
+  while (getreg32(NRF54L_ICACHE_STATUS) & CACHE_STATUS_BUSY)
+    {
+    }
+
+  putreg32(enable, NRF54L_ICACHE_ENABLE);
+  UP_MB();
+}
+
+/****************************************************************************
+ * Name: nrf54l_flash_wait
+ *
+ * Description:
+ *   Wait for pending writes to reach nonvolatile memory.
+ *
+ ****************************************************************************/
+
+static void nrf54l_flash_wait(void)
+{
+  while (!(getreg32(NRF54L_RRAMC_READY) & RRAMC_READY_READY))
+    {
+    }
+}
+
+/****************************************************************************
+ * Name: nrf54l_flash_program
+ *
+ * Description:
+ *   Write consecutive words, or fill with the erased value if buf is NULL.
+ *   The caller holds g_flash_lock and has validated the destination range.
+ *
+ ****************************************************************************/
+
+static int nrf54l_flash_program(size_t addr, const uint8_t *buf,
+                               size_t count)
+{
+  uint32_t cache;
+  uint32_t config;
+  uint32_t word;
+  size_t i;
+  int ret = OK;
+
+  cache = nrf54l_flash_cache_bypass();
+  nrf54l_flash_wait();
+  config = getreg32(NRF54L_RRAMC_CONFIG);
+  putreg32(0, NRF54L_RRAMC_EVENTS_ACCESSERROR);
+  putreg32((config & ~RRAMC_CONFIG_WRITEBUFSIZE_MASK) |
+           RRAMC_CONFIG_WEN | RRAMC_CONFIG_WRITEBUFSIZE_32,
+           NRF54L_RRAMC_CONFIG);
+  nrf54l_flash_wait();
+  UP_MB();
+
+  for (i = 0; i < count; i += sizeof(word))
+    {
+      word = UINT32_MAX;
+      if (buf != NULL)
+        {
+          memcpy(&word, buf + i, sizeof(word));
+        }
+
+      putreg32(word, addr + i);
+    }
+
+  putreg32(1, NRF54L_RRAMC_TASKS_COMMITWRITEBUF);
+  UP_MB();
+  nrf54l_flash_wait();
+  UP_MB();
+  putreg32(config & ~RRAMC_CONFIG_WEN, NRF54L_RRAMC_CONFIG);
+
+  if (getreg32(NRF54L_RRAMC_EVENTS_ACCESSERROR) != 0)
+    {
+      ret = -EACCES;
+    }
+  else
+    {
+      for (i = 0; i < count; i += sizeof(word))
+        {
+          word = UINT32_MAX;
+          if (buf != NULL)
+            {
+              memcpy(&word, buf + i, sizeof(word));
+            }
+
+          if (getreg32(addr + i) != word)
+            {
+              ret = -EIO;
+              break;
+            }
+        }
+    }
+
+  nrf54l_flash_cache_restore(cache);
+  return ret;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_progmem_pagesize
+ *
+ * Description:
+ *   Return page size
+ *
+ ****************************************************************************/
+
+size_t up_progmem_pagesize(size_t page)
+{
+  if (page >= up_progmem_neraseblocks())
+    {
+      return 0;
+    }
+  else
+    {
+      return nrf54l_get_page_size();
+    }
+}
+
+/****************************************************************************
+ * Name: up_progmem_erasesize
+ *
+ * Description:
+ *   Return erase block size
+ *
+ ****************************************************************************/
+
+size_t up_progmem_erasesize(size_t block)
+{
+  return up_progmem_pagesize(block);
+}
+
+/****************************************************************************
+ * Name: up_progmem_getpage
+ *
+ * Description:
+ *   Address to page conversion
+ *
+ * Input Parameters:
+ *   addr - Address to be converted
+ *
+ * Returned Value:
+ *   Page or negative value on error.  The following errors are reported
+ *   (errno is not set!):
+ *
+ *     -EFAULT: On invalid address
+ *
+ ****************************************************************************/
+
+ssize_t up_progmem_getpage(size_t addr)
+{
+  if (addr >= nrf54l_get_flash_size())
+    {
+      return -EFAULT;
+    }
+
+  return addr / nrf54l_get_page_size();
+}
+
+/****************************************************************************
+ * Name: up_progmem_getaddress
+ *
+ * Description:
+ *   Page to address conversion
+ *
+ * Input Parameters:
+ *   page - Page to be converted
+ *
+ * Returned Value:
+ *   Base address of given page, maximum size if page is not valid.
+ *
+ ****************************************************************************/
+
+size_t up_progmem_getaddress(size_t page)
+{
+  if (page >= up_progmem_neraseblocks())
+    {
+      return SIZE_MAX;
+    }
+
+  return page * nrf54l_get_page_size();
+}
+
+/****************************************************************************
+ * Name: up_progmem_neraseblocks
+ *
+ * Description:
+ *   Return number of erase blocks in the available FLASH memory.
+ *
+ ****************************************************************************/
+
+size_t up_progmem_neraseblocks(void)
+{
+  return nrf54l_get_flash_size() / nrf54l_get_page_size();
+}
+
+/****************************************************************************
+ * Name: up_progmem_isuniform
+ *
+ * Description:
+ *   The emulated erase blocks have a uniform size.
+ *
+ ****************************************************************************/
+
+bool up_progmem_isuniform(void)
+{
+  return true;
+}
+
+/****************************************************************************
+ * Name: up_progmem_eraseblock
+ *
+ * Description:
+ *   Erase selected block.
+ *
+ * Input Parameters:
+ *   block - Block to be erased
+ *
+ * Returned Value:
+ *   Page size or negative value on error.  The following errors are reported
+ *   (errno is not set!):
+ *
+ *     -EFAULT: On invalid page
+ *     -EIO:    On unsuccessful erase
+ *     -EROFS:  On access to write protected area
+ *     -EACCES: Insufficient permissions (read/write protected)
+ *     -EPERM:  If operation is not permitted due to some other constraints
+ *              (i.e. some internal block is not running etc.)
+ *
+ ****************************************************************************/
+
+ssize_t up_progmem_eraseblock(size_t block)
+{
+  size_t page_address;
+  int ret;
+
+  if (block >= up_progmem_neraseblocks())
+    {
+      return -EFAULT;
+    }
+
+  page_address = up_progmem_getaddress(block);
+
+  ret = nxmutex_lock(&g_flash_lock);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  /* RRAM can overwrite both zeroes and ones; erase is an ordinary write. */
+
+  ret = nrf54l_flash_program(page_address, NULL, NRF54L_FLASH_PAGESIZE);
+  nxmutex_unlock(&g_flash_lock);
+  return ret < 0 ? ret : NRF54L_FLASH_PAGESIZE;
+}
+
+/****************************************************************************
+ * Name: up_progmem_ispageerased
+ *
+ * Description:
+ *   Checks whether a page is erased
+ *
+ * Input Parameters:
+ *    page - Page to be checked
+ *
+ * Returned Value:
+ *   Returns number of bytes not erased or negative value on error. If it
+ *   returns zero then complete page is empty (erased).
+ *
+ *   The following errors are reported (errno is not set!)
+ *     -EFAULT: On invalid page
+ *
+ ****************************************************************************/
+
+ssize_t up_progmem_ispageerased(size_t page)
+{
+  size_t addr;
+  size_t count;
+  size_t bwritten = 0;
+
+  if (page >= nrf54l_get_pages_num())
+    {
+      return -EFAULT;
+    }
+
+  /* Verify */
+
+  for (addr = up_progmem_getaddress(page), count = up_progmem_pagesize(page);
+       count; count--, addr++)
+    {
+      if (getreg8(addr) != NRF54L_FLASH_ERASEDVAL)
+        {
+          bwritten++;
+        }
+    }
+
+  return bwritten;
+}
+
+/****************************************************************************
+ * Name: up_progmem_write
+ *
+ * Description:
+ *   Program data at given address
+ *
+ * Input Parameters:
+ *   addr  - Address with or without flash offset
+ *   buf   - Pointer to buffer
+ *   count - Number of bytes to write
+ *
+ * Returned Value:
+ *   Bytes written or negative value on error.  The following errors are
+ *   reported (errno is not set!)
+ *
+ *     EINVAL: If buflen is not aligned with the flash boundaries (i.e.
+ *             some MCU's require per half-word or even word access)
+ *     EFAULT: On invalid address
+ *     EIO:    On unsuccessful write
+ *     EROFS:  On access to write protected area
+ *     EACCES: Insufficient permissions (read/write protected)
+ *     EPERM:  If operation is not permitted due to some other constraints
+ *             (i.e. some internal block is not running etc.)
+ *
+ ****************************************************************************/
+
+ssize_t up_progmem_write(size_t addr, const void *buf, size_t count)
+{
+  int ret;
+
+  /* Use word writes, allowing an unaligned source buffer. */
+
+  if ((addr & 0x3) != 0 || (count & 0x3) != 0 ||
+      (buf == NULL && count != 0))
+    {
+      return -EINVAL;
+    }
+
+  /* Check for valid address range */
+
+  if (addr > nrf54l_get_flash_size() ||
+      count > nrf54l_get_flash_size() - addr)
+    {
+      return -EFAULT;
+    }
+
+  if (count == 0)
+    {
+      return 0;
+    }
+
+  ret = nxmutex_lock(&g_flash_lock);
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  ret = nrf54l_flash_program(addr, buf, count);
+  nxmutex_unlock(&g_flash_lock);
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  return count;
+}
+
+/****************************************************************************
+ * Name: up_progmem_erasestate
+ *
+ * Description:
+ *   Return value of erase state.
+ *
+ ****************************************************************************/
+
+uint8_t up_progmem_erasestate(void)
+{
+  return NRF54L_FLASH_ERASEDVAL;
+}

Reply via email to