stm32x_info->register_base = FLASH_REG_BASE_B0;
stm32x_info->user_bank_size = bank->size;
+ /* The flash write must be aligned to a halfword boundary */
+ bank->write_start_alignment = bank->write_end_alignment = 2;
+
return ERROR_OK;
}
break;
if (timeout-- <= 0) {
LOG_ERROR("timed out waiting for flash");
- return ERROR_FAIL;
+ return ERROR_FLASH_BUSY;
}
alive_sleep(1);
}
if (status & FLASH_WRPRTERR) {
LOG_ERROR("stm32x device protected");
- retval = ERROR_FAIL;
+ retval = ERROR_FLASH_PROTECTED;
}
if (status & FLASH_PGERR) {
- LOG_ERROR("stm32x device programming failed");
- retval = ERROR_FAIL;
+ LOG_ERROR("stm32x device programming failed / flash not erased");
+ retval = ERROR_FLASH_OPERATION_FAILED;
}
/* Clear but report errors */
{
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
struct target *target = bank->target;
- uint32_t buffer_size = 16384;
+ uint32_t buffer_size;
struct working_area *write_algorithm;
struct working_area *source;
- struct reg_param reg_params[5];
struct armv7m_algorithm armv7m_info;
- int retval = ERROR_OK;
+ int retval;
static const uint8_t stm32x_flash_write_code[] = {
#include "../../../contrib/loaders/flash/stm32/stm32f1x.inc"
}
/* memory buffer */
- while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
- buffer_size /= 2;
- buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */
- if (buffer_size <= 256) {
- /* we already allocated the writing code, but failed to get a
- * buffer, free the 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;
- }
+ buffer_size = target_get_working_area_avail(target);
+ buffer_size = MIN(hwords_count * 2, MAX(buffer_size, 256));
+ /* Normally we allocate all available working area.
+ * MIN shrinks buffer_size if the size of the written block is smaller.
+ * MAX prevents using async algo if the available working area is smaller
+ * than 256, the following allocation fails with
+ * ERROR_TARGET_RESOURCE_NOT_AVAILABLE and slow flashing takes place.
+ */
+
+ retval = target_alloc_working_area(target, buffer_size, &source);
+ /* Allocated size is always 32-bit word aligned */
+ if (retval != ERROR_OK) {
+ target_free_working_area(target, write_algorithm);
+ LOG_WARNING("no large enough working area available, can't do block memory writes");
+ /* target_alloc_working_area() may return ERROR_FAIL if area backup fails:
+ * convert any error to ERROR_TARGET_RESOURCE_NOT_AVAILABLE
+ */
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
+ struct reg_param reg_params[5];
+
init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* flash base (in), status (out) */
init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* count (halfword-16bit) */
init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* buffer start */
retval = target_run_flash_async_algorithm(target, buffer, hwords_count, 2,
0, NULL,
- 5, reg_params,
+ ARRAY_SIZE(reg_params), reg_params,
source->address, source->size,
write_algorithm->address, 0,
&armv7m_info);
if (retval == ERROR_FLASH_OPERATION_FAILED) {
- LOG_ERROR("flash write failed at address 0x%"PRIx32,
- buf_get_u32(reg_params[4].value, 0, 32));
-
- if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_PGERR) {
- LOG_ERROR("flash memory not erased before writing");
- /* Clear but report errors */
- target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), FLASH_PGERR);
- }
+ /* Actually we just need to check for programming errors
+ * stm32x_wait_status_busy also reports error and clears status bits.
+ *
+ * Target algo returns flash status in r0 only if properly finished.
+ * It is safer to re-read status register.
+ */
+ int retval2 = stm32x_wait_status_busy(bank, 5);
+ if (retval2 != ERROR_OK)
+ retval = retval2;
- if (buf_get_u32(reg_params[0].value, 0, 32) & FLASH_WRPRTERR) {
- LOG_ERROR("flash memory write protected");
- /* Clear but report errors */
- target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), FLASH_WRPRTERR);
- }
+ LOG_ERROR("flash write failed just before address 0x%"PRIx32,
+ buf_get_u32(reg_params[4].value, 0, 32));
}
+ for (unsigned int i = 0; i < ARRAY_SIZE(reg_params); i++)
+ destroy_reg_param(®_params[i]);
+
target_free_working_area(target, source);
target_free_working_area(target, write_algorithm);
- destroy_reg_param(®_params[0]);
- destroy_reg_param(®_params[1]);
- destroy_reg_param(®_params[2]);
- destroy_reg_param(®_params[3]);
- destroy_reg_param(®_params[4]);
-
return retval;
}
{
struct target *target = bank->target;
+ /* The flash write must be aligned to a halfword boundary.
+ * The flash infrastructure ensures it, do just a security check
+ */
+ assert(address % 2 == 0);
+
/* try using a block write - on ARM architecture or... */
int retval = stm32x_write_block_async(bank, buffer, address, hwords_count);
uint32_t offset, uint32_t count)
{
struct target *target = bank->target;
- uint8_t *new_buffer = NULL;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- if (offset & 0x1) {
- 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) {
- 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);
- new_buffer[count++] = 0xff;
- }
+ /* The flash write must be aligned to a halfword boundary.
+ * The flash infrastructure ensures it, do just a security check
+ */
+ assert(offset % 2 == 0);
+ assert(count % 2 == 0);
int retval, retval2;
/* unlock flash registers */
retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1);
if (retval != ERROR_OK)
- goto cleanup;
+ return retval;
retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2);
if (retval != ERROR_OK)
goto reset_pg_and_lock;
if (retval == ERROR_OK)
retval = retval2;
-cleanup:
- free(new_buffer);
return retval;
}