|
|
@ -290,18 +290,19 @@ bool stm32l0_probe(target *t) |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
/** Lock the NVM control registers preventing writes or erases. */ |
|
|
|
/* Lock the NVM control registers preventing writes or erases. */ |
|
|
|
static void stm32lx_nvm_lock(target *t, uint32_t nvm) |
|
|
|
{ |
|
|
|
target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PELOCK); |
|
|
|
} |
|
|
|
|
|
|
|
/** Unlock the NVM control registers for modifying program or
|
|
|
|
data flash. Returns true if the unlock succeeds. */ |
|
|
|
/*
|
|
|
|
* Unlock the NVM control registers for modifying program or data flash. |
|
|
|
* Returns true if the unlock succeeds. |
|
|
|
*/ |
|
|
|
static bool stm32lx_nvm_prog_data_unlock(target *t, uint32_t nvm) |
|
|
|
{ |
|
|
|
/* Always lock first because that's the only way to know that the
|
|
|
|
unlock can succeed on the STM32L0's. */ |
|
|
|
/* Always lock first because that's the only way to know that the unlock can succeed on the STM32L0's. */ |
|
|
|
target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PELOCK); |
|
|
|
target_mem_write32(t, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY1); |
|
|
|
target_mem_write32(t, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY2); |
|
|
@ -311,12 +312,13 @@ static bool stm32lx_nvm_prog_data_unlock(target *t, uint32_t nvm) |
|
|
|
return !(target_mem_read32(t, STM32Lx_NVM_PECR(nvm)) & STM32Lx_NVM_PECR_PRGLOCK); |
|
|
|
} |
|
|
|
|
|
|
|
/** Unlock the NVM control registers for modifying option bytes.
|
|
|
|
Returns true if the unlock succeeds. */ |
|
|
|
/*
|
|
|
|
* Unlock the NVM control registers for modifying option bytes. |
|
|
|
* Returns true if the unlock succeeds. |
|
|
|
*/ |
|
|
|
static bool stm32lx_nvm_opt_unlock(target *t, uint32_t nvm) |
|
|
|
{ |
|
|
|
/* Always lock first because that's the only way to know that the
|
|
|
|
unlock can succeed on the STM32L0's. */ |
|
|
|
/* Always lock first because that's the only way to know that the unlock can succeed on the STM32L0's. */ |
|
|
|
target_mem_write32(t, STM32Lx_NVM_PECR(nvm), STM32Lx_NVM_PECR_PELOCK); |
|
|
|
target_mem_write32(t, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY1); |
|
|
|
target_mem_write32(t, STM32Lx_NVM_PEKEYR(nvm), STM32Lx_NVM_PEKEY2); |
|
|
@ -326,10 +328,12 @@ static bool stm32lx_nvm_opt_unlock(target *t, uint32_t nvm) |
|
|
|
return !(target_mem_read32(t, STM32Lx_NVM_PECR(nvm)) & STM32Lx_NVM_PECR_OPTLOCK); |
|
|
|
} |
|
|
|
|
|
|
|
/** 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. */ |
|
|
|
/*
|
|
|
|
* 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 + length inclusive. |
|
|
|
* The NVM register base is automatically determined based on the target. |
|
|
|
*/ |
|
|
|
static int stm32lx_nvm_prog_erase(struct target_flash *f, const target_addr addr, const size_t length) |
|
|
|
{ |
|
|
|
target *t = f->t; |
|
|
@ -376,8 +380,7 @@ static int stm32lx_nvm_prog_erase(struct target_flash *f, const target_addr addr |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/** Write to program flash using operations through the debug
|
|
|
|
interface. */ |
|
|
|
/* Write to program flash using operations through the debug interface. */ |
|
|
|
static int stm32lx_nvm_prog_write(struct target_flash *f, target_addr dest, const void *src, size_t length) |
|
|
|
{ |
|
|
|
target *t = f->t; |
|
|
@ -386,8 +389,7 @@ static int stm32lx_nvm_prog_write(struct target_flash *f, target_addr dest, cons |
|
|
|
if (!stm32lx_nvm_prog_data_unlock(t, nvm)) |
|
|
|
return -1; |
|
|
|
|
|
|
|
/* Wait for BSY to clear because we cannot write the PECR until
|
|
|
|
the previous operation completes on STM32Lxxx. */ |
|
|
|
/* Wait for BSY to clear because we cannot write the PECR until the previous operation completes */ |
|
|
|
while (target_mem_read32(t, STM32Lx_NVM_SR(nvm)) & STM32Lx_NVM_SR_BSY) { |
|
|
|
if (target_check_error(t)) |
|
|
|
return -1; |
|
|
@ -410,10 +412,11 @@ static int stm32lx_nvm_prog_write(struct target_flash *f, target_addr dest, cons |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/** 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. */ |
|
|
|
/*
|
|
|
|
* Erase a region of data flash using operations through the debug interface. |
|
|
|
* The flash is erased for all pages from addr to addr + length, inclusive, on a word boundary. |
|
|
|
* The NVM register base is automatically determined based on the target. |
|
|
|
*/ |
|
|
|
static int stm32lx_nvm_data_erase(struct target_flash *f, const target_addr addr, const size_t length) |
|
|
|
{ |
|
|
|
target *t = f->t; |
|
|
@ -449,10 +452,11 @@ static int stm32lx_nvm_data_erase(struct target_flash *f, const target_addr addr |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
/** 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). */ |
|
|
|
/*
|
|
|
|
* Write to data flash using operations through the debug interface. |
|
|
|
* The NVM register base is automatically determined based on the target. |
|
|
|
* Unaligned destination writes are supported (though unaligned sources are not). |
|
|
|
*/ |
|
|
|
static int stm32lx_nvm_data_write(struct target_flash *f, target_addr dest, const void *src, const size_t length) |
|
|
|
{ |
|
|
|
target *t = f->t; |
|
|
|