summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Glass <sjg@chromium.org>2013-06-13 15:41:48 -0700
committerKatie Roberts-Hoffman <katierh@chromium.org>2013-06-19 11:04:40 -0700
commit7a17b9830054429d9e864289ff3a4760369690a3 (patch)
tree79d4e796c077b23ec54e16a189687aa282a8da93
parentaaac3935d2e82b281979045a390f0b7d2c79b281 (diff)
downloadchrome-ec-7a17b9830054429d9e864289ff3a4760369690a3.tar.gz
Revert "Remove 64-byte workaround from STM32L flash writing"
This reverts commit b144a584af63891b134c3f789fdd00ac232a9577. Temporary work-around for EC flash_write problems. Do not submit. BUG=chromium:249186 BRANCH=none TEST=manual Run 'cros_test swsync rw' in U-Boot and see that it works again. Change-Id: Ib1b7415c0aedc462c4dd782ee1d3c1ce20b40afa Signed-off-by: Simon Glass <sjg@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/59267 Commit-Queue: Katie Roberts-Hoffman <katierh@chromium.org> Reviewed-by: Katie Roberts-Hoffman <katierh@chromium.org> Tested-by: Katie Roberts-Hoffman <katierh@chromium.org>
-rw-r--r--chip/stm32/config-stm32l15x.h9
-rw-r--r--chip/stm32/flash-stm32l15x.c80
2 files changed, 54 insertions, 35 deletions
diff --git a/chip/stm32/config-stm32l15x.h b/chip/stm32/config-stm32l15x.h
index eac9347ecb..b752636c5a 100644
--- a/chip/stm32/config-stm32l15x.h
+++ b/chip/stm32/config-stm32l15x.h
@@ -9,7 +9,16 @@
#define CONFIG_FLASH_SIZE CONFIG_FLASH_PHYSICAL_SIZE
#define CONFIG_FLASH_BANK_SIZE 0x1000
#define CONFIG_FLASH_ERASE_SIZE 0x0100 /* erase bank size */
+
+/* crosbug.comb/p/9811 workaround 64-byte payload limitation */
+#define CONFIG_64B_WORKAROUND
+
+#ifdef CONFIG_64B_WORKAROUND
+#define CONFIG_FLASH_WRITE_SIZE 0x0040 /* claimed minimum write size */
+#define CONFIG_FLASH_REAL_WRITE_SIZE 0x0080 /* actual minimum write size */
+#else
#define CONFIG_FLASH_WRITE_SIZE 0x0080
+#endif
#define CONFIG_RAM_BASE 0x20000000
#define CONFIG_RAM_SIZE 0x00004000
diff --git a/chip/stm32/flash-stm32l15x.c b/chip/stm32/flash-stm32l15x.c
index a5394497d1..4e20ba4db8 100644
--- a/chip/stm32/flash-stm32l15x.c
+++ b/chip/stm32/flash-stm32l15x.c
@@ -25,6 +25,19 @@
#define FLASH_TIMEOUT_LOOP \
(FLASH_TIMEOUT_US * (CPU_CLOCK / SECOND) / CYCLE_PER_FLASH_LOOP)
+#ifdef CONFIG_64B_WORKAROUND
+/*
+ * Use the real write buffer size inside the driver. We only lie to the
+ * outside world so it'll feed data to us in smaller pieces.
+ */
+#undef CONFIG_FLASH_WRITE_SIZE
+#define CONFIG_FLASH_WRITE_SIZE CONFIG_FLASH_REAL_WRITE_SIZE
+
+/* Used to buffer the write payload smaller than the half page size */
+static uint32_t write_buffer[CONFIG_FLASH_WRITE_SIZE / sizeof(uint32_t)];
+static int buffered_off = -1;
+#endif
+
/**
* Lock all the locks.
*/
@@ -164,15 +177,35 @@ void __attribute__((section(".iram.text")))
int flash_physical_write(int offset, int size, const char *data)
{
+ /*
+ * TODO: (crosbug.com/p/9526) Enforce alignment instead of blindly
+ * casting data to uint32_t *.
+ */
uint32_t *data32 = (uint32_t *)data;
- uint32_t *address = (uint32_t *)(CONFIG_FLASH_BASE + offset);
+ uint32_t *address;
int res = EC_SUCCESS;
- int word_mode = 0;
- int i;
- /* Fail if offset, size, and data aren't at least word-aligned */
- if ((offset | size | (uint32_t)(uintptr_t)data) & 3)
- return EC_ERROR_INVAL;
+#ifdef CONFIG_64B_WORKAROUND
+ if ((size < CONFIG_FLASH_WRITE_SIZE) || (offset & 64)) {
+ if ((size != 64) ||
+ ((offset & 64) && (buffered_off != offset - 64))) {
+ res = EC_ERROR_UNKNOWN;
+ goto exit_wr;
+ }
+ if (offset & 64) {
+ /* second 64B packet : flash ! */
+ memcpy(write_buffer + 16, data32, 64);
+ offset -= 64;
+ size += 64;
+ data32 = write_buffer;
+ } else {
+ /* first 64B packet : just store it */
+ buffered_off = offset;
+ memcpy(write_buffer, data32, 64);
+ return EC_SUCCESS;
+ }
+ }
+#endif
/* Unlock program area */
res = unlock(STM32_FLASH_PECR_PRG_LOCK);
@@ -182,40 +215,17 @@ int flash_physical_write(int offset, int size, const char *data)
/* Clear previous error status */
STM32_FLASH_SR = 0xf00;
- /*
- * If offset and size aren't on word boundaries, do word writes. This
- * is slower, but since we claim to the outside world that writes must
- * be half-page size, the only code which hits this path is writing
- * pstate (which is just writing one word).
- */
- if ((offset | size) & (CONFIG_FLASH_WRITE_SIZE - 1))
- word_mode = 1;
-
- while (size > 0) {
+ for (address = (uint32_t *)(CONFIG_FLASH_BASE + offset) ;
+ size > 0; size -= CONFIG_FLASH_WRITE_SIZE) {
/*
* Reload the watchdog timer to avoid watchdog reset when doing
* long writing with interrupt disabled.
*/
watchdog_reload();
+ iram_flash_write(address, data32);
- if (word_mode) {
- /* Word write */
- *address++ = *data32++;
-
- /* Wait for writes to complete */
- for (i = 0; ((STM32_FLASH_SR & 9) != 8) &&
- (i < FLASH_TIMEOUT_LOOP) ; i++)
- ;
-
- size -= sizeof(uint32_t);
- } else {
- /* Half page write */
- iram_flash_write(address, data32);
- address += CONFIG_FLASH_WRITE_SIZE / sizeof(uint32_t);
- data32 += CONFIG_FLASH_WRITE_SIZE / sizeof(uint32_t);
- size -= CONFIG_FLASH_WRITE_SIZE;
- }
-
+ address += CONFIG_FLASH_WRITE_SIZE / sizeof(uint32_t);
+ data32 += CONFIG_FLASH_WRITE_SIZE / sizeof(uint32_t);
if (STM32_FLASH_SR & 1) {
res = EC_ERROR_TIMEOUT;
goto exit_wr;
@@ -225,7 +235,7 @@ int flash_physical_write(int offset, int size, const char *data)
* Check for error conditions: erase failed, voltage error,
* protection error
*/
- if (STM32_FLASH_SR & 0xf00) {
+ if (STM32_FLASH_SR & 0xF00) {
res = EC_ERROR_UNKNOWN;
goto exit_wr;
}