struct stm32x_flash_bank {
struct stm32x_options option_bytes;
- struct working_area *write_algorithm;
int ppage_size;
int probed;
stm32x_info = malloc(sizeof(struct stm32x_flash_bank));
bank->driver_priv = stm32x_info;
- stm32x_info->write_algorithm = NULL;
stm32x_info->probed = 0;
stm32x_info->has_dual_banks = false;
stm32x_info->register_base = FLASH_REG_BASE_B0;
stm32x_info = bank->driver_priv;
+ /* stlink is currently does not support 16bit
+ * read/writes. so we cannot write option bytes */
+ struct armv7m_common *armv7m = target_to_armv7m(target);
+ if (armv7m && armv7m->stlink) {
+ LOG_ERROR("Option bytes currently unsupported for stlink");
+ return ERROR_FAIL;
+ }
+
/* read current options */
stm32x_read_options(bank);
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
struct target *target = bank->target;
uint32_t buffer_size = 16384;
+ struct working_area *write_algorithm;
struct working_area *source;
uint32_t address = bank->base + offset;
struct reg_param reg_params[5];
/* flash write code */
if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code),
- &stm32x_info->write_algorithm) != ERROR_OK) {
+ &write_algorithm) != ERROR_OK) {
LOG_WARNING("no working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
};
- retval = target_write_buffer(target, stm32x_info->write_algorithm->address,
+ retval = target_write_buffer(target, write_algorithm->address,
sizeof(stm32x_flash_write_code), (uint8_t *)stm32x_flash_write_code);
if (retval != ERROR_OK)
return retval;
buffer_size /= 2;
buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */
if (buffer_size <= 256) {
- /* if we already allocated the writing code, but failed to get a
+ /* we already allocated the writing code, but failed to get a
* buffer, free the algorithm */
- if (stm32x_info->write_algorithm)
- target_free_working_area(target, stm32x_info->write_algorithm);
+ target_free_working_area(target, write_algorithm);
LOG_WARNING("no large enough working area available, can't do block memory writes");
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
0, NULL,
5, reg_params,
source->address, source->size,
- stm32x_info->write_algorithm->address, 0,
+ write_algorithm->address, 0,
&armv7m_info);
if (retval == ERROR_FLASH_OPERATION_FAILED) {
}
target_free_working_area(target, source);
- target_free_working_area(target, stm32x_info->write_algorithm);
+ target_free_working_area(target, write_algorithm);
destroy_reg_param(®_params[0]);
destroy_reg_param(®_params[1]);
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");
}
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;
}
snprintf(buf, buf_size, "1.0");
break;
+ case 0x2000:
+ snprintf(buf, buf_size, "2.0");
+ break;
+
default:
snprintf(buf, buf_size, "unknown");
break;
snprintf(buf, buf_size, "1.0");
break;
+ case 0x2000:
+ snprintf(buf, buf_size, "2.0");
+ break;
+
default:
snprintf(buf, buf_size, "unknown");
break;