aboutsummaryrefslogtreecommitdiff
path: root/src/flash
diff options
context:
space:
mode:
authorAndreas Fritiofson <andreas.fritiofson@gmail.com>2012-07-20 14:44:22 +0200
committerFreddie Chopin <freddie.chopin@gmail.com>2012-08-01 21:12:07 +0000
commitc89eb70a20230edfc79153c17c0c4c3f9dc64819 (patch)
tree4314c94f26520c5a1acb92848a925b33125ed0e3 /src/flash
parentb8862229d01c803142388d8456473b908fee22ea (diff)
downloadriscv-openocd-c89eb70a20230edfc79153c17c0c4c3f9dc64819.zip
riscv-openocd-c89eb70a20230edfc79153c17c0c4c3f9dc64819.tar.gz
riscv-openocd-c89eb70a20230edfc79153c17c0c4c3f9dc64819.tar.bz2
flash: stm32f1x: Pad odd byte writes early to avoid 16-bit writes
For odd byte counts, stm32x_write() pads the last byte and writes it using a discrete 16-bit access. The stlink debugger can't issue 16-bit writes so it fails for odd byte writes. This patch changes stm32x_write() to pad odd byte writes into a new buffer and use the normal code path with a single block write. The fallback path, when working area cannot be allocated, has to use 16-bit writes though which means that sufficient working area is required for stlink and odd byte writes. Change-Id: I4c5dc456300b6e1056f76b0095be8aceee3e954f Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com> Reviewed-on: http://openocd.zylin.com/756 Tested-by: jenkins Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk> Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
Diffstat (limited to 'src/flash')
-rw-r--r--src/flash/nor/stm32f1x.c103
1 files changed, 49 insertions, 54 deletions
diff --git a/src/flash/nor/stm32f1x.c b/src/flash/nor/stm32f1x.c
index d06016a..baf6b27 100644
--- a/src/flash/nor/stm32f1x.c
+++ b/src/flash/nor/stm32f1x.c
@@ -724,11 +724,7 @@ static int stm32x_write(struct flash_bank *bank, uint8_t *buffer,
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
- uint32_t words_remaining = (count / 2);
- uint32_t bytes_remaining = (count & 0x00000001);
- uint32_t address = bank->base + offset;
- uint32_t bytes_written = 0;
- int retval;
+ uint8_t *new_buffer = NULL;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
@@ -736,76 +732,75 @@ static int stm32x_write(struct flash_bank *bank, uint8_t *buffer,
}
if (offset & 0x1) {
- LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
+ LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
}
+ /* If there's an odd number of bytes, the data has to be padded. Duplicate
+ * the buffer and use the normal code path with a single block write since
+ * it's probably cheaper than to special case the last odd write using
+ * discrete accesses. */
+ if (count & 1) {
+ new_buffer = malloc(count + 1);
+ if (new_buffer == NULL) {
+ LOG_ERROR("odd number of bytes to write and no memory for padding buffer");
+ return ERROR_FAIL;
+ }
+ LOG_INFO("odd number of bytes to write, padding with 0xff");
+ buffer = memcpy(new_buffer, buffer, count);
+ buffer[count++] = 0xff;
+ }
+
+ uint32_t words_remaining = count / 2;
+ int retval, retval2;
+
/* unlock flash registers */
retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1);
if (retval != ERROR_OK)
- return retval;
+ goto cleanup;
retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2);
if (retval != ERROR_OK)
- return retval;
+ goto cleanup;
retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG);
if (retval != ERROR_OK)
- return retval;
+ goto cleanup;
- /* multiple half words (2-byte) to be programmed? */
- if (words_remaining > 0) {
- /* try using a block write */
- retval = stm32x_write_block(bank, buffer, offset, words_remaining);
- if (retval != ERROR_OK) {
- if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
- /* if block write failed (no sufficient working area),
- * we use normal (slow) single dword accesses */
- LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
- }
- } else {
- buffer += words_remaining * 2;
- address += words_remaining * 2;
- words_remaining = 0;
- }
- }
+ /* try using a block write */
+ retval = stm32x_write_block(bank, buffer, offset, words_remaining);
- if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE))
- goto reset_pg_and_lock;
+ if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
+ /* if block write failed (no sufficient working area),
+ * we use normal (slow) single halfword accesses */
+ LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
- while (words_remaining > 0) {
- uint16_t value;
- memcpy(&value, buffer + bytes_written, sizeof(uint16_t));
+ while (words_remaining > 0) {
+ uint16_t value;
+ memcpy(&value, buffer, sizeof(uint16_t));
- retval = target_write_u16(target, address, value);
- if (retval != ERROR_OK)
- goto reset_pg_and_lock;
+ retval = target_write_u16(target, bank->base + offset, value);
+ if (retval != ERROR_OK)
+ goto reset_pg_and_lock;
- retval = stm32x_wait_status_busy(bank, 5);
- if (retval != ERROR_OK)
- goto reset_pg_and_lock;
+ retval = stm32x_wait_status_busy(bank, 5);
+ if (retval != ERROR_OK)
+ goto reset_pg_and_lock;
- bytes_written += 2;
- words_remaining--;
- address += 2;
+ words_remaining--;
+ buffer += 2;
+ offset += 2;
+ }
}
- if (bytes_remaining) {
- uint16_t value = 0xffff;
- memcpy(&value, buffer + bytes_written, bytes_remaining);
-
- retval = target_write_u16(target, address, value);
- if (retval != ERROR_OK)
- goto reset_pg_and_lock;
-
- retval = stm32x_wait_status_busy(bank, 5);
- if (retval != ERROR_OK)
- goto reset_pg_and_lock;
- }
+reset_pg_and_lock:
+ retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK);
+ if (retval == ERROR_OK)
+ retval = retval2;
- return target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK);
+cleanup:
+ if (new_buffer)
+ free(new_buffer);
-reset_pg_and_lock:
- target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK);
return retval;
}