flash/nor/stm32f1x: allow write fallback for flash options
Mostly refactoring. Rename original stm32x_write_block() to stm32x_write_block_async() as it uses target async algo. Introduce new stm32x_write_block() and move slow, host controlled fallback flash write there. The change allows stm32x_write_options() to use slow flash write fallback. While on it rename variables where halfword count is stored. Change-Id: I386ae15cf052b1490461ed8f7eea5b4403d466f7 Signed-off-by: Tomas Vanek <vanekt@fbl.cz> Reviewed-on: https://review.openocd.org/c/openocd/+/6706 Tested-by: jenkins Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
This commit is contained in:
parent
7c6d379cf4
commit
dd532e87c0
|
@ -131,7 +131,7 @@ struct stm32x_flash_bank {
|
||||||
static int stm32x_mass_erase(struct flash_bank *bank);
|
static int stm32x_mass_erase(struct flash_bank *bank);
|
||||||
static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id);
|
static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id);
|
||||||
static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
|
static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
uint32_t address, uint32_t count);
|
uint32_t address, uint32_t hwords_count);
|
||||||
|
|
||||||
/* flash bank stm32x <base> <size> 0 0 <target#>
|
/* flash bank stm32x <base> <size> 0 0 <target#>
|
||||||
*/
|
*/
|
||||||
|
@ -329,12 +329,14 @@ static int stm32x_write_options(struct flash_bank *bank)
|
||||||
target_buffer_set_u16(target, opt_bytes + 12, (stm32x_info->option_bytes.protection >> 16) & 0xff);
|
target_buffer_set_u16(target, opt_bytes + 12, (stm32x_info->option_bytes.protection >> 16) & 0xff);
|
||||||
target_buffer_set_u16(target, opt_bytes + 14, (stm32x_info->option_bytes.protection >> 24) & 0xff);
|
target_buffer_set_u16(target, opt_bytes + 14, (stm32x_info->option_bytes.protection >> 24) & 0xff);
|
||||||
|
|
||||||
|
/* Block write is preferred in favour of operation with ancient ST-Link
|
||||||
|
* firmwares without 16-bit memory access. See
|
||||||
|
* 480: flash: stm32f1x: write option bytes using the loader
|
||||||
|
* https://review.openocd.org/c/openocd/+/480
|
||||||
|
*/
|
||||||
retval = stm32x_write_block(bank, opt_bytes, STM32_OB_RDP, sizeof(opt_bytes) / 2);
|
retval = stm32x_write_block(bank, opt_bytes, STM32_OB_RDP, sizeof(opt_bytes) / 2);
|
||||||
if (retval != ERROR_OK) {
|
if (retval != ERROR_OK)
|
||||||
if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
|
|
||||||
LOG_ERROR("working area required to erase options bytes");
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
|
||||||
|
|
||||||
retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK);
|
retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
|
@ -442,8 +444,8 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first,
|
||||||
return stm32x_write_options(bank);
|
return stm32x_write_options(bank);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
|
static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
uint32_t address, uint32_t count)
|
uint32_t address, uint32_t hwords_count)
|
||||||
{
|
{
|
||||||
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
|
||||||
struct target *target = bank->target;
|
struct target *target = bank->target;
|
||||||
|
@ -493,7 +495,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */
|
init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */
|
||||||
|
|
||||||
buf_set_u32(reg_params[0].value, 0, 32, stm32x_info->register_base);
|
buf_set_u32(reg_params[0].value, 0, 32, stm32x_info->register_base);
|
||||||
buf_set_u32(reg_params[1].value, 0, 32, count);
|
buf_set_u32(reg_params[1].value, 0, 32, hwords_count);
|
||||||
buf_set_u32(reg_params[2].value, 0, 32, source->address);
|
buf_set_u32(reg_params[2].value, 0, 32, source->address);
|
||||||
buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size);
|
buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size);
|
||||||
buf_set_u32(reg_params[4].value, 0, 32, address);
|
buf_set_u32(reg_params[4].value, 0, 32, address);
|
||||||
|
@ -501,7 +503,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
|
||||||
armv7m_info.core_mode = ARM_MODE_THREAD;
|
armv7m_info.core_mode = ARM_MODE_THREAD;
|
||||||
|
|
||||||
retval = target_run_flash_async_algorithm(target, buffer, count, 2,
|
retval = target_run_flash_async_algorithm(target, buffer, hwords_count, 2,
|
||||||
0, NULL,
|
0, NULL,
|
||||||
5, reg_params,
|
5, reg_params,
|
||||||
source->address, source->size,
|
source->address, source->size,
|
||||||
|
@ -537,6 +539,40 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Writes a block to flash either using target algorithm
|
||||||
|
* or use fallback, host controlled halfword-by-halfword access.
|
||||||
|
* Flash controller must be unlocked before this call.
|
||||||
|
*/
|
||||||
|
static int stm32x_write_block(struct flash_bank *bank,
|
||||||
|
const uint8_t *buffer, uint32_t address, uint32_t hwords_count)
|
||||||
|
{
|
||||||
|
struct target *target = bank->target;
|
||||||
|
|
||||||
|
/* try using a block write - on ARM architecture or... */
|
||||||
|
int retval = stm32x_write_block_async(bank, buffer, address, hwords_count);
|
||||||
|
|
||||||
|
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 (hwords_count > 0) {
|
||||||
|
retval = target_write_memory(target, address, 2, 1, buffer);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
retval = stm32x_wait_status_busy(bank, 5);
|
||||||
|
if (retval != ERROR_OK)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
hwords_count--;
|
||||||
|
buffer += 2;
|
||||||
|
address += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
|
static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
uint32_t offset, uint32_t count)
|
uint32_t offset, uint32_t count)
|
||||||
{
|
{
|
||||||
|
@ -568,7 +604,6 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
new_buffer[count++] = 0xff;
|
new_buffer[count++] = 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t words_remaining = count / 2;
|
|
||||||
int retval, retval2;
|
int retval, retval2;
|
||||||
|
|
||||||
/* unlock flash registers */
|
/* unlock flash registers */
|
||||||
|
@ -577,34 +612,15 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2);
|
retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2);
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto cleanup;
|
goto reset_pg_and_lock;
|
||||||
|
|
||||||
|
/* enable flash programming */
|
||||||
retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG);
|
retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG);
|
||||||
if (retval != ERROR_OK)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
/* try using a block write */
|
|
||||||
retval = stm32x_write_block(bank, buffer, bank->base + offset, words_remaining);
|
|
||||||
|
|
||||||
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) {
|
|
||||||
retval = target_write_memory(target, bank->base + offset, 2, 1, buffer);
|
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto reset_pg_and_lock;
|
goto reset_pg_and_lock;
|
||||||
|
|
||||||
retval = stm32x_wait_status_busy(bank, 5);
|
/* write to flash */
|
||||||
if (retval != ERROR_OK)
|
retval = stm32x_write_block(bank, buffer, bank->base + offset, count / 2);
|
||||||
goto reset_pg_and_lock;
|
|
||||||
|
|
||||||
words_remaining--;
|
|
||||||
buffer += 2;
|
|
||||||
offset += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
reset_pg_and_lock:
|
reset_pg_and_lock:
|
||||||
retval2 = 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);
|
||||||
|
|
Loading…
Reference in New Issue