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 <bank_id> [enable|disable]' helps to automatically skip using the flashloader if needed. Change-Id: Id29213c85ee5c7c487cfee21554f5a7ea50db6c9 Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com> Reviewed-on: https://review.openocd.org/c/openocd/+/6273 Reviewed-by: Oleksij Rempel <linux@rempel-privat.de> Tested-by: jenkins
This commit is contained in:
parent
e609d5a5de
commit
1247eee4e6
|
@ -7344,6 +7344,13 @@ Unlocks the entire stm32 device.
|
||||||
The @var{num} parameter is a value shown by @command{flash banks}.
|
The @var{num} parameter is a value shown by @command{flash banks}.
|
||||||
@end deffn
|
@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
|
@deffn {Command} {stm32l4x mass_erase} num
|
||||||
Mass erases the entire stm32l4x device.
|
Mass erases the entire stm32l4x device.
|
||||||
The @var{num} parameter is a value shown by @command{flash banks}.
|
The @var{num} parameter is a value shown by @command{flash banks}.
|
||||||
|
|
|
@ -116,6 +116,7 @@
|
||||||
/* Erase time can be as high as 25ms, 10x this and assume it's toast... */
|
/* Erase time can be as high as 25ms, 10x this and assume it's toast... */
|
||||||
|
|
||||||
#define FLASH_ERASE_TIMEOUT 250
|
#define FLASH_ERASE_TIMEOUT 250
|
||||||
|
#define FLASH_WRITE_TIMEOUT 50
|
||||||
|
|
||||||
|
|
||||||
/* relevant STM32L4 flags ****************************************************/
|
/* relevant STM32L4 flags ****************************************************/
|
||||||
|
@ -223,6 +224,7 @@ struct stm32l4_flash_bank {
|
||||||
uint32_t flash_regs_base;
|
uint32_t flash_regs_base;
|
||||||
const uint32_t *flash_regs;
|
const uint32_t *flash_regs;
|
||||||
bool otp_enabled;
|
bool otp_enabled;
|
||||||
|
bool use_flashloader;
|
||||||
enum stm32l4_rdp rdp;
|
enum stm32l4_rdp rdp;
|
||||||
bool tzen;
|
bool tzen;
|
||||||
uint32_t optr;
|
uint32_t optr;
|
||||||
|
@ -545,6 +547,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command)
|
||||||
stm32l4_info->probed = false;
|
stm32l4_info->probed = false;
|
||||||
stm32l4_info->otp_enabled = false;
|
stm32l4_info->otp_enabled = false;
|
||||||
stm32l4_info->user_bank_size = bank->size;
|
stm32l4_info->user_bank_size = bank->size;
|
||||||
|
stm32l4_info->use_flashloader = true;
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
@ -1362,6 +1365,49 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
return retval;
|
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,
|
static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
uint32_t offset, uint32_t count)
|
uint32_t offset, uint32_t count)
|
||||||
{
|
{
|
||||||
|
@ -1434,6 +1480,7 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
if (retval != ERROR_OK)
|
if (retval != ERROR_OK)
|
||||||
goto err_lock;
|
goto err_lock;
|
||||||
|
|
||||||
|
if (stm32l4_info->use_flashloader) {
|
||||||
/* For TrustZone enabled devices, when TZEN is set and RDP level is 0.5,
|
/* For TrustZone enabled devices, when TZEN is set and RDP level is 0.5,
|
||||||
* the debug is possible only in non-secure state.
|
* the debug is possible only in non-secure state.
|
||||||
* Thus means the flashloader will run in non-secure mode,
|
* Thus means the flashloader will run in non-secure mode,
|
||||||
|
@ -1442,6 +1489,13 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
|
||||||
LOG_INFO("RDP level is 0.5, the work-area should reside in non-secure RAM");
|
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);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
err_lock:
|
err_lock:
|
||||||
retval2 = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_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);
|
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)
|
COMMAND_HANDLER(stm32l4_handle_option_load_command)
|
||||||
{
|
{
|
||||||
if (CMD_ARGC != 1)
|
if (CMD_ARGC != 1)
|
||||||
|
@ -2222,6 +2296,13 @@ static const struct command_registration stm32l4_exec_command_handlers[] = {
|
||||||
.usage = "bank_id",
|
.usage = "bank_id",
|
||||||
.help = "Unlock entire protected flash device.",
|
.help = "Unlock entire protected flash device.",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.name = "flashloader",
|
||||||
|
.handler = stm32l4_handle_flashloader_command,
|
||||||
|
.mode = COMMAND_EXEC,
|
||||||
|
.usage = "<bank_id> [enable|disable]",
|
||||||
|
.help = "Configure the flashloader usage",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
.name = "mass_erase",
|
.name = "mass_erase",
|
||||||
.handler = stm32l4_handle_mass_erase_command,
|
.handler = stm32l4_handle_mass_erase_command,
|
||||||
|
|
Loading…
Reference in New Issue