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}
};
static int 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_erase(target_flash_s *f, target_addr_t addr, 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);
/* Flash Program ad Erase Controller Register Map */
@ -357,19 +357,33 @@ static int stm32f1_flash_unlock(target *t, uint32_t bank_offset)
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_addr_t end = addr + len - 1;
target_addr_t start = addr;
if (t->part_id == 0x430 && end >= FLASH_BANK_SPLIT)
if (stm32f1_flash_unlock(t, FLASH_BANK2_OFFSET))
return -1;
return false;
if (addr < FLASH_BANK_SPLIT)
if (stm32f1_flash_unlock(t, 0))
return -1;
return false;
while (len) {
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 */
target_mem_write32(t, FLASH_CR + bank_offset, FLASH_CR_STRT | FLASH_CR_PER);
/* Read FLASH_SR to poll for BSY bit */
while (target_mem_read32(t, FLASH_SR + bank_offset) & FLASH_SR_BSY) {
if (target_check_error(t)) {
DEBUG_WARN("stm32f1 flash erase: comm error\n");
return -1;
}
}
/* Wait for completion or an error */
if (!stm32f1_flash_busy_wait(t, bank_offset))
return false;
if (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;
}
/* Check for error */
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;
return true;
}
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;
uint32_t sr;
size_t length = 0;
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);
cortexm_mem_write_sized(t, dest, src, length, ALIGN_HALFWORD);
/* 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("stm32f1 flash write: comm error\n");
return -1;
}
} while (sr & FLASH_SR_BSY);
if (!stm32f1_flash_busy_wait(t, 0))
return false;
if (sr & SR_ERROR_MASK) {
DEBUG_WARN("stm32f1 flash write error 0x%" PRIx32 "\n", sr);
return -1;
}
dest += 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 */
target_mem_write32(t, FLASH_CR + FLASH_BANK2_OFFSET, FLASH_CR_PG);
cortexm_mem_write_sized(t, dest, src, length, ALIGN_HALFWORD);
/* Read FLASH_SR to poll for BSY bit */
/* Wait for completion or an error */
do {
sr = target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET);
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;
}
/* Wait for completion or an error */
if (!stm32f1_flash_busy_wait(t, FLASH_BANK2_OFFSET))
return false;
}
return 0;
return true;
}
static bool stm32f1_mass_erase(target *t)
@ -479,6 +452,7 @@ static bool stm32f1_mass_erase(target *t)
if (stm32f1_flash_unlock(t, 0))
return false;
uint32_t sr;
platform_timeout timeout;
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_STRT | FLASH_CR_MER);
/* Read FLASH_SR to poll for BSY bit */
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) {
if (target_check_error(t))
/* Wait for completion or an error */
do {
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;
}
target_print_progress(&timeout);
}
/* Check for error */
uint16_t sr = target_mem_read32(t, FLASH_SR);
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP))
return false;
} while (sr & FLASH_SR_BSY);
if (t->part_id == 0x430) {
if (stm32f1_flash_unlock(t, FLASH_BANK2_OFFSET))
@ -506,15 +478,15 @@ 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_STRT | FLASH_CR_MER);
/* Read FLASH_SR to poll for BSY bit */
while (target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET) & FLASH_SR_BSY)
if (target_check_error(t))
/* Wait for completion or an error */
do {
sr = target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET);
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP) || target_check_error(t)) {
DEBUG_WARN("stm32f1 flash error 0x%" PRIx32 "\n", sr);
return false;
/* Check for error */
sr = target_mem_read32(t, FLASH_SR + FLASH_BANK2_OFFSET);
if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP))
return false;
}
target_print_progress(&timeout);
} while (sr & FLASH_SR_BSY);
}
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_STRT | FLASH_CR_OPTER | FLASH_CR_OPTWRE);
/* Read FLASH_SR to poll for BSY bit */
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
if (target_check_error(t))
return false;
return true;
/* Wait for completion or an error */
return stm32f1_flash_busy_wait(t, 0);
}
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
target_mem_write16(t, addr, value);
/* Read FLASH_SR to poll for BSY bit */
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
if (target_check_error(t))
return false;
return true;
/* Wait for completion or an error */
return stm32f1_flash_busy_wait(t, 0);
}
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 int 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_erase(target_flash_s *f, target_addr_t addr, 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);
/* 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;
struct stm32f4_flash *sf = (struct stm32f4_flash *)f;
uint32_t sr;
/* No address translation is needed here, as we erase by sector number */
uint8_t sector = sf->base_sector + (addr - f->start)/f->blocksize;
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 */
target_mem_write32(t, FLASH_CR, cr | FLASH_CR_STRT);
/* Read FLASH_SR to poll for BSY bit */
while(target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
if(target_check_error(t)) {
DEBUG_WARN("stm32f4 flash erase: comm error\n");
return -1;
}
/* Wait for completion or an error */
if (!stm32f4_flash_busy_wait(t))
return false;
if (len > f->blocksize)
len -= f->blocksize;
else
@ -428,42 +441,23 @@ static int stm32f4_flash_erase(target_flash_s *f, target_addr_t addr, size_t len
sector = 16;
}
/* Check for error */
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;
return true;
}
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 */
if ((dest >= ITCM_BASE) && (dest < AXIM_BASE)) {
dest = AXIM_BASE + (dest - ITCM_BASE);
}
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) {
DEBUG_WARN("stm32f4 flash write error 0x%" PRIx32 "\n", sr);
return -1;
}
return 0;
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);
/* Wait for completion or an error */
return stm32f4_flash_busy_wait(t);
}
static bool stm32f4_mass_erase(target *t)
@ -481,15 +475,15 @@ static bool stm32f4_mass_erase(target *t)
platform_timeout timeout;
platform_timeout_set(&timeout, 500);
/* Read FLASH_SR to poll for BSY bit */
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) {
if (target_check_error(t))
uint32_t sr;
do {
sr = target_mem_read32(t, FLASH_SR);
if ((sr & SR_ERROR_MASK) || target_check_error(t))
return false;
target_print_progress(&timeout);
}
} while (sr & FLASH_SR_BSY);
/* Check for error */
const uint32_t result = target_mem_read32(t, FLASH_SR);
return !(result & SR_ERROR_MASK);
return true;
}
/* 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, OPTKEY2);
while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY)
if(target_check_error(t))
return -1;
if (!stm32f4_flash_busy_wait(t))
return false;
/* WRITE option bytes instruction */
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] | FLASH_OPTCR_OPTSTRT);
const char spinner[] = "|/-\\";
int spinindex = 0;
tc_printf(t, "Erasing flash... This may take a few seconds. ");
/* Read FLASH_SR to poll for BSY bit */
while(target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) {
platform_delay(100);
tc_printf(t, "\b%c", spinner[spinindex++ % 4]);
if(target_check_error(t)) {
platform_timeout timeout;
platform_timeout_set(&timeout, 100);
uint32_t sr;
do {
sr = target_mem_read32(t, FLASH_SR);
if ((sr & SR_ERROR_MASK) || target_check_error(t)) {
tc_printf(t, " failed\n");
return false;
}
}
target_print_progress(&timeout);
} while (sr & FLASH_SR_BSY);
tc_printf(t, "\n");
target_mem_write32(t, FLASH_OPTCR, FLASH_OPTCR_OPTLOCK);
/* Reset target to reload option bits.*/

View File

@ -160,8 +160,8 @@ typedef struct stm32g0_priv {
static bool stm32g0_attach(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 int stm32g0_flash_write(target_flash_s *f, target_addr_t dest, const void *src, size_t len);
static bool stm32g0_flash_erase(target_flash_s *f, target_addr_t addr, 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);
/* Custom commands */
@ -340,14 +340,14 @@ static void stm32g0_flash_op_finish(target *t)
* Flash erasure function.
* 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;
/* Wait for Flash ready */
if (!stm32g0_wait_busy(t)) {
stm32g0_flash_op_finish(t);
return -1;
return false;
}
/* 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) {
stm32g0_flash_op_finish(t);
return 0;
return true;
}
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)) {
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)
DEBUG_WARN("stm32g0 flash erase error: sr 0x%" PRIx32 "\n", status);
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
* 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;
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) {
tc_printf(t, "Irreversible operations disabled\n");
stm32g0_flash_op_finish(t);
return -1;
return false;
}
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)) {
DEBUG_WARN("stm32g0 flash write: comm error\n");
stm32g0_flash_op_finish(t);
return -1;
return false;
}
const uint32_t status = target_mem_read32(t, FLASH_SR);
if (status & FLASH_SR_ERROR_MASK) {
DEBUG_WARN("stm32g0 flash write error: sr 0x%" PRIx32 "\n", status);
stm32g0_flash_op_finish(t);
return -1;
return false;
}
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);
return 0;
return true;
}
static bool stm32g0_mass_erase(target *t)

View File

@ -52,8 +52,8 @@ const struct command_s stm32h7_cmd_list[] = {
{NULL, NULL, NULL}
};
static int 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_erase(target_flash_s *f, target_addr_t addr, 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 const char stm32h7_driver_str[] = "STM32H7";
@ -243,22 +243,30 @@ bool stm32h7_probe(target *t)
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)
{
uint32_t regbase = FPEC1_BASE;
if (addr >= BANK2_START)
regbase = FPEC2_BASE;
while (target_mem_read32(t, regbase + FLASH_SR) & FLASH_SR_BSY) {
if (target_check_error(t))
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);
if (!stm32h7_flash_busy_wait(t, regbase))
return false;
}
if (target_mem_read32(t, regbase + FLASH_CR) & FLASH_CR_LOCK) {
/* Enable FLASH controller access */
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);
}
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;
struct stm32h7_flash *sf = (struct stm32h7_flash *)f;
if (!stm32h7_flash_unlock(t, addr))
return -1;
return false;
/* We come out of reset with HSI 64 MHz. Adapt FLASH_ACR.*/
target_mem_write32(t, sf->regbase + FLASH_ACR, 0);
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",
target_mem_read32(t, sf->regbase + FLASH_CR),
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) {
DEBUG_WARN("stm32h7_flash_erase: error, sr: %08" PRIx32 "\n", status);
return -1;
}
if (!stm32h7_flash_busy_wait(t, sf->regbase))
return false;
++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;
struct stm32h7_flash *sf = (struct stm32h7_flash *)f;
enum align psize = sf->psize;
if (!stm32h7_flash_unlock(t, dest))
return -1;
return false;
uint32_t cr = psize * FLASH_CR_PSIZE16;
target_mem_write32(t, sf->regbase + FLASH_CR, cr);
cr |= FLASH_CR_PG;
target_mem_write32(t, sf->regbase + FLASH_CR, cr);
/* does H7 stall?*/
uint32_t status_reg = sf->regbase + FLASH_SR;
uint32_t status = 0;
target_mem_write(t, dest, src, len);
while ((status = target_mem_read32(t, status_reg)) & FLASH_SR_BSY) {
if(target_check_error(t)) {
DEBUG_WARN("stm32h7_flash_write: BSY comm failed\n");
return -1;
}
}
if (status & FLASH_SR_ERROR_MASK) {
DEBUG_WARN("stm32h7_flash_write: error sr %08" PRIx32 "\n", status);
return -1;
}
if (!stm32h7_flash_busy_wait(t, sf->regbase))
return false;
/* Close write windows.*/
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,

View File

@ -143,11 +143,11 @@
#define STM32L1_NVM_OPTR_BOR_LEV_M (0xf)
#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 int stm32lx_nvm_prog_write(target_flash_s *f, target_addr_t destination, const void *src, size_t size);
static bool stm32lx_nvm_prog_erase(target_flash_s *f, target_addr_t addr, size_t len);
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 int stm32lx_nvm_data_write(target_flash_s *f, target_addr_t destination, const void *source, size_t size);
static bool stm32lx_nvm_data_erase(target_flash_s *f, target_addr_t addr, size_t len);
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_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);
}
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
interface. This is slower than stubbed versions(see NOTES). The
flash array is erased for all pages from addr to addr+len
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;
const size_t page_size = f->blocksize;
const uint32_t nvm = stm32lx_nvm_phys(t);
if (!stm32lx_nvm_prog_data_unlock(t, nvm))
return -1;
return false;
/* Flash page erase instruction */
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))
return -1;
return false;
/* Clear errors. Note that this only works when we wait for the NVM
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);
/* Wait for completion or an error */
uint32_t sr;
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;
return stm32lx_nvm_busy_wait(t, nvm);
}
/** Write to program flash using operations through the debug
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;
const uint32_t nvm = stm32lx_nvm_phys(t);
if (!stm32lx_nvm_prog_data_unlock(t, nvm))
return -1;
return false;
/* Wait for BSY to clear because we cannot write the PECR until
the previous operation completes on STM32Lxxx. */
while (target_mem_read32(t, STM32Lx_NVM_SR(nvm)) & STM32Lx_NVM_SR_BSY)
if (target_check_error(t))
return -1;
if (!stm32lx_nvm_busy_wait(t, nvm))
return false;
target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PROG | STM32Lx_NVM_PECR_FPRG);
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);
/* Wait for completion or an error */
uint32_t sr;
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;
return stm32lx_nvm_busy_wait(t, nvm);
}
/** Erase a region of data flash using operations through the debug
interface . The flash is erased for all pages from addr to
addr+len, inclusive, on a word boundary. NVM register file
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;
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;
if (!stm32lx_nvm_prog_data_unlock(t, nvm))
return -1;
return false;
/* Flash data erase instruction */
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));
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) {
/* 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);
/* Wait for completion or an error */
uint32_t sr;
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;
return stm32lx_nvm_busy_wait(t, nvm);
}
/** Write to data flash using operations through the debug interface.
NVM register file address chosen from target. Unaligned
destination writes are supported (though unaligned sources are
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;
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;
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);
@ -477,22 +464,14 @@ static int stm32lx_nvm_data_write(target_flash_s *f, target_addr_t destination,
destination += 4;
if (target_check_error(t))
return -1;
return false;
}
/* Disable further programming by locking PECR */
stm32lx_nvm_lock(t, nvm);
/* Wait for completion or an error */
uint32_t sr;
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;
return stm32lx_nvm_busy_wait(t, nvm);
}
/** 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, address, value);
uint32_t sr;
do {
sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm));
} while (sr & STM32Lx_NVM_SR_BSY);
return !(sr & STM32Lx_NVM_SR_ERR_M);
return stm32lx_nvm_busy_wait(t, nvm);
}
/** 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
return false;
uint32_t sr;
do {
sr = target_mem_read32(t, STM32Lx_NVM_SR(nvm));
} while (sr & STM32Lx_NVM_SR_BSY);
return !(sr & STM32Lx_NVM_SR_ERR_M);
return stm32lx_nvm_busy_wait(t, nvm);
}
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}
};
static int 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_erase(target_flash_s *f, target_addr_t addr, 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);
/* 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;
stm32l4_flash_unlock(t);
/* Read FLASH_SR to poll for BSY bit */
while (stm32l4_flash_read32(t, FLASH_SR) & FLASH_SR_BSY) {
if (target_check_error(t))
return -1;
}
if (!stm32l4_flash_busy_wait(t))
return false;
/* Fixme: OPTVER always set after reset! Wrong option defaults?*/
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;
stm32l4_flash_write32(t, FLASH_CR, ctrl_reg);
/* Read FLASH_SR to poll for BSY bit */
while (stm32l4_flash_read32(t, FLASH_SR) & FLASH_SR_BSY) {
if (target_check_error(t))
return -1;
}
if (!stm32l4_flash_busy_wait(t))
return false;
if (len > blocksize)
len -= blocksize;
else
@ -608,32 +618,17 @@ static int stm32l4_flash_erase(target_flash_s *f, target_addr_t addr, size_t len
page++;
}
/* Check for error */
if (stm32l4_flash_read32(t, FLASH_SR) & FLASH_SR_ERROR_MASK)
return -1;
return 0;
return true;
}
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;
stm32l4_flash_write32(t, FLASH_CR, FLASH_CR_PG);
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) {
DEBUG_WARN("stm32l4 flash write error: sr 0x%" PRIx32 "\n", status);
return -1;
}
return 0;
/* Wait for completion or an error */
return stm32l4_flash_busy_wait(t);
}
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 | FLASH_CR_STRT);
/* Read FLASH_SR to poll for BSY bit */
uint32_t sr;
platform_timeout timeout;
platform_timeout_set(&timeout, 500);
/* Read FLASH_SR to poll for BSY bit */
while (stm32l4_flash_read32(t, FLASH_SR) & FLASH_SR_BSY) {
if(target_check_error(t))
do {
sr = stm32l4_flash_read32(t, FLASH_SR);
if ((sr & FLASH_SR_ERROR_MASK) || target_check_error(t))
return false;
target_print_progress(&timeout);
}
} while (sr & FLASH_SR_BSY);
/* Check for error */
return !(stm32l4_flash_read32(t, FLASH_SR) & FLASH_SR_ERROR_MASK);
return true;
}
static bool stm32l4_mass_erase(target *const t)
@ -701,15 +698,13 @@ static bool stm32l4_option_write(
stm32l4_flash_unlock(t);
stm32l4_flash_write32(t, FLASH_OPTKEYR, OPTKEY1);
stm32l4_flash_write32(t, FLASH_OPTKEYR, OPTKEY2);
while (stm32l4_flash_read32(t, FLASH_SR) & FLASH_SR_BSY)
if(target_check_error(t))
return true;
if (!stm32l4_flash_busy_wait(t))
return true;
for (int i = 0; i < len; i++)
target_mem_write32(t, fpec_base + i2offset[i], values[i]);
stm32l4_flash_write32(t, FLASH_CR, FLASH_CR_OPTSTRT);
while (stm32l4_flash_read32(t, FLASH_SR) & FLASH_SR_BSY)
if(target_check_error(t))
return true;
if (!stm32l4_flash_busy_wait(t))
return false;
stm32l4_flash_write32(t, FLASH_CR, FLASH_CR_OBL_LAUNCH);
while (stm32l4_flash_read32(t, FLASH_CR) & FLASH_CR_OBL_LAUNCH)
if(target_check_error(t))