target/stm: flash read write return bool
This commit is contained in:
parent
67c9f3f6e2
commit
085dcb7bc9
|
@ -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)
|
||||||
|
|
|
@ -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.*/
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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))
|
||||||
|
|
Loading…
Reference in New Issue