From 1247eee4e6e55889b14bec8d81c4748767bb67b8 Mon Sep 17 00:00:00 2001 From: Tarek BOCHKATI Date: Tue, 25 May 2021 11:54:50 +0100 Subject: [PATCH] flash/stm32l4x: introduce flash programming without loader this capability permits to program the flash if we cannot reserve a workarea. the introduction the command 'stm32l4x flashloader [enable|disable]' helps to automatically skip using the flashloader if needed. Change-Id: Id29213c85ee5c7c487cfee21554f5a7ea50db6c9 Signed-off-by: Tarek BOCHKATI Reviewed-on: https://review.openocd.org/c/openocd/+/6273 Reviewed-by: Oleksij Rempel Tested-by: jenkins --- doc/openocd.texi | 7 +++ src/flash/nor/stm32l4x.c | 95 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 95 insertions(+), 7 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 33812499a..4404807a6 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -7344,6 +7344,13 @@ Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn +@deffn Command {stm32l4x flashloader} num [@option{enable} | @option{disable}] +Enables or disables the flashloader usage (enabled by default), +when disabled it will fall back to direct memory access to program the Flash or OTP memories. +if neither @option{enabled} nor @option{disable} are specified, the command will display +the current configuration. +@end deffn + @deffn {Command} {stm32l4x mass_erase} num Mass erases the entire stm32l4x device. The @var{num} parameter is a value shown by @command{flash banks}. diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c index de36d56c7..5bc23090f 100644 --- a/src/flash/nor/stm32l4x.c +++ b/src/flash/nor/stm32l4x.c @@ -116,6 +116,7 @@ /* Erase time can be as high as 25ms, 10x this and assume it's toast... */ #define FLASH_ERASE_TIMEOUT 250 +#define FLASH_WRITE_TIMEOUT 50 /* relevant STM32L4 flags ****************************************************/ @@ -223,6 +224,7 @@ struct stm32l4_flash_bank { uint32_t flash_regs_base; const uint32_t *flash_regs; bool otp_enabled; + bool use_flashloader; enum stm32l4_rdp rdp; bool tzen; uint32_t optr; @@ -545,6 +547,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command) stm32l4_info->probed = false; stm32l4_info->otp_enabled = false; stm32l4_info->user_bank_size = bank->size; + stm32l4_info->use_flashloader = true; return ERROR_OK; } @@ -1362,6 +1365,49 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer, return retval; } +/* Count is in double-words */ +static int stm32l4_write_block_without_loader(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + uint32_t address = bank->base + offset; + int retval = ERROR_OK; + + /* wait for BSY bit */ + retval = stm32l4_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + /* set PG in FLASH_CR */ + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_PG); + if (retval != ERROR_OK) + return retval; + + + /* write directly to flash memory */ + const uint8_t *src = buffer; + while (count--) { + retval = target_write_memory(target, address, 4, 2, src); + if (retval != ERROR_OK) + return retval; + + /* wait for BSY bit */ + retval = stm32l4_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + if (retval != ERROR_OK) + return retval; + + src += 8; + address += 8; + } + + /* reset PG in FLASH_CR */ + retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, 0); + if (retval != ERROR_OK) + return retval; + + return retval; +} + static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { @@ -1434,14 +1480,22 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) goto err_lock; - /* For TrustZone enabled devices, when TZEN is set and RDP level is 0.5, - * the debug is possible only in non-secure state. - * Thus means the flashloader will run in non-secure mode, - * and the workarea need to be in non-secure RAM */ - if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0_5)) - LOG_INFO("RDP level is 0.5, the work-area should reside in non-secure RAM"); + if (stm32l4_info->use_flashloader) { + /* For TrustZone enabled devices, when TZEN is set and RDP level is 0.5, + * the debug is possible only in non-secure state. + * Thus means the flashloader will run in non-secure mode, + * and the workarea need to be in non-secure RAM */ + if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0_5)) + LOG_INFO("RDP level is 0.5, the work-area should reside in non-secure RAM"); + + retval = stm32l4_write_block(bank, buffer, offset, count / 8); + } + + if (!stm32l4_info->use_flashloader || retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { + LOG_INFO("falling back to single memory accesses"); + retval = stm32l4_write_block_without_loader(bank, buffer, offset, count / 8); + } - retval = stm32l4_write_block(bank, buffer, offset, count / 8); err_lock: retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_LOCK); @@ -2017,6 +2071,26 @@ COMMAND_HANDLER(stm32l4_handle_trustzone_command) return stm32l4_perform_obl_launch(bank); } +COMMAND_HANDLER(stm32l4_handle_flashloader_command) +{ + if (CMD_ARGC < 1 || CMD_ARGC > 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (retval != ERROR_OK) + return retval; + + struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv; + + if (CMD_ARGC == 2) + COMMAND_PARSE_ENABLE(CMD_ARGV[1], stm32l4_info->use_flashloader); + + command_print(CMD, "FlashLoader usage is %s", stm32l4_info->use_flashloader ? "enabled" : "disabled"); + + return ERROR_OK; +} + COMMAND_HANDLER(stm32l4_handle_option_load_command) { if (CMD_ARGC != 1) @@ -2222,6 +2296,13 @@ static const struct command_registration stm32l4_exec_command_handlers[] = { .usage = "bank_id", .help = "Unlock entire protected flash device.", }, + { + .name = "flashloader", + .handler = stm32l4_handle_flashloader_command, + .mode = COMMAND_EXEC, + .usage = " [enable|disable]", + .help = "Configure the flashloader usage", + }, { .name = "mass_erase", .handler = stm32l4_handle_mass_erase_command,