Skip to content

Commit

Permalink
flash: stm32l4: disable dcache before writting
Browse files Browse the repository at this point in the history
Disable the data cache before writing to Flash, in order to workaround
silicon errata 2.2.3: "Data cache might be corrupted during Flash memory
read-while-write operation". The data cache is conditionally re-enabled
once the write is completed.

This silicon bug has been encountered while stress testing the
implementation. Here are the events leading to the fault:
- Code is executing from Flash bank 1
- A write to Flash bank 2 is initiated
- The Cortex SysTick interrupt fires while waiting for Flash write
  completion

In that case, the Flash controller will perform a read-while-write
operation in order to execute the ISR code. As the data cache is enabled
by default after reset, a corruption occurs due to the silicon bug,
leading to bizarre data bus faults or unaligned access faults inside
_timer_int_handler() or one of the functions called by the ISR.

Applying the workaround devised by ST fixes the problem.

Signed-off-by: Florian Vaussard <florian.vaussard@gmail.com>
  • Loading branch information
vaussard authored and galak committed Mar 19, 2019
1 parent 29cc3b5 commit 2320973
Showing 1 changed file with 23 additions and 0 deletions.
23 changes: 23 additions & 0 deletions drivers/flash/flash_stm32l4x.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ static int write_dword(struct device *dev, off_t offset, u64_t val)
{
volatile u32_t *flash = (u32_t *)(offset + CONFIG_FLASH_BASE_ADDRESS);
struct stm32l4x_flash *regs = FLASH_STM32_REGS(dev);
#ifdef FLASH_OPTR_DUALBANK
bool dcache_enabled = false;
#endif /* FLASH_OPTR_DUALBANK */
u32_t tmp;
int rc;

Expand All @@ -68,6 +71,17 @@ static int write_dword(struct device *dev, off_t offset, u64_t val)
return -EIO;
}

#ifdef FLASH_OPTR_DUALBANK
/*
* Disable the data cache to avoid the silicon errata 2.2.3:
* "Data cache might be corrupted during Flash memory read-while-write operation"
*/
if (regs->acr.val & FLASH_ACR_DCEN) {
dcache_enabled = true;
regs->acr.val &= (~FLASH_ACR_DCEN);
}
#endif /* FLASH_OPTR_DUALBANK */

/* Set the PG bit */
regs->cr |= FLASH_CR_PG;

Expand All @@ -84,6 +98,15 @@ static int write_dword(struct device *dev, off_t offset, u64_t val)
/* Clear the PG bit */
regs->cr &= (~FLASH_CR_PG);

#ifdef FLASH_OPTR_DUALBANK
/* Reset/enable the data cache if previously enabled */
if (dcache_enabled) {
regs->acr.val |= FLASH_ACR_DCRST;
regs->acr.val &= (~FLASH_ACR_DCRST);
regs->acr.val |= FLASH_ACR_DCEN;
}
#endif /* FLASH_OPTR_DUALBANK */

return rc;
}

Expand Down

0 comments on commit 2320973

Please sign in to comment.