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>__archive__
parent
b8862229d0
commit
c89eb70a20
|
@ -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,47 +732,53 @@ 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 */
|
||||
* we use normal (slow) single halfword 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;
|
||||
}
|
||||
}
|
||||
|
||||
if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE))
|
||||
goto reset_pg_and_lock;
|
||||
|
||||
while (words_remaining > 0) {
|
||||
uint16_t value;
|
||||
memcpy(&value, buffer + bytes_written, sizeof(uint16_t));
|
||||
memcpy(&value, buffer, sizeof(uint16_t));
|
||||
|
||||
retval = target_write_u16(target, address, value);
|
||||
retval = target_write_u16(target, bank->base + offset, value);
|
||||
if (retval != ERROR_OK)
|
||||
goto reset_pg_and_lock;
|
||||
|
||||
|
@ -784,28 +786,21 @@ static int stm32x_write(struct flash_bank *bank, uint8_t *buffer,
|
|||
if (retval != ERROR_OK)
|
||||
goto reset_pg_and_lock;
|
||||
|
||||
bytes_written += 2;
|
||||
words_remaining--;
|
||||
address += 2;
|
||||
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;
|
||||
}
|
||||
|
||||
return target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK);
|
||||
|
||||
reset_pg_and_lock:
|
||||
target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK);
|
||||
retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK);
|
||||
if (retval == ERROR_OK)
|
||||
retval = retval2;
|
||||
|
||||
cleanup:
|
||||
if (new_buffer)
|
||||
free(new_buffer);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue