+ command_print(CMD, "stm32x mass erase complete");
+ } else {
+ command_print(CMD, "stm32x mass erase failed");
+ }
+
+ return retval;
+}
+
+COMMAND_HANDLER(stm32f2x_handle_options_read_command)
+{
+ int retval;
+ struct flash_bank *bank;
+ struct stm32x_flash_bank *stm32x_info = NULL;
+
+ if (CMD_ARGC != 1) {
+ command_print(CMD, "stm32f2x options_read <bank>");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ retval = stm32x_read_options(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ stm32x_info = bank->driver_priv;
+ if (stm32x_info->has_extra_options) {
+ if (stm32x_info->has_boot_addr) {
+ uint32_t boot_addr = stm32x_info->option_bytes.boot_addr;
+
+ command_print(CMD, "stm32f2x user_options 0x%03X,"
+ " boot_add0 0x%04X, boot_add1 0x%04X",
+ stm32x_info->option_bytes.user_options,
+ boot_addr & 0xffff, (boot_addr & 0xffff0000) >> 16);
+ if (stm32x_info->has_optcr2_pcrop) {
+ command_print(CMD, "stm32f2x optcr2_pcrop 0x%08X",
+ stm32x_info->option_bytes.optcr2_pcrop);
+ }
+ } else {
+ command_print(CMD, "stm32f2x user_options 0x%03X",
+ stm32x_info->option_bytes.user_options);
+ }
+ } else {
+ command_print(CMD, "stm32f2x user_options 0x%02X",
+ stm32x_info->option_bytes.user_options);
+
+ }
+
+ return retval;
+}
+
+COMMAND_HANDLER(stm32f2x_handle_options_write_command)
+{
+ int retval;
+ struct flash_bank *bank;
+ struct stm32x_flash_bank *stm32x_info = NULL;
+ uint16_t user_options, boot_addr0, boot_addr1, options_mask;
+
+ if (CMD_ARGC < 1) {
+ command_print(CMD, "stm32f2x options_write <bank> ...");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ retval = stm32x_read_options(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ stm32x_info = bank->driver_priv;
+ if (stm32x_info->has_boot_addr) {
+ if (CMD_ARGC != 4) {
+ command_print(CMD, "stm32f2x options_write <bank> <user_options>"
+ " <boot_addr0> <boot_addr1>");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[2], boot_addr0);
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[3], boot_addr1);
+ stm32x_info->option_bytes.boot_addr = boot_addr0 | (((uint32_t) boot_addr1) << 16);
+ } else {
+ if (CMD_ARGC != 2) {
+ command_print(CMD, "stm32f2x options_write <bank> <user_options>");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ }
+
+ COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], user_options);
+ options_mask = !stm32x_info->has_extra_options ? ~0xfc :
+ ~(((0xf00 << (stm32x_info->protection_bits - 12)) | 0xff) & 0xffc);
+ if (user_options & options_mask) {
+ command_print(CMD, "stm32f2x invalid user_options");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ stm32x_info->option_bytes.user_options = user_options;
+
+ if (stm32x_write_options(bank) != ERROR_OK) {
+ command_print(CMD, "stm32f2x failed to write options");
+ return ERROR_OK;
+ }
+
+ /* switching between single- and dual-bank modes requires re-probe */
+ /* ... and reprogramming of whole flash */
+ stm32x_info->probed = false;
+
+ command_print(CMD, "stm32f2x write options complete.\n"
+ "INFO: a reset or power cycle is required "
+ "for the new settings to take effect.");
+ return retval;
+}
+
+COMMAND_HANDLER(stm32f2x_handle_optcr2_write_command)
+{
+ int retval;
+ struct flash_bank *bank;
+ struct stm32x_flash_bank *stm32x_info = NULL;
+ uint32_t optcr2_pcrop;
+
+ if (CMD_ARGC != 2) {
+ command_print(CMD, "stm32f2x optcr2_write <bank> <optcr2_value>");
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ stm32x_info = bank->driver_priv;
+ if (!stm32x_info->has_optcr2_pcrop) {
+ command_print(CMD, "no optcr2 register");
+ return ERROR_COMMAND_ARGUMENT_INVALID;
+ }
+
+ command_print(CMD, "INFO: To disable PCROP, set PCROP_RDP"
+ " with PCROPi bits STILL SET, then\nlock device and"
+ " finally unlock it. Clears PCROP and mass erases flash.");
+
+ retval = stm32x_read_options(bank);
+ if (ERROR_OK != retval)
+ return retval;
+
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], optcr2_pcrop);
+ stm32x_info->option_bytes.optcr2_pcrop = optcr2_pcrop;
+
+ if (stm32x_write_options(bank) != ERROR_OK) {
+ command_print(CMD, "stm32f2x failed to write options");
+ return ERROR_OK;
+ }
+
+ command_print(CMD, "stm32f2x optcr2_write complete.");
+ return retval;
+}
+
+COMMAND_HANDLER(stm32x_handle_otp_command)
+{
+ if (CMD_ARGC < 2) {
+ command_print(CMD, "stm32x otp <bank> (enable|disable|show)");
+ 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;
+ if (stm32x_is_otp(bank)) {
+ if (strcmp(CMD_ARGV[1], "enable") == 0) {
+ stm32x_otp_enable(bank);
+ } else if (strcmp(CMD_ARGV[1], "disable") == 0) {
+ stm32x_otp_disable(bank);
+ } else if (strcmp(CMD_ARGV[1], "show") == 0) {
+ command_print(CMD,
+ "OTP memory bank #%d is %s for write commands.",
+ bank->bank_number,
+ stm32x_is_otp_unlocked(bank) ? "enabled" : "disabled");
+ } else {
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }