+COMMAND_HANDLER(stm32l4_handle_option_read_command)
+{
+ if (CMD_ARGC < 2) {
+ command_print(CMD_CTX, "stm32l4x option_read <STM32L4 bank> <option_reg offset>");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ uint32_t reg_addr = STM32_FLASH_BASE;
+ uint32_t value = 0;
+
+ reg_addr += strtoul(CMD_ARGV[1], NULL, 16);
+
+ retval = stm32l4_read_option(bank, reg_addr, &value);
+ if (ERROR_OK != retval)
+ return retval;
+
+ command_print(CMD_CTX, "Option Register: <0x%" PRIx32 "> = 0x%" PRIx32 "", reg_addr, value);
+
+ return retval;
+}
+
+COMMAND_HANDLER(stm32l4_handle_option_write_command)
+{
+ if (CMD_ARGC < 3) {
+ command_print(CMD_CTX, "stm32l4x option_write <STM32L4 bank> <option_reg offset> <value> [mask]");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ uint32_t reg_addr = STM32_FLASH_BASE;
+ uint32_t value = 0;
+ uint32_t mask = 0xFFFFFFFF;
+
+ reg_addr += strtoul(CMD_ARGV[1], NULL, 16);
+ value = strtoul(CMD_ARGV[2], NULL, 16);
+ if (CMD_ARGC > 3)
+ mask = strtoul(CMD_ARGV[3], NULL, 16);
+
+ command_print(CMD_CTX, "%s Option written.\n"
+ "INFO: a reset or power cycle is required "
+ "for the new settings to take effect.", bank->driver->name);
+
+ retval = stm32l4_write_option(bank, reg_addr, value, mask);
+ return retval;
+}
+
+COMMAND_HANDLER(stm32l4_handle_option_load_command)
+{
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ struct target *target = bank->target;
+
+ retval = stm32l4_unlock_reg(target);
+ if (ERROR_OK != retval)
+ return retval;
+
+ retval = stm32l4_unlock_option_reg(target);
+ if (ERROR_OK != retval)
+ return retval;
+
+ /* Write the OBLLAUNCH bit in CR -> Cause device "POR" and option bytes reload */
+ retval = target_write_u32(target, stm32l4_get_flash_reg(bank, STM32_FLASH_CR), FLASH_OBLLAUNCH);
+
+ command_print(CMD_CTX, "stm32l4x option load (POR) completed.");
+ return retval;
+}
+
+COMMAND_HANDLER(stm32l4_handle_lock_command)
+{
+ struct target *target = NULL;
+
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ target = bank->target;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ /* set readout protection level 1 by erasing the RDP option byte */
+ if (stm32l4_write_option(bank, STM32_FLASH_OPTR, 0, 0x000000FF) != ERROR_OK) {
+ command_print(CMD_CTX, "%s failed to lock device", bank->driver->name);
+ return ERROR_OK;
+ }
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(stm32l4_handle_unlock_command)
+{
+ struct target *target = NULL;
+
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ struct flash_bank *bank;
+ int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ target = bank->target;
+
+ if (target->state != TARGET_HALTED) {
+ LOG_ERROR("Target not halted");
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (stm32l4_write_option(bank, STM32_FLASH_OPTR, RDP_LEVEL_0, 0x000000FF) != ERROR_OK) {
+ command_print(CMD_CTX, "%s failed to unlock device", bank->driver->name);
+ return ERROR_OK;
+ }
+
+ return ERROR_OK;
+}
+