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;
+}