X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Fflash%2Fnor%2Fstm32h7x.c;h=512aca57a73d301d7ee3a4a9fb2637ef5f34748e;hp=01e6f06dce2f6f39b180bfbf676ea0d99a6bf2da;hb=e6990bdd00e80b48ba49e4b440c8d654a9431a34;hpb=6a66cccbad7e51ac1b3ea929ab0c86dd02617797 diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c index 01e6f06dce..512aca57a7 100644 --- a/src/flash/nor/stm32h7x.c +++ b/src/flash/nor/stm32h7x.c @@ -38,18 +38,18 @@ #define FLASH_SR 0x10 #define FLASH_CCR 0x14 #define FLASH_OPTCR 0x18 -#define FLASH_OPTCUR 0x1C -#define FLASH_OPTPRG 0x20 +#define FLASH_OPTSR_CUR 0x1C +#define FLASH_OPTSR_PRG 0x20 #define FLASH_OPTCCR 0x24 -#define FLASH_WPSNCUR 0x38 -#define FLASH_WPSNPRG 0x3C +#define FLASH_WPSN_CUR 0x38 +#define FLASH_WPSN_PRG 0x3C /* FLASH_CR register bits */ #define FLASH_LOCK (1 << 0) #define FLASH_PG (1 << 1) #define FLASH_SER (1 << 2) -#define FLASH_BER_CMD (1 << 3) +#define FLASH_BER (1 << 3) #define FLASH_PSIZE_8 (0 << 4) #define FLASH_PSIZE_16 (1 << 4) #define FLASH_PSIZE_32 (2 << 4) @@ -61,10 +61,11 @@ /* FLASH_SR register bits */ #define FLASH_BSY (1 << 0) /* Operation in progress */ +#define FLASH_QW (1 << 2) /* Operation queue in progress */ #define FLASH_WRPERR (1 << 17) /* Write protection error */ #define FLASH_PGSERR (1 << 18) /* Programming sequence error */ #define FLASH_STRBERR (1 << 19) /* Strobe error */ -#define FLASH_INCERR (1 << 21) /* Increment error */ +#define FLASH_INCERR (1 << 21) /* Inconsistency error */ #define FLASH_OPERR (1 << 22) /* Operation error */ #define FLASH_RDPERR (1 << 23) /* Read Protection error */ #define FLASH_RDSERR (1 << 24) /* Secure Protection error */ @@ -78,9 +79,6 @@ #define OPT_LOCK (1 << 0) #define OPT_START (1 << 1) -/* FLASH_OPTCUR bit definitions (reading) */ -#define IWDG1_HW (1 << 4) - /* register unlock keys */ #define KEY1 0x45670123 #define KEY2 0xCDEF89AB @@ -109,7 +107,6 @@ struct stm32x_options { uint8_t user_options; uint8_t user2_options; uint8_t user3_options; - uint8_t independent_watchdog_selection; }; struct stm32h7x_part_info { @@ -136,7 +133,7 @@ struct stm32h7x_flash_bank { }; static const struct stm32h7x_rev stm32_450_revs[] = { - { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2001, "X" }, }; static const struct stm32h7x_part_info stm32h7x_parts[] = { @@ -188,38 +185,40 @@ static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *sta return target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_SR), status); } -static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) +static int stm32x_wait_flash_op_queue(struct flash_bank *bank, int timeout) { struct target *target = bank->target; struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; uint32_t status; int retval; - /* wait for busy to clear */ + /* wait for flash operations completion */ for (;;) { retval = stm32x_get_flash_status(bank, &status); if (retval != ERROR_OK) { - LOG_INFO("wait_status_busy, target_read_u32 : error : remote address 0x%x", stm32x_info->flash_base); + LOG_INFO("wait_flash_op_queue, target_read_u32 : error : remote address 0x%x", stm32x_info->flash_base); return retval; } - if ((status & FLASH_BSY) == 0) + if ((status & FLASH_QW) == 0) break; if (timeout-- <= 0) { - LOG_INFO("wait_status_busy, time out expired, status: 0x%" PRIx32 "", status); + LOG_INFO("wait_flash_op_queue, time out expired, status: 0x%" PRIx32 "", status); return ERROR_FAIL; } alive_sleep(1); } if (status & FLASH_WRPERR) { - LOG_INFO("wait_status_busy, WRPERR : error : remote address 0x%x", stm32x_info->flash_base); + LOG_INFO("wait_flash_op_queue, WRPERR : error : remote address 0x%x", stm32x_info->flash_base); retval = ERROR_FAIL; } /* Clear error + EOP flags but report errors */ if (status & FLASH_ERROR) { + if (retval == ERROR_OK) + retval = ERROR_FAIL; /* If this operation fails, we ignore it and report the original retval */ target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), status); } @@ -315,7 +314,7 @@ static int stm32x_read_options(struct flash_bank *bank) stm32x_info = bank->driver_priv; /* read current option bytes */ - int retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCUR, &optiondata); + int retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTSR_CUR, &optiondata); if (retval != ERROR_OK) return retval; @@ -323,24 +322,19 @@ static int stm32x_read_options(struct flash_bank *bank) stm32x_info->option_bytes.user_options = optiondata & 0xfc; stm32x_info->option_bytes.RDP = (optiondata >> 8) & 0xff; stm32x_info->option_bytes.user2_options = (optiondata >> 16) & 0xff; - stm32x_info->option_bytes.user3_options = (optiondata >> 24) & 0x83; - - if (optiondata & IWDG1_HW) - stm32x_info->option_bytes.independent_watchdog_selection = 1; - else - stm32x_info->option_bytes.independent_watchdog_selection = 0; + stm32x_info->option_bytes.user3_options = (optiondata >> 24) & 0xa3; if (stm32x_info->option_bytes.RDP != 0xAA) LOG_INFO("Device Security Bit Set"); /* read current WPSN option bytes */ - retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSNCUR, &optiondata); + retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSN_CUR, &optiondata); if (retval != ERROR_OK) return retval; stm32x_info->option_bytes.protection = optiondata & 0xff; /* read current WPSN2 option bytes */ - retval = target_read_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSNCUR, &optiondata); + retval = target_read_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSN_CUR, &optiondata); if (retval != ERROR_OK) return retval; stm32x_info->option_bytes.protection2 = optiondata & 0xff; @@ -364,35 +358,30 @@ static int stm32x_write_options(struct flash_bank *bank) optiondata = stm32x_info->option_bytes.user_options; optiondata |= (stm32x_info->option_bytes.RDP << 8); optiondata |= (stm32x_info->option_bytes.user2_options & 0xff) << 16; - optiondata |= (stm32x_info->option_bytes.user3_options & 0x83) << 24; - - if (stm32x_info->option_bytes.independent_watchdog_selection) - optiondata |= IWDG1_HW; - else - optiondata &= ~IWDG1_HW; + optiondata |= (stm32x_info->option_bytes.user3_options & 0xa3) << 24; /* program options */ - retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTPRG, optiondata); - if (retval != ERROR_OK) - return retval; + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTSR_PRG, optiondata); + if (retval != ERROR_OK) + return retval; optiondata = stm32x_info->option_bytes.protection & 0xff; /* Program protection WPSNPRG */ - retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSNPRG, optiondata); - if (retval != ERROR_OK) - return retval; + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSN_PRG, optiondata); + if (retval != ERROR_OK) + return retval; optiondata = stm32x_info->option_bytes.protection2 & 0xff; /* Program protection WPSNPRG2 */ - retval = target_write_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSNPRG, optiondata); - if (retval != ERROR_OK) - return retval; + retval = target_write_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSN_PRG, optiondata); + if (retval != ERROR_OK) + return retval; optiondata = 0x40000000; /* Remove OPT error flag before programming */ retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCCR, optiondata); - if (retval != ERROR_OK) - return retval; + if (retval != ERROR_OK) + return retval; /* start programming cycle */ retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, OPT_START); @@ -405,14 +394,14 @@ static int stm32x_write_options(struct flash_bank *bank) uint32_t status; retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_SR, &status); if (retval != ERROR_OK) { - LOG_INFO("stm32x_write_options: wait_status_busy : error"); + LOG_INFO("stm32x_write_options: wait_flash_op_queue : error"); return retval; } - if ((status & FLASH_BSY) == 0) + if ((status & FLASH_QW) == 0) break; if (timeout-- <= 0) { - LOG_INFO("wait_status_busy, time out expired, status: 0x%" PRIx32 "", status); + LOG_INFO("wait_flash_op_queue, time out expired, status: 0x%" PRIx32 "", status); return ERROR_FAIL; } alive_sleep(1); @@ -471,12 +460,12 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) /* Sector Erase To erase a sector, follow the procedure below: - 1. Check that no Flash memory operation is ongoing by checking the BSY bit in the + 1. Check that no Flash memory operation is ongoing by checking the QW bit in the FLASH_SR register 2. Set the SER bit and select the sector you wish to erase (SNB) in the FLASH_CR register 3. Set the STRT bit in the FLASH_CR register - 4. Wait for the BSY bit to be cleared + 4. Wait for flash operations completion */ for (int i = first; i <= last; i++) { LOG_DEBUG("erase sector %d", i); @@ -492,10 +481,10 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) LOG_ERROR("Error erase sector %d", i); return retval; } - retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + retval = stm32x_wait_flash_op_queue(bank, FLASH_ERASE_TIMEOUT); if (retval != ERROR_OK) { - LOG_ERROR("erase time-out error sector %d", i); + LOG_ERROR("erase time-out or operation error sector %d", i); return retval; } bank->sectors[i].is_erased = 1; @@ -568,51 +557,8 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; int retval = ERROR_OK; - /* see contrib/loaders/flash/smt32h7x.S for src */ static const uint8_t stm32x_flash_write_code[] = { - /* : */ - 0x45, 0x68, /* ldr r5, [r0, #4] */ - /* : */ - 0x06, 0x68, /* ldr r6, [r0, #0] */ - 0x26, 0xb3, /* cbz r6, */ - 0x76, 0x1b, /* subs r6, r6, r5 */ - 0x42, 0xbf, /* ittt mi */ - 0x76, 0x18, /* addmi r6, r6, r1 */ - 0x36, 0x1a, /* submi r6, r6, r0 */ - 0x08, 0x3e, /* submi r6, #8 */ - 0x20, 0x2e, /* cmp r6, #32 */ - 0xf6, 0xd3, /* bcc.n */ - 0x4f, 0xf0, 0x32, 0x06, /* mov.w r6, #STM32_PROG */ - 0xe6, 0x60, /* str r6, [r4, #STM32_FLASH_CR_OFFSET] */ - 0x4f, 0xf0, 0x08, 0x07, /* mov.w r7, #8 */ - /* : */ - 0x55, 0xf8, 0x04, 0x6b, /* ldr.w r6, [r5], #4 */ - 0x42, 0xf8, 0x04, 0x6b, /* str.w r6, [r2], #4 */ - 0xbf, 0xf3, 0x4f, 0x8f, /* dsb sy */ - 0x8d, 0x42, /* cmp r5, r1 */ - 0x28, 0xbf, /* it cs */ - 0x00, 0xf1, 0x08, 0x05, /* addcs.w r5, r0, #8 */ - 0x01, 0x3f, /* subs r7, #1 */ - 0xf3, 0xd1, /* bne.n */ - /* : */ - 0x26, 0x69, /* ldr r6, [r4, #STM32_FLASH_SR_OFFSET] */ - 0x16, 0xf0, 0x01, 0x0f, /* tst.w r6, #STM32_SR_BUSY_MASK */ - 0xfb, 0xd1, /* bne.n */ - 0x05, 0x4f, /* ldr r7, [pc, #20] ; () */ - 0x3e, 0x42, /* tst r6, r7 */ - 0x03, 0xd1, /* bne.n */ - 0x45, 0x60, /* str r5, [r0, #4] */ - 0x01, 0x3b, /* subs r3, #1 */ - 0xdb, 0xd1, /* bne.n */ - 0x01, 0xe0, /* b.n */ - /* : */ - 0x00, 0x27, /* movs r7, #0 */ - 0x47, 0x60, /* str r7, [r0, #4] */ - /* : */ - 0x30, 0x46, /* mov r0, r6 */ - 0x00, 0xbe, /* bkpt 0x0000 */ - /* : */ - 0x00, 0x00, 0xee, 0x03 /* .word 0x03ee0000 ; (STM32_SR_ERROR_MASK) */ +#include "../../../contrib/loaders/flash/stm32/stm32h7x.inc" }; if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), @@ -624,8 +570,10 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, retval = target_write_buffer(target, write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + target_free_working_area(target, write_algorithm); return retval; + } /* memory buffer */ while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { @@ -740,11 +688,11 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, /* Standard programming The Flash memory programming sequence is as follows: - 1. Check that no main Flash memory operation is ongoing by checking the BSY bit in the + 1. Check that no main Flash memory operation is ongoing by checking the QW bit in the FLASH_SR register. 2. Set the PG bit in the FLASH_CR register 3. 8 x Word access (or Force Write FW) - 4. Wait for the BSY bit to be cleared + 4. Wait for flash operations completion */ while (blocks_remaining > 0) { retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64); @@ -755,7 +703,7 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) goto flash_lock; - retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + retval = stm32x_wait_flash_op_queue(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) goto flash_lock; @@ -778,7 +726,7 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, if (retval != ERROR_OK) goto flash_lock; - retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + retval = stm32x_wait_flash_op_queue(bank, FLASH_WRITE_TIMEOUT); if (retval != ERROR_OK) goto flash_lock; } @@ -872,8 +820,8 @@ static int stm32x_probe(struct flash_bank *bank) /* This is the first bank */ flash_size_in_kb = stm32x_info->part_info->first_bank_size_kb; } else { - LOG_WARNING("STM32H flash bank base address config is incorrect." - " 0x%" PRIx32 " but should rather be 0x%" PRIx32 " or 0x%" PRIx32, + LOG_WARNING("STM32H flash bank base address config is incorrect. " + TARGET_ADDR_FMT " but should rather be 0x%" PRIx32 " or 0x%" PRIx32, bank->base, base_address, second_bank_base); return ERROR_FAIL; } @@ -1004,7 +952,7 @@ COMMAND_HANDLER(stm32x_handle_lock_command) } if (stm32x_read_options(bank) != ERROR_OK) { - command_print(CMD_CTX, "%s failed to read options", + command_print(CMD, "%s failed to read options", bank->driver->name); return ERROR_OK; } @@ -1012,11 +960,11 @@ COMMAND_HANDLER(stm32x_handle_lock_command) stm32x_info->option_bytes.RDP = 0; if (stm32x_write_options(bank) != ERROR_OK) { - command_print(CMD_CTX, "%s failed to lock device", + command_print(CMD, "%s failed to lock device", bank->driver->name); return ERROR_OK; } - command_print(CMD_CTX, "%s locked", bank->driver->name); + command_print(CMD, "%s locked", bank->driver->name); return ERROR_OK; } @@ -1050,7 +998,7 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) } if (stm32x_read_options(bank) != ERROR_OK) { - command_print(CMD_CTX, "%s failed to read options", bank->driver->name); + command_print(CMD, "%s failed to read options", bank->driver->name); return ERROR_OK; } @@ -1059,10 +1007,10 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) stm32x_info->option_bytes.RDP = 0xAA; if (stm32x_write_options(bank) != ERROR_OK) { - command_print(CMD_CTX, "%s failed to unlock device", bank->driver->name); + command_print(CMD, "%s failed to unlock device", bank->driver->name); return ERROR_OK; } - command_print(CMD_CTX, "%s unlocked.\n", bank->driver->name); + command_print(CMD, "%s unlocked.\n", bank->driver->name); return ERROR_OK; } @@ -1082,16 +1030,16 @@ static int stm32x_mass_erase(struct flash_bank *bank) return retval; /* mass erase flash memory bank */ - retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_BER_CMD | FLASH_PSIZE_64); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_BER | FLASH_PSIZE_64); if (retval != ERROR_OK) return retval; retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), - FLASH_BER_CMD | FLASH_PSIZE_64 | FLASH_START); + FLASH_BER | FLASH_PSIZE_64 | FLASH_START); if (retval != ERROR_OK) return retval; - retval = stm32x_wait_status_busy(bank, 30000); + retval = stm32x_wait_flash_op_queue(bank, 30000); if (retval != ERROR_OK) return retval; @@ -1108,7 +1056,7 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command) int i; if (CMD_ARGC < 1) { - command_print(CMD_CTX, "stm32h7x mass_erase "); + command_print(CMD, "stm32h7x mass_erase "); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -1123,9 +1071,9 @@ COMMAND_HANDLER(stm32x_handle_mass_erase_command) for (i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; - command_print(CMD_CTX, "stm32h7x mass erase complete"); + command_print(CMD, "stm32h7x mass erase complete"); } else { - command_print(CMD_CTX, "stm32h7x mass erase failed"); + command_print(CMD, "stm32h7x mass erase failed"); } return retval; @@ -1167,7 +1115,7 @@ static const struct command_registration stm32x_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct flash_driver stm32h7x_flash = { +const struct flash_driver stm32h7x_flash = { .name = "stm32h7x", .commands = stm32x_command_handlers, .flash_bank_command = stm32x_flash_bank_command, @@ -1180,4 +1128,5 @@ struct flash_driver stm32h7x_flash = { .erase_check = default_flash_blank_check, .protect_check = stm32x_protect_check, .info = stm32x_get_info, + .free_driver_priv = default_flash_free_driver_priv, };