Skip to content

Commit

Permalink
drivers: flash: atmel SAM0 fix flash_write to handle smaller length.
Browse files Browse the repository at this point in the history
Fix flash_sam0_write to handle byte lengths smaller than FLASH_PAGE_SIZE

Signed-off-by: Daniel Evans <[email protected]>
  • Loading branch information
photonthunder committed Jun 29, 2023
1 parent 2f5068f commit 7b637e8
Showing 1 changed file with 26 additions and 13 deletions.
39 changes: 26 additions & 13 deletions drivers/flash/flash_sam0.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
*/

#define DT_DRV_COMPAT atmel_sam0_nvmctrl
#define SOC_NV_FLASH_NODE DT_INST(0, soc_nv_flash)

#define FLASH_WRITE_BLK_SZ DT_PROP(SOC_NV_FLASH_NODE, write_block_size)

#define LOG_LEVEL CONFIG_FLASH_LOG_LEVEL
#include <zephyr/logging/log.h>
Expand Down Expand Up @@ -67,7 +70,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,
};
Expand Down Expand Up @@ -148,10 +151,9 @@ static int flash_sam0_check_status(off_t offset)
}

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);
uint32_t *dst = FLASH_MEM(offset);
int err;

Expand All @@ -163,10 +165,11 @@ static int flash_sam0_write_page(const struct device *dev, off_t offset,
flash_sam0_wait_ready();

/* Ensure writes happen 32 bits at a time. */
for (; src != end; src++, dst++) {
*dst = UNALIGNED_GET((uint32_t *)src);
for (; len > 0; len -= sizeof(*src)) {
*dst++ = UNALIGNED_GET((uint32_t *)src++);
}


#ifdef NVMCTRL_CTRLA_CMD_WP
NVMCTRL->CTRLA.reg = NVMCTRL_CTRLA_CMD_WP | NVMCTRL_CTRLA_CMDEX_KEY;
#else
Expand All @@ -178,7 +181,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;
}
Expand Down Expand Up @@ -213,7 +216,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;
}
Expand Down Expand Up @@ -275,24 +278,25 @@ static int flash_sam0_write(const struct device *dev, off_t offset,

#else /* CONFIG_SOC_FLASH_SAM0_EMULATE_BYTE_PAGES */

BUILD_ASSERT((FLASH_WRITE_BLK_SZ % sizeof(uint32_t)) == 0, "unsupported write-block-size");

static int flash_sam0_write(const struct device *dev, off_t offset,
const void *data, size_t len)
{
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;
}
Expand All @@ -301,12 +305,21 @@ 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]);
while (len > 0) {
size_t eop_len, write_len;

/* Maximum size without crossing a page */
eop_len = -(offset | ~(FLASH_PAGE_SIZE - 1));
write_len = MIN(len, eop_len);

err = flash_sam0_write_page(dev, offset, pdata, write_len);
if (err != 0) {
break;
}

offset += write_len;
pdata += write_len;
len -= write_len;
}
}

Expand Down

0 comments on commit 7b637e8

Please sign in to comment.