From 1320d97e89b816f20d5007ddabb5fef749ca61ec Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 26 Nov 2024 14:02:08 +0100 Subject: [PATCH 1/2] cpu/sam0_common: flashpage: disable cache while writing fix errata 2.14.1: NVM Read Corruption --- cpu/sam0_common/periph/flashpage.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cpu/sam0_common/periph/flashpage.c b/cpu/sam0_common/periph/flashpage.c index 3481229870fb..ba49aa3d1db0 100644 --- a/cpu/sam0_common/periph/flashpage.c +++ b/cpu/sam0_common/periph/flashpage.c @@ -73,7 +73,12 @@ static unsigned _unlock(void) PAC1->WPCLR.reg = PAC1_WPROT_DEFAULT_VAL; #endif + /* NVM reads could be corrupted when mixing NVM reads with Page Buffer writes. */ return irq_disable(); +#ifdef NVMCTRL_CTRLA_CACHEDIS1 + _NVMCTRL->CTRLA.reg |= NVMCTRL_CTRLA_CACHEDIS0 + | NVMCTRL_CTRLA_CACHEDIS1; +#endif } static void _lock(unsigned state) @@ -87,6 +92,11 @@ static void _lock(unsigned state) PAC1->WPSET.reg = PAC1_WPROT_DEFAULT_VAL; #endif +#ifdef NVMCTRL_CTRLA_CACHEDIS1 + _NVMCTRL->CTRLA.reg &= ~NVMCTRL_CTRLA_CACHEDIS0 + & ~NVMCTRL_CTRLA_CACHEDIS1; +#endif + /* cached flash contents may have changed - invalidate cache */ #ifdef CMCC CMCC->MAINT0.reg |= CMCC_MAINT0_INVALL; From fd49d16cbab8f9046374f07d2008c0fb2d2593ea Mon Sep 17 00:00:00 2001 From: Benjamin Valentin Date: Tue, 26 Nov 2024 14:04:35 +0100 Subject: [PATCH 2/2] cpu/sam0_common: flashpage: don't disable interruipts while writing --- cpu/sam0_common/periph/flashpage.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/cpu/sam0_common/periph/flashpage.c b/cpu/sam0_common/periph/flashpage.c index ba49aa3d1db0..d128e88f0d77 100644 --- a/cpu/sam0_common/periph/flashpage.c +++ b/cpu/sam0_common/periph/flashpage.c @@ -64,7 +64,7 @@ static inline void wait_nvm_is_ready(void) #endif } -static unsigned _unlock(void) +static void _unlock(void) { /* remove peripheral access lock for the NVMCTRL peripheral */ #ifdef REG_PAC_WRCTRL @@ -74,14 +74,13 @@ static unsigned _unlock(void) #endif /* NVM reads could be corrupted when mixing NVM reads with Page Buffer writes. */ - return irq_disable(); #ifdef NVMCTRL_CTRLA_CACHEDIS1 _NVMCTRL->CTRLA.reg |= NVMCTRL_CTRLA_CACHEDIS0 | NVMCTRL_CTRLA_CACHEDIS1; #endif } -static void _lock(unsigned state) +static void _lock(void) { wait_nvm_is_ready(); @@ -101,8 +100,6 @@ static void _lock(unsigned state) #ifdef CMCC CMCC->MAINT0.reg |= CMCC_MAINT0_INVALL; #endif - - irq_restore(state); } static void _cmd_clear_page_buffer(void) @@ -239,7 +236,7 @@ static void _write_page(void* dst, const void *data, size_t len, void (*cmd_writ /* word align destination address */ uint32_t *dst32 = (void*)((uintptr_t)dst & ~0x3); - unsigned state = _unlock(); + _unlock(); _cmd_clear_page_buffer(); /* write the first, unaligned bytes */ @@ -266,7 +263,7 @@ static void _write_page(void* dst, const void *data, size_t len, void (*cmd_writ } cmd_write(); - _lock(state); + _lock(); } static void _erase_page(void* page, void (*cmd_erase)(void)) @@ -274,7 +271,7 @@ static void _erase_page(void* page, void (*cmd_erase)(void)) uintptr_t page_addr = (uintptr_t)page; /* erase given page (the ADDR register uses 16-bit addresses) */ - unsigned state = _unlock(); + _unlock(); /* ADDR drives the hardware (16-bit) address to the NVM when a command is executed using CMDEX. * 8-bit addresses must be shifted one bit to the right before writing to this register. @@ -287,7 +284,7 @@ static void _erase_page(void* page, void (*cmd_erase)(void)) _NVMCTRL->ADDR.reg = page_addr; cmd_erase(); - _lock(state); + _lock(); } static void _write_row(uint8_t *dst, const void *_data, size_t len, size_t chunk_size,