target/stm: flash read write return bool

This commit is contained in:
Rafael Silva 2022-08-24 12:39:07 +01:00 committed by Rachel Mant
parent 67c9f3f6e2
commit 085dcb7bc9
6 changed files with 222 additions and 304 deletions

View File

@ -46,8 +46,8 @@ const struct command_s stm32f1_cmd_list[] = {
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };
static int stm32f1_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); static bool stm32f1_flash_erase(target_flash_s *f, target_addr_t addr, size_t len);
static int stm32f1_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len); static bool stm32f1_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len);
static bool stm32f1_mass_erase(target *t); static bool stm32f1_mass_erase(target *t);
/* Flash Program ad Erase Controller Register Map */ /* Flash Program ad Erase Controller Register Map */
@ -357,19 +357,33 @@ static int stm32f1_flash_unlock(target *t, uint32_t bank_offset)
return 0; return 0;
} }
static int stm32f1_flash_erase(target_flash_s *f, target_addr_t addr, size_t len) static bool stm32f1_flash_busy_wait(target *t, uint32_t bank_offset)
{
/* Read FLASH_SR to poll for BSY bit */
uint32_t sr;
do {
sr = target_mem_read32(t, FLASH_SR + bank_offset);
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP) || target_check_error(t)) {
DEBUG_WARN("stm32f1 flash error 0x%" PRIx32 "\n", sr);
return false;
}
} while (sr & FLASH_SR_BSY);
return true;
}
static bool stm32f1_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
{ {
target *t = f->t; target *t = f->t;
target_addr_t end = addr + len - 1; target_addr_t end = addr + len - 1;
target_addr_t start = addr;
if (t->part_id == 0x430 && end >= FLASH_BANK_SPLIT) if (t->part_id == 0x430 && end >= FLASH_BANK_SPLIT)
if (stm32f1_flash_unlock(t, FLASH_BANK2_OFFSET)) if (stm32f1_flash_unlock(t, FLASH_BANK2_OFFSET))
return -1; return false;
if (addr < FLASH_BANK_SPLIT) if (addr < FLASH_BANK_SPLIT)
if (stm32f1_flash_unlock(t, 0)) if (stm32f1_flash_unlock(t, 0))
return -1; return false;
while (len) { while (len) {
uint32_t bank_offset = 0; uint32_t bank_offset = 0;
@ -383,13 +397,9 @@ static int stm32f1_flash_erase(target_flash_s *f, target_addr_t addr, size_t len
/* Flash page erase start instruction */ /* Flash page erase start instruction */
target_mem_write32(t, FLASH_CR + bank_offset, FLASH_CR_STRT | FLASH_CR_PER); target_mem_write32(t, FLASH_CR + bank_offset, FLASH_CR_STRT | FLASH_CR_PER);
/* Read FLASH_SR to poll for BSY bit */ /* Wait for completion or an error */
while (target_mem_read32(t, FLASH_SR + bank_offset) & FLASH_SR_BSY) { if (!stm32f1_flash_busy_wait(t, bank_offset))
if (target_check_error(t)) { return false;
DEBUG_WARN("stm32f1 flash erase: comm error\n");
return -1;
}
}
if (len > f->blocksize) if (len > f->blocksize)
len -= f->blocksize; len -= f->blocksize;
@ -399,29 +409,12 @@ static int stm32f1_flash_erase(target_flash_s *f, target_addr_t addr, size_t len
addr += f->blocksize; addr += f->blocksize;
} }
/* Check for error */ return true;
if (start < FLASH_BANK_SPLIT) {
const uint32_t status = target_mem_read32(t, FLASH_SR);
if ((status & SR_ERROR_MASK) || !(status & SR_EOP)) {
DEBUG_INFO("stm32f1 flash erase error 0x%" PRIx32 "\n", status);
return -1;
}
}
if (t->part_id == 0x430 && end >= FLASH_BANK_SPLIT) {
const uint32_t status = target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET);
if ((status & SR_ERROR_MASK) || !(status & SR_EOP)) {
DEBUG_INFO("stm32f1 bank 2 flash erase error 0x%" PRIx32 "\n", status);
return -1;
}
}
return 0;
} }
static int stm32f1_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len) static bool stm32f1_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len)
{ {
target *t = f->t; target *t = f->t;
uint32_t sr;
size_t length = 0; size_t length = 0;
if (dest < FLASH_BANK_SPLIT) { if (dest < FLASH_BANK_SPLIT) {
@ -433,20 +426,10 @@ static int stm32f1_flash_write(target_flash_s *f, target_addr_t dest, const void
target_mem_write32(t, FLASH_CR, FLASH_CR_PG); target_mem_write32(t, FLASH_CR, FLASH_CR_PG);
cortexm_mem_write_sized(t, dest, src, length, ALIGN_HALFWORD); cortexm_mem_write_sized(t, dest, src, length, ALIGN_HALFWORD);
/* Read FLASH_SR to poll for BSY bit */
/* Wait for completion or an error */ /* Wait for completion or an error */
do { if (!stm32f1_flash_busy_wait(t, 0))
sr = target_mem_read32(t, FLASH_SR); return false;
if (target_check_error(t)) {
DEBUG_WARN("stm32f1 flash write: comm error\n");
return -1;
}
} while (sr & FLASH_SR_BSY);
if (sr & SR_ERROR_MASK) {
DEBUG_WARN("stm32f1 flash write error 0x%" PRIx32 "\n", sr);
return -1;
}
dest += length; dest += length;
src += length; src += length;
} }
@ -455,23 +438,13 @@ static int stm32f1_flash_write(target_flash_s *f, target_addr_t dest, const void
if (t->part_id == 0x430 && length) { /* Write on bank 2 */ if (t->part_id == 0x430 && length) { /* Write on bank 2 */
target_mem_write32(t, FLASH_CR + FLASH_BANK2_OFFSET, FLASH_CR_PG); target_mem_write32(t, FLASH_CR + FLASH_BANK2_OFFSET, FLASH_CR_PG);
cortexm_mem_write_sized(t, dest, src, length, ALIGN_HALFWORD); cortexm_mem_write_sized(t, dest, src, length, ALIGN_HALFWORD);
/* Read FLASH_SR to poll for BSY bit */
/* Wait for completion or an error */ /* Wait for completion or an error */
do { if (!stm32f1_flash_busy_wait(t, FLASH_BANK2_OFFSET))
sr = target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET); return false;
if (target_check_error(t)) {
DEBUG_WARN("stm32f1 flash bank2 write: comm error\n");
return -1;
}
} while (sr & FLASH_SR_BSY);
if (sr & SR_ERROR_MASK) {
DEBUG_WARN("stm32f1 flash bank2 write error 0x%" PRIx32 "\n", sr);
return -1;
}
} }
return 0; return true;
} }
static bool stm32f1_mass_erase(target *t) static bool stm32f1_mass_erase(target *t)
@ -479,6 +452,7 @@ static bool stm32f1_mass_erase(target *t)
if (stm32f1_flash_unlock(t, 0)) if (stm32f1_flash_unlock(t, 0))
return false; return false;
uint32_t sr;
platform_timeout timeout; platform_timeout timeout;
platform_timeout_set(&timeout, 500); platform_timeout_set(&timeout, 500);
@ -486,17 +460,15 @@ static bool stm32f1_mass_erase(target *t)
target_mem_write32(t, FLASH_CR, FLASH_CR_MER); target_mem_write32(t, FLASH_CR, FLASH_CR_MER);
target_mem_write32(t, FLASH_CR, FLASH_CR_STRT | FLASH_CR_MER); target_mem_write32(t, FLASH_CR, FLASH_CR_STRT | FLASH_CR_MER);
/* Read FLASH_SR to poll for BSY bit */ /* Wait for completion or an error */
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) { do {
if (target_check_error(t)) sr = target_mem_read32(t, FLASH_SR);
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP) || target_check_error(t)) {
DEBUG_WARN("stm32f1 flash error 0x%" PRIx32 "\n", sr);
return false; return false;
target_print_progress(&timeout);
} }
target_print_progress(&timeout);
/* Check for error */ } while (sr & FLASH_SR_BSY);
uint16_t sr = target_mem_read32(t, FLASH_SR);
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP))
return false;
if (t->part_id == 0x430) { if (t->part_id == 0x430) {
if (stm32f1_flash_unlock(t, FLASH_BANK2_OFFSET)) if (stm32f1_flash_unlock(t, FLASH_BANK2_OFFSET))
@ -506,16 +478,16 @@ static bool stm32f1_mass_erase(target *t)
target_mem_write32(t, FLASH_CR + FLASH_BANK2_OFFSET, FLASH_CR_MER); target_mem_write32(t, FLASH_CR + FLASH_BANK2_OFFSET, FLASH_CR_MER);
target_mem_write32(t, FLASH_CR + FLASH_BANK2_OFFSET, FLASH_CR_STRT | FLASH_CR_MER); target_mem_write32(t, FLASH_CR + FLASH_BANK2_OFFSET, FLASH_CR_STRT | FLASH_CR_MER);
/* Read FLASH_SR to poll for BSY bit */ /* Wait for completion or an error */
while (target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET) & FLASH_SR_BSY) do {
if (target_check_error(t))
return false;
/* Check for error */
sr = target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET); sr = target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET);
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP)) if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP) || target_check_error(t)) {
DEBUG_WARN("stm32f1 flash error 0x%" PRIx32 "\n", sr);
return false; return false;
} }
target_print_progress(&timeout);
} while (sr & FLASH_SR_BSY);
}
return true; return true;
} }
@ -526,12 +498,8 @@ static bool stm32f1_option_erase(target *t)
target_mem_write32(t, FLASH_CR, FLASH_CR_OPTER | FLASH_CR_OPTWRE); target_mem_write32(t, FLASH_CR, FLASH_CR_OPTER | FLASH_CR_OPTWRE);
target_mem_write32(t, FLASH_CR, FLASH_CR_STRT | FLASH_CR_OPTER | FLASH_CR_OPTWRE); target_mem_write32(t, FLASH_CR, FLASH_CR_STRT | FLASH_CR_OPTER | FLASH_CR_OPTWRE);
/* Read FLASH_SR to poll for BSY bit */ /* Wait for completion or an error */
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) return stm32f1_flash_busy_wait(t, 0);
if (target_check_error(t))
return false;
return true;
} }
static bool stm32f1_option_write_erased(target *t, uint32_t addr, uint16_t value, bool width_word) static bool stm32f1_option_write_erased(target *t, uint32_t addr, uint16_t value, bool width_word)
@ -547,12 +515,8 @@ static bool stm32f1_option_write_erased(target *t, uint32_t addr, uint16_t value
else else
target_mem_write16(t, addr, value); target_mem_write16(t, addr, value);
/* Read FLASH_SR to poll for BSY bit */ /* Wait for completion or an error */
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) return stm32f1_flash_busy_wait(t, 0);
if (target_check_error(t))
return false;
return true;
} }
static bool stm32f1_option_write(target *t, uint32_t addr, uint16_t value) static bool stm32f1_option_write(target *t, uint32_t addr, uint16_t value)

View File

@ -47,8 +47,8 @@ const struct command_s stm32f4_cmd_list[] = {
}; };
static bool stm32f4_attach(target *t); static bool stm32f4_attach(target *t);
static int stm32f4_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); static bool stm32f4_flash_erase(target_flash_s *f, target_addr_t addr, size_t len);
static int stm32f4_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len); static bool stm32f4_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len);
static bool stm32f4_mass_erase(target *t); static bool stm32f4_mass_erase(target *t);
/* Flash Program and Erase Controller Register Map */ /* Flash Program and Erase Controller Register Map */
@ -390,11 +390,26 @@ static void stm32f4_flash_unlock(target *t)
} }
} }
static int stm32f4_flash_erase(target_flash_s *f, target_addr_t addr, size_t len) static bool stm32f4_flash_busy_wait(target *t)
{
/* Read FLASH_SR to poll for BSY bit */
uint32_t sr;
do {
sr = target_mem_read32(t, FLASH_SR);
if ((sr & SR_ERROR_MASK) || target_check_error(t)) {
DEBUG_WARN("stm32f4 flash error 0x%" PRIx32 "\n", sr);
return false;
}
} while (sr & FLASH_SR_BSY);
return true;
}
static bool stm32f4_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
{ {
target *t = f->t; target *t = f->t;
struct stm32f4_flash *sf = (struct stm32f4_flash *)f; struct stm32f4_flash *sf = (struct stm32f4_flash *)f;
uint32_t sr;
/* No address translation is needed here, as we erase by sector number */ /* No address translation is needed here, as we erase by sector number */
uint8_t sector = sf->base_sector + (addr - f->start)/f->blocksize; uint8_t sector = sf->base_sector + (addr - f->start)/f->blocksize;
stm32f4_flash_unlock(t); stm32f4_flash_unlock(t);
@ -413,12 +428,10 @@ static int stm32f4_flash_erase(target_flash_s *f, target_addr_t addr, size_t len
/* write address to FMA */ /* write address to FMA */
target_mem_write32(t, FLASH_CR, cr | FLASH_CR_STRT); target_mem_write32(t, FLASH_CR, cr | FLASH_CR_STRT);
/* Read FLASH_SR to poll for BSY bit */ /* Wait for completion or an error */
while(target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) if (!stm32f4_flash_busy_wait(t))
if(target_check_error(t)) { return false;
DEBUG_WARN("stm32f4 flash erase: comm error\n");
return -1;
}
if (len > f->blocksize) if (len > f->blocksize)
len -= f->blocksize; len -= f->blocksize;
else else
@ -428,42 +441,23 @@ static int stm32f4_flash_erase(target_flash_s *f, target_addr_t addr, size_t len
sector = 16; sector = 16;
} }
/* Check for error */ return true;
sr = target_mem_read32(t, FLASH_SR);
if(sr & SR_ERROR_MASK) {
DEBUG_WARN("stm32f4 flash erase: sr error: 0x%" PRIx32 "\n", sr);
return -1;
}
return 0;
} }
static int stm32f4_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len) static bool stm32f4_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len)
{ {
/* Translate ITCM addresses to AXIM */ /* Translate ITCM addresses to AXIM */
if ((dest >= ITCM_BASE) && (dest < AXIM_BASE)) { if ((dest >= ITCM_BASE) && (dest < AXIM_BASE)) {
dest = AXIM_BASE + (dest - ITCM_BASE); dest = AXIM_BASE + (dest - ITCM_BASE);
} }
target *t = f->t; target *t = f->t;
uint32_t sr;
enum align psize = ((struct stm32f4_flash *)f)->psize;
target_mem_write32(t, FLASH_CR,
(psize * FLASH_CR_PSIZE16) | FLASH_CR_PG);
cortexm_mem_write_sized(t, dest, src, len, psize);
/* Read FLASH_SR to poll for BSY bit */
/* Wait for completion or an error */
do {
sr = target_mem_read32(t, FLASH_SR);
if(target_check_error(t)) {
DEBUG_WARN("stm32f4 flash write: comm error\n");
return -1;
}
} while (sr & FLASH_SR_BSY);
if (sr & SR_ERROR_MASK) { enum align psize = ((struct stm32f4_flash *)f)->psize;
DEBUG_WARN("stm32f4 flash write error 0x%" PRIx32 "\n", sr); target_mem_write32(t, FLASH_CR, (psize * FLASH_CR_PSIZE16) | FLASH_CR_PG);
return -1; cortexm_mem_write_sized(t, dest, src, len, psize);
}
return 0; /* Wait for completion or an error */
return stm32f4_flash_busy_wait(t);
} }
static bool stm32f4_mass_erase(target *t) static bool stm32f4_mass_erase(target *t)
@ -481,15 +475,15 @@ static bool stm32f4_mass_erase(target *t)
platform_timeout timeout; platform_timeout timeout;
platform_timeout_set(&timeout, 500); platform_timeout_set(&timeout, 500);
/* Read FLASH_SR to poll for BSY bit */ /* Read FLASH_SR to poll for BSY bit */
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) { uint32_t sr;
if (target_check_error(t)) do {
sr = target_mem_read32(t, FLASH_SR);
if ((sr & SR_ERROR_MASK) || target_check_error(t))
return false; return false;
target_print_progress(&timeout); target_print_progress(&timeout);
} } while (sr & FLASH_SR_BSY);
/* Check for error */ return true;
const uint32_t result = target_mem_read32(t, FLASH_SR);
return !(result & SR_ERROR_MASK);
} }
/* Dev | DOC |Rev|ID |OPTCR |OPTCR |OPTCR1 |OPTCR1 | OPTCR2 /* Dev | DOC |Rev|ID |OPTCR |OPTCR |OPTCR1 |OPTCR1 | OPTCR2
@ -574,9 +568,9 @@ static bool stm32f4_option_write(target *t, uint32_t *val, int count)
} }
target_mem_write32(t, FLASH_OPTKEYR, OPTKEY1); target_mem_write32(t, FLASH_OPTKEYR, OPTKEY1);
target_mem_write32(t, FLASH_OPTKEYR, OPTKEY2); target_mem_write32(t, FLASH_OPTKEYR, OPTKEY2);
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
if(target_check_error(t)) if (!stm32f4_flash_busy_wait(t))
return -1; return false;
/* WRITE option bytes instruction */ /* WRITE option bytes instruction */
if (((t->part_id == ID_STM32F42X) || (t->part_id == ID_STM32F46X) || if (((t->part_id == ID_STM32F42X) || (t->part_id == ID_STM32F46X) ||
@ -589,18 +583,22 @@ static bool stm32f4_option_write(target *t, uint32_t *val, int count)
target_mem_write32(t, FLASH_OPTCR, val[0]); target_mem_write32(t, FLASH_OPTCR, val[0]);
target_mem_write32(t, FLASH_OPTCR, val[0] | FLASH_OPTCR_OPTSTRT); target_mem_write32(t, FLASH_OPTCR, val[0] | FLASH_OPTCR_OPTSTRT);
const char spinner[] = "|/-\\";
int spinindex = 0;
tc_printf(t, "Erasing flash... This may take a few seconds. "); tc_printf(t, "Erasing flash... This may take a few seconds. ");
/* Read FLASH_SR to poll for BSY bit */ /* Read FLASH_SR to poll for BSY bit */
while(target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) { platform_timeout timeout;
platform_delay(100); platform_timeout_set(&timeout, 100);
tc_printf(t, "\b%c", spinner[spinindex++ % 4]); uint32_t sr;
if(target_check_error(t)) { do {
sr = target_mem_read32(t, FLASH_SR);
if ((sr & SR_ERROR_MASK) || target_check_error(t)) {
tc_printf(t, " failed\n"); tc_printf(t, " failed\n");
return false; return false;
} }
} target_print_progress(&timeout);
} while (sr & FLASH_SR_BSY);
tc_printf(t, "\n"); tc_printf(t, "\n");
target_mem_write32(t, FLASH_OPTCR, FLASH_OPTCR_OPTLOCK); target_mem_write32(t, FLASH_OPTCR, FLASH_OPTCR_OPTLOCK);
/* Reset target to reload option bits.*/ /* Reset target to reload option bits.*/

View File

@ -160,8 +160,8 @@ typedef struct stm32g0_priv {
static bool stm32g0_attach(target *t); static bool stm32g0_attach(target *t);
static void stm32g0_detach(target *t); static void stm32g0_detach(target *t);
static int stm32g0_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); static bool stm32g0_flash_erase(target_flash_s *f, target_addr_t addr, size_t len);
static int stm32g0_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len); static bool stm32g0_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len);
static bool stm32g0_mass_erase(target *t); static bool stm32g0_mass_erase(target *t);
/* Custom commands */ /* Custom commands */
@ -340,14 +340,14 @@ static void stm32g0_flash_op_finish(target *t)
* Flash erasure function. * Flash erasure function.
* OTP case: this function clears any previous error and returns. * OTP case: this function clears any previous error and returns.
*/ */
static int stm32g0_flash_erase(target_flash_s *f, target_addr_t addr, size_t len) static bool stm32g0_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
{ {
target *const t = f->t; target *const t = f->t;
/* Wait for Flash ready */ /* Wait for Flash ready */
if (!stm32g0_wait_busy(t)) { if (!stm32g0_wait_busy(t)) {
stm32g0_flash_op_finish(t); stm32g0_flash_op_finish(t);
return -1; return false;
} }
/* Clear any previous programming error */ /* Clear any previous programming error */
@ -355,7 +355,7 @@ static int stm32g0_flash_erase(target_flash_s *f, target_addr_t addr, size_t len
if (addr >= FLASH_OTP_START) { if (addr >= FLASH_OTP_START) {
stm32g0_flash_op_finish(t); stm32g0_flash_op_finish(t);
return 0; return true;
} }
const size_t pages_to_erase = ((len - 1U) / f->blocksize) + 1U; const size_t pages_to_erase = ((len - 1U) / f->blocksize) + 1U;
@ -382,7 +382,7 @@ static int stm32g0_flash_erase(target_flash_s *f, target_addr_t addr, size_t len
if (!stm32g0_wait_busy(t)) { if (!stm32g0_wait_busy(t)) {
stm32g0_flash_op_finish(t); stm32g0_flash_op_finish(t);
return -1; return false;
} }
} }
@ -391,7 +391,7 @@ static int stm32g0_flash_erase(target_flash_s *f, target_addr_t addr, size_t len
if (status & FLASH_SR_ERROR_MASK) if (status & FLASH_SR_ERROR_MASK)
DEBUG_WARN("stm32g0 flash erase error: sr 0x%" PRIx32 "\n", status); DEBUG_WARN("stm32g0 flash erase error: sr 0x%" PRIx32 "\n", status);
stm32g0_flash_op_finish(t); stm32g0_flash_op_finish(t);
return (status & FLASH_SR_ERROR_MASK) ? -1 : 0; return !(status & FLASH_SR_ERROR_MASK);
} }
/* /*
@ -402,7 +402,7 @@ static int stm32g0_flash_erase(target_flash_s *f, target_addr_t addr, size_t len
* OTP area is programmed as the "program" area. It can be programmed 8-bytes * OTP area is programmed as the "program" area. It can be programmed 8-bytes
* by 8-bytes. * by 8-bytes.
*/ */
static int stm32g0_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len) static bool stm32g0_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len)
{ {
target *const t = f->t; target *const t = f->t;
stm32g0_priv_s *ps = (stm32g0_priv_s *)t->target_storage; stm32g0_priv_s *ps = (stm32g0_priv_s *)t->target_storage;
@ -410,7 +410,7 @@ static int stm32g0_flash_write(target_flash_s *f, target_addr_t dest, const void
if (dest >= FLASH_OTP_START && !ps->irreversible_enabled) { if (dest >= FLASH_OTP_START && !ps->irreversible_enabled) {
tc_printf(t, "Irreversible operations disabled\n"); tc_printf(t, "Irreversible operations disabled\n");
stm32g0_flash_op_finish(t); stm32g0_flash_op_finish(t);
return -1; return false;
} }
stm32g0_flash_unlock(t); stm32g0_flash_unlock(t);
@ -421,14 +421,14 @@ static int stm32g0_flash_write(target_flash_s *f, target_addr_t dest, const void
if (!stm32g0_wait_busy(t)) { if (!stm32g0_wait_busy(t)) {
DEBUG_WARN("stm32g0 flash write: comm error\n"); DEBUG_WARN("stm32g0 flash write: comm error\n");
stm32g0_flash_op_finish(t); stm32g0_flash_op_finish(t);
return -1; return false;
} }
const uint32_t status = target_mem_read32(t, FLASH_SR); const uint32_t status = target_mem_read32(t, FLASH_SR);
if (status & FLASH_SR_ERROR_MASK) { if (status & FLASH_SR_ERROR_MASK) {
DEBUG_WARN("stm32g0 flash write error: sr 0x%" PRIx32 "\n", status); DEBUG_WARN("stm32g0 flash write error: sr 0x%" PRIx32 "\n", status);
stm32g0_flash_op_finish(t); stm32g0_flash_op_finish(t);
return -1; return false;
} }
if (dest == FLASH_START && target_mem_read32(t, FLASH_START) != 0xFFFFFFFF) { if (dest == FLASH_START && target_mem_read32(t, FLASH_START) != 0xFFFFFFFF) {
@ -437,7 +437,7 @@ static int stm32g0_flash_write(target_flash_s *f, target_addr_t dest, const void
} }
stm32g0_flash_op_finish(t); stm32g0_flash_op_finish(t);
return 0; return true;
} }
static bool stm32g0_mass_erase(target *t) static bool stm32g0_mass_erase(target *t)

View File

@ -52,8 +52,8 @@ const struct command_s stm32h7_cmd_list[] = {
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };
static int stm32h7_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); static bool stm32h7_flash_erase(target_flash_s *f, target_addr_t addr, size_t len);
static int stm32h7_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len); static bool stm32h7_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len);
static bool stm32h7_mass_erase(target *t); static bool stm32h7_mass_erase(target *t);
static const char stm32h7_driver_str[] = "STM32H7"; static const char stm32h7_driver_str[] = "STM32H7";
@ -243,22 +243,30 @@ bool stm32h7_probe(target *t)
return false; return false;
} }
static bool stm32h7_flash_busy_wait(target *t, uint32_t regbase)
{
uint32_t sr;
do {
sr = target_mem_read32(t, regbase + FLASH_SR);
if ((sr & FLASH_SR_ERROR_MASK) || target_check_error(t)) {
DEBUG_WARN("stm32h7_flash_write: error sr %08" PRIx32 "\n", sr);
target_mem_write32(t, regbase + FLASH_CCR, sr & FLASH_SR_ERROR_MASK);
return false;
}
} while (sr & (FLASH_SR_BSY | FLASH_SR_QW));
return true;
}
static bool stm32h7_flash_unlock(target *t, const uint32_t addr) static bool stm32h7_flash_unlock(target *t, const uint32_t addr)
{ {
uint32_t regbase = FPEC1_BASE; uint32_t regbase = FPEC1_BASE;
if (addr >= BANK2_START) if (addr >= BANK2_START)
regbase = FPEC2_BASE; regbase = FPEC2_BASE;
while (target_mem_read32(t, regbase + FLASH_SR) & FLASH_SR_BSY) { if (!stm32h7_flash_busy_wait(t, regbase))
if (target_check_error(t))
return false; return false;
}
const uint32_t status = target_mem_read32(t, regbase + FLASH_SR) & FLASH_SR_ERROR_MASK;
if (status) {
DEBUG_WARN("%s error 0x%08" PRIx32, __func__, status);
target_mem_write32(t, regbase + FLASH_CCR, status);
return false;
}
if (target_mem_read32(t, regbase + FLASH_CR) & FLASH_CR_LOCK) { if (target_mem_read32(t, regbase + FLASH_CR) & FLASH_CR_LOCK) {
/* Enable FLASH controller access */ /* Enable FLASH controller access */
target_mem_write32(t, regbase + FLASH_KEYR, KEY1); target_mem_write32(t, regbase + FLASH_KEYR, KEY1);
@ -267,12 +275,12 @@ static bool stm32h7_flash_unlock(target *t, const uint32_t addr)
return !(target_mem_read32(t, regbase + FLASH_CR) & FLASH_CR_LOCK); return !(target_mem_read32(t, regbase + FLASH_CR) & FLASH_CR_LOCK);
} }
static int stm32h7_flash_erase(target_flash_s *f, target_addr_t addr, size_t len) static bool stm32h7_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
{ {
target *t = f->t; target *t = f->t;
struct stm32h7_flash *sf = (struct stm32h7_flash *)f; struct stm32h7_flash *sf = (struct stm32h7_flash *)f;
if (!stm32h7_flash_unlock(t, addr)) if (!stm32h7_flash_unlock(t, addr))
return -1; return false;
/* We come out of reset with HSI 64 MHz. Adapt FLASH_ACR.*/ /* We come out of reset with HSI 64 MHz. Adapt FLASH_ACR.*/
target_mem_write32(t, sf->regbase + FLASH_ACR, 0); target_mem_write32(t, sf->regbase + FLASH_ACR, 0);
addr &= (NUM_SECTOR_PER_BANK * FLASH_SECTOR_SIZE) - 1; addr &= (NUM_SECTOR_PER_BANK * FLASH_SECTOR_SIZE) - 1;
@ -288,53 +296,37 @@ static int stm32h7_flash_erase(target_flash_s *f, target_addr_t addr, size_t len
DEBUG_INFO(" started cr %08" PRIx32 " sr %08" PRIx32 "\n", DEBUG_INFO(" started cr %08" PRIx32 " sr %08" PRIx32 "\n",
target_mem_read32(t, sf->regbase + FLASH_CR), target_mem_read32(t, sf->regbase + FLASH_CR),
target_mem_read32(t, sf->regbase + FLASH_SR)); target_mem_read32(t, sf->regbase + FLASH_SR));
uint32_t status = 0;
do {
status = target_mem_read32(t, sf->regbase + FLASH_SR);
if (target_check_error(t)) {
DEBUG_WARN("stm32h7_flash_erase: comm failed\n");
return -1;
}
// target_mem_write32(t, H7_IWDG_BASE, 0x0000aaaa);
} while (status & (FLASH_SR_QW | FLASH_SR_BSY));
if (status & FLASH_SR_ERROR_MASK) { if (!stm32h7_flash_busy_wait(t, sf->regbase))
DEBUG_WARN("stm32h7_flash_erase: error, sr: %08" PRIx32 "\n", status); return false;
return -1;
}
++start_sector; ++start_sector;
} }
return 0; return true;
} }
static int stm32h7_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len) static bool stm32h7_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len)
{ {
target *t = f->t; target *t = f->t;
struct stm32h7_flash *sf = (struct stm32h7_flash *)f; struct stm32h7_flash *sf = (struct stm32h7_flash *)f;
enum align psize = sf->psize; enum align psize = sf->psize;
if (!stm32h7_flash_unlock(t, dest)) if (!stm32h7_flash_unlock(t, dest))
return -1; return false;
uint32_t cr = psize * FLASH_CR_PSIZE16; uint32_t cr = psize * FLASH_CR_PSIZE16;
target_mem_write32(t, sf->regbase + FLASH_CR, cr); target_mem_write32(t, sf->regbase + FLASH_CR, cr);
cr |= FLASH_CR_PG; cr |= FLASH_CR_PG;
target_mem_write32(t, sf->regbase + FLASH_CR, cr); target_mem_write32(t, sf->regbase + FLASH_CR, cr);
/* does H7 stall?*/ /* does H7 stall?*/
uint32_t status_reg = sf->regbase + FLASH_SR;
uint32_t status = 0;
target_mem_write(t, dest, src, len); target_mem_write(t, dest, src, len);
while ((status = target_mem_read32(t, status_reg)) & FLASH_SR_BSY) {
if(target_check_error(t)) { if (!stm32h7_flash_busy_wait(t, sf->regbase))
DEBUG_WARN("stm32h7_flash_write: BSY comm failed\n"); return false;
return -1;
}
}
if (status & FLASH_SR_ERROR_MASK) {
DEBUG_WARN("stm32h7_flash_write: error sr %08" PRIx32 "\n", status);
return -1;
}
/* Close write windows.*/ /* Close write windows.*/
target_mem_write32(t, sf->regbase + FLASH_CR, 0); target_mem_write32(t, sf->regbase + FLASH_CR, 0);
return 0;
return true;
} }
static bool stm32h7_erase_bank(target *const t, const enum align psize, static bool stm32h7_erase_bank(target *const t, const enum align psize,

View File

@ -143,11 +143,11 @@
#define STM32L1_NVM_OPTR_BOR_LEV_M (0xf) #define STM32L1_NVM_OPTR_BOR_LEV_M (0xf)
#define STM32L1_NVM_OPTR_SPRMOD (1 << 8) #define STM32L1_NVM_OPTR_SPRMOD (1 << 8)
static int stm32lx_nvm_prog_erase(target_flash_s *f, target_addr_t addr, size_t len); static bool stm32lx_nvm_prog_erase(target_flash_s *f, target_addr_t addr, size_t len);
static int stm32lx_nvm_prog_write(target_flash_s *f, target_addr_t destination, const void *src, size_t size); static bool stm32lx_nvm_prog_write(target_flash_s *f, target_addr_t destination, const void *src, size_t size);
static int stm32lx_nvm_data_erase(target_flash_s *f, target_addr_t addr, size_t len); static bool stm32lx_nvm_data_erase(target_flash_s *f, target_addr_t addr, size_t len);
static int stm32lx_nvm_data_write(target_flash_s *f, target_addr_t destination, const void *source, size_t size); static bool stm32lx_nvm_data_write(target_flash_s *f, target_addr_t destination, const void *source, size_t size);
static bool stm32lx_cmd_option(target *t, int argc, char **argv); static bool stm32lx_cmd_option(target *t, int argc, char **argv);
static bool stm32lx_cmd_eeprom(target *t, int argc, char **argv); static bool stm32lx_cmd_eeprom(target *t, int argc, char **argv);
@ -321,25 +321,37 @@ static bool stm32lx_nvm_opt_unlock(target *t, uint32_t nvm)
return !(target_mem_read32(t, STM32Lx_NVM_PECR(nvm)) & STM32Lx_NVM_PECR_OPTLOCK); return !(target_mem_read32(t, STM32Lx_NVM_PECR(nvm)) & STM32Lx_NVM_PECR_OPTLOCK);
} }
static bool stm32lx_nvm_busy_wait(target *t, uint32_t nvm)
{
uint32_t sr;
do {
sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm));
if ((sr & STM32Lx_NVM_SR_ERR_M) || !(sr & STM32Lx_NVM_SR_EOP) || target_check_error(t))
return false;
} while (sr & STM32Lx_NVM_SR_BSY);
return true;
}
/** Erase a region of program flash using operations through the debug /** Erase a region of program flash using operations through the debug
interface. This is slower than stubbed versions(see NOTES). The interface. This is slower than stubbed versions(see NOTES). The
flash array is erased for all pages from addr to addr+len flash array is erased for all pages from addr to addr+len
inclusive. NVM register file address chosen from target. */ inclusive. NVM register file address chosen from target. */
static int stm32lx_nvm_prog_erase(target_flash_s *f, target_addr_t addr, size_t len) static bool stm32lx_nvm_prog_erase(target_flash_s *f, target_addr_t addr, size_t len)
{ {
target *t = f->t; target *t = f->t;
const size_t page_size = f->blocksize; const size_t page_size = f->blocksize;
const uint32_t nvm = stm32lx_nvm_phys(t); const uint32_t nvm = stm32lx_nvm_phys(t);
if (!stm32lx_nvm_prog_data_unlock(t, nvm)) if (!stm32lx_nvm_prog_data_unlock(t, nvm))
return -1; return false;
/* Flash page erase instruction */ /* Flash page erase instruction */
target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_PROG); target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_PROG);
uint32_t pecr = target_mem_read32(t, STM32Lx_NVM_PECR(nvm)); const uint32_t pecr = target_mem_read32(t, STM32Lx_NVM_PECR(nvm));
if ((pecr & (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE)) != (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE)) if ((pecr & (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE)) != (STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_ERASE))
return -1; return false;
/* Clear errors. Note that this only works when we wait for the NVM /* Clear errors. Note that this only works when we wait for the NVM
block to complete the last operation. */ block to complete the last operation. */
@ -359,32 +371,23 @@ static int stm32lx_nvm_prog_erase(target_flash_s *f, target_addr_t addr, size_t
stm32lx_nvm_lock(t, nvm); stm32lx_nvm_lock(t, nvm);
/* Wait for completion or an error */ /* Wait for completion or an error */
uint32_t sr; return stm32lx_nvm_busy_wait(t, nvm);
do {
sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm));
} while (sr & STM32Lx_NVM_SR_BSY);
if ((sr & STM32Lx_NVM_SR_ERR_M) || !(sr & STM32Lx_NVM_SR_EOP) || target_check_error(t))
return -1;
return 0;
} }
/** Write to program flash using operations through the debug /** Write to program flash using operations through the debug
interface. */ interface. */
static int stm32lx_nvm_prog_write(target_flash_s *f, target_addr_t dest, const void *src, size_t size) static bool stm32lx_nvm_prog_write(target_flash_s *f, target_addr_t dest, const void *src, size_t size)
{ {
target *t = f->t; target *t = f->t;
const uint32_t nvm = stm32lx_nvm_phys(t); const uint32_t nvm = stm32lx_nvm_phys(t);
if (!stm32lx_nvm_prog_data_unlock(t, nvm)) if (!stm32lx_nvm_prog_data_unlock(t, nvm))
return -1; return false;
/* Wait for BSY to clear because we cannot write the PECR until /* Wait for BSY to clear because we cannot write the PECR until
the previous operation completes on STM32Lxxx. */ the previous operation completes on STM32Lxxx. */
while (target_mem_read32(t, STM32Lx_NVM_SR(nvm)) & STM32Lx_NVM_SR_BSY) if (!stm32lx_nvm_busy_wait(t, nvm))
if (target_check_error(t)) return false;
return -1;
target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_FPRG); target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_FPRG);
target_mem_write(t, dest, src, size); target_mem_write(t, dest, src, size);
@ -393,22 +396,14 @@ static int stm32lx_nvm_prog_write(target_flash_s *f, target_addr_t dest, const v
stm32lx_nvm_lock(t, nvm); stm32lx_nvm_lock(t, nvm);
/* Wait for completion or an error */ /* Wait for completion or an error */
uint32_t sr; return stm32lx_nvm_busy_wait(t, nvm);
do {
sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm));
} while (sr & STM32Lx_NVM_SR_BSY);
if ((sr & STM32Lx_NVM_SR_ERR_M) || !(sr & STM32Lx_NVM_SR_EOP) || target_check_error(t))
return -1;
return 0;
} }
/** Erase a region of data flash using operations through the debug /** Erase a region of data flash using operations through the debug
interface . The flash is erased for all pages from addr to interface . The flash is erased for all pages from addr to
addr+len, inclusive, on a word boundary. NVM register file addr+len, inclusive, on a word boundary. NVM register file
address chosen from target. */ address chosen from target. */
static int stm32lx_nvm_data_erase(target_flash_s *f, target_addr_t addr, size_t len) static bool stm32lx_nvm_data_erase(target_flash_s *f, target_addr_t addr, size_t len)
{ {
target *t = f->t; target *t = f->t;
const size_t page_size = f->blocksize; const size_t page_size = f->blocksize;
@ -419,14 +414,14 @@ static int stm32lx_nvm_data_erase(target_flash_s *f, target_addr_t addr, size_t
addr &= ~3; addr &= ~3;
if (!stm32lx_nvm_prog_data_unlock(t, nvm)) if (!stm32lx_nvm_prog_data_unlock(t, nvm))
return -1; return false;
/* Flash data erase instruction */ /* Flash data erase instruction */
target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA); target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA);
uint32_t pecr = target_mem_read32(t, STM32Lx_NVM_PECR(nvm)); uint32_t pecr = target_mem_read32(t, STM32Lx_NVM_PECR(nvm));
if ((pecr & (STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA)) != (STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA)) if ((pecr & (STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA)) != (STM32Lx_NVM_PECR_ERASE | STM32Lx_NVM_PECR_DATA))
return -1; return false;
while (len > 0) { while (len > 0) {
/* Write first word of page to 0 */ /* Write first word of page to 0 */
@ -443,22 +438,14 @@ static int stm32lx_nvm_data_erase(target_flash_s *f, target_addr_t addr, size_t
stm32lx_nvm_lock(t, nvm); stm32lx_nvm_lock(t, nvm);
/* Wait for completion or an error */ /* Wait for completion or an error */
uint32_t sr; return stm32lx_nvm_busy_wait(t, nvm);
do {
sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm));
} while (sr & STM32Lx_NVM_SR_BSY);
if ((sr & STM32Lx_NVM_SR_ERR_M) || !(sr & STM32Lx_NVM_SR_EOP) || target_check_error(t))
return -1;
return 0;
} }
/** Write to data flash using operations through the debug interface. /** Write to data flash using operations through the debug interface.
NVM register file address chosen from target. Unaligned NVM register file address chosen from target. Unaligned
destination writes are supported (though unaligned sources are destination writes are supported (though unaligned sources are
not). */ not). */
static int stm32lx_nvm_data_write(target_flash_s *f, target_addr_t destination, const void *src, size_t size) static bool stm32lx_nvm_data_write(target_flash_s *f, target_addr_t destination, const void *src, size_t size)
{ {
target *t = f->t; target *t = f->t;
const uint32_t nvm = stm32lx_nvm_phys(t); const uint32_t nvm = stm32lx_nvm_phys(t);
@ -466,7 +453,7 @@ static int stm32lx_nvm_data_write(target_flash_s *f, target_addr_t destination,
uint32_t *source = (uint32_t *)src; uint32_t *source = (uint32_t *)src;
if (!stm32lx_nvm_prog_data_unlock(t, nvm)) if (!stm32lx_nvm_prog_data_unlock(t, nvm))
return -1; return false;
target_mem_write32(t, STM32Lx_NVM_PECR(nvm), is_stm32l1 ? 0 : STM32Lx_NVM_PECR_DATA); target_mem_write32(t, STM32Lx_NVM_PECR(nvm), is_stm32l1 ? 0 : STM32Lx_NVM_PECR_DATA);
@ -477,22 +464,14 @@ static int stm32lx_nvm_data_write(target_flash_s *f, target_addr_t destination,
destination += 4; destination += 4;
if (target_check_error(t)) if (target_check_error(t))
return -1; return false;
} }
/* Disable further programming by locking PECR */ /* Disable further programming by locking PECR */
stm32lx_nvm_lock(t, nvm); stm32lx_nvm_lock(t, nvm);
/* Wait for completion or an error */ /* Wait for completion or an error */
uint32_t sr; return stm32lx_nvm_busy_wait(t, nvm);
do {
sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm));
} while (sr & STM32Lx_NVM_SR_BSY);
if ((sr & STM32Lx_NVM_SR_ERR_M) || !(sr & STM32Lx_NVM_SR_EOP) || target_check_error(t))
return -1;
return 0;
} }
/** Write one option word. The address is the physical address of the /** Write one option word. The address is the physical address of the
@ -509,12 +488,7 @@ static bool stm32lx_option_write(target *t, uint32_t address, uint32_t value)
target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_FIX); target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_FIX);
target_mem_write32(t, address, value); target_mem_write32(t, address, value);
uint32_t sr; return stm32lx_nvm_busy_wait(t, nvm);
do {
sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm));
} while (sr & STM32Lx_NVM_SR_BSY);
return !(sr & STM32Lx_NVM_SR_ERR_M);
} }
/** Write one eeprom value. This version is more flexible than that /** Write one eeprom value. This version is more flexible than that
@ -543,12 +517,7 @@ static bool stm32lx_eeprom_write(target *t, uint32_t address, size_t cb, uint32_
else else
return false; return false;
uint32_t sr; return stm32lx_nvm_busy_wait(t, nvm);
do {
sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm));
} while (sr & STM32Lx_NVM_SR_BSY);
return !(sr & STM32Lx_NVM_SR_ERR_M);
} }
static bool stm32lx_cmd_option(target *t, int argc, char **argv) static bool stm32lx_cmd_option(target *t, int argc, char **argv)

View File

@ -53,8 +53,8 @@ const struct command_s stm32l4_cmd_list[] = {
{NULL, NULL, NULL} {NULL, NULL, NULL}
}; };
static int stm32l4_flash_erase(target_flash_s *f, target_addr_t addr, size_t len); static bool stm32l4_flash_erase(target_flash_s *f, target_addr_t addr, size_t len);
static int stm32l4_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len); static bool stm32l4_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len);
static bool stm32l4_mass_erase(target *t); static bool stm32l4_mass_erase(target *t);
/* Flash Program ad Erase Controller Register Map */ /* Flash Program ad Erase Controller Register Map */
@ -569,16 +569,28 @@ static void stm32l4_flash_unlock(target *t)
} }
} }
static int stm32l4_flash_erase(target_flash_s *f, target_addr_t addr, size_t len) static bool stm32l4_flash_busy_wait(target *t)
{
/* Read FLASH_SR to poll for BSY bit */
uint32_t sr;
do {
sr = stm32l4_flash_read32(t, FLASH_SR);
if ((sr & FLASH_SR_ERROR_MASK) || target_check_error(t)) {
DEBUG_WARN("stm32l4 flash error: sr 0x%" PRIx32 "\n", sr);
return false;
}
} while (sr & FLASH_SR_BSY);
return true;
}
static bool stm32l4_flash_erase(target_flash_s *f, target_addr_t addr, size_t len)
{ {
target *t = f->t; target *t = f->t;
stm32l4_flash_unlock(t); stm32l4_flash_unlock(t);
/* Read FLASH_SR to poll for BSY bit */ if (!stm32l4_flash_busy_wait(t))
while (stm32l4_flash_read32(t, FLASH_SR) & FLASH_SR_BSY) { return false;
if (target_check_error(t))
return -1;
}
/* Fixme: OPTVER always set after reset! Wrong option defaults?*/ /* Fixme: OPTVER always set after reset! Wrong option defaults?*/
stm32l4_flash_write32(t, FLASH_SR, stm32l4_flash_read32(t, FLASH_SR)); stm32l4_flash_write32(t, FLASH_SR, stm32l4_flash_read32(t, FLASH_SR));
@ -595,11 +607,9 @@ static int stm32l4_flash_erase(target_flash_s *f, target_addr_t addr, size_t len
ctrl_reg |= FLASH_CR_STRT; ctrl_reg |= FLASH_CR_STRT;
stm32l4_flash_write32(t, FLASH_CR, ctrl_reg); stm32l4_flash_write32(t, FLASH_CR, ctrl_reg);
/* Read FLASH_SR to poll for BSY bit */ if (!stm32l4_flash_busy_wait(t))
while (stm32l4_flash_read32(t, FLASH_SR) & FLASH_SR_BSY) { return false;
if (target_check_error(t))
return -1;
}
if (len > blocksize) if (len > blocksize)
len -= blocksize; len -= blocksize;
else else
@ -608,32 +618,17 @@ static int stm32l4_flash_erase(target_flash_s *f, target_addr_t addr, size_t len
page++; page++;
} }
/* Check for error */ return true;
if (stm32l4_flash_read32(t, FLASH_SR) & FLASH_SR_ERROR_MASK)
return -1;
return 0;
} }
static int stm32l4_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len) static bool stm32l4_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len)
{ {
target *t = f->t; target *t = f->t;
stm32l4_flash_write32(t, FLASH_CR, FLASH_CR_PG); stm32l4_flash_write32(t, FLASH_CR, FLASH_CR_PG);
target_mem_write(t, dest, src, len); target_mem_write(t, dest, src, len);
/* Wait for completion or an error */
uint32_t status;
do {
status = stm32l4_flash_read32(t, FLASH_SR);
if (target_check_error(t)) {
DEBUG_WARN("stm32l4 flash write: comm error\n");
return -1;
}
} while (status & FLASH_SR_BSY);
if (status & FLASH_SR_ERROR_MASK) { /* Wait for completion or an error */
DEBUG_WARN("stm32l4 flash write error: sr 0x%" PRIx32 "\n", status); return stm32l4_flash_busy_wait(t);
return -1;
}
return 0;
} }
static bool stm32l4_cmd_erase(target *const t, const uint32_t action) static bool stm32l4_cmd_erase(target *const t, const uint32_t action)
@ -644,17 +639,19 @@ static bool stm32l4_cmd_erase(target *const t, const uint32_t action)
stm32l4_flash_write32(t, FLASH_CR, action); stm32l4_flash_write32(t, FLASH_CR, action);
stm32l4_flash_write32(t, FLASH_CR, action | FLASH_CR_STRT); stm32l4_flash_write32(t, FLASH_CR, action | FLASH_CR_STRT);
/* Read FLASH_SR to poll for BSY bit */
uint32_t sr;
platform_timeout timeout; platform_timeout timeout;
platform_timeout_set(&timeout, 500); platform_timeout_set(&timeout, 500);
/* Read FLASH_SR to poll for BSY bit */ do {
while (stm32l4_flash_read32(t, FLASH_SR) & FLASH_SR_BSY) { sr = stm32l4_flash_read32(t, FLASH_SR);
if(target_check_error(t)) if ((sr & FLASH_SR_ERROR_MASK) || target_check_error(t))
return false; return false;
target_print_progress(&timeout); target_print_progress(&timeout);
} } while (sr & FLASH_SR_BSY);
/* Check for error */ /* Check for error */
return !(stm32l4_flash_read32(t, FLASH_SR) & FLASH_SR_ERROR_MASK); return true;
} }
static bool stm32l4_mass_erase(target *const t) static bool stm32l4_mass_erase(target *const t)
@ -701,15 +698,13 @@ static bool stm32l4_option_write(
stm32l4_flash_unlock(t); stm32l4_flash_unlock(t);
stm32l4_flash_write32(t, FLASH_OPTKEYR, OPTKEY1); stm32l4_flash_write32(t, FLASH_OPTKEYR, OPTKEY1);
stm32l4_flash_write32(t, FLASH_OPTKEYR, OPTKEY2); stm32l4_flash_write32(t, FLASH_OPTKEYR, OPTKEY2);
while (stm32l4_flash_read32(t, FLASH_SR) & FLASH_SR_BSY) if (!stm32l4_flash_busy_wait(t))
if(target_check_error(t))
return true; return true;
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
target_mem_write32(t, fpec_base + i2offset[i], values[i]); target_mem_write32(t, fpec_base + i2offset[i], values[i]);
stm32l4_flash_write32(t, FLASH_CR, FLASH_CR_OPTSTRT); stm32l4_flash_write32(t, FLASH_CR, FLASH_CR_OPTSTRT);
while (stm32l4_flash_read32(t, FLASH_SR) & FLASH_SR_BSY) if (!stm32l4_flash_busy_wait(t))
if(target_check_error(t)) return false;
return true;
stm32l4_flash_write32(t, FLASH_CR, FLASH_CR_OBL_LAUNCH); stm32l4_flash_write32(t, FLASH_CR, FLASH_CR_OBL_LAUNCH);
while (stm32l4_flash_read32(t, FLASH_CR) & FLASH_CR_OBL_LAUNCH) while (stm32l4_flash_read32(t, FLASH_CR) & FLASH_CR_OBL_LAUNCH)
if(target_check_error(t)) if(target_check_error(t))