X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fstm32x.c;h=b4300bef32aaa0d8585954021b7a771aad29889b;hb=f6315d5e5b7b71515ef051711e5f818a42d6b3b3;hp=0edadfd2ae82e90b98eedcd24d8d2f5265b41120;hpb=5d09972931e55c4d2bba7471df9c725f5bebc18c;p=openocd.git diff --git a/src/flash/nor/stm32x.c b/src/flash/nor/stm32x.c index 0edadfd2ae..b4300bef32 100644 --- a/src/flash/nor/stm32x.c +++ b/src/flash/nor/stm32x.c @@ -29,7 +29,6 @@ #include #include - /* stm32x register locations */ #define STM32_FLASH_ACR 0x40022000 @@ -77,12 +76,18 @@ #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 { @@ -97,11 +102,12 @@ struct stm32x_flash_bank struct working_area *write_algorithm; int ppage_size; int probed; -}; -struct stm32x_mem_layout { - uint32_t sector_start; - uint32_t sector_size; + bool has_dual_banks; + /* used to access dual flash bank stm32xl + * 0x00 will address bank 0 flash + * 0x40 will address bank 1 flash */ + int register_offset; }; static int stm32x_mass_erase(struct flash_bank *bank); @@ -123,14 +129,22 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) stm32x_info->write_algorithm = NULL; stm32x_info->probed = 0; + stm32x_info->has_dual_banks = false; + stm32x_info->register_offset = FLASH_OFFSET_B0; return ERROR_OK; } -static int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status) +static inline int stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg) +{ + struct stm32x_flash_bank *stm32x_info = bank->driver_priv; + return reg + stm32x_info->register_offset; +} + +static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status) { struct target *target = bank->target; - return target_read_u32(target, STM32_FLASH_SR, status); + return target_read_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), status); } static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) @@ -174,11 +188,27 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) /* If this operation fails, we ignore it and report the original * retval */ - target_write_u32(target, STM32_FLASH_SR, FLASH_WRPRTERR | FLASH_PGERR); + target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_SR), + FLASH_WRPRTERR | FLASH_PGERR); } 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; @@ -362,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; @@ -437,22 +471,24 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) } /* unlock flash registers */ - int retval = target_write_u32(target, STM32_FLASH_KEYR, KEY1); + int retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_KEYR, KEY2); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) return retval; for (i = first; i <= last; i++) { - retval = target_write_u32(target, STM32_FLASH_CR, FLASH_PER); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_AR, bank->base + bank->sectors[i].offset); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_AR), + bank->base + bank->sectors[i].offset); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_CR, FLASH_PER | FLASH_STRT); + retval = target_write_u32(target, + stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PER | FLASH_STRT); if (retval != ERROR_OK) return retval; @@ -463,7 +499,7 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) bank->sectors[i].is_erased = 1; } - retval = target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); if (retval != ERROR_OK) return retval; @@ -487,17 +523,28 @@ static int stm32x_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_TARGET_NOT_HALTED; } - if ((first && (first % stm32x_info->ppage_size)) || ((last + 1) && - (last + 1) % stm32x_info->ppage_size)) + 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", + stm32x_info->ppage_size); + first = first - (first % stm32x_info->ppage_size); + } + if (((last + 1) % stm32x_info->ppage_size) != 0) { - LOG_WARNING("Error: start and end sectors must be on a %d sector boundary", + LOG_WARNING("aligned end protect sector to a %d sector boundary", stm32x_info->ppage_size); - return ERROR_FLASH_SECTOR_INVALID; + last++; + last = last - (last % stm32x_info->ppage_size); + 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; @@ -579,7 +626,8 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, /* #define STM32_FLASH_CR_OFFSET 0x10 */ /* #define STM32_FLASH_SR_OFFSET 0x0C */ /* write: */ - 0xdf, 0xf8, 0x20, 0x40, /* ldr r4, STM32_FLASH_BASE */ + 0x08, 0x4c, /* ldr r4, STM32_FLASH_BASE */ + 0x1c, 0x44, /* add r4, r3 */ /* write_half_word: */ 0x01, 0x23, /* movs r3, #0x01 */ 0x23, 0x61, /* str r3, [r4, #STM32_FLASH_CR_OFFSET] */ @@ -633,7 +681,7 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); - init_reg_param(®_params[3], "r3", 32, PARAM_IN); + init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT); while (count > 0) { @@ -647,6 +695,7 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, buf_set_u32(reg_params[0].value, 0, 32, source->address); buf_set_u32(reg_params[1].value, 0, 32, address); buf_set_u32(reg_params[2].value, 0, 32, thisrun_count); + buf_set_u32(reg_params[3].value, 0, 32, stm32x_info->register_offset); if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, stm32x_info->write_algorithm->address, @@ -714,10 +763,10 @@ static int stm32x_write(struct flash_bank *bank, uint8_t *buffer, } /* unlock flash registers */ - retval = target_write_u32(target, STM32_FLASH_KEYR, KEY1); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_KEYR, KEY2); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) return retval; @@ -750,7 +799,7 @@ static int stm32x_write(struct flash_bank *bank, uint8_t *buffer, uint16_t value; memcpy(&value, buffer + bytes_written, sizeof(uint16_t)); - retval = target_write_u32(target, STM32_FLASH_CR, FLASH_PG); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, address, value); @@ -771,7 +820,7 @@ static int stm32x_write(struct flash_bank *bank, uint8_t *buffer, uint16_t value = 0xffff; memcpy(&value, buffer + bytes_written, bytes_remaining); - retval = target_write_u32(target, STM32_FLASH_CR, FLASH_PG); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG); if (retval != ERROR_OK) return retval; retval = target_write_u16(target, address, value); @@ -794,8 +843,10 @@ static int stm32x_probe(struct flash_bank *bank) uint16_t num_pages; uint32_t device_id; int page_size; + uint32_t base_address = 0x08000000; stm32x_info->probed = 0; + stm32x_info->register_offset = FLASH_OFFSET_B0; /* read stm32 device id register */ int retval = target_read_u32(target, 0xE0042000, &device_id); @@ -887,6 +938,36 @@ static int stm32x_probe(struct flash_bank *bank) num_pages = 128; } } + else if ((device_id & 0x7ff) == 0x430) + { + /* xl line density - we have 2k pages + * 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) + { + /* number of sectors may be incorrrect on early silicon */ + LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 1024k flash"); + num_pages = 1024; + } + + /* split reported size into matching bank */ + if (bank->base != 0x08080000) + { + /* bank 0 will be fixed 512k */ + num_pages = 512; + } + else + { + num_pages -= 512; + /* bank1 also uses a register offset */ + stm32x_info->register_offset = FLASH_OFFSET_B1; + base_address = 0x08080000; + } + } else { LOG_WARNING("Cannot identify target as a STM32 family."); @@ -904,7 +985,7 @@ static int stm32x_probe(struct flash_bank *bank) bank->sectors = NULL; } - bank->base = 0x08000000; + bank->base = base_address; bank->size = (num_pages * page_size); bank->num_sectors = num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); @@ -1057,6 +1138,23 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) break; } } + else if ((device_id & 0x7ff) == 0x430) + { + printed = snprintf(buf, buf_size, "stm32x (XL) - Rev: "); + buf += printed; + buf_size -= printed; + + switch (device_id >> 16) + { + case 0x1000: + snprintf(buf, buf_size, "A"); + break; + + default: + snprintf(buf, buf_size, "unknown"); + break; + } + } else { snprintf(buf, buf_size, "Cannot identify target as a stm32x\n"); @@ -1092,6 +1190,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"); @@ -1115,7 +1217,6 @@ COMMAND_HANDLER(stm32x_handle_lock_command) COMMAND_HANDLER(stm32x_handle_unlock_command) { struct target *target = NULL; - struct stm32x_flash_bank *stm32x_info = NULL; if (CMD_ARGC < 1) { @@ -1128,8 +1229,6 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) if (ERROR_OK != retval) return retval; - stm32x_info = bank->driver_priv; - target = bank->target; if (target->state != TARGET_HALTED) @@ -1138,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"); @@ -1184,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; @@ -1212,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; } @@ -1223,7 +1338,8 @@ COMMAND_HANDLER(stm32x_handle_options_write_command) if (CMD_ARGC < 4) { - command_print(CMD_CTX, "stm32x options_write "); + command_print(CMD_CTX, "stm32x options_write " + " "); return ERROR_OK; } @@ -1242,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. */ @@ -1256,8 +1376,8 @@ COMMAND_HANDLER(stm32x_handle_options_write_command) optionbyte &= ~(1 << 0); } - /* OPT_RDRSTSTDBY */ - if (strcmp(CMD_ARGV[2], "NORSTSTNDBY") == 0) + /* OPT_RDRSTSTOP */ + if (strcmp(CMD_ARGV[2], "NORSTSTOP") == 0) { optionbyte |= (1 << 1); } @@ -1266,8 +1386,8 @@ COMMAND_HANDLER(stm32x_handle_options_write_command) optionbyte &= ~(1 << 1); } - /* OPT_RDRSTSTOP */ - if (strcmp(CMD_ARGV[3], "NORSTSTOP") == 0) + /* OPT_RDRSTSTDBY */ + if (strcmp(CMD_ARGV[3], "NORSTSTNDBY") == 0) { optionbyte |= (1 << 2); } @@ -1276,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"); @@ -1308,18 +1441,18 @@ static int stm32x_mass_erase(struct flash_bank *bank) } /* unlock option flash registers */ - int retval = target_write_u32(target, STM32_FLASH_KEYR, KEY1); + int retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY1); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_KEYR, KEY2); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2); if (retval != ERROR_OK) return retval; /* mass erase flash memory */ - retval = target_write_u32(target, STM32_FLASH_CR, FLASH_MER); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER); if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_CR, FLASH_MER | FLASH_STRT); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_MER | FLASH_STRT); if (retval != ERROR_OK) return retval; @@ -1327,7 +1460,7 @@ static int stm32x_mass_erase(struct flash_bank *bank) if (retval != ERROR_OK) return retval; - retval = target_write_u32(target, STM32_FLASH_CR, FLASH_LOCK); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); if (retval != ERROR_OK) return retval;