From 143f9bfd4e1aed2320d46df6de4dbf1d09f4d69d Mon Sep 17 00:00:00 2001 From: Dominik Ermel Date: Wed, 11 Mar 2020 10:46:48 +0000 Subject: [PATCH] drivers/flash/nrfx: Enable partial erase of flash When enabled, instead of erasing entire flash page at once, page will be erased in defined time slices. Erasing single page stalls CPU for significant time share (~80ms) and partial erase divides the operation in to the shorter time periods, resuming CPU operation in meantime and enabling better scheduling of time sensitive operations. Signed-off-by: Dominik Ermel --- drivers/flash/Kconfig.nrf | 23 ++++++++++++ drivers/flash/soc_flash_nrf.c | 51 ++++++++++++++++++++++---- soc/arm/nordic_nrf/Kconfig.peripherals | 4 ++ soc/arm/nordic_nrf/nrf52/Kconfig.soc | 4 ++ soc/arm/nordic_nrf/nrf53/Kconfig.soc | 2 + soc/arm/nordic_nrf/nrf91/Kconfig.soc | 1 + 6 files changed, 78 insertions(+), 7 deletions(-) diff --git a/drivers/flash/Kconfig.nrf b/drivers/flash/Kconfig.nrf index 6aaa0178002..57ac4abf522 100644 --- a/drivers/flash/Kconfig.nrf +++ b/drivers/flash/Kconfig.nrf @@ -27,6 +27,29 @@ config SOC_FLASH_NRF_RADIO_SYNC help Enable synchronization between flash memory driver and radio. +config SOC_FLASH_NRF_PARTIAL_ERASE + bool "Nordic nRFx flash driver partial erase" + depends on HAS_HW_NRF_NVMC_PE + help + Enable partial erase feature. Partial erase is performed in time + slices instead of blocking MCU, for the time it is needed to + complete operation over given area. + This allows interrupting flash erase between operations + to perform other task by MCU. + This feature may also be used for better syncing flash erase + operations, when compiled with SOC_FLASH_NRF_RADIO_SYNC, + with Bluetooth. + +config SOC_FLASH_NRF_PARTIAL_ERASE_MS + int "Partial erase timeout in MS" + depends on SOC_FLASH_NRF_PARTIAL_ERASE + default 3 + help + This is maximum time, in ms, that NVMC will use to erase part + of Flash, before stopping to let CPU resume operation. + Minimal timeout is 2ms maximum should not exceed half of + FLASH_PAGE_ERASE_MAX_TIME_US im ms. + config SOC_FLASH_NRF_UICR bool "Access to UICR" depends on !TRUSTED_EXECUTION_NONSECURE diff --git a/drivers/flash/soc_flash_nrf.c b/drivers/flash/soc_flash_nrf.c index 7b62897ed75..04c6e7c09e8 100644 --- a/drivers/flash/soc_flash_nrf.c +++ b/drivers/flash/soc_flash_nrf.c @@ -26,18 +26,33 @@ #define FLASH_RADIO_ABORT_DELAY_US 1500 #define FLASH_RADIO_WORK_DELAY_US 200 -#define FLASH_SLOT_ERASE FLASH_PAGE_ERASE_MAX_TIME_US + #define FLASH_INTERVAL_ERASE (FLASH_RADIO_ABORT_DELAY_US + \ FLASH_RADIO_WORK_DELAY_US + \ FLASH_SLOT_ERASE) -#define FLASH_INTERVAL_WRITE 7500 #define FLASH_SLOT_WRITE (FLASH_INTERVAL_WRITE - \ FLASH_RADIO_ABORT_DELAY_US - \ FLASH_RADIO_WORK_DELAY_US) +#define FLASH_INTERVAL_WRITE 7500 + +#if defined(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE) + +/* The timeout is multiplied by 1.5 because switching tasks may take + * significant portion of time. + */ +#define FLASH_TIMEOUT_MS ((FLASH_PAGE_ERASE_MAX_TIME_US) * \ + (FLASH_PAGE_MAX_CNT) / 1000 * 15 / 10) +#define FLASH_SLOT_ERASE (MAX(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE_MS * 1000, \ + 7500)) +#else + +#define FLASH_TIMEOUT_MS ((FLASH_PAGE_ERASE_MAX_TIME_US) * \ + (FLASH_PAGE_MAX_CNT) / 1000) +#define FLASH_SLOT_ERASE FLASH_PAGE_ERASE_MAX_TIME_US + +#endif /* CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE */ -#define FLASH_TIMEOUT_MS ((FLASH_PAGE_ERASE_MAX_TIME_US)\ - * (FLASH_PAGE_MAX_CNT) / 1000) #endif /* CONFIG_SOC_FLASH_NRF_RADIO_SYNC */ #define FLASH_OP_DONE (0) /* 0 for compliance with the driver API. */ @@ -52,6 +67,9 @@ struct flash_context { u32_t interval; /* timeslot interval. */ u32_t slot; /* timeslot length. */ #endif /* CONFIG_SOC_FLASH_NRF_RADIO_SYNC */ +#if defined(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE) + u32_t flash_addr_next; +#endif /* CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE */ }; /*< Context type for f. @ref write_op @ref erase_op */ #if defined(CONFIG_SOC_FLASH_NRF_RADIO_SYNC) @@ -426,7 +444,10 @@ static int erase_in_timeslice(u32_t addr, u32_t size) .len = size, .enable_time_limit = 1, /* enable time limit */ .interval = FLASH_INTERVAL_ERASE, - .slot = FLASH_SLOT_ERASE + .slot = FLASH_SLOT_ERASE, +#if defined(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE) + .flash_addr_next = addr +#endif }; struct flash_op_desc flash_op_desc = { @@ -481,10 +502,23 @@ static int erase_op(void *context) #endif do { - (void)nrfx_nvmc_page_erase(e_ctx->flash_addr); +#if defined(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE) + if (e_ctx->flash_addr == e_ctx->flash_addr_next) { + nrfx_nvmc_page_partial_erase_init(e_ctx->flash_addr, + CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE_MS); + e_ctx->flash_addr_next += pg_size; + } + + if (nrfx_nvmc_page_partial_erase_continue()) { + e_ctx->len -= pg_size; + e_ctx->flash_addr += pg_size; + } +#else + (void)nrfx_nvmc_page_erase(e_ctx->flash_addr); e_ctx->len -= pg_size; e_ctx->flash_addr += pg_size; +#endif /* CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE */ #if defined(CONFIG_SOC_FLASH_NRF_RADIO_SYNC) i++; @@ -597,8 +631,11 @@ static int erase(u32_t addr, u32_t size) .flash_addr = addr, .len = size, #if defined(CONFIG_SOC_FLASH_NRF_RADIO_SYNC) - .enable_time_limit = 0 /* disable time limit */ + .enable_time_limit = 0, /* disable time limit */ #endif /* CONFIG_SOC_FLASH_NRF_RADIO_SYNC */ +#if defined(CONFIG_SOC_FLASH_NRF_PARTIAL_ERASE) + .flash_addr_next = addr +#endif }; return erase_op(&context); diff --git a/soc/arm/nordic_nrf/Kconfig.peripherals b/soc/arm/nordic_nrf/Kconfig.peripherals index bc5606c0b1e..b29bd097fdd 100644 --- a/soc/arm/nordic_nrf/Kconfig.peripherals +++ b/soc/arm/nordic_nrf/Kconfig.peripherals @@ -78,6 +78,10 @@ config HAS_HW_NRF_MWU config HAS_HW_NRF_NFCT bool +# NVMC supports partial erase +config HAS_HW_NRF_NVMC_PE + bool + config HAS_HW_NRF_PDM bool diff --git a/soc/arm/nordic_nrf/nrf52/Kconfig.soc b/soc/arm/nordic_nrf/nrf52/Kconfig.soc index ce9c3abda1e..c3ab1d6cb56 100644 --- a/soc/arm/nordic_nrf/nrf52/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf52/Kconfig.soc @@ -15,6 +15,7 @@ config SOC_NRF52810 select HAS_HW_NRF_EGU1 select HAS_HW_NRF_GPIO0 select HAS_HW_NRF_GPIOTE + select HAS_HW_NRF_NVMC_PE select HAS_HW_NRF_PDM select HAS_HW_NRF_POWER select HAS_HW_NRF_PPI @@ -56,6 +57,7 @@ config SOC_NRF52811 select HAS_HW_NRF_EGU1 select HAS_HW_NRF_GPIO0 select HAS_HW_NRF_GPIOTE + select HAS_HW_NRF_NVMC_PE select HAS_HW_NRF_PDM select HAS_HW_NRF_POWER select HAS_HW_NRF_PPI @@ -179,6 +181,7 @@ config SOC_NRF52833 select HAS_HW_NRF_LPCOMP select HAS_HW_NRF_MWU select HAS_HW_NRF_NFCT + select HAS_HW_NRF_NVMC_PE select HAS_HW_NRF_PDM select HAS_HW_NRF_POWER select HAS_HW_NRF_PPI @@ -252,6 +255,7 @@ config SOC_NRF52840 select HAS_HW_NRF_LPCOMP select HAS_HW_NRF_MWU select HAS_HW_NRF_NFCT + select HAS_HW_NRF_NVMC_PE select HAS_HW_NRF_PDM select HAS_HW_NRF_POWER select HAS_HW_NRF_PPI diff --git a/soc/arm/nordic_nrf/nrf53/Kconfig.soc b/soc/arm/nordic_nrf/nrf53/Kconfig.soc index e3bc3498fd4..6817d17b7a6 100644 --- a/soc/arm/nordic_nrf/nrf53/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf53/Kconfig.soc @@ -25,6 +25,7 @@ config SOC_NRF5340_CPUAPP select HAS_HW_NRF_I2S select HAS_HW_NRF_IPC select HAS_HW_NRF_NFCT + select HAS_HW_NRF_NVMC_PE select HAS_HW_NRF_PDM select HAS_HW_NRF_POWER select HAS_HW_NRF_PWM0 @@ -75,6 +76,7 @@ config SOC_NRF5340_CPUNET select HAS_HW_NRF_GPIO1 select HAS_HW_NRF_GPIOTE select HAS_HW_NRF_IPC + select HAS_HW_NRF_NVMC_PE select HAS_HW_NRF_POWER select HAS_HW_NRF_RADIO_BLE_CODED select HAS_HW_NRF_RADIO_IEEE802154 diff --git a/soc/arm/nordic_nrf/nrf91/Kconfig.soc b/soc/arm/nordic_nrf/nrf91/Kconfig.soc index ab954bbff7c..333d1f92b51 100644 --- a/soc/arm/nordic_nrf/nrf91/Kconfig.soc +++ b/soc/arm/nordic_nrf/nrf91/Kconfig.soc @@ -19,6 +19,7 @@ config SOC_NRF9160 select HAS_HW_NRF_GPIOTE select HAS_HW_NRF_I2S select HAS_HW_NRF_IPC + select HAS_HW_NRF_NVMC_PE select HAS_HW_NRF_PDM select HAS_HW_NRF_POWER select HAS_HW_NRF_PWM0