Skip to content

Commit 823cd28

Browse files
committed
[nrf noup] drivers: flash: nrf_mram: wait until mramc is ready before write
When writes are issued to the mram controller without verifying that it is ready, it can cause the reads to be stalled until all writes finish. Fix this by adding a wait busy loop before each MRAM_WORD aligned write and disable autopowerdown before starting the write. Signed-off-by: Riadh Ghaddab <[email protected]>
1 parent c09c6ab commit 823cd28

File tree

2 files changed

+101
-6
lines changed

2 files changed

+101
-6
lines changed

drivers/flash/Kconfig.nrf_mram

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ config SOC_FLASH_NRF_MRAM
1111
select FLASH_HAS_DRIVER_ENABLED
1212
select FLASH_HAS_PAGE_LAYOUT
1313
select FLASH_HAS_NO_EXPLICIT_ERASE
14+
select MRAM_LATENCY
15+
select NRF_IRONSIDE_BOOT_REPORT
1416
imply MPU_ALLOW_FLASH_WRITE if ARM_MPU
1517
help
1618
Enables Nordic Semiconductor flash driver for MRAM in direct write mode.

drivers/flash/soc_flash_nrf_mram.c

Lines changed: 99 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#include <zephyr/drivers/flash.h>
1010
#include <zephyr/logging/log.h>
1111
#include <zephyr/sys/barrier.h>
12+
#include <zephyr/cache.h>
13+
#include "../soc/nordic/common/mram_latency.h"
14+
#include "../soc/nordic/ironside/include/nrf_ironside/boot_report.h"
1215

1316
LOG_MODULE_REGISTER(flash_nrf_mram, CONFIG_FLASH_LOG_LEVEL);
1417

@@ -25,10 +28,37 @@ LOG_MODULE_REGISTER(flash_nrf_mram, CONFIG_FLASH_LOG_LEVEL);
2528

2629
#define ERASE_VALUE 0xff
2730

31+
#define SOC_NRF_MRAM_BANK_11_OFFSET 0x100000
32+
#define SOC_NRF_MRAM_BANK_11_ADDRESS (MRAM_START + SOC_NRF_MRAM_BANK_11_OFFSET)
33+
#define SOC_NRF_MRAMC_BASE_ADDR_10 0x5f092000
34+
#define SOC_NRF_MRAMC_BASE_ADDR_11 0x5f093000
35+
#define SOC_NRF_MRAMC_READY_REG_0 (SOC_NRF_MRAMC_BASE_ADDR_10 + 0x400)
36+
#define SOC_NRF_MRAMC_READY_REG_1 (SOC_NRF_MRAMC_BASE_ADDR_11 + 0x400)
37+
38+
#define IRONSIDE_SE_VER_MASK 0x000000FF /* This is the Mask for Ironside SE Seqnum */
39+
#define IRONSIDE_SE_SUPPORT_READY_VER 21
40+
2841
BUILD_ASSERT(MRAM_START > 0, "nordic,mram: start address expected to be non-zero");
2942
BUILD_ASSERT((ERASE_BLOCK_SIZE % WRITE_BLOCK_SIZE) == 0,
3043
"erase-block-size expected to be a multiple of write-block-size");
3144

45+
struct nrf_mram_data_t {
46+
uint8_t ironside_se_ver;
47+
};
48+
49+
static inline uint32_t nrf_mram_ready(uint32_t addr, uint8_t ironside_se_ver)
50+
{
51+
if (ironside_se_ver < IRONSIDE_SE_SUPPORT_READY_VER) {
52+
return 1;
53+
}
54+
55+
if (addr < SOC_NRF_MRAM_BANK_11_ADDRESS) {
56+
return sys_read32(SOC_NRF_MRAMC_READY_REG_0);
57+
} else {
58+
return sys_read32(SOC_NRF_MRAMC_READY_REG_1);
59+
}
60+
}
61+
3262
/**
3363
* @param[in,out] offset Relative offset into memory, from the driver API.
3464
* @param[in] len Number of bytes for the intended operation.
@@ -101,7 +131,8 @@ static int nrf_mram_read(const struct device *dev, off_t offset, void *data, siz
101131

102132
static int nrf_mram_write(const struct device *dev, off_t offset, const void *data, size_t len)
103133
{
104-
ARG_UNUSED(dev);
134+
struct nrf_mram_data_t *nrf_mram_data = dev->data;
135+
uint8_t ironside_se_ver = nrf_mram_data->ironside_se_ver;
105136

106137
const uintptr_t addr = validate_and_map_addr(offset, len, true);
107138

@@ -111,15 +142,36 @@ static int nrf_mram_write(const struct device *dev, off_t offset, const void *da
111142

112143
LOG_DBG("write: %p:%zu", (void *)addr, len);
113144

114-
memcpy((void *)addr, data, len);
145+
if (ironside_se_ver >= IRONSIDE_SE_SUPPORT_READY_VER) {
146+
mram_no_latency_sync_request();
147+
}
148+
for (uint32_t i = 0; i < (len / MRAM_WORD_SIZE); i++) {
149+
while (!nrf_mram_ready(addr + (i * MRAM_WORD_SIZE), ironside_se_ver)) {
150+
/* Wait until MRAM controller is ready */
151+
}
152+
memcpy((void *)(addr + (i * MRAM_WORD_SIZE)),
153+
(void *)((uintptr_t)data + (i * MRAM_WORD_SIZE)), MRAM_WORD_SIZE);
154+
}
155+
156+
if (len % MRAM_WORD_SIZE) {
157+
while (!nrf_mram_ready(addr + (len & ~MRAM_WORD_MASK), ironside_se_ver)) {
158+
/* Wait until MRAM controller is ready */
159+
}
160+
memcpy((void *)(addr + (len & ~MRAM_WORD_MASK)),
161+
(void *)((uintptr_t)data + (len & ~MRAM_WORD_MASK)), len & MRAM_WORD_MASK);
162+
}
115163
commit_changes(addr + len);
164+
if (ironside_se_ver >= IRONSIDE_SE_SUPPORT_READY_VER) {
165+
mram_no_latency_sync_release();
166+
}
116167

117168
return 0;
118169
}
119170

120171
static int nrf_mram_erase(const struct device *dev, off_t offset, size_t size)
121172
{
122-
ARG_UNUSED(dev);
173+
struct nrf_mram_data_t *nrf_mram_data = dev->data;
174+
uint8_t ironside_se_ver = nrf_mram_data->ironside_se_ver;
123175

124176
const uintptr_t addr = validate_and_map_addr(offset, size, true);
125177

@@ -129,8 +181,27 @@ static int nrf_mram_erase(const struct device *dev, off_t offset, size_t size)
129181

130182
LOG_DBG("erase: %p:%zu", (void *)addr, size);
131183

132-
memset((void *)addr, ERASE_VALUE, size);
184+
/* Ensure that the mramc banks are powered on */
185+
if (ironside_se_ver >= IRONSIDE_SE_SUPPORT_READY_VER) {
186+
mram_no_latency_sync_request();
187+
}
188+
for (uint32_t i = 0; i < (size / MRAM_WORD_SIZE); i++) {
189+
while (!nrf_mram_ready(addr + (i * MRAM_WORD_SIZE), ironside_se_ver)) {
190+
/* Wait until MRAM controller is ready */
191+
}
192+
memset((void *)(addr + (i * MRAM_WORD_SIZE)), ERASE_VALUE, MRAM_WORD_SIZE);
193+
}
194+
if (size % MRAM_WORD_SIZE) {
195+
while (!nrf_mram_ready(addr + (size & ~MRAM_WORD_MASK), ironside_se_ver)) {
196+
/* Wait until MRAM controller is ready */
197+
}
198+
memset((void *)(addr + (size & ~MRAM_WORD_MASK)), ERASE_VALUE,
199+
size & MRAM_WORD_MASK);
200+
}
133201
commit_changes(addr + size);
202+
if (ironside_se_ver >= IRONSIDE_SE_SUPPORT_READY_VER) {
203+
mram_no_latency_sync_release();
204+
}
134205

135206
return 0;
136207
}
@@ -186,5 +257,27 @@ static DEVICE_API(flash, nrf_mram_api) = {
186257
#endif
187258
};
188259

189-
DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY,
190-
&nrf_mram_api);
260+
static int nrf_mram_init(const struct device *dev)
261+
{
262+
struct nrf_mram_data_t *nrf_mram_data = dev->data;
263+
const struct ironside_boot_report *report;
264+
int rc = 0;
265+
266+
rc = ironside_boot_report_get(&report);
267+
268+
if (rc) {
269+
LOG_ERR("Failed to get Ironside boot report");
270+
return rc;
271+
}
272+
273+
nrf_mram_data->ironside_se_ver = FIELD_GET(IRONSIDE_SE_VER_MASK,
274+
report->ironside_se_version_int);
275+
LOG_DBG("Ironside SE version: %u", nrf_mram_data->ironside_se_ver);
276+
277+
return 0;
278+
}
279+
280+
static struct nrf_mram_data_t nrf_mram_data;
281+
282+
DEVICE_DT_INST_DEFINE(0, nrf_mram_init, NULL, &nrf_mram_data, NULL, POST_KERNEL,
283+
CONFIG_FLASH_INIT_PRIORITY, &nrf_mram_api);

0 commit comments

Comments
 (0)