From 626910f7f3ec2034bec393417963655b61ecd127 Mon Sep 17 00:00:00 2001 From: Riadh Ghaddab Date: Thu, 16 Oct 2025 10:40:56 +0200 Subject: [PATCH 1/2] [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 --- drivers/flash/Kconfig.nrf_mram | 3 + drivers/flash/soc_flash_nrf_mram.c | 105 +++++++++++++++++++++++++++-- 2 files changed, 102 insertions(+), 6 deletions(-) diff --git a/drivers/flash/Kconfig.nrf_mram b/drivers/flash/Kconfig.nrf_mram index be41cead07f1..4f57c1955317 100644 --- a/drivers/flash/Kconfig.nrf_mram +++ b/drivers/flash/Kconfig.nrf_mram @@ -11,6 +11,9 @@ config SOC_FLASH_NRF_MRAM select FLASH_HAS_DRIVER_ENABLED select FLASH_HAS_PAGE_LAYOUT select FLASH_HAS_NO_EXPLICIT_ERASE + select NRFS + select MRAM_LATENCY + select NRF_IRONSIDE_BOOT_REPORT imply MPU_ALLOW_FLASH_WRITE if ARM_MPU help Enables Nordic Semiconductor flash driver for MRAM in direct write mode. diff --git a/drivers/flash/soc_flash_nrf_mram.c b/drivers/flash/soc_flash_nrf_mram.c index 51331786dcf5..4598cbbe4017 100644 --- a/drivers/flash/soc_flash_nrf_mram.c +++ b/drivers/flash/soc_flash_nrf_mram.c @@ -9,6 +9,9 @@ #include #include #include +#include +#include "../soc/nordic/common/mram_latency.h" +#include "../soc/nordic/ironside/include/nrf_ironside/boot_report.h" LOG_MODULE_REGISTER(flash_nrf_mram, CONFIG_FLASH_LOG_LEVEL); @@ -25,10 +28,37 @@ LOG_MODULE_REGISTER(flash_nrf_mram, CONFIG_FLASH_LOG_LEVEL); #define ERASE_VALUE 0xff +#define SOC_NRF_MRAM_BANK_11_OFFSET 0x100000 +#define SOC_NRF_MRAM_BANK_11_ADDRESS (MRAM_START + SOC_NRF_MRAM_BANK_11_OFFSET) +#define SOC_NRF_MRAMC_BASE_ADDR_10 0x5f092000 +#define SOC_NRF_MRAMC_BASE_ADDR_11 0x5f093000 +#define SOC_NRF_MRAMC_READY_REG_0 (SOC_NRF_MRAMC_BASE_ADDR_10 + 0x400) +#define SOC_NRF_MRAMC_READY_REG_1 (SOC_NRF_MRAMC_BASE_ADDR_11 + 0x400) + +#define IRONSIDE_SE_VER_MASK 0x000000FF /* This is the Mask for Ironside SE Seqnum */ +#define IRONSIDE_SE_SUPPORT_READY_VER 21 + BUILD_ASSERT(MRAM_START > 0, "nordic,mram: start address expected to be non-zero"); BUILD_ASSERT((ERASE_BLOCK_SIZE % WRITE_BLOCK_SIZE) == 0, "erase-block-size expected to be a multiple of write-block-size"); +struct nrf_mram_data_t { + uint8_t ironside_se_ver; +}; + +static inline uint32_t nrf_mram_ready(uint32_t addr, uint8_t ironside_se_ver) +{ + if (ironside_se_ver < IRONSIDE_SE_SUPPORT_READY_VER) { + return 1; + } + + if (addr < SOC_NRF_MRAM_BANK_11_ADDRESS) { + return sys_read32(SOC_NRF_MRAMC_READY_REG_0); + } else { + return sys_read32(SOC_NRF_MRAMC_READY_REG_1); + } +} + /** * @param[in,out] offset Relative offset into memory, from the driver API. * @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 static int nrf_mram_write(const struct device *dev, off_t offset, const void *data, size_t len) { - ARG_UNUSED(dev); + struct nrf_mram_data_t *nrf_mram_data = dev->data; + uint8_t ironside_se_ver = nrf_mram_data->ironside_se_ver; const uintptr_t addr = validate_and_map_addr(offset, len, true); @@ -111,15 +142,36 @@ static int nrf_mram_write(const struct device *dev, off_t offset, const void *da LOG_DBG("write: %p:%zu", (void *)addr, len); - memcpy((void *)addr, data, len); + if (ironside_se_ver >= IRONSIDE_SE_SUPPORT_READY_VER) { + mram_no_latency_sync_request(); + } + for (uint32_t i = 0; i < (len / MRAM_WORD_SIZE); i++) { + while (!nrf_mram_ready(addr + (i * MRAM_WORD_SIZE), ironside_se_ver)) { + /* Wait until MRAM controller is ready */ + } + memcpy((void *)(addr + (i * MRAM_WORD_SIZE)), + (void *)((uintptr_t)data + (i * MRAM_WORD_SIZE)), MRAM_WORD_SIZE); + } + + if (len % MRAM_WORD_SIZE) { + while (!nrf_mram_ready(addr + (len & ~MRAM_WORD_MASK), ironside_se_ver)) { + /* Wait until MRAM controller is ready */ + } + memcpy((void *)(addr + (len & ~MRAM_WORD_MASK)), + (void *)((uintptr_t)data + (len & ~MRAM_WORD_MASK)), len & MRAM_WORD_MASK); + } commit_changes(addr + len); + if (ironside_se_ver >= IRONSIDE_SE_SUPPORT_READY_VER) { + mram_no_latency_sync_release(); + } return 0; } static int nrf_mram_erase(const struct device *dev, off_t offset, size_t size) { - ARG_UNUSED(dev); + struct nrf_mram_data_t *nrf_mram_data = dev->data; + uint8_t ironside_se_ver = nrf_mram_data->ironside_se_ver; const uintptr_t addr = validate_and_map_addr(offset, size, true); @@ -129,8 +181,27 @@ static int nrf_mram_erase(const struct device *dev, off_t offset, size_t size) LOG_DBG("erase: %p:%zu", (void *)addr, size); - memset((void *)addr, ERASE_VALUE, size); + /* Ensure that the mramc banks are powered on */ + if (ironside_se_ver >= IRONSIDE_SE_SUPPORT_READY_VER) { + mram_no_latency_sync_request(); + } + for (uint32_t i = 0; i < (size / MRAM_WORD_SIZE); i++) { + while (!nrf_mram_ready(addr + (i * MRAM_WORD_SIZE), ironside_se_ver)) { + /* Wait until MRAM controller is ready */ + } + memset((void *)(addr + (i * MRAM_WORD_SIZE)), ERASE_VALUE, MRAM_WORD_SIZE); + } + if (size % MRAM_WORD_SIZE) { + while (!nrf_mram_ready(addr + (size & ~MRAM_WORD_MASK), ironside_se_ver)) { + /* Wait until MRAM controller is ready */ + } + memset((void *)(addr + (size & ~MRAM_WORD_MASK)), ERASE_VALUE, + size & MRAM_WORD_MASK); + } commit_changes(addr + size); + if (ironside_se_ver >= IRONSIDE_SE_SUPPORT_READY_VER) { + mram_no_latency_sync_release(); + } return 0; } @@ -186,5 +257,27 @@ static DEVICE_API(flash, nrf_mram_api) = { #endif }; -DEVICE_DT_INST_DEFINE(0, NULL, NULL, NULL, NULL, POST_KERNEL, CONFIG_FLASH_INIT_PRIORITY, - &nrf_mram_api); +static int nrf_mram_init(const struct device *dev) +{ + struct nrf_mram_data_t *nrf_mram_data = dev->data; + const struct ironside_boot_report *report; + int rc = 0; + + rc = ironside_boot_report_get(&report); + + if (rc) { + LOG_ERR("Failed to get Ironside boot report"); + return rc; + } + + nrf_mram_data->ironside_se_ver = FIELD_GET(IRONSIDE_SE_VER_MASK, + report->ironside_se_version_int); + LOG_DBG("Ironside SE version: %u", nrf_mram_data->ironside_se_ver); + + return 0; +} + +static struct nrf_mram_data_t nrf_mram_data; + +DEVICE_DT_INST_DEFINE(0, nrf_mram_init, NULL, &nrf_mram_data, NULL, POST_KERNEL, + CONFIG_FLASH_INIT_PRIORITY, &nrf_mram_api); From deb80799afe400c3e9d6e12d0d4168cad586915f Mon Sep 17 00:00:00 2001 From: Riadh Ghaddab Date: Wed, 10 Dec 2025 12:33:48 +0100 Subject: [PATCH 2/2] [nrf noup] tests: quarantine drivers.mspi.flash.mspi_nor_no_multithreading Quarantine this test as it needs NO_MULTITHREADING while MRAM selects it Signed-off-by: Riadh Ghaddab --- scripts/quarantine.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/quarantine.yaml b/scripts/quarantine.yaml index 20c4f9248ea9..0903054928c3 100644 --- a/scripts/quarantine.yaml +++ b/scripts/quarantine.yaml @@ -86,3 +86,9 @@ - nrf5340dk_nrf5340_cpuapp_ns - nrf9160dk_nrf9160_ns comment: "Due to using sdk-zephyr manifest instead of nrf. Should be fixed after the change" + +- scenarios: + - drivers.mspi.flash.mspi_nor_no_multithreading + platforms: + - nrf54h20dk_nrf54h20_cpuapp + comment: "MRAM needs NRFS which requires multithreading"