Skip to content

Commit 6dde96f

Browse files
committed
[nrf fromtree] drivers: flash: nordic: Introduce nrf_mramc driver
Add SHIM layer for nrfx_mramc driver for zephyr Signed-off-by: Travis Lam <[email protected]> (cherry picked from commit 7f0a993bbd8fdd5858bf00cf2b6e7f835637bec4)
1 parent ef52a5e commit 6dde96f

File tree

9 files changed

+281
-0
lines changed

9 files changed

+281
-0
lines changed

drivers/flash/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_MAX32 flash_max32.c)
5353
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_MCUX soc_flash_mcux.c)
5454
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF soc_flash_nrf.c)
5555
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF_MRAM soc_flash_nrf_mram.c)
56+
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF_MRAMC soc_flash_nrf_mramc.c)
5657
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF_RRAM soc_flash_nrf_rram.c)
5758
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NUMAKER soc_flash_numaker.c)
5859
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NUMAKER_RMC soc_flash_numaker_rmc.c)

drivers/flash/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,7 @@ source "drivers/flash/Kconfig.nordic_qspi_nor"
186186
source "drivers/flash/Kconfig.npcx_fiu"
187187
source "drivers/flash/Kconfig.nrf"
188188
source "drivers/flash/Kconfig.nrf_mram"
189+
source "drivers/flash/Kconfig.nrf_mramc"
189190
source "drivers/flash/Kconfig.nrf_rram"
190191
source "drivers/flash/Kconfig.numaker"
191192
source "drivers/flash/Kconfig.numaker_rmc"

drivers/flash/Kconfig.nrf_mramc

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
7+
config SOC_FLASH_NRF_MRAMC
8+
bool "Nordic Semiconductor flash driver for MRAM using MRAM Controller"
9+
default y
10+
depends on DT_HAS_NORDIC_NRF_MRAMC_ENABLED
11+
select NRFX_MRAMC
12+
select FLASH_HAS_DRIVER_ENABLED
13+
select FLASH_HAS_PAGE_LAYOUT
14+
select FLASH_HAS_NO_EXPLICIT_ERASE
15+
select SOC_FLASH_NRF_MRAMC_FLUSH_CACHE
16+
imply MPU_ALLOW_FLASH_WRITE if ARM_MPU
17+
help
18+
Enables Nordic Semiconductor flash driver for MRAMC in direct write mode.
19+
20+
config SOC_FLASH_NRF_MRAMC_FLUSH_CACHE
21+
bool "Invalidate MRAM cache after erase operations"
22+
default y
23+
depends on SOC_FLASH_NRF_MRAMC
24+
help
25+
Enables invalidation of the MRAM cache after write and erase operations to
26+
ensure data read consistency.

drivers/flash/soc_flash_nrf_mramc.c

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
/*
2+
* Copyright (c) 2025 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <string.h>
8+
9+
#include <zephyr/drivers/flash.h>
10+
#include <zephyr/logging/log.h>
11+
#include <nrfx_mramc.h>
12+
#if defined(CONFIG_SOC_FLASH_NRF_MRAMC_FLUSH_CACHE)
13+
#include <hal/nrf_cache.h>
14+
#endif
15+
16+
LOG_MODULE_REGISTER(flash_nrf_mramc, CONFIG_FLASH_LOG_LEVEL);
17+
18+
#define DT_DRV_COMPAT nordic_nrf_mramc
19+
20+
#define _ADD_SIZE(node_id) + DT_REG_SIZE(node_id)
21+
#define _WBS(node_id) DT_PROP(node_id, write_block_size),
22+
#define _EBS(node_id) DT_PROP(node_id, erase_block_size),
23+
24+
#define MRAM_SIZE (0 DT_INST_FOREACH_CHILD_STATUS_OKAY(0, _ADD_SIZE))
25+
#define ERASE_VALUE (uint8_t)NRFY_MRAMC_WORD_AFTER_ERASED
26+
27+
/* Use DT_FOREACH_CHILD_STATUS_OKAY of mramc with _FIRST() helper
28+
* macro to get the write block size and erase block size from
29+
* the first child node.
30+
*/
31+
#define WBS_LIST DT_INST_FOREACH_CHILD_STATUS_OKAY(0, _WBS)
32+
#define EBS_LIST DT_INST_FOREACH_CHILD_STATUS_OKAY(0, _EBS)
33+
34+
#define _FIRST_HELPER(first, ...) first
35+
#define _FIRST(...) _FIRST_HELPER(__VA_ARGS__)
36+
37+
#define WRITE_BLOCK_SIZE _FIRST(WBS_LIST)
38+
#define ERASE_BLOCK_SIZE _FIRST(EBS_LIST)
39+
40+
BUILD_ASSERT((ERASE_BLOCK_SIZE % WRITE_BLOCK_SIZE) == 0,
41+
"erase-block-size expected to be a multiple of write-block-size");
42+
43+
/**
44+
* @param[in] addr Address of mram memory.
45+
* @param[in] len Number of bytes for the intended operation.
46+
* @param[in] must_align Require MRAM word alignment, if applicable.
47+
*
48+
* @return true if the address and length are valid, false otherwise.
49+
*/
50+
static bool validate_action(uint32_t addr, size_t len, bool must_align)
51+
{
52+
if (!nrfx_mramc_valid_address_check(addr, true)) {
53+
LOG_ERR("Invalid address: %x", addr);
54+
return false;
55+
}
56+
57+
if (!nrfx_mramc_fits_memory_check(addr, true, len)) {
58+
LOG_ERR("Address %x with length %zu exceeds MRAM size", addr, len);
59+
return false;
60+
}
61+
62+
if (must_align && !(nrfx_is_word_aligned((void const *)addr))) {
63+
LOG_ERR("Address %x is not word aligned", addr);
64+
return false;
65+
}
66+
67+
return true;
68+
}
69+
70+
static int nrf_mramc_read(const struct device *dev, off_t offset, void *data, size_t len)
71+
{
72+
ARG_UNUSED(dev);
73+
uint32_t addr = NRFX_MRAMC_MAP_TO_ADDR(offset);
74+
75+
if (data == NULL) {
76+
LOG_ERR("Data pointer is NULL");
77+
return -EINVAL;
78+
}
79+
80+
/* Validate addr and length in the range */
81+
if (!validate_action(addr, len, false)) {
82+
return -EINVAL;
83+
}
84+
85+
LOG_DBG("read: %x:%zu", addr, len);
86+
87+
/* Buffer read number of bytes and store in data pointer.
88+
*/
89+
nrfx_mramc_buffer_read(data, addr, len);
90+
return 0;
91+
}
92+
93+
static int nrf_mramc_write(const struct device *dev, off_t offset,
94+
const void *data, size_t len)
95+
{
96+
ARG_UNUSED(dev);
97+
uint32_t addr = NRFX_MRAMC_MAP_TO_ADDR(offset);
98+
99+
if (data == NULL) {
100+
LOG_ERR("Data pointer is NULL");
101+
return -EINVAL;
102+
}
103+
104+
/* Validate addr and length in the range */
105+
if (!validate_action(addr, len, true)) {
106+
return -EINVAL;
107+
}
108+
109+
LOG_DBG("write: %x:%zu", addr, len);
110+
111+
/* Words write function takes second argument as number of write blocks
112+
* and not number of bytes
113+
*/
114+
nrfx_mramc_words_write(addr, data, len / WRITE_BLOCK_SIZE);
115+
#if defined(CONFIG_SOC_FLASH_NRF_MRAMC_FLUSH_CACHE)
116+
if (nrf_cache_enable_check(NRF_ICACHE)) {
117+
while (nrf_cache_busy_check(NRF_ICACHE)) {
118+
}
119+
nrf_cache_invalidate(NRF_ICACHE);
120+
}
121+
#endif
122+
return 0;
123+
}
124+
125+
static int nrf_mramc_erase(const struct device *dev, off_t offset, size_t size)
126+
{
127+
ARG_UNUSED(dev);
128+
uint32_t addr = NRFX_MRAMC_MAP_TO_ADDR(offset);
129+
130+
/* Validate addr and length in the range */
131+
if (size == 0) {
132+
LOG_DBG("No data to erase");
133+
return 0;
134+
}
135+
136+
if (!validate_action(addr, size, true)) {
137+
return -EINVAL;
138+
}
139+
140+
LOG_DBG("erase: %p:%zu", (void *)addr, size);
141+
142+
/* Erase function takes second argument as number of write blocks
143+
* and not number of bytes
144+
*/
145+
nrfx_mramc_area_erase(addr, size / WRITE_BLOCK_SIZE);
146+
#if defined(CONFIG_SOC_FLASH_NRF_MRAMC_FLUSH_CACHE)
147+
if (nrf_cache_enable_check(NRF_ICACHE)) {
148+
while (nrf_cache_busy_check(NRF_ICACHE)) {
149+
}
150+
nrf_cache_invalidate(NRF_ICACHE);
151+
}
152+
#endif
153+
return 0;
154+
}
155+
156+
static int nrf_mramc_get_size(const struct device *dev, uint64_t *size)
157+
{
158+
ARG_UNUSED(dev);
159+
*size = nrfx_mramc_memory_size_get();
160+
return 0;
161+
}
162+
163+
static const struct flash_parameters *nrf_mramc_get_parameters(const struct device *dev)
164+
{
165+
ARG_UNUSED(dev);
166+
167+
static const struct flash_parameters parameters = {
168+
.write_block_size = WRITE_BLOCK_SIZE,
169+
.erase_value = ERASE_VALUE,
170+
.caps = {
171+
.no_explicit_erase = true,
172+
},
173+
};
174+
175+
return &parameters;
176+
}
177+
178+
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
179+
static void nrf_mramc_page_layout(const struct device *dev,
180+
const struct flash_pages_layout **layout, size_t *layout_size)
181+
{
182+
ARG_UNUSED(dev);
183+
184+
static const struct flash_pages_layout pages_layout = {
185+
.pages_count = MRAM_SIZE / (ERASE_BLOCK_SIZE),
186+
.pages_size = ERASE_BLOCK_SIZE,
187+
};
188+
189+
*layout = &pages_layout;
190+
*layout_size = 1;
191+
}
192+
#endif
193+
194+
static int mramc_sys_init(const struct device *dev)
195+
{
196+
ARG_UNUSED(dev);
197+
198+
nrfx_mramc_config_t config = NRFX_MRAMC_DEFAULT_CONFIG();
199+
nrfx_err_t err = nrfx_mramc_init(&config, NULL);
200+
201+
if (err != NRFX_SUCCESS) {
202+
LOG_ERR("Failed to initialize MRAMC: %d", err);
203+
return -EIO;
204+
}
205+
LOG_DBG("MRAMC initialized successfully");
206+
return 0;
207+
}
208+
209+
static DEVICE_API(flash, nrf_mram_api) = {
210+
.read = nrf_mramc_read,
211+
.write = nrf_mramc_write,
212+
.erase = nrf_mramc_erase,
213+
.get_size = nrf_mramc_get_size,
214+
.get_parameters = nrf_mramc_get_parameters,
215+
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
216+
.page_layout = nrf_mramc_page_layout,
217+
#endif
218+
};
219+
220+
DEVICE_DT_INST_DEFINE(0, mramc_sys_init, NULL, NULL, NULL, POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY,
221+
&nrf_mram_api);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
7+
description: |
8+
Nordic MRAMC (Magnetoresistive Random Access Memory Controller)
9+
10+
The Magnetoresistive random access memory controller (MRAMC) is used for writing
11+
the internal MRAM memory, the secure information configuration registers (SICR),
12+
and the user information configuration registers (UICR).
13+
14+
compatible: "nordic,nrf-mramc"
15+
16+
include: base.yaml

modules/hal_nordic/nrfx/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ zephyr_library_sources_ifdef(CONFIG_NRFX_GRTC ${SRC_DIR}/nrfx_grtc.c)
135135
zephyr_library_sources_ifdef(CONFIG_NRFX_I2S ${SRC_DIR}/nrfx_i2s.c)
136136
zephyr_library_sources_ifdef(CONFIG_NRFX_IPC ${SRC_DIR}/nrfx_ipc.c)
137137
zephyr_library_sources_ifdef(CONFIG_NRFX_LPCOMP ${SRC_DIR}/nrfx_lpcomp.c)
138+
zephyr_library_sources_ifdef(CONFIG_NRFX_MRAMC ${SRC_DIR}/nrfx_mramc.c)
138139
zephyr_library_sources_ifdef(CONFIG_NRFX_NFCT ${SRC_DIR}/nrfx_nfct.c)
139140
zephyr_library_sources_ifdef(CONFIG_NRFX_NVMC ${SRC_DIR}/nrfx_nvmc.c)
140141
zephyr_library_sources_ifdef(CONFIG_NRFX_PDM ${SRC_DIR}/nrfx_pdm.c)

modules/hal_nordic/nrfx/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ config NRFX_LPCOMP
265265
bool "LPCOMP driver"
266266
depends on $(dt_nodelabel_exists,comp) && !SOC_NRF52810 && !SOC_NRF52811 && !SOC_NRF52820
267267

268+
config NRFX_MRAMC
269+
bool "MRAMC driver"
270+
depends on $(dt_has_compat,$(DT_COMPAT_NORDIC_NRF_MRAMC))
271+
268272
config NRFX_NFCT
269273
bool "NFCT driver"
270274
depends on $(dt_nodelabel_exists,nfct)

modules/hal_nordic/nrfx/Kconfig.logging

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ config NRFX_LPCOMP_LOG
4444
bool "LPCOMP driver logging"
4545
depends on NRFX_LPCOMP
4646

47+
config NRFX_MRAMC_LOG
48+
bool "MRAMC driver logging"
49+
depends on NRFX_MRAMC
50+
4751
config NRFX_NFCT_LOG
4852
bool "NFCT driver logging"
4953
depends on NRFX_NFCT

modules/hal_nordic/nrfx/nrfx_kconfig.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,13 @@
239239
#define NRFX_LPCOMP_CONFIG_LOG_ENABLED 1
240240
#endif
241241

242+
#ifdef CONFIG_NRFX_MRAMC
243+
#define NRFX_MRAMC_ENABLED 1
244+
#endif
245+
#ifdef CONFIG_NRFX_MRAMC_LOG
246+
#define NRFX_MRAMC_CONFIG_LOG_ENABLED 1
247+
#endif
248+
242249
#ifdef CONFIG_NRFX_NFCT
243250
#define NRFX_NFCT_ENABLED 1
244251
#endif

0 commit comments

Comments
 (0)