drivers: flash: nrf_qspi_nor: optionally support write from NVMC

The Nordic QSPI peripheral uses DMA transfers so data to write must be
located in SRAM.  Add a Kconfig that enables copying data from NVMC to
a stack SRAM buffer so it can be written to flash.

Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
This commit is contained in:
Peter Bigot 2020-06-04 12:15:02 -05:00 committed by Carles Cufí
commit f2ac844cf7
2 changed files with 53 additions and 2 deletions

View file

@ -29,4 +29,15 @@ config NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE
that API. By default the page size corresponds to the block
size (65536). Other option include the sector size (4096).
config NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE
int "Size of a stack-based buffer to support writes from NVMC"
default 0
help
The QSPI peripheral uses DMA and cannot write data that is
read from the internal flash. A non-zero value here enables
a stack buffer into which data is copied to allow the write
to proceed. Multiple transfers will be initiated if the
data is larger than the configured limit. Must be a
multiple of 4. The feature is disabled when set to 0.
endif # NORDIC_QSPI_NOR

View file

@ -563,14 +563,52 @@ static inline nrfx_err_t write_sub_word(struct device *dev, off_t addr,
qspi_wait_for_completion(dev, res);
if (res == NRFX_SUCCESS) {
memcpy(sptr, buf, slen);
res = nrfx_qspi_write(src, size, addr);
memcpy(buf, sptr, slen);
res = nrfx_qspi_write(buf, sizeof(buf), addr);
qspi_wait_for_completion(dev, res);
}
return res;
}
BUILD_ASSERT((CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE % 4) == 0,
"NOR stack buffer must be multiple of 4 bytes");
#define NVMC_WRITE_OK (CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE > 0)
/* If enabled write using a stack-allocated aligned SRAM buffer as
* required for DMA transfers by QSPI peripheral.
*
* If not enabled return the error the peripheral would have produced.
*/
static inline nrfx_err_t write_from_nvmc(struct device *dev, off_t addr,
const void *sptr, size_t slen)
{
#if NVMC_WRITE_OK
uint8_t __aligned(4) buf[CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE];
const uint8_t *sp = sptr;
nrfx_err_t res = NRFX_SUCCESS;
while ((slen > 0) && (res == NRFX_SUCCESS)) {
size_t len = MIN(slen, sizeof(buf));
memcpy(buf, sp, len);
res = nrfx_qspi_write(buf, sizeof(buf),
addr);
qspi_wait_for_completion(dev, res);
if (res == NRFX_SUCCESS) {
slen -= len;
sp += len;
addr += len;
}
}
#else /* NVMC_WRITE_OK */
nrfx_err_t res = NRFX_ERROR_INVALID_ADDR;
#endif /* NVMC_WRITE_OK */
return res;
}
static int qspi_nor_write(struct device *dev, off_t addr, const void *src,
size_t size)
{
@ -610,6 +648,8 @@ static int qspi_nor_write(struct device *dev, off_t addr, const void *src,
if (size < 4U) {
res = write_sub_word(dev, addr, src, size);
} else if (((uintptr_t)src < CONFIG_SRAM_BASE_ADDRESS)) {
res = write_from_nvmc(dev, addr, src, size);
} else {
res = nrfx_qspi_write(src, size, addr);
qspi_wait_for_completion(dev, res);