From 622b5d356136f9172db7fe7ba240cd9e45097a19 Mon Sep 17 00:00:00 2001 From: Marek Vasut Date: Wed, 28 Sep 2022 18:45:04 +0200 Subject: [PATCH] cmd: sf: Handle unaligned 'update' start offset Currently the 'sf update' command fails in case the 'start' offset is not aligned to SPI NOR erase block size. Add the missing alignment calculation. In case the start offset is in the middle of erase block, round start address down to the nearest aligned one, compare only the updated data between what is in the SPI NOR and what is being written, copy new data at offset of the compare buffer, and write back the entire erase block. This is useful e.g. on i.MX6Q where the u-boot-with-spl.imx is at offset 0x400 in the SPI NOR, while the SPI NOR may have erase block size e.g. 0x1000 bytes. Signed-off-by: Marek Vasut Reviewed-by: Jagan Teki --- cmd/sf.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/cmd/sf.c b/cmd/sf.c index bd102f5..f9b2d9a 100644 --- a/cmd/sf.c +++ b/cmd/sf.c @@ -179,16 +179,18 @@ static const char *spi_flash_update_block(struct spi_flash *flash, u32 offset, size_t len, const char *buf, char *cmp_buf, size_t *skipped) { char *ptr = (char *)buf; + u32 start_offset = offset % flash->sector_size; + u32 read_offset = offset - start_offset; - debug("offset=%#x, sector_size=%#x, len=%#zx\n", - offset, flash->sector_size, len); + debug("offset=%#x+%#x, sector_size=%#x, len=%#zx\n", + read_offset, start_offset, flash->sector_size, len); /* Read the entire sector so to allow for rewriting */ - if (spi_flash_read(flash, offset, flash->sector_size, cmp_buf)) + if (spi_flash_read(flash, read_offset, flash->sector_size, cmp_buf)) return "read"; /* Compare only what is meaningful (len) */ - if (memcmp(cmp_buf, buf, len) == 0) { - debug("Skip region %x size %zx: no change\n", - offset, len); + if (memcmp(cmp_buf + start_offset, buf, len) == 0) { + debug("Skip region %x+%x size %zx: no change\n", + start_offset, read_offset, len); *skipped += len; return NULL; } @@ -197,7 +199,7 @@ static const char *spi_flash_update_block(struct spi_flash *flash, u32 offset, return "erase"; /* If it's a partial sector, copy the data into the temp-buffer */ if (len != flash->sector_size) { - memcpy(cmp_buf, buf, len); + memcpy(cmp_buf + start_offset, buf, len); ptr = cmp_buf; } /* Write one complete sector */ @@ -238,6 +240,8 @@ static int spi_flash_update(struct spi_flash *flash, u32 offset, for (; buf < end && !err_oper; buf += todo, offset += todo) { todo = min_t(size_t, end - buf, flash->sector_size); + todo = min_t(size_t, end - buf, + flash->sector_size - (offset % flash->sector_size)); if (get_timer(last_update) > 100) { printf(" \rUpdating, %zu%% %lu B/s", 100 - (end - buf) / scale, -- 2.7.4