diff options
-rw-r--r-- | src/flash/nor/stm32x.c | 87 |
1 files changed, 79 insertions, 8 deletions
diff --git a/src/flash/nor/stm32x.c b/src/flash/nor/stm32x.c index 6393aa40..70624b2e 100644 --- a/src/flash/nor/stm32x.c +++ b/src/flash/nor/stm32x.c @@ -76,12 +76,19 @@ #define OPT_RDWDGSW 2 #define OPT_RDRSTSTOP 3 #define OPT_RDRSTSTDBY 4 +#define OPT_BFB2 5 /* dual flash bank only */ /* register unlock keys */ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB +/* we use an offset to access the second bank on dual flash devices + * strangely the protection of the second bank is done on the bank0 reg's */ + +#define FLASH_OFFSET_B0 0x00 +#define FLASH_OFFSET_B1 0x40 + struct stm32x_options { uint16_t RDP; @@ -96,9 +103,10 @@ struct stm32x_flash_bank int ppage_size; int probed; + bool has_dual_banks; /* used to access dual flash bank stm32xl - * 0x00 will address sector 0 flash - * 0x40 will address sector 1 flash */ + * 0x00 will address bank 0 flash + * 0x40 will address bank 1 flash */ int register_offset; }; @@ -121,7 +129,8 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) stm32x_info->write_algorithm = NULL; stm32x_info->probed = 0; - stm32x_info->register_offset = 0x00; + stm32x_info->has_dual_banks = false; + stm32x_info->register_offset = FLASH_OFFSET_B0; return ERROR_OK; } @@ -185,6 +194,21 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) return retval; } +int stm32x_check_operation_supported(struct flash_bank *bank) +{ + struct stm32x_flash_bank *stm32x_info = bank->driver_priv; + + /* if we have a dual flash bank device then + * we need to perform option byte stuff on bank0 only */ + if (stm32x_info->register_offset != FLASH_OFFSET_B0) + { + LOG_ERROR("Option Byte Operation's must use bank0"); + return ERROR_FLASH_OPERATION_FAILED; + } + + return ERROR_OK; +} + static int stm32x_read_options(struct flash_bank *bank) { uint32_t optiondata; @@ -368,9 +392,13 @@ static int stm32x_protect_check(struct flash_bank *bank) return ERROR_TARGET_NOT_HALTED; } + int retval = stm32x_check_operation_supported(bank); + if (ERROR_OK != retval) + return retval; + /* medium density - each bit refers to a 4bank protection * high density - each bit refers to a 2bank protection */ - int retval = target_read_u32(target, STM32_FLASH_WRPR, &protection); + retval = target_read_u32(target, STM32_FLASH_WRPR, &protection); if (retval != ERROR_OK) return retval; @@ -495,6 +523,10 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_TARGET_NOT_HALTED; } + int retval = stm32x_check_operation_supported(bank); + if (ERROR_OK != retval) + return retval; + if ((first % stm32x_info->ppage_size) != 0) { LOG_WARNING("aligned start protect sector to a %d sector boundary", @@ -512,7 +544,7 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last) /* medium density - each bit refers to a 4bank protection * high density - each bit refers to a 2bank protection */ - int retval = target_read_u32(target, STM32_FLASH_WRPR, &protection); + retval = target_read_u32(target, STM32_FLASH_WRPR, &protection); if (retval != ERROR_OK) return retval; @@ -813,7 +845,7 @@ static int stm32x_probe(struct flash_bank *bank) int page_size; stm32x_info->probed = 0; - stm32x_info->register_offset = 0x00; + stm32x_info->register_offset = FLASH_OFFSET_B0; /* read stm32 device id register */ int retval = target_read_u32(target, 0xE0042000, &device_id); @@ -911,6 +943,7 @@ static int stm32x_probe(struct flash_bank *bank) * 2 pages for a protection area */ page_size = 2048; stm32x_info->ppage_size = 2; + stm32x_info->has_dual_banks = true; /* check for early silicon */ if (num_pages == 0xffff) @@ -930,7 +963,7 @@ static int stm32x_probe(struct flash_bank *bank) { num_pages -= 512; /* bank1 also uses a register offset */ - stm32x_info->register_offset = 0x40; + stm32x_info->register_offset = FLASH_OFFSET_B1; } } else @@ -1154,6 +1187,10 @@ COMMAND_HANDLER(stm32x_handle_lock_command) return ERROR_TARGET_NOT_HALTED; } + retval = stm32x_check_operation_supported(bank); + if (ERROR_OK != retval) + return retval; + if (stm32x_erase_options(bank) != ERROR_OK) { command_print(CMD_CTX, "stm32x failed to erase options"); @@ -1200,6 +1237,10 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) return ERROR_TARGET_NOT_HALTED; } + retval = stm32x_check_operation_supported(bank); + if (ERROR_OK != retval) + return retval; + if (stm32x_erase_options(bank) != ERROR_OK) { command_print(CMD_CTX, "stm32x failed to unlock device"); @@ -1246,6 +1287,10 @@ COMMAND_HANDLER(stm32x_handle_options_read_command) return ERROR_TARGET_NOT_HALTED; } + retval = stm32x_check_operation_supported(bank); + if (ERROR_OK != retval) + return retval; + retval = target_read_u32(target, STM32_FLASH_OBR, &optionbyte); if (retval != ERROR_OK) return retval; @@ -1274,6 +1319,14 @@ COMMAND_HANDLER(stm32x_handle_options_read_command) else command_print(CMD_CTX, "Standby: Reset generated"); + if (stm32x_info->has_dual_banks) + { + if (buf_get_u32((uint8_t*)&optionbyte, OPT_BFB2, 1)) + command_print(CMD_CTX, "Boot: Bank 0"); + else + command_print(CMD_CTX, "Boot: Bank 1"); + } + return ERROR_OK; } @@ -1285,7 +1338,8 @@ COMMAND_HANDLER(stm32x_handle_options_write_command) if (CMD_ARGC < 4) { - command_print(CMD_CTX, "stm32x options_write <bank> <SWWDG | HWWDG> <RSTSTNDBY | NORSTSTNDBY> <RSTSTOP | NORSTSTOP>"); + command_print(CMD_CTX, "stm32x options_write <bank> <SWWDG | HWWDG> " + "<RSTSTNDBY | NORSTSTNDBY> <RSTSTOP | NORSTSTOP> <BOOT0 | BOOT1>"); return ERROR_OK; } @@ -1304,6 +1358,10 @@ COMMAND_HANDLER(stm32x_handle_options_write_command) return ERROR_TARGET_NOT_HALTED; } + retval = stm32x_check_operation_supported(bank); + if (ERROR_OK != retval) + return retval; + /* REVISIT: ignores some options which we will display... * and doesn't insist on the specified syntax. */ @@ -1338,6 +1396,19 @@ COMMAND_HANDLER(stm32x_handle_options_write_command) optionbyte &= ~(1 << 2); } + if (CMD_ARGC > 4 && stm32x_info->has_dual_banks) + { + /* OPT_BFB2 */ + if (strcmp(CMD_ARGV[4], "BOOT0") == 0) + { + optionbyte |= (1 << 3); + } + else + { + optionbyte &= ~(1 << 3); + } + } + if (stm32x_erase_options(bank) != ERROR_OK) { command_print(CMD_CTX, "stm32x failed to erase options"); |