drivers: flash: nrf_qspi_nor: Fix writing from unaligned RAM buffers

Flash API states that drivers should support write requests without
any restrictions on location or alignment of the source buffer.
Due to hardware limitations of the QSPI peripheral, the nrf_qspi_nor
driver currently fails to perform a write from a RAM buffer that is
not word-aligned. Fix this by using in such case the same mechanism
that is used when the source buffer is located in the internal flash
(copy data to a buffer located on stack).
Also correct the length parameter for writes from this stack-based
buffer to be the actual data chunk length, not always the size of
the buffer (as for CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE > 4
this may lead to overwriting of some data located next in the flash).

Signed-off-by: Andrzej Głąbek <andrzej.glabek@nordicsemi.no>
This commit is contained in:
Andrzej Głąbek 2023-07-13 08:57:48 +02:00 committed by Carles Cufí
commit 41c33d7f32
2 changed files with 14 additions and 12 deletions

View file

@ -28,14 +28,15 @@ config NORDIC_QSPI_NOR_FLASH_LAYOUT_PAGE_SIZE
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"
int "Size of a stack-based buffer to handle writes not supported by QSPI"
default 4
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.
The QSPI peripheral uses DMA and can only write data that is read
from a word-aligned location in RAM. A non-zero value here enables
a stack buffer to be used for any source data that does not meet
these restrictions. Such data will be copied into this buffer to
allow the write to proceed. Multiple transfers will be initiated
if the data is larger than the configured size.
Must be a multiple of 4. When set to 0, the feature is disabled.
endif # NORDIC_QSPI_NOR

View file

@ -1060,8 +1060,8 @@ BUILD_ASSERT((CONFIG_NORDIC_QSPI_NOR_STACK_WRITE_BUFFER_SIZE % 4) == 0,
*
* If not enabled return the error the peripheral would have produced.
*/
static inline nrfx_err_t write_from_nvmc(const struct device *dev, off_t addr,
const void *sptr, size_t slen)
static nrfx_err_t write_through_buffer(const struct device *dev, off_t addr,
const void *sptr, size_t slen)
{
nrfx_err_t res = NRFX_SUCCESS;
@ -1073,7 +1073,7 @@ static inline nrfx_err_t write_from_nvmc(const struct device *dev, off_t addr,
size_t len = MIN(slen, sizeof(buf));
memcpy(buf, sp, len);
res = nrfx_qspi_write(buf, sizeof(buf), addr);
res = nrfx_qspi_write(buf, len, addr);
qspi_wait_for_completion(dev, res);
if (res == NRFX_SUCCESS) {
@ -1131,8 +1131,9 @@ static int qspi_nor_write(const struct device *dev, off_t addr,
if (!res) {
if (size < 4U) {
res = write_sub_word(dev, addr, src, size);
} else if (!nrfx_is_in_ram(src)) {
res = write_from_nvmc(dev, addr, src, size);
} else if (!nrfx_is_in_ram(src) ||
!nrfx_is_word_aligned(src)) {
res = write_through_buffer(dev, addr, src, size);
} else {
res = nrfx_qspi_write(src, size, addr);
qspi_wait_for_completion(dev, res);