From 21c1bf96282e8ac6bf6ff43cb537cbdefd84fc65 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Mon, 20 Aug 2012 07:24:06 +0100 Subject: [PATCH] flash: Only erase flash block that contain data It wastes time to erase blocks that are already erased and it is faster on stm32 to check first. Add a check in flash_physical_erase() on all chips, using a common flash_is_erased() function. BUG=none BRANCH=snow,link TEST=manual Do software sync in U-Boot and see that it succeeds. This tests that we can still erase and then boot a written image. It typically saves a second on a full sync over i2c. SMDK5250 # cros_test swsync -f SF: Detected W25Q32 with page size 4 KiB, total 4 MiB Flashing RW EC image: erasing, writing, done Flashing RO EC image: erasing, writing, done Full software sync completed in 22.949s SMDK5250 # Also see that second erase is faster: SMDK5250 # time mkbp erase rw time: 0.952 seconds, 952 ticks SMDK5250 # time mkbp erase rw time: 0.054 seconds, 54 ticks SMDK5250 # Change-Id: I3699577217fdbb2f212d20d150d3ca15fdff03eb Signed-off-by: Simon Glass Reviewed-on: https://gerrit.chromium.org/gerrit/30851 Reviewed-by: Randall Spangler --- chip/lm4/flash.c | 12 ++++++++---- chip/stm32/flash-stm32f100.c | 12 +++++++----- chip/stm32/flash-stm32l15x.c | 6 ++++++ common/flash_common.c | 17 +++++++++++++++++ include/flash.h | 11 +++++++++++ 5 files changed, 49 insertions(+), 9 deletions(-) diff --git a/chip/lm4/flash.c b/chip/lm4/flash.c index 8eab52ca9c..c9922b4ea4 100644 --- a/chip/lm4/flash.c +++ b/chip/lm4/flash.c @@ -227,11 +227,17 @@ int flash_physical_write(int offset, int size, const char *data) int flash_physical_erase(int offset, int size) { LM4_FLASH_FCMISC = LM4_FLASH_FCRIS; /* Clear previous error status */ - LM4_FLASH_FMA = offset; - for ( ; size > 0; size -= CONFIG_FLASH_ERASE_SIZE) { + for ( ; size > 0; size -= CONFIG_FLASH_ERASE_SIZE, + offset += CONFIG_FLASH_ERASE_SIZE) { int t; + /* Do nothing if already erased */ + if (flash_is_erased(offset, CONFIG_FLASH_ERASE_SIZE)) + continue; + + LM4_FLASH_FMA = offset; + #ifdef CONFIG_TASK_WATCHDOG /* Reload the watchdog timer, so that erasing many flash pages * doesn't cause a watchdog reset. May not need this now that @@ -253,8 +259,6 @@ int flash_physical_erase(int offset, int size) * protection error */ if (LM4_FLASH_FCRIS & 0x0a01) return EC_ERROR_UNKNOWN; - - LM4_FLASH_FMA += CONFIG_FLASH_ERASE_SIZE; } return EC_SUCCESS; diff --git a/chip/stm32/flash-stm32f100.c b/chip/stm32/flash-stm32f100.c index fe8af24d54..b42400ec7a 100644 --- a/chip/stm32/flash-stm32f100.c +++ b/chip/stm32/flash-stm32f100.c @@ -349,7 +349,6 @@ exit_wr: int flash_physical_erase(int offset, int size) { - uint32_t address; int res = EC_SUCCESS; if (unlock(PRG_LOCK) != EC_SUCCESS) @@ -361,13 +360,16 @@ int flash_physical_erase(int offset, int size) /* set PER bit */ STM32_FLASH_CR |= PER; - for (address = CONFIG_FLASH_BASE + offset ; - size > 0; size -= CONFIG_FLASH_ERASE_SIZE, - address += CONFIG_FLASH_ERASE_SIZE) { + for (; size > 0; size -= CONFIG_FLASH_ERASE_SIZE, + offset += CONFIG_FLASH_ERASE_SIZE) { timestamp_t deadline; + /* Do nothing if already erased */ + if (flash_is_erased(offset, CONFIG_FLASH_ERASE_SIZE)) + continue; + /* select page to erase */ - STM32_FLASH_AR = address; + STM32_FLASH_AR = CONFIG_FLASH_BASE + offset; /* set STRT bit : start erase */ STM32_FLASH_CR |= STRT; diff --git a/chip/stm32/flash-stm32l15x.c b/chip/stm32/flash-stm32l15x.c index 98255915ec..4ba2c66940 100644 --- a/chip/stm32/flash-stm32l15x.c +++ b/chip/stm32/flash-stm32l15x.c @@ -235,6 +235,12 @@ int flash_physical_erase(int offset, int size) address += CONFIG_FLASH_ERASE_SIZE / sizeof(uint32_t)) { timestamp_t deadline; + /* + * crosbug.com/p/13066 + * We can't do the flash_is_erased() trick on stm32l since + * bits erase to 0, not 1. Will address later if needed. + */ + /* Start erase */ *address = 0x00000000; diff --git a/common/flash_common.c b/common/flash_common.c index af7ff919eb..6beb95e0f1 100644 --- a/common/flash_common.c +++ b/common/flash_common.c @@ -26,6 +26,23 @@ int flash_dataptr(int offset, int size_req, int align, char **ptrp) return CONFIG_FLASH_SIZE - offset; } +/* crosbug.com/p/13066 - not supported on STM32L */ +#ifndef CHIP_VARIANT_stm32l15x +int flash_is_erased(uint32_t offset, int size) +{ + uint32_t *ptr; + + if (flash_dataptr(offset, size, sizeof(uint32_t), (char **)&ptr) < 0) + return 0; + + for (size /= sizeof(uint32_t); size > 0; size -= 4, ptr++) + if (*ptr != -1U) + return 0; + + return 1; +} +#endif + int flash_write(int offset, int size, const char *data) { if (flash_dataptr(offset, size, CONFIG_FLASH_WRITE_SIZE, NULL) < 0) diff --git a/include/flash.h b/include/flash.h index 2e31cf0f22..8bf0264c14 100644 --- a/include/flash.h +++ b/include/flash.h @@ -31,6 +31,17 @@ static inline char *flash_physical_dataptr(int offset) return (char *)(CONFIG_FLASH_BASE + offset); } +/** + * Check if a region of flash is erased + * + * It is assumed that an erased region has all bits set to 1. + * + * @param offset Flash offset to check + * @param size Number of bytes to check (word-aligned) + * @return 1 if erased, 0 if not erased + */ +int flash_is_erased(uint32_t offset, int size); + /** * Write to physical flash. *