X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fstm32f2x.c;h=6457f203847a80c62447db008dace514755d1351;hp=c2f586a7a8983fe47bdbe5670c8ea37bbe583a2d;hb=2a34cc8eb6a8431ecebad1279d19ce919978a778;hpb=b066a7db2498eadcdeb55ea763d805c75fbbd00b diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index c2f586a7a8..6457f20384 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -165,8 +165,7 @@ FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) if (CMD_ARGC < 6) { - LOG_WARNING("incomplete flash_bank stm32x configuration"); - return ERROR_FLASH_BANK_INVALID; + return ERROR_COMMAND_SYNTAX_ERROR; } stm32x_info = malloc(sizeof(struct stm32x_flash_bank)); @@ -233,14 +232,36 @@ static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) static int stm32x_unlock_reg(struct target *target) { + uint32_t ctrl; + + /* first check if not already unlocked + * otherwise writing on STM32_FLASH_KEYR will fail + */ + int retval = target_read_u32(target, STM32_FLASH_CR, &ctrl); + if (retval != ERROR_OK) + return retval; + + if ((ctrl & FLASH_LOCK) == 0) + return ERROR_OK; + /* unlock flash registers */ - int retval = target_write_u32(target, STM32_FLASH_KEYR, KEY1); + retval = target_write_u32(target, STM32_FLASH_KEYR, KEY1); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, STM32_FLASH_KEYR, KEY2); if (retval != ERROR_OK) return retval; + + retval = target_read_u32(target, STM32_FLASH_CR, &ctrl); + if (retval != ERROR_OK) + return retval; + + if (ctrl & FLASH_LOCK) { + LOG_ERROR("flash not unlocked STM32_FLASH_CR: %x", ctrl); + return ERROR_TARGET_FAILURE; + } + return ERROR_OK; } @@ -314,32 +335,31 @@ static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; - /* see contib/loaders/flash/stm32x.s for src */ + /* see contrib/loaders/flash/stm32f2x.S for src */ static const uint16_t stm32x_flash_write_code_16[] = { -// 00000000 : - 0x4b07, // ldr r3, [pc, #28] (20 ) - 0x6123, // str r3, [r4, #16] - 0xf830, 0x3b02, //ldrh.w r3, [r0], #2 - 0xf821, 0x3b02, //strh.w r3, [r1], #2 - - //0000000c : - 0x68e3, //ldr r3, [r4, #12] -0xf413, 0x3f80, // tst.w r3, #65536 ; 0x10000 -0xd0fb, //beq.n c -0xf013, 0x0ff0, //tst.w r3, #240 ; 0xf0 -0xd101, //bne.n 1e -0x3a01, //subs r2, #1 -0xd1f0, //bne.n 0 - //0000001e : - 0xbe00, // bkpt 0x0000 - - //00000020 : - 0x0101, 0x0000, // .word 0x00000101 - + /* 00000000 : */ + 0x4b07, /* ldr r3, [pc, #28] (20 ) */ + 0x6123, /* str r3, [r4, #16] */ + 0xf830, 0x3b02, /* ldrh.w r3, [r0], #2 */ + 0xf821, 0x3b02, /* strh.w r3, [r1], #2 */ + + /* 0000000c : */ + 0x68e3, /* ldr r3, [r4, #12] */ + 0xf413, 0x3f80, /* tst.w r3, #65536 ; 0x10000 */ + 0xd0fb, /* beq.n c */ + 0xf013, 0x0ff0, /* tst.w r3, #240 ; 0xf0 */ + 0xd101, /* bne.n 1e */ + 0x3a01, /* subs r2, #1 */ + 0xd1f0, /* bne.n 0 */ + /* 0000001e : */ + 0xbe00, /* bkpt 0x0000 */ + + /* 00000020 : */ + 0x0101, 0x0000, /* .word 0x00000101 */ }; - // Flip endian + /* Flip endian */ uint8_t stm32x_flash_write_code[sizeof(stm32x_flash_write_code_16)*2]; for (unsigned i = 0; i < sizeof(stm32x_flash_write_code_16) / 2; i++) { @@ -565,7 +585,7 @@ static int stm32x_probe(struct flash_bank *bank) struct target *target = bank->target; struct stm32x_flash_bank *stm32x_info = bank->driver_priv; int i; - uint16_t num_pages; + uint16_t flash_size_in_kb; uint32_t device_id; uint32_t base_address = 0x08000000; @@ -577,22 +597,45 @@ static int stm32x_probe(struct flash_bank *bank) return retval; LOG_INFO("device id = 0x%08" PRIx32 "", device_id); - if ((device_id & 0x7ff) != 0x411) - { - LOG_WARNING("Cannot identify target as a STM32 family, try the other STM32 drivers."); + /* get flash size from target. */ + retval = target_read_u16(target, 0x1FFF7A10, &flash_size_in_kb); + if (retval != ERROR_OK) { + LOG_WARNING("failed reading flash size, default to max target family"); + /* failed reading flash size, default to max target family */ + flash_size_in_kb = 0xffff; + } + + if ((device_id & 0xfff) == 0x411) { + /* check for early silicon */ + if (flash_size_in_kb == 0xffff) { + /* number of sectors may be incorrrect on early silicon */ + LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 512k flash"); + flash_size_in_kb = 512; + } + } else if ((device_id & 0xfff) == 0x413) { + /* check for early silicon */ + if (flash_size_in_kb == 0xffff) { + /* number of sectors may be incorrrect on early silicon */ + LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming 512k flash"); + flash_size_in_kb = 512; + } + } else { + LOG_WARNING("Cannot identify target as a STM32 family."); return ERROR_FAIL; } - /* sectors sizes vary, handle this in a different code path - * than the rest. - */ - // Uhhh.... what to use here? + LOG_INFO("flash size = %dkbytes", flash_size_in_kb); - /* calculate numbers of pages*/ - num_pages = 4 + 1 + 7; + /* did we assign flash size? */ + assert(flash_size_in_kb != 0xffff); - if (bank->sectors) - { + /* calculate numbers of pages */ + int num_pages = (flash_size_in_kb / 128) + 4; + + /* check that calculation result makes sense */ + assert(num_pages > 0); + + if (bank->sectors) { free(bank->sectors); bank->sectors = NULL; } @@ -600,20 +643,20 @@ static int stm32x_probe(struct flash_bank *bank) bank->base = base_address; bank->num_sectors = num_pages; bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); - bank->size = 0; + + /* fixed memory */ setup_sector(bank, 0, 4, 16 * 1024); setup_sector(bank, 4, 1, 64 * 1024); - setup_sector(bank, 4+1, 7, 128 * 1024); - for (i = 0; i < num_pages; i++) - { + /* dynamic memory */ + setup_sector(bank, 4 + 1, num_pages - 5, 128 * 1024); + + for (i = 0; i < num_pages; i++) { bank->sectors[i].is_erased = -1; bank->sectors[i].is_protected = 0; } - LOG_INFO("flash size = %dkBytes", bank->size / 1024); - stm32x_info->probed = 1; return ERROR_OK; @@ -638,14 +681,12 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) if (retval != ERROR_OK) return retval; - if ((device_id & 0x7ff) == 0x411) - { - printed = snprintf(buf, buf_size, "stm32x (1mByte part) - Rev: "); + if ((device_id & 0xfff) == 0x411) { + printed = snprintf(buf, buf_size, "stm32f2x - Rev: "); buf += printed; buf_size -= printed; - switch (device_id >> 16) - { + switch (device_id >> 16) { case 0x1000: snprintf(buf, buf_size, "A"); break; @@ -666,9 +707,21 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) snprintf(buf, buf_size, "unknown"); break; } - } - else - { + } else if ((device_id & 0xfff) == 0x413) { + printed = snprintf(buf, buf_size, "stm32f4x - 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"); return ERROR_FAIL; } @@ -676,7 +729,76 @@ static int get_stm32x_info(struct flash_bank *bank, char *buf, int buf_size) return ERROR_OK; } +static int stm32x_mass_erase(struct flash_bank *bank) +{ + int retval; + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + retval = stm32x_unlock_reg(target); + if (retval != ERROR_OK) + return retval; + + /* mass erase flash memory */ + 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, stm32x_get_flash_reg(bank, STM32_FLASH_CR), + FLASH_MER | FLASH_STRT); + if (retval != ERROR_OK) + return retval; + + retval = stm32x_wait_status_busy(bank, 30000); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +COMMAND_HANDLER(stm32x_handle_mass_erase_command) +{ + int i; + + if (CMD_ARGC < 1) { + command_print(CMD_CTX, "stm32x mass_erase "); + 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; + + retval = stm32x_mass_erase(bank); + if (retval == ERROR_OK) { + /* set all sectors as erased */ + for (i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_erased = 1; + + command_print(CMD_CTX, "stm32x mass erase complete"); + } else { + command_print(CMD_CTX, "stm32x mass erase failed"); + } + + return retval; +} + static const struct command_registration stm32x_exec_command_handlers[] = { + { + .name = "mass_erase", + .handler = stm32x_handle_mass_erase_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Erase entire flash device.", + }, COMMAND_REGISTRATION_DONE }; @@ -685,6 +807,7 @@ static const struct command_registration stm32x_command_handlers[] = { .name = "stm32f2x", .mode = COMMAND_ANY, .help = "stm32f2x flash command group", + .usage = "", .chain = stm32x_exec_command_handlers, }, COMMAND_REGISTRATION_DONE