drivers: flash: atmel SAM0 fix flash_write to handle smaller length.
Fix flash_sam0_write to handle byte lengths smaller than FLASH_PAGE_SIZE Signed-off-by: Daniel Evans <photonthunder@gmail.com>
This commit is contained in:
parent
d3a73cdb0e
commit
debc65fa63
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#define DT_DRV_COMPAT atmel_sam0_nvmctrl
|
||||
#define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash)
|
||||
|
||||
#define LOG_LEVEL CONFIG_FLASH_LOG_LEVEL
|
||||
#include <zephyr/logging/log.h>
|
||||
|
@ -17,6 +18,9 @@ LOG_MODULE_REGISTER(flash_sam0);
|
|||
#include <soc.h>
|
||||
#include <string.h>
|
||||
|
||||
#define FLASH_WRITE_BLK_SZ DT_PROP(SOC_NV_FLASH_NODE, write_block_size)
|
||||
BUILD_ASSERT((FLASH_WRITE_BLK_SZ % sizeof(uint32_t)) == 0, "unsupported write-block-size");
|
||||
|
||||
/*
|
||||
* Zephyr and the SAM0 series use different and conflicting names for
|
||||
* the erasable units and programmable units:
|
||||
|
@ -67,7 +71,7 @@ static const struct flash_parameters flash_sam0_parameters = {
|
|||
#if CONFIG_SOC_FLASH_SAM0_EMULATE_BYTE_PAGES
|
||||
.write_block_size = 1,
|
||||
#else
|
||||
.write_block_size = DT_PROP(DT_INST(0, soc_nv_flash), write_block_size),
|
||||
.write_block_size = FLASH_WRITE_BLK_SZ,
|
||||
#endif
|
||||
.erase_value = 0xff,
|
||||
};
|
||||
|
@ -147,11 +151,18 @@ static int flash_sam0_check_status(off_t offset)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Data to be written to the NVM block are first written to and stored
|
||||
* in an internal buffer called the page buffer. The page buffer contains
|
||||
* the same number of bytes as an NVM page. Writes to the page buffer must
|
||||
* be 16 or 32 bits. 8-bit writes to the page buffer are not allowed and
|
||||
* will cause a system exception
|
||||
*/
|
||||
static int flash_sam0_write_page(const struct device *dev, off_t offset,
|
||||
const void *data)
|
||||
const void *data, size_t len)
|
||||
{
|
||||
const uint32_t *src = data;
|
||||
const uint32_t *end = src + FLASH_PAGE_SIZE / sizeof(*src);
|
||||
const uint32_t *end = src + (len / sizeof(*src));
|
||||
uint32_t *dst = FLASH_MEM(offset);
|
||||
int err;
|
||||
|
||||
|
@ -178,7 +189,7 @@ static int flash_sam0_write_page(const struct device *dev, off_t offset,
|
|||
return err;
|
||||
}
|
||||
|
||||
if (memcmp(data, FLASH_MEM(offset), FLASH_PAGE_SIZE) != 0) {
|
||||
if (memcmp(data, FLASH_MEM(offset), len) != 0) {
|
||||
LOG_ERR("verify error at offset 0x%lx", (long)offset);
|
||||
return -EIO;
|
||||
}
|
||||
|
@ -213,7 +224,7 @@ static int flash_sam0_commit(const struct device *dev, off_t base)
|
|||
for (page = 0; page < PAGES_PER_ROW; page++) {
|
||||
err = flash_sam0_write_page(
|
||||
dev, base + page * FLASH_PAGE_SIZE,
|
||||
&ctx->buf[page * FLASH_PAGE_SIZE]);
|
||||
&ctx->buf[page * FLASH_PAGE_SIZE], ROW_SIZE);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
@ -280,19 +291,18 @@ static int flash_sam0_write(const struct device *dev, off_t offset,
|
|||
{
|
||||
const uint8_t *pdata = data;
|
||||
int err;
|
||||
size_t idx;
|
||||
|
||||
err = flash_sam0_valid_range(offset, len);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if ((offset % FLASH_PAGE_SIZE) != 0) {
|
||||
if ((offset % FLASH_WRITE_BLK_SZ) != 0) {
|
||||
LOG_WRN("0x%lx: not on a write block boundary", (long)offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((len % FLASH_PAGE_SIZE) != 0) {
|
||||
if ((len % FLASH_WRITE_BLK_SZ) != 0) {
|
||||
LOG_WRN("%zu: not a integer number of write blocks", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -301,12 +311,20 @@ static int flash_sam0_write(const struct device *dev, off_t offset,
|
|||
|
||||
err = flash_sam0_write_protection(dev, false);
|
||||
if (err == 0) {
|
||||
for (idx = 0; idx < len; idx += FLASH_PAGE_SIZE) {
|
||||
err = flash_sam0_write_page(dev, offset + idx,
|
||||
&pdata[idx]);
|
||||
/* Maximum size without crossing a page */
|
||||
size_t eop_len = FLASH_PAGE_SIZE - (offset % FLASH_PAGE_SIZE);
|
||||
size_t write_len = MIN(len, eop_len);
|
||||
|
||||
while (len > 0) {
|
||||
err = flash_sam0_write_page(dev, offset, pdata, write_len);
|
||||
if (err != 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
offset += write_len;
|
||||
pdata += write_len;
|
||||
len -= write_len;
|
||||
write_len = MIN(len, FLASH_PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,6 +472,9 @@ static int flash_sam0_init(const struct device *dev)
|
|||
#ifdef NVMCTRL_CTRLB_MANW
|
||||
/* Require an explicit write command */
|
||||
NVMCTRL->CTRLB.bit.MANW = 1;
|
||||
#elif NVMCTRL_CTRLA_WMODE
|
||||
/* Set manual write mode */
|
||||
NVMCTRL->CTRLA.bit.WMODE = NVMCTRL_CTRLA_WMODE_MAN_Val;
|
||||
#endif
|
||||
|
||||
return flash_sam0_write_protection(dev, false);
|
||||
|
|
Loading…
Reference in a new issue