Skip to content

Commit 123d2b4

Browse files
nordicjmlemrey
authored andcommitted
drivers: flash: Add softdevice-based flash driver
Adds flash driver that uses the softdevice Signed-off-by: Jamie McCrae <[email protected]>
1 parent 752f3ed commit 123d2b4

File tree

6 files changed

+295
-0
lines changed

6 files changed

+295
-0
lines changed

drivers/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ add_compile_options($<TARGET_PROPERTY:compiler,warning_shadow_variables>)
99

1010
add_subdirectory_ifdef(CONFIG_CONSOLE console)
1111
add_subdirectory_ifdef(CONFIG_CLOCK_CONTROL clock_control)
12+
add_subdirectory_ifdef(CONFIG_FLASH flash)

drivers/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ menu "Device Drivers"
77

88
# zephyr-keep-sorted-start
99
rsource "console/Kconfig"
10+
rsource "flash/Kconfig"
1011
# zephyr-keep-sorted-stop
1112

1213
endmenu

drivers/flash/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
3+
zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/flash.h)
4+
5+
zephyr_library_amend()
6+
7+
# zephyr-keep-sorted-start
8+
zephyr_library_sources_ifdef(CONFIG_SOC_FLASH_NRF_RRAM_BM soc_flash_nrf_rram.c)
9+
# zephyr-keep-sorted-stop

drivers/flash/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor
3+
#
4+
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
5+
#
6+
7+
if FLASH
8+
9+
# zephyr-keep-sorted-start
10+
rsource "Kconfig.nrf_rram"
11+
# zephyr-keep-sorted-stop
12+
13+
endif # FLASH

drivers/flash/Kconfig.nrf_rram

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#
2+
# Copyright (c) 2025 Nordic Semiconductor ASA
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
#
6+
7+
menuconfig SOC_FLASH_NRF_RRAM_BM
8+
bool "Nordic Semiconductor nRF SoftDevice-based RRAM flash driver"
9+
depends on DT_HAS_NORDIC_RRAM_CONTROLLER_ENABLED
10+
depends on FLASH
11+
select NRFX_RRAMC if !BUILD_WITH_TFM
12+
select FLASH_HAS_DRIVER_ENABLED
13+
select FLASH_HAS_PAGE_LAYOUT
14+
select FLASH_HAS_NO_EXPLICIT_ERASE
15+
select FLASH_NRF_FORCE_ALT
16+
select MPU_ALLOW_FLASH_WRITE if ARM_MPU
17+
default y if SOFTDEVICE
18+
help
19+
Enables Nordic Semiconductor nRF RRAM flash driver using the SoftDevice.
20+
21+
if SOC_FLASH_NRF_RRAM_BM
22+
23+
config NRF_RRAM_REGION_ADDRESS_RESOLUTION
24+
hex
25+
default 0x1000
26+
help
27+
RRAMC's region protection address resolution.
28+
Applies to region with configurable start address.
29+
30+
config NRF_RRAM_REGION_SIZE_UNIT
31+
hex
32+
default 0x1000
33+
help
34+
Base unit for the size of RRAMC's region protection.
35+
36+
endif # SOC_FLASH_NRF_RRAM_BM

drivers/flash/soc_flash_nrf_rram.c

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
/*
2+
* Copyright (c) 2024 Nordic Semiconductor ASA
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT nordic_rram_controller
8+
9+
#include <string.h>
10+
#include <zephyr/kernel.h>
11+
#include <zephyr/device.h>
12+
#include <zephyr/drivers/flash.h>
13+
#include <zephyr/logging/log.h>
14+
#include <zephyr/irq.h>
15+
#include <zephyr/sys/barrier.h>
16+
#include <hal/nrf_rramc.h>
17+
#include "nrf_soc.h"
18+
#include "nrf_sdh.h"
19+
#include "nrf_sdh_soc.h"
20+
21+
/* Note that it is supported to compile this driver for both secure
22+
* and non-secure images, but non-secure images cannot call
23+
* nrf_rramc_config_set because NRF_RRAMC_NS does not exist.
24+
*
25+
* Instead, when TF-M boots, it will configure RRAMC with this static
26+
* configuration:
27+
*
28+
* nrf_rramc_config_t config = {
29+
* .mode_write = true,
30+
* .write_buff_size = WRITE_BUFFER_SIZE
31+
* };
32+
*
33+
* nrf_rramc_ready_next_timeout_t params = {
34+
* .value = CONFIG_NRF_RRAM_READYNEXT_TIMEOUT_VALUE,
35+
* .enable = true,
36+
* };
37+
*
38+
* For more details see NCSDK-26982.
39+
*/
40+
41+
LOG_MODULE_REGISTER(flash_nrf_rram, CONFIG_FLASH_LOG_LEVEL);
42+
43+
#define RRAM DT_INST(0, soc_nv_flash)
44+
45+
#if defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
46+
#define RRAM_START NRF_RRAM_BASE_ADDR
47+
#else
48+
#define RRAM_START DT_REG_ADDR(RRAM)
49+
#endif
50+
#define RRAM_SIZE DT_REG_SIZE(RRAM)
51+
52+
#define PAGE_SIZE DT_PROP(RRAM, erase_block_size)
53+
#define PAGE_COUNT ((RRAM_SIZE) / (PAGE_SIZE))
54+
55+
#define WRITE_BLOCK_SIZE_FROM_DT DT_PROP(RRAM, write_block_size)
56+
#define ERASE_VALUE 0xFF
57+
#define WRITE_LINE_SIZE WRITE_BLOCK_SIZE_FROM_DT
58+
59+
static inline bool is_aligned_32(uint32_t data)
60+
{
61+
return (data & 0x3) ? false : true;
62+
}
63+
64+
static inline bool is_within_bounds(off_t addr, size_t len, off_t boundary_start,
65+
size_t boundary_size)
66+
{
67+
return (addr >= boundary_start && (addr < (boundary_start + boundary_size)) &&
68+
(len <= (boundary_start + boundary_size - addr)));
69+
}
70+
71+
static int nrf_rram_read(const struct device *dev, off_t addr, void *data, size_t len)
72+
{
73+
ARG_UNUSED(dev);
74+
75+
if (!is_within_bounds(addr, len, 0, RRAM_SIZE)) {
76+
return -EINVAL;
77+
}
78+
addr += RRAM_START;
79+
80+
#if CONFIG_TRUSTED_EXECUTION_NONSECURE && USE_PARTITION_MANAGER && PM_APP_ADDRESS
81+
if (addr < PM_APP_ADDRESS) {
82+
return soc_secure_mem_read(data, (void *)addr, len);
83+
}
84+
#endif
85+
86+
memcpy(data, (void *)addr, len);
87+
88+
return 0;
89+
}
90+
91+
static int nrf_rram_write(const struct device *dev, off_t addr, const void *data, size_t len)
92+
{
93+
int ret = 0;
94+
95+
ARG_UNUSED(dev);
96+
97+
if (data == NULL) {
98+
return -EINVAL;
99+
}
100+
101+
if (!is_within_bounds(addr, len, 0, RRAM_SIZE)) {
102+
return -EINVAL;
103+
}
104+
105+
addr += RRAM_START;
106+
107+
if (!is_aligned_32(addr) || (len % sizeof(uint32_t))) {
108+
LOG_ERR("Not word-aligned: 0x%08lx:%zu", (unsigned long)addr, len);
109+
return -EINVAL;
110+
}
111+
112+
if (!len) {
113+
return 0;
114+
}
115+
116+
LOG_DBG("Write: %p: %zu", (void *)addr, len);
117+
118+
ret = sd_flash_write((uint32_t *)addr, data, len / sizeof(uint32_t));
119+
120+
if (ret) {
121+
return -EIO;
122+
}
123+
124+
while (1) {
125+
int taskid;
126+
127+
sd_app_evt_wait();
128+
ret = sd_evt_get(&taskid);
129+
130+
if (!ret && (taskid == NRF_EVT_FLASH_OPERATION_SUCCESS ||
131+
taskid == NRF_EVT_FLASH_OPERATION_ERROR)) {
132+
if (taskid != NRF_EVT_FLASH_OPERATION_SUCCESS) {
133+
ret = -EIO;
134+
}
135+
136+
break;
137+
}
138+
}
139+
140+
barrier_dmem_fence_full(); /* Barrier following our last write. */
141+
142+
return ret;
143+
}
144+
145+
static int nrf_rram_erase(const struct device *dev, off_t addr, size_t len)
146+
{
147+
int ret = 0;
148+
uint8_t dummy_buf[16];
149+
150+
memset(dummy_buf, ERASE_VALUE, sizeof(dummy_buf));
151+
152+
if (!is_aligned_32(addr) || (len % sizeof(uint32_t))) {
153+
LOG_ERR("Not word-aligned: 0x%08lx:%zu", (unsigned long)addr, len);
154+
return -EINVAL;
155+
}
156+
157+
while (len) {
158+
uint8_t erase_len = (len < sizeof(dummy_buf) ? len : sizeof(dummy_buf));
159+
160+
ret = nrf_rram_write(dev, addr, dummy_buf, erase_len);
161+
162+
if (ret) {
163+
break;
164+
}
165+
166+
len -= erase_len;
167+
addr += erase_len;
168+
}
169+
170+
barrier_dmem_fence_full(); /* Barrier following our last write. */
171+
172+
return ret;
173+
}
174+
175+
int nrf_rram_get_size(const struct device *dev, uint64_t *size)
176+
{
177+
ARG_UNUSED(dev);
178+
179+
*size = RRAM_SIZE;
180+
181+
return 0;
182+
}
183+
184+
static const struct flash_parameters *nrf_rram_get_parameters(const struct device *dev)
185+
{
186+
ARG_UNUSED(dev);
187+
188+
static const struct flash_parameters parameters = {
189+
.write_block_size = WRITE_LINE_SIZE,
190+
.erase_value = ERASE_VALUE,
191+
.caps = {
192+
.no_explicit_erase = true,
193+
},
194+
};
195+
196+
return &parameters;
197+
}
198+
199+
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
200+
static void nrf_rram_page_layout(const struct device *dev,
201+
const struct flash_pages_layout **layout,
202+
size_t *layout_size)
203+
{
204+
ARG_UNUSED(dev);
205+
206+
static const struct flash_pages_layout pages_layout = {
207+
.pages_count = PAGE_COUNT,
208+
.pages_size = PAGE_SIZE,
209+
};
210+
211+
*layout = &pages_layout;
212+
*layout_size = 1;
213+
}
214+
#endif
215+
216+
static DEVICE_API(flash, nrf_rram_api) = {
217+
.read = nrf_rram_read,
218+
.write = nrf_rram_write,
219+
.erase = nrf_rram_erase,
220+
.get_size = nrf_rram_get_size,
221+
.get_parameters = nrf_rram_get_parameters,
222+
#if defined(CONFIG_FLASH_PAGE_LAYOUT)
223+
.page_layout = nrf_rram_page_layout,
224+
#endif
225+
};
226+
227+
static int nrf_rram_init(const struct device *dev)
228+
{
229+
ARG_UNUSED(dev);
230+
231+
return 0;
232+
}
233+
234+
DEVICE_DT_INST_DEFINE(0, nrf_rram_init, NULL, NULL, NULL, POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY,
235+
&nrf_rram_api);

0 commit comments

Comments
 (0)